Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/SoftEtherVPN/SoftEtherVPN_Stable.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src/Cedar
diff options
context:
space:
mode:
Diffstat (limited to 'src/Cedar')
-rw-r--r--src/Cedar/Account.c1419
-rw-r--r--src/Cedar/Account.h293
-rw-r--r--src/Cedar/Admin.c13742
-rw-r--r--src/Cedar/Admin.h1505
-rw-r--r--src/Cedar/AzureClient.c658
-rw-r--r--src/Cedar/AzureClient.h149
-rw-r--r--src/Cedar/AzureServer.c90
-rw-r--r--src/Cedar/AzureServer.h94
-rw-r--r--src/Cedar/Bridge.c532
-rw-r--r--src/Cedar/Bridge.h152
-rw-r--r--src/Cedar/BridgeUnix.c1813
-rw-r--r--src/Cedar/BridgeUnix.h191
-rw-r--r--src/Cedar/BridgeWin32.c2217
-rw-r--r--src/Cedar/BridgeWin32.h238
-rw-r--r--src/Cedar/CM.c12394
-rw-r--r--src/Cedar/CM.h132
-rw-r--r--src/Cedar/CMInner.h612
-rw-r--r--src/Cedar/Cedar.c1708
-rw-r--r--src/Cedar/Cedar.h1194
-rw-r--r--src/Cedar/Cedar.vcproj1529
-rw-r--r--src/Cedar/CedarPch.c89
-rw-r--r--src/Cedar/CedarPch.h100
-rw-r--r--src/Cedar/CedarType.h720
-rw-r--r--src/Cedar/Client.c11005
-rw-r--r--src/Cedar/Client.h849
-rw-r--r--src/Cedar/Command.c23538
-rw-r--r--src/Cedar/Command.h648
-rw-r--r--src/Cedar/Connection.c3457
-rw-r--r--src/Cedar/Connection.h341
-rw-r--r--src/Cedar/Console.c2510
-rw-r--r--src/Cedar/Console.h222
-rw-r--r--src/Cedar/DDNS.c984
-rw-r--r--src/Cedar/DDNS.h215
-rw-r--r--src/Cedar/Database.c239
-rw-r--r--src/Cedar/Database.h98
-rw-r--r--src/Cedar/EM.c1476
-rw-r--r--src/Cedar/EM.h96
-rw-r--r--src/Cedar/EMInner.h122
-rw-r--r--src/Cedar/EtherLog.c1356
-rw-r--r--src/Cedar/EtherLog.h255
-rw-r--r--src/Cedar/Hub.c7123
-rw-r--r--src/Cedar/Hub.h598
-rw-r--r--src/Cedar/IPsec.c767
-rw-r--r--src/Cedar/IPsec.h179
-rw-r--r--src/Cedar/IPsec_EtherIP.c539
-rw-r--r--src/Cedar/IPsec_EtherIP.h150
-rw-r--r--src/Cedar/IPsec_IKE.c5947
-rw-r--r--src/Cedar/IPsec_IKE.h450
-rw-r--r--src/Cedar/IPsec_IPC.c2028
-rw-r--r--src/Cedar/IPsec_IPC.h243
-rw-r--r--src/Cedar/IPsec_IkePacket.c3129
-rw-r--r--src/Cedar/IPsec_IkePacket.h711
-rw-r--r--src/Cedar/IPsec_L2TP.c2498
-rw-r--r--src/Cedar/IPsec_L2TP.h347
-rw-r--r--src/Cedar/IPsec_PPP.c2689
-rw-r--r--src/Cedar/IPsec_PPP.h311
-rw-r--r--src/Cedar/IPsec_Win7.c530
-rw-r--r--src/Cedar/IPsec_Win7.h121
-rw-r--r--src/Cedar/IPsec_Win7Inner.h160
-rw-r--r--src/Cedar/Interop_OpenVPN.c2942
-rw-r--r--src/Cedar/Interop_OpenVPN.h362
-rw-r--r--src/Cedar/Interop_SSTP.c1222
-rw-r--r--src/Cedar/Interop_SSTP.h238
-rw-r--r--src/Cedar/Layer3.c2173
-rw-r--r--src/Cedar/Layer3.h229
-rw-r--r--src/Cedar/Link.c655
-rw-r--r--src/Cedar/Link.h139
-rw-r--r--src/Cedar/Listener.c1079
-rw-r--r--src/Cedar/Listener.h188
-rw-r--r--src/Cedar/Logging.c2054
-rw-r--r--src/Cedar/Logging.h248
-rw-r--r--src/Cedar/NM.c1516
-rw-r--r--src/Cedar/NM.h96
-rw-r--r--src/Cedar/NMInner.h148
-rw-r--r--src/Cedar/Nat.c1876
-rw-r--r--src/Cedar/Nat.h291
-rw-r--r--src/Cedar/NativeStack.c417
-rw-r--r--src/Cedar/NativeStack.h123
-rw-r--r--src/Cedar/NullLan.c256
-rw-r--r--src/Cedar/NullLan.h117
-rw-r--r--src/Cedar/Protocol.c6535
-rw-r--r--src/Cedar/Protocol.h270
-rw-r--r--src/Cedar/Radius.c90
-rw-r--r--src/Cedar/Radius.h99
-rw-r--r--src/Cedar/Remote.c448
-rw-r--r--src/Cedar/Remote.h127
-rw-r--r--src/Cedar/SM.c20505
-rw-r--r--src/Cedar/SM.h95
-rw-r--r--src/Cedar/SMInner.h801
-rw-r--r--src/Cedar/SW.c6569
-rw-r--r--src/Cedar/SW.h105
-rw-r--r--src/Cedar/SWInner.h425
-rw-r--r--src/Cedar/Sam.c415
-rw-r--r--src/Cedar/Sam.h106
-rw-r--r--src/Cedar/SeLowUser.c772
-rw-r--r--src/Cedar/SeLowUser.h154
-rw-r--r--src/Cedar/SecureInfo.c90
-rw-r--r--src/Cedar/SecureInfo.h94
-rw-r--r--src/Cedar/SecureNAT.c228
-rw-r--r--src/Cedar/SecureNAT.h108
-rw-r--r--src/Cedar/Server.c10466
-rw-r--r--src/Cedar/Server.h664
-rw-r--r--src/Cedar/Session.c2242
-rw-r--r--src/Cedar/Session.h408
-rw-r--r--src/Cedar/UT.c393
-rw-r--r--src/Cedar/UT.h112
-rw-r--r--src/Cedar/UdpAccel.c1157
-rw-r--r--src/Cedar/UdpAccel.h195
-rw-r--r--src/Cedar/VG.c105
-rw-r--r--src/Cedar/VG.h101
-rw-r--r--src/Cedar/VLan.c108
-rw-r--r--src/Cedar/VLan.h112
-rw-r--r--src/Cedar/VLanUnix.c791
-rw-r--r--src/Cedar/VLanUnix.h144
-rw-r--r--src/Cedar/VLanWin32.c1587
-rw-r--r--src/Cedar/VLanWin32.h174
-rw-r--r--src/Cedar/Virtual.c10117
-rw-r--r--src/Cedar/Virtual.h659
-rw-r--r--src/Cedar/WaterMark.c4386
-rw-r--r--src/Cedar/WaterMark.h110
-rw-r--r--src/Cedar/WebUI.c1961
-rw-r--r--src/Cedar/WebUI.h119
-rw-r--r--src/Cedar/Win32Com.cpp979
-rw-r--r--src/Cedar/Win32Com.h400
-rw-r--r--src/Cedar/WinJumpList.cpp759
-rw-r--r--src/Cedar/WinUi.c11339
-rw-r--r--src/Cedar/WinUi.h906
-rw-r--r--src/Cedar/Wpc.c1326
-rw-r--r--src/Cedar/Wpc.h201
-rw-r--r--src/Cedar/netcfgn.h1335
-rw-r--r--src/Cedar/netcfgx.h1941
-rw-r--r--src/Cedar/winpcap/Devioctl.h90
-rw-r--r--src/Cedar/winpcap/Gnuc.h46
-rw-r--r--src/Cedar/winpcap/Ntddndis.h1400
-rw-r--r--src/Cedar/winpcap/Ntddpack.h26
-rw-r--r--src/Cedar/winpcap/Packet32.h423
-rw-r--r--src/Cedar/winpcap/Win32-Extensions.h86
-rw-r--r--src/Cedar/winpcap/bittypes.h135
-rw-r--r--src/Cedar/winpcap/bucket_lookup.h54
-rw-r--r--src/Cedar/winpcap/count_packets.h62
-rw-r--r--src/Cedar/winpcap/ip6_misc.h163
-rw-r--r--src/Cedar/winpcap/memory_t.h132
-rw-r--r--src/Cedar/winpcap/normal_lookup.h56
-rw-r--r--src/Cedar/winpcap/pcap-bpf.h685
-rw-r--r--src/Cedar/winpcap/pcap-int.h368
-rw-r--r--src/Cedar/winpcap/pcap-stdinc.h65
-rw-r--r--src/Cedar/winpcap/pcap.h337
-rw-r--r--src/Cedar/winpcap/pthread.h1300
-rw-r--r--src/Cedar/winpcap/remote-ext.h420
-rw-r--r--src/Cedar/winpcap/sched.h174
-rw-r--r--src/Cedar/winpcap/semaphore.h163
-rw-r--r--src/Cedar/winpcap/tcp_session.h96
-rw-r--r--src/Cedar/winpcap/time_calls.h438
-rw-r--r--src/Cedar/winpcap/tme.h174
154 files changed, 234097 insertions, 0 deletions
diff --git a/src/Cedar/Account.c b/src/Cedar/Account.c
new file mode 100644
index 00000000..42acda2e
--- /dev/null
+++ b/src/Cedar/Account.c
@@ -0,0 +1,1419 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Account.c
+// Account Manager
+
+#include "CedarPch.h"
+
+// Policy items
+POLICY_ITEM policy_item[] =
+{
+// ID, Value, Omittable, Min, Max, Default, Unit name
+// Ver 2.0
+ {0, false, false, 0, 0, 0, NULL}, // Access
+ {1, false, false, 0, 0, 0, NULL}, // DHCPFilter
+ {2, false, false, 0, 0, 0, NULL}, // DHCPNoServer
+ {3, false, false, 0, 0, 0, NULL}, // DHCPForce
+ {4, false, false, 0, 0, 0, NULL}, // NoBridge
+ {5, false, false, 0, 0, 0, NULL}, // NoRouting
+ {6, false, false, 0, 0, 0, NULL}, // CheckMac
+ {7, false, false, 0, 0, 0, NULL}, // CheckIP
+ {8, false, false, 0, 0, 0, NULL}, // ArpDhcpOnly
+ {9, false, false, 0, 0, 0, NULL}, // PrivacyFilter
+ {10, false, false, 0, 0, 0, NULL}, // NoServer
+ {11, false, false, 0, 0, 0, NULL}, // NoBroadcastLimiter
+ {12, false, false, 0, 0, 0, NULL}, // MonitorPort
+ {13, true, false, 1, 32, 32, "POL_INT_COUNT"}, // MaxConnection
+ {14, true, false, 5, 60, 20, "POL_INT_SEC"}, // TimeOut
+ {15, true, true, 1, 65535, 0, "POL_INT_COUNT"}, // MaxMac
+ {16, true, true, 1, 65535, 0, "POL_INT_COUNT"}, // MaxIP
+ {17, true, true, 1, 4294967295UL, 0, "POL_INT_BPS"}, // MaxUpload
+ {18, true, true, 1, 4294967295UL, 0, "POL_INT_BPS"}, // MaxDownload
+ {19, false, false, 0, 0, 0, NULL}, // FixPassword
+ {20, true, true, 1, 65535, 0, "POL_INT_COUNT"}, // MultiLogins
+ {21, false, false, 0, 0, 0, NULL}, // NoQoS
+// Ver 3.0
+ {22, false, false, 0, 0, 0, NULL}, // RSandRAFilter
+ {23, false, false, 0, 0, 0, NULL}, // RAFilter
+ {24, false, false, 0, 0, 0, NULL}, // DHCPv6Filter
+ {25, false, false, 0, 0, 0, NULL}, // DHCPv6NoServer
+ {26, false, false, 0, 0, 0, NULL}, // NoRoutingV6
+ {27, false, false, 0, 0, 0, NULL}, // CheckIPv6
+ {28, false, false, 0, 0, 0, NULL}, // NoServerV6
+ {29, true, true, 1, 65535, 0, "POL_INT_COUNT"}, // MaxIPv6
+ {30, false, false, 0, 0, 0, NULL}, // NoSavePassword
+ {31, true, true, 1, 4294967295UL, 0, "POL_INT_SEC"}, // AutoDisconnect
+ {32, false, false, 0, 0, 0, NULL}, // FilterIPv4
+ {33, false, false, 0, 0, 0, NULL}, // FilterIPv6
+ {34, false, false, 0, 0, 0, NULL}, // FilterNonIP
+ {35, false, false, 0, 0, 0, NULL}, // NoIPv6DefaultRouterInRA
+ {36, false, false, 0, 0, 0, NULL}, // NoIPv6DefaultRouterInRAWhenIPv6
+ {37, true, true, 1, 4095, 0, "POL_INT_VLAN"}, // VLanId
+};
+
+// Normalize policy name
+char *NormalizePolicyName(char *name)
+{
+ // Validate arguments
+ if (name == NULL)
+ {
+ return NULL;
+ }
+
+ return PolicyIdToStr(PolicyStrToId(name));
+}
+
+// Format policy value
+void FormatPolicyValue(wchar_t *str, UINT size, UINT id, UINT value)
+{
+ POLICY_ITEM *p;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return;
+ }
+
+ p = GetPolicyItem(id);
+
+ if (p->TypeInt == false)
+ {
+ // bool type
+ if (value == 0)
+ {
+ UniStrCpy(str, size, L"No");
+ }
+ else
+ {
+ UniStrCpy(str, size, L"Yes");
+ }
+ }
+ else
+ {
+ // int type
+ if (value == 0 && p->AllowZero)
+ {
+ UniStrCpy(str, size, _UU("CMD_NO_SETTINGS"));
+ }
+ else
+ {
+ UniFormat(str, size, _UU(p->FormatStr), value);
+ }
+ }
+}
+
+// Get description string for range of the policy value
+void GetPolicyValueRangeStr(wchar_t *str, UINT size, UINT id)
+{
+ POLICY_ITEM *p;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return;
+ }
+
+ p = GetPolicyItem(id);
+
+ if (p->TypeInt == false)
+ {
+ // bool type
+ UniStrCpy(str, size, _UU("CMD_PolicyList_Range_Bool"));
+ }
+ else
+ {
+ wchar_t *tag;
+ wchar_t tmp1[256], tmp2[256];
+
+ // int type
+ if (p->AllowZero)
+ {
+ tag = _UU("CMD_PolicyList_Range_Int_2");
+ }
+ else
+ {
+ tag = _UU("CMD_PolicyList_Range_Int_1");
+ }
+
+ UniFormat(tmp1, sizeof(tmp1), _UU(p->FormatStr), p->MinValue);
+ UniFormat(tmp2, sizeof(tmp2), _UU(p->FormatStr), p->MaxValue);
+
+ UniFormat(str, size, tag, tmp1, tmp2);
+ }
+}
+
+// Get a policy item for id
+POLICY_ITEM *GetPolicyItem(UINT id)
+{
+ return &policy_item[id];
+}
+
+// Does cascade connection support the specified policy?
+bool PolicyIsSupportedForCascade(UINT i)
+{
+ if (i == 0 || i == 4 || i == 5 || i == 9 || i == 12 || i == 13 ||
+ i == 14 || i == 19 || i == 20 || i == 21 || i == 26 || i == 30 || i == 31 || i == 36)
+ {
+ // These items are not supported by cascade connection.
+ return false;
+ }
+
+ return true;
+}
+
+// Get policy name
+char *PolicyIdToStr(UINT i)
+{
+ switch (i)
+ {
+ // Ver 2.0
+ case 0: return "Access";
+ case 1: return "DHCPFilter";
+ case 2: return "DHCPNoServer";
+ case 3: return "DHCPForce";
+ case 4: return "NoBridge";
+ case 5: return "NoRouting";
+ case 6: return "CheckMac";
+ case 7: return "CheckIP";
+ case 8: return "ArpDhcpOnly";
+ case 9: return "PrivacyFilter";
+ case 10: return "NoServer";
+ case 11: return "NoBroadcastLimiter";
+ case 12: return "MonitorPort";
+ case 13: return "MaxConnection";
+ case 14: return "TimeOut";
+ case 15: return "MaxMac";
+ case 16: return "MaxIP";
+ case 17: return "MaxUpload";
+ case 18: return "MaxDownload";
+ case 19: return "FixPassword";
+ case 20: return "MultiLogins";
+ case 21: return "NoQoS";
+
+ // Ver 3.0
+ case 22: return "RSandRAFilter";
+ case 23: return "RAFilter";
+ case 24: return "DHCPv6Filter";
+ case 25: return "DHCPv6NoServer";
+ case 26: return "NoRoutingV6";
+ case 27: return "CheckIPv6";
+ case 28: return "NoServerV6";
+ case 29: return "MaxIPv6";
+ case 30: return "NoSavePassword";
+ case 31: return "AutoDisconnect";
+ case 32: return "FilterIPv4";
+ case 33: return "FilterIPv6";
+ case 34: return "FilterNonIP";
+ case 35: return "NoIPv6DefaultRouterInRA";
+ case 36: return "NoIPv6DefaultRouterInRAWhenIPv6";
+ case 37: return "VLanId";
+ }
+
+ return NULL;
+}
+
+// Get policy id for name
+UINT PolicyStrToId(char *name)
+{
+ UINT i;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return INFINITE;
+ }
+
+ for (i = 0;i < NUM_POLICY_ITEM;i++)
+ {
+ if (StartWith(PolicyIdToStr(i), name))
+ {
+ return i;
+ }
+ }
+
+ return INFINITE;
+}
+
+// Get number of policies
+UINT PolicyNum()
+{
+ return NUM_POLICY_ITEM;
+}
+
+// Check the name is valid for account name
+bool IsUserName(char *name)
+{
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (name == NULL)
+ {
+ return false;
+ }
+
+ StrCpy(tmp, sizeof(tmp), name);
+ name = tmp;
+
+ Trim(name);
+
+ if (StrLen(name) == 0)
+ {
+ return false;
+ }
+
+ if (StrCmpi(name, "*") == 0)
+ {
+ return true;
+ }
+
+ if (IsSafeStr(name) == false)
+ {
+ return false;
+ }
+
+ if (StrCmpi(name, LINK_USER_NAME) == 0)
+ {
+ return false;
+ }
+
+ if (StartWith(name, L3_USERNAME))
+ {
+ return false;
+ }
+
+ if (StrCmpi(name, LINK_USER_NAME_PRINT) == 0)
+ {
+ return false;
+ }
+
+ if (StrCmpi(name, SNAT_USER_NAME) == 0)
+ {
+ return false;
+ }
+
+ if (StrCmpi(name, SNAT_USER_NAME_PRINT) == 0)
+ {
+ return false;
+ }
+
+ if (StrCmpi(name, BRIDGE_USER_NAME) == 0)
+ {
+ return false;
+ }
+
+ if (StrCmpi(name, BRIDGE_USER_NAME_PRINT) == 0)
+ {
+ return false;
+ }
+
+ if (StrCmpi(name, ADMINISTRATOR_USERNAME) == 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Get policy title
+wchar_t *GetPolicyTitle(UINT id)
+{
+ char tmp[MAX_SIZE];
+ Format(tmp, sizeof(tmp), "POL_%u", id);
+
+ return _UU(tmp);
+}
+
+// Get policy description
+wchar_t *GetPolicyDescription(UINT id)
+{
+ char tmp[MAX_SIZE];
+ Format(tmp, sizeof(tmp), "POL_EX_%u", id);
+
+ return _UU(tmp);
+}
+
+// Clone the policy value
+POLICY *ClonePolicy(POLICY *policy)
+{
+ POLICY *ret;
+ // Validate arguments
+ if (policy == NULL)
+ {
+ return NULL;
+ }
+
+ ret = ZeroMalloc(sizeof(POLICY));
+ Copy(ret, policy, sizeof(POLICY));
+
+ return ret;
+}
+
+// Overwrite policy value (If old version data overwrites new version, leave new version value as it is.)
+void OverwritePolicy(POLICY **target, POLICY *p)
+{
+ // Validate arguments
+ if (target == NULL)
+ {
+ return;
+ }
+
+ if (p == NULL)
+ {
+ // Erase policy
+ if (*target != NULL)
+ {
+ Free(*target);
+ *target = NULL;
+ }
+ }
+ else
+ {
+ if (p->Ver3)
+ {
+ // Ver 3
+ if (*target != NULL)
+ {
+ Free(*target);
+ *target = NULL;
+ }
+
+ *target = ClonePolicy(p);
+ }
+ else
+ {
+ // Ver 2
+ if (*target == NULL)
+ {
+ *target = ClonePolicy(p);
+ }
+ else
+ {
+ Copy(*target, p, NUM_POLICY_ITEM_FOR_VER2 * sizeof(UINT));
+ }
+ }
+ }
+}
+
+// Set user policy
+void SetUserPolicy(USER *u, POLICY *policy)
+{
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+
+ Lock(u->lock);
+ {
+ OverwritePolicy(&u->Policy, policy);
+ }
+ Unlock(u->lock);
+}
+
+// Get user policy
+POLICY *GetUserPolicy(USER *u)
+{
+ POLICY *ret;
+ // Validate arguments
+ if (u == NULL)
+ {
+ return NULL;
+ }
+
+ Lock(u->lock);
+ {
+ if (u->Policy == NULL)
+ {
+ ret = NULL;
+ }
+ else
+ {
+ ret = ClonePolicy(u->Policy);
+ }
+ }
+ Unlock(u->lock);
+
+ return ret;
+}
+
+// Set group policy
+void SetGroupPolicy(USERGROUP *g, POLICY *policy)
+{
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ Lock(g->lock);
+ {
+ OverwritePolicy(&g->Policy, policy);
+ }
+ Unlock(g->lock);
+}
+
+// Get group policy
+POLICY *GetGroupPolicy(USERGROUP *g)
+{
+ POLICY *ret;
+ // Validate arguments
+ if (g == NULL)
+ {
+ return NULL;
+ }
+
+ Lock(g->lock);
+ {
+ if (g->Policy == NULL)
+ {
+ ret = NULL;
+ }
+ else
+ {
+ ret = ClonePolicy(g->Policy);
+ }
+ }
+ Unlock(g->lock);
+
+ return ret;
+}
+
+// Get default policy template
+POLICY *GetDefaultPolicy()
+{
+ static POLICY def_policy =
+ {
+ true,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ 32,
+ 20,
+ 0,
+ 0,
+ 0,
+ 0,
+ false,
+ 0,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ false,
+ 0,
+ false,
+ 0,
+ false,
+ false,
+ false,
+ false,
+ false,
+ };
+
+ return &def_policy;
+}
+
+// Create a NT authentication data
+void *NewNTAuthData(wchar_t *username)
+{
+ AUTHNT *a;
+ // Validate arguments
+ a = ZeroMallocEx(sizeof(AUTHNT), true);
+ a->NtUsername = CopyUniStr(username);
+
+ return a;
+}
+
+// Create a Radius authentication data
+void *NewRadiusAuthData(wchar_t *username)
+{
+ AUTHRADIUS *a;
+ // Validate arguments
+ a = ZeroMallocEx(sizeof(AUTHRADIUS), true);
+ a->RadiusUsername = CopyUniStr(username);
+
+ return a;
+}
+
+// Create a root certification authentication data
+void *NewRootCertAuthData(X_SERIAL *serial, wchar_t *common_name)
+{
+ AUTHROOTCERT *a;
+
+ a = ZeroMallocEx(sizeof(AUTHROOTCERT), true);
+ if (common_name != NULL && UniIsEmptyStr(common_name) == false)
+ {
+ a->CommonName = CopyUniStr(common_name);
+ }
+ if (serial != NULL && serial->size >= 1)
+ {
+ a->Serial = CloneXSerial(serial);
+ }
+
+ return a;
+}
+
+// Create an authentication data for user certification
+void *NewUserCertAuthData(X *x)
+{
+ AUTHUSERCERT *a;
+
+ a = ZeroMalloc(sizeof(AUTHUSERCERT));
+ a->UserX = CloneX(x);
+
+ return a;
+}
+
+// Hash the password
+void HashPassword(void *dst, char *username, char *password)
+{
+ BUF *b;
+ char *username_upper;
+ // Validate arguments
+ if (dst == NULL || username == NULL || password == NULL)
+ {
+ return;
+ }
+
+ b = NewBuf();
+ username_upper = CopyStr(username);
+ StrUpper(username_upper);
+ WriteBuf(b, password, StrLen(password));
+ WriteBuf(b, username_upper, StrLen(username_upper));
+ Hash(dst, b->Buf, b->Size, true);
+
+ FreeBuf(b);
+ Free(username_upper);
+}
+
+// Create a password authentication data
+void *NewPasswordAuthData(char *username, char *password)
+{
+ AUTHPASSWORD *pw;
+ // Validate arguments
+ if (username == NULL || password == NULL)
+ {
+ return NULL;
+ }
+
+ pw = ZeroMalloc(sizeof(AUTHPASSWORD));
+ HashPassword(pw->HashedKey, username, password);
+ GenerateNtPasswordHash(pw->NtLmSecureHash, password);
+
+ return pw;
+}
+
+// Create a password authentication data for the hashed password
+void *NewPasswordAuthDataRaw(UCHAR *hashed_password, UCHAR *ntlm_secure_hash)
+{
+ AUTHPASSWORD *pw;
+ // Validate arguments
+ if (hashed_password == NULL)
+ {
+ return NULL;
+ }
+
+ pw = ZeroMalloc(sizeof(AUTHPASSWORD));
+ Copy(pw->HashedKey, hashed_password, SHA1_SIZE);
+
+ if (ntlm_secure_hash != NULL)
+ {
+ Copy(pw->NtLmSecureHash, ntlm_secure_hash, MD5_SIZE);
+ }
+
+ return pw;
+}
+
+// Clone authentication data
+void *CopyAuthData(void *authdata, UINT authtype)
+{
+ AUTHPASSWORD *pw = (AUTHPASSWORD *)authdata;
+ AUTHUSERCERT *usercert = (AUTHUSERCERT *)authdata;
+ AUTHROOTCERT *rootcert = (AUTHROOTCERT *)authdata;
+ AUTHRADIUS *radius = (AUTHRADIUS *)authdata;
+ AUTHNT *nt = (AUTHNT *)authdata;
+ // Validate arguments
+ if (authdata == NULL || authtype == AUTHTYPE_ANONYMOUS)
+ {
+ return NULL;
+ }
+
+ switch (authtype)
+ {
+ case AUTHTYPE_PASSWORD:
+ {
+ AUTHPASSWORD *ret = ZeroMalloc(sizeof(AUTHPASSWORD));
+ Copy(ret, pw, sizeof(AUTHPASSWORD));
+ return ret;
+ }
+ break;
+
+ case AUTHTYPE_USERCERT:
+ {
+ AUTHUSERCERT *ret = ZeroMalloc(sizeof(AUTHUSERCERT));
+ ret->UserX = CloneX(usercert->UserX);
+ return ret;
+ }
+ break;
+
+ case AUTHTYPE_ROOTCERT:
+ {
+ AUTHROOTCERT *ret = ZeroMalloc(sizeof(AUTHROOTCERT));
+ ret->CommonName = CopyUniStr(rootcert->CommonName);
+ ret->Serial = CloneXSerial(rootcert->Serial);
+ return ret;
+ }
+ break;
+
+ case AUTHTYPE_RADIUS:
+ {
+ AUTHRADIUS *ret = ZeroMalloc(sizeof(AUTHRADIUS));
+ ret->RadiusUsername = UniCopyStr(radius->RadiusUsername);
+ return ret;
+ }
+ break;
+
+ case AUTHTYPE_NT:
+ {
+ AUTHNT *ret = ZeroMalloc(sizeof(AUTHNT));
+ ret->NtUsername = UniCopyStr(nt->NtUsername);
+ return ret;
+ }
+ break;
+ }
+
+ return NULL;
+}
+
+// Set authentication data to the user
+void SetUserAuthData(USER *u, UINT authtype, void *authdata)
+{
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+ if (authtype != AUTHTYPE_ANONYMOUS && authdata == NULL)
+ {
+ return;
+ }
+
+ Lock(u->lock);
+ {
+ if (u->AuthType != AUTHTYPE_ANONYMOUS)
+ {
+ if (u->AuthType == AUTHTYPE_PASSWORD && authtype == AUTHTYPE_PASSWORD)
+ {
+ AUTHPASSWORD *pw_old = (AUTHPASSWORD *)u->AuthData;
+ AUTHPASSWORD *pw_new = (AUTHPASSWORD *)authdata;
+
+ // Copy NTLM hash for new password from old data, if the password is not changed
+ // and management tool don't send NTLM hash.
+
+ if (Cmp(pw_old->HashedKey, pw_new->HashedKey, SHA1_SIZE) == 0)
+ {
+ if (IsZero(pw_new->NtLmSecureHash, MD5_SIZE))
+ {
+ Copy(pw_new->NtLmSecureHash, pw_old->NtLmSecureHash, MD5_SIZE);
+ }
+ }
+ }
+
+ // Free current authentication data
+ FreeAuthData(u->AuthType, u->AuthData);
+ }
+ // Set new authentication data
+ u->AuthType = authtype;
+ u->AuthData = authdata;
+ }
+ Unlock(u->lock);
+}
+
+// Cumulate group traffic data
+void AddGroupTraffic(USERGROUP *g, TRAFFIC *diff)
+{
+ // Validate arguments
+ if (g == NULL || diff == NULL)
+ {
+ return;
+ }
+
+ Lock(g->lock);
+ {
+ AddTraffic(g->Traffic, diff);
+ }
+ Unlock(g->lock);
+}
+
+// Cumulate user traffic data
+void AddUserTraffic(USER *u, TRAFFIC *diff)
+{
+ // Validate arguments
+ if (u == NULL || diff == NULL)
+ {
+ return;
+ }
+
+ Lock(u->lock);
+ {
+ AddTraffic(u->Traffic, diff);
+ }
+ Unlock(u->lock);
+}
+
+// Set traffic data for group
+void SetGroupTraffic(USERGROUP *g, TRAFFIC *t)
+{
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ Lock(g->lock);
+ {
+ if (t != NULL)
+ {
+ Copy(g->Traffic, t, sizeof(TRAFFIC));
+ }
+ else
+ {
+ Zero(g->Traffic, sizeof(TRAFFIC));
+ }
+ }
+ Unlock(g->lock);
+}
+
+// Set traffic data for user
+void SetUserTraffic(USER *u, TRAFFIC *t)
+{
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+
+ Lock(u->lock);
+ {
+ if (t != NULL)
+ {
+ Copy(u->Traffic, t, sizeof(TRAFFIC));
+ }
+ else
+ {
+ Zero(u->Traffic, sizeof(TRAFFIC));
+ }
+ }
+ Unlock(u->lock);
+}
+
+// Join the user to the group
+void JoinUserToGroup(USER *u, USERGROUP *g)
+{
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+
+ if (g != NULL)
+ {
+ // Join
+ Lock(u->lock);
+ {
+ Lock(g->lock);
+ {
+ if (u->Group != NULL)
+ {
+ // Remove the user from current group first
+ //
+ ReleaseGroup(u->Group);
+ u->Group = NULL;
+ Free(u->GroupName);
+ u->GroupName = NULL;
+ }
+ // Join the user to the group
+ u->GroupName = CopyStr(g->Name);
+ u->Group = g;
+ AddRef(g->ref);
+ }
+ Unlock(g->lock);
+ }
+ Unlock(u->lock);
+ }
+ else
+ {
+ // Withdrawal
+ Lock(u->lock);
+ {
+ if (u->Group != NULL)
+ {
+ // Remove the user from current group
+ ReleaseGroup(u->Group);
+ u->Group = NULL;
+ Free(u->GroupName);
+ u->GroupName = NULL;
+ }
+ }
+ Unlock(u->lock);
+ }
+}
+
+// Validate group name
+bool AcIsGroup(HUB *h, char *name)
+{
+ USERGROUP *g;
+ // Validate arguments
+ if (h == NULL || name == NULL || NO_ACCOUNT_DB(h))
+ {
+ return false;
+ }
+
+ g = AcGetGroup(h, name);
+ if (g == NULL)
+ {
+ return false;
+ }
+ ReleaseGroup(g);
+
+ return true;
+}
+
+// Validate user name
+bool AcIsUser(HUB *h, char *name)
+{
+ USER *u;
+ // Validate arguments
+ if (h == NULL || name == NULL || NO_ACCOUNT_DB(h))
+ {
+ return false;
+ }
+
+ u = AcGetUser(h, name);
+ if (u == NULL)
+ {
+ return false;
+ }
+ ReleaseUser(u);
+
+ return true;
+}
+
+// Get group object
+USERGROUP *AcGetGroup(HUB *h, char *name)
+{
+ USERGROUP *g, t;
+ // Validate arguments
+ if (h == NULL || name == NULL || NO_ACCOUNT_DB(h))
+ {
+ return NULL;
+ }
+
+ t.Name = name;
+ g = Search(h->HubDb->GroupList, &t);
+ if (g == NULL)
+ {
+ return NULL;
+ }
+ AddRef(g->ref);
+
+ return g;
+}
+
+// Get user object
+USER *AcGetUser(HUB *h, char *name)
+{
+ USER *u, t;
+ // Validate arguments
+ if (h == NULL || name == NULL || NO_ACCOUNT_DB(h))
+ {
+ return NULL;
+ }
+
+ t.Name = name;
+ u = Search(h->HubDb->UserList, &t);
+ if (u == NULL)
+ {
+ return NULL;
+ }
+ AddRef(u->ref);
+
+ return u;
+}
+
+// Delete the user
+bool AcDeleteUser(HUB *h, char *name)
+{
+ USER *u;
+ // Validate arguments
+ if (h == NULL || name == NULL)
+ {
+ return false;
+ }
+
+ u = AcGetUser(h, name);
+ if (u == NULL)
+ {
+ return false;
+ }
+
+ if (Delete(h->HubDb->UserList, u))
+ {
+ ReleaseUser(u);
+ }
+
+ ReleaseUser(u);
+
+ return true;
+}
+
+// Delete the group
+bool AcDeleteGroup(HUB *h, char *name)
+{
+ USERGROUP *g;
+ UINT i;
+ // Validate arguments
+ if (h == NULL || name == NULL)
+ {
+ return false;
+ }
+
+ g = AcGetGroup(h, name);
+ if (g == NULL)
+ {
+ return false;
+ }
+
+ if (Delete(h->HubDb->GroupList, g))
+ {
+ ReleaseGroup(g);
+ }
+
+ for (i = 0;i < LIST_NUM(h->HubDb->UserList);i++)
+ {
+ USER *u = LIST_DATA(h->HubDb->UserList, i);
+ Lock(u->lock);
+ {
+ if (u->Group == g)
+ {
+ JoinUserToGroup(u, NULL);
+ }
+ }
+ Unlock(u->lock);
+ }
+
+ ReleaseGroup(g);
+
+ return true;
+}
+
+// Add new group to the hub
+bool AcAddGroup(HUB *h, USERGROUP *g)
+{
+ // Validate arguments
+ if (h == NULL || g == NULL || NO_ACCOUNT_DB(h))
+ {
+ return false;
+ }
+
+ if (LIST_NUM(h->HubDb->GroupList) >= MAX_GROUPS)
+ {
+ return false;
+ }
+
+ if (AcIsGroup(h, g->Name) != false)
+ {
+ return false;
+ }
+
+ Insert(h->HubDb->GroupList, g);
+ AddRef(g->ref);
+
+ return true;
+}
+
+// Add new user in the hub
+bool AcAddUser(HUB *h, USER *u)
+{
+ // Validate arguments
+ if (h == NULL || u == NULL || NO_ACCOUNT_DB(h))
+ {
+ return false;
+ }
+
+ if (LIST_NUM(h->HubDb->UserList) >= MAX_USERS)
+ {
+ return false;
+ }
+
+ if (AcIsUser(h, u->Name) != false)
+ {
+ return false;
+ }
+
+ Insert(h->HubDb->UserList, u);
+ AddRef(u->ref);
+
+ return true;
+}
+
+// Release user object (decrease reference counter)
+void ReleaseUser(USER *u)
+{
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+
+ if (Release(u->ref) == 0)
+ {
+ CleanupUser(u);
+ }
+}
+
+// Cleanup the user object
+void CleanupUser(USER *u)
+{
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+
+ DeleteLock(u->lock);
+ Free(u->Name);
+ Free(u->RealName);
+ Free(u->Note);
+ Free(u->GroupName);
+ if (u->Group != NULL)
+ {
+ ReleaseGroup(u->Group);
+ }
+
+ // Free authntication data
+ FreeAuthData(u->AuthType, u->AuthData);
+
+ if (u->Policy)
+ {
+ // Free policy data
+ Free(u->Policy);
+ }
+
+ FreeTraffic(u->Traffic);
+
+ Free(u);
+}
+
+// Free authntication data
+void FreeAuthData(UINT authtype, void *authdata)
+{
+ AUTHPASSWORD *pw = (AUTHPASSWORD *)authdata;
+ AUTHUSERCERT *uc = (AUTHUSERCERT *)authdata;
+ AUTHROOTCERT *rc = (AUTHROOTCERT *)authdata;
+ AUTHRADIUS *rd = (AUTHRADIUS *)authdata;
+ AUTHNT *nt = (AUTHNT *)authdata;
+ // Validate arguments
+ if (authtype == AUTHTYPE_ANONYMOUS || authdata == NULL)
+ {
+ return;
+ }
+
+ switch (authtype)
+ {
+ case AUTHTYPE_PASSWORD:
+ // Password authentication
+ // Nothing to free
+ break;
+
+ case AUTHTYPE_USERCERT:
+ // User certification
+ FreeX(uc->UserX);
+ break;
+
+ case AUTHTYPE_ROOTCERT:
+ // Root certification
+ if (rc->Serial != NULL)
+ {
+ FreeXSerial(rc->Serial);
+ }
+ if (rc->CommonName != NULL)
+ {
+ Free(rc->CommonName);
+ }
+ break;
+
+ case AUTHTYPE_RADIUS:
+ // Radius authentication
+ Free(rd->RadiusUsername);
+ break;
+
+ case AUTHTYPE_NT:
+ // Windows NT authentication
+ Free(nt->NtUsername);
+ break;
+ }
+
+ Free(authdata);
+}
+
+// Create new user object
+USER *NewUser(char *name, wchar_t *realname, wchar_t *note, UINT authtype, void *authdata)
+{
+ USER *u;
+ // Validate arguments
+ if (name == NULL || realname == NULL || note == NULL)
+ {
+ return NULL;
+ }
+ if (authtype != AUTHTYPE_ANONYMOUS && authdata == NULL)
+ {
+ return NULL;
+ }
+
+ u = ZeroMalloc(sizeof(USER));
+ u->lock = NewLock();
+ u->ref = NewRef();
+ u->Name = CopyStr(name);
+ u->RealName = CopyUniStr(realname);
+ u->Note = CopyUniStr(note);
+ u->GroupName = NULL;
+ u->Group = NULL;
+ u->AuthType = authtype;
+ u->AuthData = authdata;
+ u->CreatedTime = SystemTime64();
+ u->UpdatedTime = SystemTime64();
+
+ u->Policy = NULL;
+ u->Traffic = NewTraffic();
+
+ return u;
+}
+
+// Release group object (decrease reference counter)
+void ReleaseGroup(USERGROUP *g)
+{
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ if (Release(g->ref) == 0)
+ {
+ CleanupGroup(g);
+ }
+}
+
+// Cleanup the group object
+void CleanupGroup(USERGROUP *g)
+{
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ Free(g->Name);
+ Free(g->RealName);
+ Free(g->Note);
+
+ if (g->Policy)
+ {
+ // Free policy data
+ Free(g->Policy);
+ }
+
+
+ FreeTraffic(g->Traffic);
+
+ DeleteLock(g->lock);
+ Free(g);
+}
+
+// Create new group object
+USERGROUP *NewGroup(char *name, wchar_t *realname, wchar_t *note)
+{
+ USERGROUP *g;
+ // Validate arguments
+ if (name == NULL || realname == NULL || note == NULL)
+ {
+ return NULL;
+ }
+
+ g = ZeroMalloc(sizeof(USERGROUP));
+ g->lock = NewLock();
+ g->ref = NewRef();
+ g->Name = CopyStr(name);
+ g->RealName = CopyUniStr(realname);
+ g->Note = CopyUniStr(note);
+ g->Policy = NULL;
+ g->Traffic = NewTraffic();
+
+ return g;
+}
+
+// Lock the account database for the hub
+void AcLock(HUB *h)
+{
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+ if (NO_ACCOUNT_DB(h))
+ {
+ return;
+ }
+
+ // Lock group list and user list
+ LockList(h->HubDb->GroupList);
+ LockList(h->HubDb->UserList);
+}
+
+// Unlock the account database for the hub
+void AcUnlock(HUB *h)
+{
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+ if (NO_ACCOUNT_DB(h))
+ {
+ return;
+ }
+
+ // Unlock group list and user list
+ UnlockList(h->HubDb->UserList);
+ UnlockList(h->HubDb->GroupList);
+}
+
+// Compare group names (for sort)
+int CompareGroupName(void *p1, void *p2)
+{
+ USERGROUP *g1, *g2;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ g1 = *(USERGROUP **)p1;
+ g2 = *(USERGROUP **)p2;
+ if (g1 == NULL || g2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(g1->Name, g2->Name);
+}
+
+// Compare user names (for sort)
+int CompareUserName(void *p1, void *p2)
+{
+ USER *u1, *u2;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ u1 = *(USER **)p1;
+ u2 = *(USER **)p2;
+ if (u1 == NULL || u2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(u1->Name, u2->Name);
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Account.h b/src/Cedar/Account.h
new file mode 100644
index 00000000..95d1d9fe
--- /dev/null
+++ b/src/Cedar/Account.h
@@ -0,0 +1,293 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Account.h
+// Header of Account.c
+
+#ifndef ACCOUNT_H
+#define ACCOUNT_H
+
+// Policy item
+struct POLICY_ITEM
+{
+ UINT Index;
+ bool TypeInt;
+ bool AllowZero;
+ UINT MinValue;
+ UINT MaxValue;
+ UINT DefaultValue;
+ char *FormatStr;
+};
+
+// Policy
+struct POLICY
+{
+ // For Ver 2.0
+ bool Access; // Grant access
+ bool DHCPFilter; // Filter DHCP packets (IPv4)
+ bool DHCPNoServer; // Prohibit the behavior of the DHCP server (IPv4)
+ bool DHCPForce; // Force DHCP-assigned IP address (IPv4)
+ bool NoBridge; // Prohibit the bridge behavior
+ bool NoRouting; // Prohibit the router behavior (IPv4)
+ bool CheckMac; // Prohibit the duplicate MAC address
+ bool CheckIP; // Prohibit a duplicate IP address (IPv4)
+ bool ArpDhcpOnly; // Prohibit the broadcast other than ARP, DHCP, ICMPv6
+ bool PrivacyFilter; // Privacy filter mode
+ bool NoServer; // Prohibit to operate as a TCP/IP server (IPv4)
+ bool NoBroadcastLimiter; // Not to limit the number of broadcast
+ bool MonitorPort; // Allow monitoring mode
+ UINT MaxConnection; // Maximum number of TCP connections
+ UINT TimeOut; // Communication time-out period
+ UINT MaxMac; // Maximum number of MAC address
+ UINT MaxIP; // Maximum number of IP address (IPv4)
+ UINT MaxUpload; // Upload bandwidth
+ UINT MaxDownload; // Download bandwidth
+ bool FixPassword; // User can not change password
+ UINT MultiLogins; // Multiple logins limit
+ bool NoQoS; // Prohibit the use of VoIP / QoS features
+
+ // For Ver 3.0
+ bool RSandRAFilter; // Filter the Router Solicitation / Advertising packet (IPv6)
+ bool RAFilter; // Filter the router advertisement packet (IPv6)
+ bool DHCPv6Filter; // Filter DHCP packets (IPv6)
+ bool DHCPv6NoServer; // Prohibit the behavior of the DHCP server (IPv6)
+ bool NoRoutingV6; // Prohibit the router behavior (IPv6)
+ bool CheckIPv6; // Prohibit the duplicate IP address (IPv6)
+ bool NoServerV6; // Prohibit to operate as a TCP/IP server (IPv6)
+ UINT MaxIPv6; // Maximum number of IP address (IPv6)
+ bool NoSavePassword; // Prohibit to save the password in the VPN Client
+ UINT AutoDisconnect; // Disconnect the VPN Client automatically at a certain period of time
+ bool FilterIPv4; // Filter all IPv4 packets
+ bool FilterIPv6; // Filter all IPv6 packets
+ bool FilterNonIP; // Filter all non-IP packets
+ bool NoIPv6DefaultRouterInRA; // Delete the default router specification from the IPv6 router advertisement
+ bool NoIPv6DefaultRouterInRAWhenIPv6; // Delete the default router specification from the IPv6 router advertisement (Enable IPv6 connection)
+ UINT VLanId; // Specify the VLAN ID
+
+ bool Ver3; // Whether version 3.0
+};
+
+// Group
+struct USERGROUP
+{
+ LOCK *lock; // Lock
+ REF *ref; // Reference counter
+ char *Name; // Group name
+ wchar_t *RealName; // Display name
+ wchar_t *Note; // Note
+ POLICY *Policy; // Policy
+ TRAFFIC *Traffic; // Traffic data
+};
+
+// User
+struct USER
+{
+ LOCK *lock; // Lock
+ REF *ref; // Reference counter
+ char *Name; // User name
+ wchar_t *RealName; // Real name
+ wchar_t *Note; // Note
+ char *GroupName; // Group name
+ USERGROUP *Group; // Group
+ UINT AuthType; // Authentication type
+ void *AuthData; // Authentication data
+ UINT64 CreatedTime; // Creation date and time
+ UINT64 UpdatedTime; // Updating date
+ UINT64 ExpireTime; // Expiration date
+ UINT64 LastLoginTime; // Last login time
+ UINT NumLogin; // Total number of logins
+ POLICY *Policy; // Policy
+ TRAFFIC *Traffic; // Traffic data
+};
+
+// Password authentication data
+struct AUTHPASSWORD
+{
+ UCHAR HashedKey[SHA1_SIZE]; // Hashed passwords
+ UCHAR NtLmSecureHash[MD5_SIZE]; // Encrypted password for the NTLM
+};
+
+// User certificate authentication data
+struct AUTHUSERCERT
+{
+ X *UserX; // X509 certificate for the user
+};
+
+// Root certification authority authentication data
+struct AUTHROOTCERT
+{
+ X_SERIAL *Serial; // Serial number
+ wchar_t *CommonName; // CommonName
+};
+
+// Radius authentication data
+struct AUTHRADIUS
+{
+ wchar_t *RadiusUsername; // User name in the Radius
+};
+
+// Windows NT authentication data
+struct AUTHNT
+{
+ wchar_t *NtUsername; // User name on NT
+};
+
+
+
+// Macro
+#define POLICY_CURRENT_VERSION 3
+#define NUM_POLICY_ITEM ((sizeof(POLICY) / sizeof(UINT)) - 1)
+#define NUM_POLICY_ITEM_FOR_VER2 22
+#define NUM_POLICY_ITEM_FOR_VER3 38
+
+#define IS_POLICY_FOR_VER2(index) (((index) >= 0) && ((index) < NUM_POLICY_ITEM_FOR_VER2))
+#define IS_POLICY_FOR_VER3(index) (((index) >= 0) && ((index) < NUM_POLICY_ITEM_FOR_VER3))
+
+#define IS_POLICY_FOR_CURRENT_VER(index, ver) ((ver) >= 3 ? IS_POLICY_FOR_VER3(index) : IS_POLICY_FOR_VER2(index))
+
+#define POLICY_BOOL(p, i) (((bool *)(p))[(i)])
+#define POLICY_INT(p, i) (((UINT *)(p))[(i)])
+
+extern POLICY_ITEM policy_item[];
+
+
+
+
+// Function prototype
+int CompareUserName(void *p1, void *p2);
+int CompareGroupName(void *p1, void *p2);
+void AcLock(HUB *h);
+void AcUnlock(HUB *h);
+USERGROUP *NewGroup(char *name, wchar_t *realname, wchar_t *note);
+void ReleaseGroup(USERGROUP *g);
+void CleanupGroup(USERGROUP *g);
+USER *NewUser(char *name, wchar_t *realname, wchar_t *note, UINT authtype, void *authdata);
+void ReleaseUser(USER *u);
+void CleanupUser(USER *u);
+void FreeAuthData(UINT authtype, void *authdata);
+bool AcAddUser(HUB *h, USER *u);
+bool AcAddGroup(HUB *h, USERGROUP *g);
+USER *AcGetUser(HUB *h, char *name);
+USERGROUP *AcGetGroup(HUB *h, char *name);
+bool AcIsUser(HUB *h, char *name);
+bool AcIsGroup(HUB *h, char *name);
+bool AcDeleteUser(HUB *h, char *name);
+bool AcDeleteGroup(HUB *h, char *name);
+void JoinUserToGroup(USER *u, USERGROUP *g);
+void SetUserTraffic(USER *u, TRAFFIC *t);
+void SetGroupTraffic(USERGROUP *g, TRAFFIC *t);
+void AddUserTraffic(USER *u, TRAFFIC *diff);
+void AddGroupTraffic(USERGROUP *g, TRAFFIC *diff);
+void SetUserAuthData(USER *u, UINT authtype, void *authdata);
+void *NewPasswordAuthData(char *username, char *password);
+void *NewPasswordAuthDataRaw(UCHAR *hashed_password, UCHAR *ntlm_secure_hash);
+void *NewUserCertAuthData(X *x);
+void *NewRootCertAuthData(X_SERIAL *serial, wchar_t *common_name);
+void *NewRadiusAuthData(wchar_t *username);
+void *NewNTAuthData(wchar_t *username);
+void HashPassword(void *dst, char *username, char *password);
+POLICY *GetDefaultPolicy();
+POLICY *ClonePolicy(POLICY *policy);
+void SetUserPolicy(USER *u, POLICY *policy);
+void OverwritePolicy(POLICY **target, POLICY *p);
+POLICY *GetUserPolicy(USER *u);
+void SetGroupPolicy(USERGROUP *g, POLICY *policy);
+POLICY *GetGroupPolicy(USERGROUP *g);
+wchar_t *GetPolicyTitle(UINT id);
+wchar_t *GetPolicyDescription(UINT id);
+bool IsUserName(char *name);
+void *CopyAuthData(void *authdata, UINT authtype);
+UINT PolicyNum();
+bool PolicyIsSupportedForCascade(UINT i);
+UINT PolicyStrToId(char *name);
+char *PolicyIdToStr(UINT i);
+POLICY_ITEM *GetPolicyItem(UINT id);
+void GetPolicyValueRangeStr(wchar_t *str, UINT size, UINT id);
+void FormatPolicyValue(wchar_t *str, UINT size, UINT id, UINT value);
+char *NormalizePolicyName(char *name);
+
+
+#endif // ACCOUNT_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Admin.c b/src/Cedar/Admin.c
new file mode 100644
index 00000000..9bec72a4
--- /dev/null
+++ b/src/Cedar/Admin.c
@@ -0,0 +1,13742 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Admin.c
+// RPC Module for Management
+
+#include "CedarPch.h"
+
+// Macro for RPC function declaration
+#define DECLARE_RPC_EX(rpc_name, data_type, function, in_rpc, out_rpc, free_rpc) \
+ else if (StrCmpi(name, rpc_name) == 0) \
+ { \
+ data_type *t; \
+ t = ZeroMalloc(sizeof(data_type)); \
+ in_rpc(t, p); \
+ err = function(a, t); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ out_rpc(ret, t); \
+ } \
+ free_rpc(t); \
+ Free(t); \
+ ok = true; \
+ }
+#define DECLARE_RPC(rpc_name, data_type, function, in_rpc, out_rpc) \
+ else if (StrCmpi(name, rpc_name) == 0) \
+ { \
+ data_type *t; \
+ t = ZeroMalloc(sizeof(data_type)); \
+ in_rpc(t, p); \
+ err = function(a, t); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ out_rpc(ret, t); \
+ } \
+ Free(t); \
+ ok = true; \
+ }
+#define DECLARE_SC_EX(rpc_name, data_type, function, in_rpc, out_rpc, free_rpc) \
+ UINT function(RPC *r, data_type *t) \
+ { \
+ PACK *p, *ret; \
+ UINT err; \
+ if (r == NULL || t == NULL) \
+ { \
+ return ERR_INTERNAL_ERROR; \
+ } \
+ p = NewPack(); \
+ out_rpc(p, t); \
+ free_rpc(t); \
+ Zero(t, sizeof(data_type)); \
+ ret = AdminCall(r, rpc_name, p); \
+ err = GetErrorFromPack(ret); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ in_rpc(t, ret); \
+ } \
+ FreePack(ret); \
+ return err; \
+ }
+#define DECLARE_SC(rpc_name, data_type, function, in_rpc, out_rpc) \
+ UINT function(RPC *r, data_type *t) \
+ { \
+ PACK *p, *ret; \
+ UINT err; \
+ if (r == NULL || t == NULL) \
+ { \
+ return ERR_INTERNAL_ERROR; \
+ } \
+ p = NewPack(); \
+ out_rpc(p, t); \
+ ret = AdminCall(r, rpc_name, p); \
+ err = GetErrorFromPack(ret); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ in_rpc(t, ret); \
+ } \
+ FreePack(ret); \
+ return err; \
+ }
+#define CHECK_RIGHT \
+ if (a->ServerAdmin == false && (t->HubName == NULL || StrCmpi(a->HubName, t->HubName) != 0)) \
+ return ERR_NOT_ENOUGH_RIGHT; \
+ if (IsEmptyStr(t->HubName)) \
+ return ERR_INVALID_PARAMETER;
+#define SERVER_ADMIN_ONLY \
+ if (a->ServerAdmin == false) \
+ return ERR_NOT_ENOUGH_RIGHT;
+#define NO_SUPPORT_FOR_BRIDGE \
+ if (a->Server->Cedar->Bridge) \
+ return ERR_NOT_SUPPORTED;
+
+// Get server Caps (Guessing from the build number if failed to get Caps)
+CAPSLIST *ScGetCapsEx(RPC *rpc)
+{
+ RPC_SERVER_INFO info;
+ CAPSLIST *t;
+ bool is_bridge = false;
+ // Validate arguments
+ if (rpc == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&info, sizeof(info));
+ ScGetServerInfo(rpc, &info);
+
+ t = ZeroMalloc(sizeof(CAPSLIST));
+
+ // Try to get Caps by RPC
+ if (ScGetCaps(rpc, t) != ERR_NO_ERROR)
+ {
+ UINT build;
+
+ Free(t);
+ t = NewCapsList();
+
+ // Since acquisition of Caps went wrong, get build number
+ build = info.ServerBuildInt;
+
+ is_bridge = (SearchStrEx(info.ServerProductName, "bridge", 0, false) == INFINITE) ? false : true;
+
+ AddCapsInt(t, "i_max_packet_size", 1514);
+
+ if (is_bridge == false)
+ {
+ AddCapsInt(t, "i_max_hubs", 4096);
+ AddCapsInt(t, "i_max_sessions", 4096);
+
+ if (info.ServerType != SERVER_TYPE_FARM_MEMBER)
+ {
+ AddCapsInt(t, "i_max_users_per_hub", 10000);
+ AddCapsInt(t, "i_max_groups_per_hub", 10000);
+ AddCapsInt(t, "i_max_access_lists", 4096);
+ }
+ else
+ {
+ AddCapsInt(t, "i_max_users_per_hub", 0);
+ AddCapsInt(t, "i_max_groups_per_hub", 0);
+ AddCapsInt(t, "i_max_access_lists", 0);
+ }
+ }
+ else
+ {
+ AddCapsInt(t, "i_max_hubs", 0);
+ AddCapsInt(t, "i_max_sessions", 0);
+ AddCapsInt(t, "i_max_users_per_hub", 0);
+ AddCapsInt(t, "i_max_groups_per_hub", 0);
+ AddCapsInt(t, "i_max_access_lists", 0);
+ }
+
+ AddCapsInt(t, "i_max_mac_tables", 10000);
+ AddCapsInt(t, "i_max_ip_tables", 10000);
+
+ if (info.ServerType == SERVER_TYPE_STANDALONE)
+ {
+ AddCapsBool(t, "b_support_securenat", (build >= 3600) ? true : false);
+ AddCapsInt(t, "i_max_secnat_tables", 4096);
+ }
+ else
+ {
+ AddCapsBool(t, "b_support_securenat", false);
+ AddCapsInt(t, "i_max_secnat_tables", 0);
+ }
+
+ if (is_bridge)
+ {
+ AddCapsBool(t, "b_bridge", true);
+ }
+ else if (info.ServerType == SERVER_TYPE_STANDALONE)
+ {
+ AddCapsBool(t, "b_standalone", true);
+ }
+ else if (info.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ AddCapsBool(t, "b_cluster_controller", true);
+ }
+ else
+ {
+ AddCapsBool(t, "b_cluster_member", true);
+ }
+
+ AddCapsBool(t, "b_support_config_hub", info.ServerType != SERVER_TYPE_FARM_MEMBER &&
+ is_bridge == false);
+
+ AddCapsBool(t, "b_vpn_client_connect", is_bridge == false ? true : false);
+
+ AddCapsBool(t, "b_support_radius", info.ServerType != SERVER_TYPE_FARM_MEMBER &&
+ is_bridge == false);
+
+ if (build >= 3600)
+ {
+ RPC_BRIDGE_SUPPORT b;
+ Zero(&b, sizeof(b));
+ if (ScGetBridgeSupport(rpc, &b) == ERR_NO_ERROR)
+ {
+ AddCapsBool(t, "b_local_bridge", b.IsBridgeSupportedOs);
+ AddCapsBool(t, "b_must_install_pcap", b.IsWinPcapNeeded);
+ }
+ else
+ {
+ AddCapsBool(t, "b_local_bridge", false);
+ AddCapsBool(t, "b_must_install_pcap", false);
+ }
+ }
+ else
+ {
+ AddCapsBool(t, "b_local_bridge", false);
+ AddCapsBool(t, "b_must_install_pcap", false);
+ }
+
+ AddCapsBool(t, "b_tap_supported", false);
+
+ if (info.ServerType == SERVER_TYPE_STANDALONE)
+ {
+ AddCapsBool(t, "b_support_cascade", true);
+ }
+ else
+ {
+ AddCapsBool(t, "b_support_cascade", false);
+ }
+
+ AddCapsBool(t, "b_support_cascade_cert", false);
+ AddCapsBool(t, "b_support_config_log", info.ServerType != SERVER_TYPE_FARM_MEMBER);
+ AddCapsBool(t, "b_support_autodelete", false);
+ }
+ else
+ {
+ // Success getting Caps
+ if (info.ServerBuildInt <= 4350)
+ {
+ if (is_bridge == false)
+ {
+ // b_support_cluster should be true for build 4300 or earlier
+ CAPS *caps = GetCaps(t, "b_support_cluster");
+ if (caps == NULL)
+ {
+ AddCapsBool(t, "b_support_cluster", true);
+ }
+ else
+ {
+ caps->Value = 1;
+ }
+ }
+ }
+ }
+
+ if (true)
+ {
+ TOKEN_LIST *names;
+
+ // Fill items that doesn't exist in server-side as false
+ names = GetTableNameStartWith("CT_b_");
+ if (names != NULL)
+ {
+ UINT i;
+ for (i = 0;i < names->NumTokens;i++)
+ {
+ char *name = names->Token[i] + 3;
+
+ if (GetCaps(t, name) == NULL)
+ {
+ AddCapsBool(t, name, false);
+ }
+ }
+
+ FreeToken(names);
+ }
+ }
+
+ FreeRpcServerInfo(&info);
+
+ return t;
+}
+
+// Dispatch routine for Administration RPC
+PACK *AdminDispatch(RPC *rpc, char *name, PACK *p)
+{
+ ADMIN *a;
+ PACK *ret;
+ UINT err;
+ SERVER *server = NULL;
+ CEDAR *cedar = NULL;
+ bool ok = false;
+ // Validate arguments
+ if (rpc == NULL || name == NULL || p == NULL)
+ {
+ return NULL;
+ }
+
+ ret = NewPack();
+ err = ERR_NO_ERROR;
+
+ // Administration structure
+ a = (ADMIN *)rpc->Param;
+ if (a == NULL)
+ {
+ FreePack(ret);
+ return NULL;
+ }
+
+ server = a->Server;
+
+ if (server != NULL)
+ {
+ cedar = server->Cedar;
+ }
+
+ Lock(cedar->CedarSuperLock);
+
+ if (true)
+ {
+ char tmp[MAX_PATH];
+ char ip[MAX_PATH];
+ UINT rpc_id = 0;
+
+ StrCpy(ip, sizeof(ip), "Unknown");
+
+ if (rpc->Sock != NULL)
+ {
+ IPToStr(ip, sizeof(ip), &rpc->Sock->RemoteIP);
+ rpc_id = rpc->Sock->socket;
+ }
+
+ Format(tmp, sizeof(tmp), "RPC: RPC-%u (%s): Entering RPC [%s]...",
+ rpc_id, ip, name);
+
+ SiDebugLog(a->Server, tmp);
+ }
+
+ if (0) {}
+
+ // RPC function declaration: from here
+ DECLARE_RPC_EX("Test", RPC_TEST, StTest, InRpcTest, OutRpcTest, FreeRpcTest)
+ DECLARE_RPC_EX("GetServerInfo", RPC_SERVER_INFO, StGetServerInfo, InRpcServerInfo, OutRpcServerInfo, FreeRpcServerInfo)
+ DECLARE_RPC("GetServerStatus", RPC_SERVER_STATUS, StGetServerStatus, InRpcServerStatus, OutRpcServerStatus)
+ DECLARE_RPC("CreateListener", RPC_LISTENER, StCreateListener, InRpcListener, OutRpcListener)
+ DECLARE_RPC_EX("EnumListener", RPC_LISTENER_LIST, StEnumListener, InRpcListenerList, OutRpcListenerList, FreeRpcListenerList)
+ DECLARE_RPC("DeleteListener", RPC_LISTENER, StDeleteListener, InRpcListener, OutRpcListener)
+ DECLARE_RPC("EnableListener", RPC_LISTENER, StEnableListener, InRpcListener, OutRpcListener)
+ DECLARE_RPC("SetServerPassword", RPC_SET_PASSWORD, StSetServerPassword, InRpcSetPassword, OutRpcSetPassword)
+ DECLARE_RPC_EX("SetFarmSetting", RPC_FARM, StSetFarmSetting, InRpcFarm, OutRpcFarm, FreeRpcFarm)
+ DECLARE_RPC_EX("GetFarmSetting", RPC_FARM, StGetFarmSetting, InRpcFarm, OutRpcFarm, FreeRpcFarm)
+ DECLARE_RPC_EX("GetFarmInfo", RPC_FARM_INFO, StGetFarmInfo, InRpcFarmInfo, OutRpcFarmInfo, FreeRpcFarmInfo)
+ DECLARE_RPC_EX("EnumFarmMember", RPC_ENUM_FARM, StEnumFarmMember, InRpcEnumFarm, OutRpcEnumFarm, FreeRpcEnumFarm)
+ DECLARE_RPC("GetFarmConnectionStatus", RPC_FARM_CONNECTION_STATUS, StGetFarmConnectionStatus, InRpcFarmConnectionStatus, OutRpcFarmConnectionStatus)
+ DECLARE_RPC_EX("SetServerCert", RPC_KEY_PAIR, StSetServerCert, InRpcKeyPair, OutRpcKeyPair, FreeRpcKeyPair)
+ DECLARE_RPC_EX("GetServerCert", RPC_KEY_PAIR, StGetServerCert, InRpcKeyPair, OutRpcKeyPair, FreeRpcKeyPair)
+ DECLARE_RPC_EX("GetServerCipher", RPC_STR, StGetServerCipher, InRpcStr, OutRpcStr, FreeRpcStr)
+ DECLARE_RPC_EX("SetServerCipher", RPC_STR, StSetServerCipher, InRpcStr, OutRpcStr, FreeRpcStr)
+ DECLARE_RPC("CreateHub", RPC_CREATE_HUB, StCreateHub, InRpcCreateHub, OutRpcCreateHub)
+ DECLARE_RPC("SetHub", RPC_CREATE_HUB, StSetHub, InRpcCreateHub, OutRpcCreateHub)
+ DECLARE_RPC("GetHub", RPC_CREATE_HUB, StGetHub, InRpcCreateHub, OutRpcCreateHub)
+ DECLARE_RPC_EX("EnumHub", RPC_ENUM_HUB, StEnumHub, InRpcEnumHub, OutRpcEnumHub, FreeRpcEnumHub)
+ DECLARE_RPC("DeleteHub", RPC_DELETE_HUB, StDeleteHub, InRpcDeleteHub, OutRpcDeleteHub)
+ DECLARE_RPC("GetHubRadius", RPC_RADIUS, StGetHubRadius, InRpcRadius, OutRpcRadius)
+ DECLARE_RPC("SetHubRadius", RPC_RADIUS, StSetHubRadius, InRpcRadius, OutRpcRadius)
+ DECLARE_RPC_EX("EnumConnection", RPC_ENUM_CONNECTION, StEnumConnection, InRpcEnumConnection, OutRpcEnumConnection, FreeRpcEnumConnetion)
+ DECLARE_RPC("DisconnectConnection", RPC_DISCONNECT_CONNECTION, StDisconnectConnection, InRpcDisconnectConnection, OutRpcDisconnectConnection)
+ DECLARE_RPC("GetConnectionInfo", RPC_CONNECTION_INFO, StGetConnectionInfo, InRpcConnectionInfo, OutRpcConnectionInfo)
+ DECLARE_RPC("SetHubOnline", RPC_SET_HUB_ONLINE, StSetHubOnline, InRpcSetHubOnline, OutRpcSetHubOnline)
+ DECLARE_RPC("GetHubStatus", RPC_HUB_STATUS, StGetHubStatus, InRpcHubStatus, OutRpcHubStatus)
+ DECLARE_RPC("SetHubLog", RPC_HUB_LOG, StSetHubLog, InRpcHubLog, OutRpcHubLog)
+ DECLARE_RPC("GetHubLog", RPC_HUB_LOG, StGetHubLog, InRpcHubLog, OutRpcHubLog)
+ DECLARE_RPC_EX("AddCa", RPC_HUB_ADD_CA, StAddCa, InRpcHubAddCa, OutRpcHubAddCa, FreeRpcHubAddCa)
+ DECLARE_RPC_EX("EnumCa", RPC_HUB_ENUM_CA, StEnumCa, InRpcHubEnumCa, OutRpcHubEnumCa, FreeRpcHubEnumCa)
+ DECLARE_RPC_EX("GetCa", RPC_HUB_GET_CA, StGetCa, InRpcHubGetCa, OutRpcHubGetCa, FreeRpcHubGetCa)
+ DECLARE_RPC("DeleteCa", RPC_HUB_DELETE_CA, StDeleteCa, InRpcHubDeleteCa, OutRpcHubDeleteCa)
+ DECLARE_RPC("SetLinkOnline", RPC_LINK, StSetLinkOnline, InRpcLink, OutRpcLink)
+ DECLARE_RPC("SetLinkOffline", RPC_LINK, StSetLinkOffline, InRpcLink, OutRpcLink)
+ DECLARE_RPC("DeleteLink", RPC_LINK, StDeleteLink, InRpcLink, OutRpcLink)
+ DECLARE_RPC("RenameLink", RPC_RENAME_LINK, StRenameLink, InRpcRenameLink, OutRpcRenameLink)
+ DECLARE_RPC_EX("CreateLink", RPC_CREATE_LINK, StCreateLink, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+ DECLARE_RPC_EX("GetLink", RPC_CREATE_LINK, StGetLink, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+ DECLARE_RPC_EX("SetLink", RPC_CREATE_LINK, StSetLink, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+ DECLARE_RPC_EX("EnumLink", RPC_ENUM_LINK, StEnumLink, InRpcEnumLink, OutRpcEnumLink, FreeRpcEnumLink)
+ DECLARE_RPC_EX("GetLinkStatus", RPC_LINK_STATUS, StGetLinkStatus, InRpcLinkStatus, OutRpcLinkStatus, FreeRpcLinkStatus)
+ DECLARE_RPC("AddAccess", RPC_ADD_ACCESS, StAddAccess, InRpcAddAccess, OutRpcAddAccess)
+ DECLARE_RPC("DeleteAccess", RPC_DELETE_ACCESS, StDeleteAccess, InRpcDeleteAccess, OutRpcDeleteAccess)
+ DECLARE_RPC_EX("EnumAccess", RPC_ENUM_ACCESS_LIST, StEnumAccess, InRpcEnumAccessList, OutRpcEnumAccessList, FreeRpcEnumAccessList)
+ DECLARE_RPC_EX("SetAccessList", RPC_ENUM_ACCESS_LIST, StSetAccessList, InRpcEnumAccessList, OutRpcEnumAccessList, FreeRpcEnumAccessList)
+ DECLARE_RPC_EX("CreateUser", RPC_SET_USER, StCreateUser, InRpcSetUser, OutRpcSetUser, FreeRpcSetUser)
+ DECLARE_RPC_EX("SetUser", RPC_SET_USER, StSetUser, InRpcSetUser, OutRpcSetUser, FreeRpcSetUser)
+ DECLARE_RPC_EX("GetUser", RPC_SET_USER, StGetUser, InRpcSetUser, OutRpcSetUser, FreeRpcSetUser)
+ DECLARE_RPC("DeleteUser", RPC_DELETE_USER, StDeleteUser, InRpcDeleteUser, OutRpcDeleteUser)
+ DECLARE_RPC_EX("EnumUser", RPC_ENUM_USER, StEnumUser, InRpcEnumUser, OutRpcEnumUser, FreeRpcEnumUser)
+ DECLARE_RPC_EX("CreateGroup", RPC_SET_GROUP, StCreateGroup, InRpcSetGroup, OutRpcSetGroup, FreeRpcSetGroup)
+ DECLARE_RPC_EX("SetGroup", RPC_SET_GROUP, StSetGroup, InRpcSetGroup, OutRpcSetGroup, FreeRpcSetGroup)
+ DECLARE_RPC_EX("GetGroup", RPC_SET_GROUP, StGetGroup, InRpcSetGroup, OutRpcSetGroup, FreeRpcSetGroup)
+ DECLARE_RPC("DeleteGroup", RPC_DELETE_USER, StDeleteGroup, InRpcDeleteUser, OutRpcDeleteUser)
+ DECLARE_RPC_EX("EnumGroup", RPC_ENUM_GROUP, StEnumGroup, InRpcEnumGroup, OutRpcEnumGroup, FreeRpcEnumGroup)
+ DECLARE_RPC_EX("EnumSession", RPC_ENUM_SESSION, StEnumSession, InRpcEnumSession, OutRpcEnumSession, FreeRpcEnumSession)
+ DECLARE_RPC_EX("GetSessionStatus", RPC_SESSION_STATUS, StGetSessionStatus, InRpcSessionStatus, OutRpcSessionStatus, FreeRpcSessionStatus)
+ DECLARE_RPC("DeleteSession", RPC_DELETE_SESSION, StDeleteSession, InRpcDeleteSession, OutRpcDeleteSession)
+ DECLARE_RPC_EX("EnumMacTable", RPC_ENUM_MAC_TABLE, StEnumMacTable, InRpcEnumMacTable, OutRpcEnumMacTable, FreeRpcEnumMacTable)
+ DECLARE_RPC("DeleteMacTable", RPC_DELETE_TABLE, StDeleteMacTable, InRpcDeleteTable, OutRpcDeleteTable)
+ DECLARE_RPC_EX("EnumIpTable", RPC_ENUM_IP_TABLE, StEnumIpTable, InRpcEnumIpTable, OutRpcEnumIpTable, FreeRpcEnumIpTable)
+ DECLARE_RPC("DeleteIpTable", RPC_DELETE_TABLE, StDeleteIpTable, InRpcDeleteTable, OutRpcDeleteTable)
+ DECLARE_RPC("SetKeep", RPC_KEEP, StSetKeep, InRpcKeep, OutRpcKeep)
+ DECLARE_RPC("GetKeep", RPC_KEEP, StGetKeep, InRpcKeep, OutRpcKeep)
+ DECLARE_RPC("EnableSecureNAT", RPC_HUB, StEnableSecureNAT, InRpcHub, OutRpcHub)
+ DECLARE_RPC("DisableSecureNAT", RPC_HUB, StDisableSecureNAT, InRpcHub, OutRpcHub)
+ DECLARE_RPC("SetSecureNATOption", VH_OPTION, StSetSecureNATOption, InVhOption, OutVhOption)
+ DECLARE_RPC("GetSecureNATOption", VH_OPTION, StGetSecureNATOption, InVhOption, OutVhOption)
+ DECLARE_RPC_EX("EnumNAT", RPC_ENUM_NAT, StEnumNAT, InRpcEnumNat, OutRpcEnumNat, FreeRpcEnumNat)
+ DECLARE_RPC_EX("EnumDHCP", RPC_ENUM_DHCP, StEnumDHCP, InRpcEnumDhcp, OutRpcEnumDhcp, FreeRpcEnumDhcp)
+ DECLARE_RPC("GetSecureNATStatus", RPC_NAT_STATUS, StGetSecureNATStatus, InRpcNatStatus, OutRpcNatStatus)
+ DECLARE_RPC_EX("EnumEthernet", RPC_ENUM_ETH, StEnumEthernet, InRpcEnumEth, OutRpcEnumEth, FreeRpcEnumEth)
+ DECLARE_RPC("AddLocalBridge", RPC_LOCALBRIDGE, StAddLocalBridge, InRpcLocalBridge, OutRpcLocalBridge)
+ DECLARE_RPC("DeleteLocalBridge", RPC_LOCALBRIDGE, StDeleteLocalBridge, InRpcLocalBridge, OutRpcLocalBridge)
+ DECLARE_RPC_EX("EnumLocalBridge", RPC_ENUM_LOCALBRIDGE, StEnumLocalBridge, InRpcEnumLocalBridge, OutRpcEnumLocalBridge, FreeRpcEnumLocalBridge)
+ DECLARE_RPC("GetBridgeSupport", RPC_BRIDGE_SUPPORT, StGetBridgeSupport, InRpcBridgeSupport, OutRpcBridgeSupport)
+ DECLARE_RPC("RebootServer", RPC_TEST, StRebootServer, InRpcTest, OutRpcTest)
+ DECLARE_RPC_EX("GetCaps", CAPSLIST, StGetCaps, InRpcCapsList, OutRpcCapsList, FreeRpcCapsList)
+ DECLARE_RPC_EX("GetConfig", RPC_CONFIG, StGetConfig, InRpcConfig, OutRpcConfig, FreeRpcConfig)
+ DECLARE_RPC_EX("SetConfig", RPC_CONFIG, StSetConfig, InRpcConfig, OutRpcConfig, FreeRpcConfig)
+ DECLARE_RPC_EX("GetDefaultHubAdminOptions", RPC_ADMIN_OPTION, StGetDefaultHubAdminOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+ DECLARE_RPC_EX("GetHubAdminOptions", RPC_ADMIN_OPTION, StGetHubAdminOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+ DECLARE_RPC_EX("SetHubAdminOptions", RPC_ADMIN_OPTION, StSetHubAdminOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+ DECLARE_RPC_EX("GetHubExtOptions", RPC_ADMIN_OPTION, StGetHubExtOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+ DECLARE_RPC_EX("SetHubExtOptions", RPC_ADMIN_OPTION, StSetHubExtOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+ DECLARE_RPC("AddL3Switch", RPC_L3SW, StAddL3Switch, InRpcL3Sw, OutRpcL3Sw)
+ DECLARE_RPC("DelL3Switch", RPC_L3SW, StDelL3Switch, InRpcL3Sw, OutRpcL3Sw)
+ DECLARE_RPC_EX("EnumL3Switch", RPC_ENUM_L3SW, StEnumL3Switch, InRpcEnumL3Sw, OutRpcEnumL3Sw, FreeRpcEnumL3Sw)
+ DECLARE_RPC("StartL3Switch", RPC_L3SW, StStartL3Switch, InRpcL3Sw, OutRpcL3Sw)
+ DECLARE_RPC("StopL3Switch", RPC_L3SW, StStopL3Switch, InRpcL3Sw, OutRpcL3Sw)
+ DECLARE_RPC("AddL3If", RPC_L3IF, StAddL3If, InRpcL3If, OutRpcL3If)
+ DECLARE_RPC("DelL3If", RPC_L3IF, StDelL3If, InRpcL3If, OutRpcL3If)
+ DECLARE_RPC_EX("EnumL3If", RPC_ENUM_L3IF, StEnumL3If, InRpcEnumL3If, OutRpcEnumL3If, FreeRpcEnumL3If)
+ DECLARE_RPC("AddL3Table", RPC_L3TABLE, StAddL3Table, InRpcL3Table, OutRpcL3Table)
+ DECLARE_RPC("DelL3Table", RPC_L3TABLE, StDelL3Table, InRpcL3Table, OutRpcL3Table)
+ DECLARE_RPC_EX("EnumL3Table", RPC_ENUM_L3TABLE, StEnumL3Table, InRpcEnumL3Table, OutRpcEnumL3Table, FreeRpcEnumL3Table)
+ DECLARE_RPC_EX("EnumCrl", RPC_ENUM_CRL, StEnumCrl, InRpcEnumCrl, OutRpcEnumCrl, FreeRpcEnumCrl)
+ DECLARE_RPC_EX("AddCrl", RPC_CRL, StAddCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+ DECLARE_RPC_EX("DelCrl", RPC_CRL, StDelCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+ DECLARE_RPC_EX("GetCrl", RPC_CRL, StGetCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+ DECLARE_RPC_EX("SetCrl", RPC_CRL, StSetCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+ DECLARE_RPC_EX("SetAcList", RPC_AC_LIST, StSetAcList, InRpcAcList, OutRpcAcList, FreeRpcAcList)
+ DECLARE_RPC_EX("GetAcList", RPC_AC_LIST, StGetAcList, InRpcAcList, OutRpcAcList, FreeRpcAcList)
+ DECLARE_RPC_EX("EnumLogFile", RPC_ENUM_LOG_FILE, StEnumLogFile, InRpcEnumLogFile, OutRpcEnumLogFile, FreeRpcEnumLogFile)
+ DECLARE_RPC_EX("ReadLogFile", RPC_READ_LOG_FILE, StReadLogFile, InRpcReadLogFile, OutRpcReadLogFile, FreeRpcReadLogFile)
+ DECLARE_RPC("AddLicenseKey", RPC_TEST, StAddLicenseKey, InRpcTest, OutRpcTest)
+ DECLARE_RPC("DelLicenseKey", RPC_TEST, StDelLicenseKey, InRpcTest, OutRpcTest)
+ DECLARE_RPC_EX("EnumLicenseKey", RPC_ENUM_LICENSE_KEY, StEnumLicenseKey, InRpcEnumLicenseKey, OutRpcEnumLicenseKey, FreeRpcEnumLicenseKey)
+ DECLARE_RPC("GetLicenseStatus", RPC_LICENSE_STATUS, StGetLicenseStatus, InRpcLicenseStatus, OutRpcLicenseStatus)
+ DECLARE_RPC("SetSysLog", SYSLOG_SETTING, StSetSysLog, InRpcSysLogSetting, OutRpcSysLogSetting)
+ DECLARE_RPC("GetSysLog", SYSLOG_SETTING, StGetSysLog, InRpcSysLogSetting, OutRpcSysLogSetting)
+ DECLARE_RPC_EX("EnumEthVLan", RPC_ENUM_ETH_VLAN, StEnumEthVLan, InRpcEnumEthVLan, OutRpcEnumEthVLan, FreeRpcEnumEthVLan)
+ DECLARE_RPC("SetEnableEthVLan", RPC_TEST, StSetEnableEthVLan, InRpcTest, OutRpcTest)
+ DECLARE_RPC_EX("SetHubMsg", RPC_MSG, StSetHubMsg, InRpcMsg, OutRpcMsg, FreeRpcMsg)
+ DECLARE_RPC_EX("GetHubMsg", RPC_MSG, StGetHubMsg, InRpcMsg, OutRpcMsg, FreeRpcMsg)
+ DECLARE_RPC("Crash", RPC_TEST, StCrash, InRpcTest, OutRpcTest)
+ DECLARE_RPC_EX("GetAdminMsg", RPC_MSG, StGetAdminMsg, InRpcMsg, OutRpcMsg, FreeRpcMsg)
+ DECLARE_RPC("Flush", RPC_TEST, StFlush, InRpcTest, OutRpcTest)
+ DECLARE_RPC("Debug", RPC_TEST, StDebug, InRpcTest, OutRpcTest)
+ DECLARE_RPC("SetIPsecServices", IPSEC_SERVICES, StSetIPsecServices, InIPsecServices, OutIPsecServices)
+ DECLARE_RPC("GetIPsecServices", IPSEC_SERVICES, StGetIPsecServices, InIPsecServices, OutIPsecServices)
+ DECLARE_RPC("AddEtherIpId", ETHERIP_ID, StAddEtherIpId, InEtherIpId, OutEtherIpId)
+ DECLARE_RPC("GetEtherIpId", ETHERIP_ID, StGetEtherIpId, InEtherIpId, OutEtherIpId)
+ DECLARE_RPC("DeleteEtherIpId", ETHERIP_ID, StDeleteEtherIpId, InEtherIpId, OutEtherIpId)
+ DECLARE_RPC_EX("EnumEtherIpId", RPC_ENUM_ETHERIP_ID, StEnumEtherIpId, InRpcEnumEtherIpId, OutRpcEnumEtherIpId, FreeRpcEnumEtherIpId)
+ DECLARE_RPC("SetOpenVpnSstpConfig", OPENVPN_SSTP_CONFIG, StSetOpenVpnSstpConfig, InOpenVpnSstpConfig, OutOpenVpnSstpConfig)
+ DECLARE_RPC("GetOpenVpnSstpConfig", OPENVPN_SSTP_CONFIG, StGetOpenVpnSstpConfig, InOpenVpnSstpConfig, OutOpenVpnSstpConfig)
+ DECLARE_RPC("GetDDnsClientStatus", DDNS_CLIENT_STATUS, StGetDDnsClientStatus, InDDnsClientStatus, OutDDnsClientStatus)
+ DECLARE_RPC("ChangeDDnsClientHostname", RPC_TEST, StChangeDDnsClientHostname, InRpcTest, OutRpcTest)
+ DECLARE_RPC("RegenerateServerCert", RPC_TEST, StRegenerateServerCert, InRpcTest, OutRpcTest)
+ DECLARE_RPC_EX("MakeOpenVpnConfigFile", RPC_READ_LOG_FILE, StMakeOpenVpnConfigFile, InRpcReadLogFile, OutRpcReadLogFile, FreeRpcReadLogFile)
+ DECLARE_RPC("SetSpecialListener", RPC_SPECIAL_LISTENER, StSetSpecialListener, InRpcSpecialListener, OutRpcSpecialListener)
+ DECLARE_RPC("GetSpecialListener", RPC_SPECIAL_LISTENER, StGetSpecialListener, InRpcSpecialListener, OutRpcSpecialListener)
+ DECLARE_RPC("GetAzureStatus", RPC_AZURE_STATUS, StGetAzureStatus, InRpcAzureStatus, OutRpcAzureStatus)
+ DECLARE_RPC("SetAzureStatus", RPC_AZURE_STATUS, StSetAzureStatus, InRpcAzureStatus, OutRpcAzureStatus)
+ DECLARE_RPC("GetDDnsInternetSettng", INTERNET_SETTING, StGetDDnsInternetSetting, InRpcInternetSetting, OutRpcInternetSetting)
+ DECLARE_RPC("SetDDnsInternetSettng", INTERNET_SETTING, StSetDDnsInternetSetting, InRpcInternetSetting, OutRpcInternetSetting)
+ // RPC function declaration: till here
+
+
+ if (ok == false)
+ {
+ err = ERR_NOT_SUPPORTED;
+ }
+
+ if (err != ERR_NO_ERROR)
+ {
+ PackAddInt(ret, "error", err);
+ }
+
+ if (true)
+ {
+ char tmp[MAX_PATH];
+ char ip[MAX_PATH];
+ UINT rpc_id = 0;
+
+ StrCpy(ip, sizeof(ip), "Unknown");
+
+ if (rpc->Sock != NULL)
+ {
+ IPToStr(ip, sizeof(ip), &rpc->Sock->RemoteIP);
+ rpc_id = rpc->Sock->socket;
+ }
+
+ Format(tmp, sizeof(tmp), "RPC: RPC-%u (%s): Leaving RPC [%s] (Error: %u).",
+ rpc_id, ip, name, err);
+
+ SiDebugLog(a->Server, tmp);
+ }
+
+ Unlock(cedar->CedarSuperLock);
+
+ return ret;
+}
+
+// RPC call function declaration: from here
+DECLARE_SC_EX("Test", RPC_TEST, ScTest, InRpcTest, OutRpcTest, FreeRpcTest)
+DECLARE_SC_EX("GetServerInfo", RPC_SERVER_INFO, ScGetServerInfo, InRpcServerInfo, OutRpcServerInfo, FreeRpcServerInfo)
+DECLARE_SC("GetServerStatus", RPC_SERVER_STATUS, ScGetServerStatus, InRpcServerStatus, OutRpcServerStatus)
+DECLARE_SC("CreateListener", RPC_LISTENER, ScCreateListener, InRpcListener, OutRpcListener)
+DECLARE_SC_EX("EnumListener", RPC_LISTENER_LIST, ScEnumListener, InRpcListenerList, OutRpcListenerList, FreeRpcListenerList)
+DECLARE_SC("DeleteListener", RPC_LISTENER, ScDeleteListener, InRpcListener, OutRpcListener)
+DECLARE_SC("EnableListener", RPC_LISTENER, ScEnableListener, InRpcListener, OutRpcListener)
+DECLARE_SC("SetServerPassword", RPC_SET_PASSWORD, ScSetServerPassword, InRpcSetPassword, OutRpcSetPassword)
+DECLARE_SC_EX("SetFarmSetting", RPC_FARM, ScSetFarmSetting, InRpcFarm, OutRpcFarm, FreeRpcFarm)
+DECLARE_SC_EX("GetFarmSetting", RPC_FARM, ScGetFarmSetting, InRpcFarm, OutRpcFarm, FreeRpcFarm)
+DECLARE_SC_EX("GetFarmInfo", RPC_FARM_INFO, ScGetFarmInfo, InRpcFarmInfo, OutRpcFarmInfo, FreeRpcFarmInfo)
+DECLARE_SC_EX("EnumFarmMember", RPC_ENUM_FARM, ScEnumFarmMember, InRpcEnumFarm, OutRpcEnumFarm, FreeRpcEnumFarm)
+DECLARE_SC("GetFarmConnectionStatus", RPC_FARM_CONNECTION_STATUS, ScGetFarmConnectionStatus, InRpcFarmConnectionStatus, OutRpcFarmConnectionStatus)
+DECLARE_SC_EX("SetServerCert", RPC_KEY_PAIR, ScSetServerCert, InRpcKeyPair, OutRpcKeyPair, FreeRpcKeyPair)
+DECLARE_SC_EX("GetServerCert", RPC_KEY_PAIR, ScGetServerCert, InRpcKeyPair, OutRpcKeyPair, FreeRpcKeyPair)
+DECLARE_SC_EX("GetServerCipher", RPC_STR, ScGetServerCipher, InRpcStr, OutRpcStr, FreeRpcStr)
+DECLARE_SC_EX("SetServerCipher", RPC_STR, ScSetServerCipher, InRpcStr, OutRpcStr, FreeRpcStr)
+DECLARE_SC("CreateHub", RPC_CREATE_HUB, ScCreateHub, InRpcCreateHub, OutRpcCreateHub)
+DECLARE_SC("SetHub", RPC_CREATE_HUB, ScSetHub, InRpcCreateHub, OutRpcCreateHub)
+DECLARE_SC("GetHub", RPC_CREATE_HUB, ScGetHub, InRpcCreateHub, OutRpcCreateHub)
+DECLARE_SC_EX("EnumHub", RPC_ENUM_HUB, ScEnumHub, InRpcEnumHub, OutRpcEnumHub, FreeRpcEnumHub)
+DECLARE_SC("DeleteHub", RPC_DELETE_HUB, ScDeleteHub, InRpcDeleteHub, OutRpcDeleteHub)
+DECLARE_SC("GetHubRadius", RPC_RADIUS, ScGetHubRadius, InRpcRadius, OutRpcRadius)
+DECLARE_SC("SetHubRadius", RPC_RADIUS, ScSetHubRadius, InRpcRadius, OutRpcRadius)
+DECLARE_SC_EX("EnumConnection", RPC_ENUM_CONNECTION, ScEnumConnection, InRpcEnumConnection, OutRpcEnumConnection, FreeRpcEnumConnetion)
+DECLARE_SC("DisconnectConnection", RPC_DISCONNECT_CONNECTION, ScDisconnectConnection, InRpcDisconnectConnection, OutRpcDisconnectConnection)
+DECLARE_SC("GetConnectionInfo", RPC_CONNECTION_INFO, ScGetConnectionInfo, InRpcConnectionInfo, OutRpcConnectionInfo)
+DECLARE_SC("SetHubOnline", RPC_SET_HUB_ONLINE, ScSetHubOnline, InRpcSetHubOnline, OutRpcSetHubOnline)
+DECLARE_SC("GetHubStatus", RPC_HUB_STATUS, ScGetHubStatus, InRpcHubStatus, OutRpcHubStatus)
+DECLARE_SC("SetHubLog", RPC_HUB_LOG, ScSetHubLog, InRpcHubLog, OutRpcHubLog)
+DECLARE_SC("GetHubLog", RPC_HUB_LOG, ScGetHubLog, InRpcHubLog, OutRpcHubLog)
+DECLARE_SC_EX("AddCa", RPC_HUB_ADD_CA, ScAddCa, InRpcHubAddCa, OutRpcHubAddCa, FreeRpcHubAddCa)
+DECLARE_SC_EX("EnumCa", RPC_HUB_ENUM_CA, ScEnumCa, InRpcHubEnumCa, OutRpcHubEnumCa, FreeRpcHubEnumCa)
+DECLARE_SC_EX("GetCa", RPC_HUB_GET_CA, ScGetCa, InRpcHubGetCa, OutRpcHubGetCa, FreeRpcHubGetCa)
+DECLARE_SC("DeleteCa", RPC_HUB_DELETE_CA, ScDeleteCa, InRpcHubDeleteCa, OutRpcHubDeleteCa)
+DECLARE_SC_EX("CreateLink", RPC_CREATE_LINK, ScCreateLink, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+DECLARE_SC_EX("GetLink", RPC_CREATE_LINK, ScGetLink, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+DECLARE_SC_EX("SetLink", RPC_CREATE_LINK, ScSetLink, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+DECLARE_SC_EX("EnumLink", RPC_ENUM_LINK, ScEnumLink, InRpcEnumLink, OutRpcEnumLink, FreeRpcEnumLink)
+DECLARE_SC_EX("GetLinkStatus", RPC_LINK_STATUS, ScGetLinkStatus, InRpcLinkStatus, OutRpcLinkStatus, FreeRpcLinkStatus)
+DECLARE_SC("SetLinkOnline", RPC_LINK, ScSetLinkOnline, InRpcLink, OutRpcLink)
+DECLARE_SC("SetLinkOffline", RPC_LINK, ScSetLinkOffline, InRpcLink, OutRpcLink)
+DECLARE_SC("DeleteLink", RPC_LINK, ScDeleteLink, InRpcLink, OutRpcLink)
+DECLARE_SC("RenameLink", RPC_RENAME_LINK, ScRenameLink, InRpcRenameLink, OutRpcRenameLink)
+DECLARE_SC("AddAccess", RPC_ADD_ACCESS, ScAddAccess, InRpcAddAccess, OutRpcAddAccess)
+DECLARE_SC("DeleteAccess", RPC_DELETE_ACCESS, ScDeleteAccess, InRpcDeleteAccess, OutRpcDeleteAccess)
+DECLARE_SC_EX("EnumAccess", RPC_ENUM_ACCESS_LIST, ScEnumAccess, InRpcEnumAccessList, OutRpcEnumAccessList, FreeRpcEnumAccessList)
+DECLARE_SC_EX("SetAccessList", RPC_ENUM_ACCESS_LIST, ScSetAccessList, InRpcEnumAccessList, OutRpcEnumAccessList, FreeRpcEnumAccessList)
+DECLARE_SC_EX("CreateUser", RPC_SET_USER, ScCreateUser, InRpcSetUser, OutRpcSetUser, FreeRpcSetUser)
+DECLARE_SC_EX("SetUser", RPC_SET_USER, ScSetUser, InRpcSetUser, OutRpcSetUser, FreeRpcSetUser)
+DECLARE_SC_EX("GetUser", RPC_SET_USER, ScGetUser, InRpcSetUser, OutRpcSetUser, FreeRpcSetUser)
+DECLARE_SC("DeleteUser", RPC_DELETE_USER, ScDeleteUser, InRpcDeleteUser, OutRpcDeleteUser)
+DECLARE_SC_EX("EnumUser", RPC_ENUM_USER, ScEnumUser, InRpcEnumUser, OutRpcEnumUser, FreeRpcEnumUser)
+DECLARE_SC_EX("CreateGroup", RPC_SET_GROUP, ScCreateGroup, InRpcSetGroup, OutRpcSetGroup, FreeRpcSetGroup)
+DECLARE_SC_EX("SetGroup", RPC_SET_GROUP, ScSetGroup, InRpcSetGroup, OutRpcSetGroup, FreeRpcSetGroup)
+DECLARE_SC_EX("GetGroup", RPC_SET_GROUP, ScGetGroup, InRpcSetGroup, OutRpcSetGroup, FreeRpcSetGroup)
+DECLARE_SC("DeleteGroup", RPC_DELETE_USER, ScDeleteGroup, InRpcDeleteUser, OutRpcDeleteUser)
+DECLARE_SC_EX("EnumGroup", RPC_ENUM_GROUP, ScEnumGroup, InRpcEnumGroup, OutRpcEnumGroup, FreeRpcEnumGroup)
+DECLARE_SC_EX("EnumSession", RPC_ENUM_SESSION, ScEnumSession, InRpcEnumSession, OutRpcEnumSession, FreeRpcEnumSession)
+DECLARE_SC_EX("GetSessionStatus", RPC_SESSION_STATUS, ScGetSessionStatus, InRpcSessionStatus, OutRpcSessionStatus, FreeRpcSessionStatus)
+DECLARE_SC("DeleteSession", RPC_DELETE_SESSION, ScDeleteSession, InRpcDeleteSession, OutRpcDeleteSession)
+DECLARE_SC_EX("EnumMacTable", RPC_ENUM_MAC_TABLE, ScEnumMacTable, InRpcEnumMacTable, OutRpcEnumMacTable, FreeRpcEnumMacTable)
+DECLARE_SC("DeleteMacTable", RPC_DELETE_TABLE, ScDeleteMacTable, InRpcDeleteTable, OutRpcDeleteTable)
+DECLARE_SC_EX("EnumIpTable", RPC_ENUM_IP_TABLE, ScEnumIpTable, InRpcEnumIpTable, OutRpcEnumIpTable, FreeRpcEnumIpTable)
+DECLARE_SC("DeleteIpTable", RPC_DELETE_TABLE, ScDeleteIpTable, InRpcDeleteTable, OutRpcDeleteTable)
+DECLARE_SC("SetKeep", RPC_KEEP, ScSetKeep, InRpcKeep, OutRpcKeep)
+DECLARE_SC("GetKeep", RPC_KEEP, ScGetKeep, InRpcKeep, OutRpcKeep)
+DECLARE_SC("EnableSecureNAT", RPC_HUB, ScEnableSecureNAT, InRpcHub, OutRpcHub)
+DECLARE_SC("DisableSecureNAT", RPC_HUB, ScDisableSecureNAT, InRpcHub, OutRpcHub)
+DECLARE_SC("SetSecureNATOption", VH_OPTION, ScSetSecureNATOption, InVhOption, OutVhOption)
+DECLARE_SC("GetSecureNATOption", VH_OPTION, ScGetSecureNATOption, InVhOption, OutVhOption)
+DECLARE_SC_EX("EnumNAT", RPC_ENUM_NAT, ScEnumNAT, InRpcEnumNat, OutRpcEnumNat, FreeRpcEnumNat)
+DECLARE_SC_EX("EnumDHCP", RPC_ENUM_DHCP, ScEnumDHCP, InRpcEnumDhcp, OutRpcEnumDhcp, FreeRpcEnumDhcp)
+DECLARE_SC("GetSecureNATStatus", RPC_NAT_STATUS, ScGetSecureNATStatus, InRpcNatStatus, OutRpcNatStatus)
+DECLARE_SC_EX("EnumEthernet", RPC_ENUM_ETH, ScEnumEthernet, InRpcEnumEth, OutRpcEnumEth, FreeRpcEnumEth)
+DECLARE_SC("AddLocalBridge", RPC_LOCALBRIDGE, ScAddLocalBridge, InRpcLocalBridge, OutRpcLocalBridge)
+DECLARE_SC("DeleteLocalBridge", RPC_LOCALBRIDGE, ScDeleteLocalBridge, InRpcLocalBridge, OutRpcLocalBridge)
+DECLARE_SC_EX("EnumLocalBridge", RPC_ENUM_LOCALBRIDGE, ScEnumLocalBridge, InRpcEnumLocalBridge, OutRpcEnumLocalBridge, FreeRpcEnumLocalBridge)
+DECLARE_SC("GetBridgeSupport", RPC_BRIDGE_SUPPORT, ScGetBridgeSupport, InRpcBridgeSupport, OutRpcBridgeSupport)
+DECLARE_SC("RebootServer", RPC_TEST, ScRebootServer, InRpcTest, OutRpcTest)
+DECLARE_SC_EX("GetCaps", CAPSLIST, ScGetCaps, InRpcCapsList, OutRpcCapsList, FreeRpcCapsList)
+DECLARE_SC_EX("GetConfig", RPC_CONFIG, ScGetConfig, InRpcConfig, OutRpcConfig, FreeRpcConfig)
+DECLARE_SC_EX("SetConfig", RPC_CONFIG, ScSetConfig, InRpcConfig, OutRpcConfig, FreeRpcConfig)
+DECLARE_SC_EX("GetHubAdminOptions", RPC_ADMIN_OPTION, ScGetHubAdminOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+DECLARE_SC_EX("SetHubAdminOptions", RPC_ADMIN_OPTION, ScSetHubAdminOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+DECLARE_SC_EX("GetHubExtOptions", RPC_ADMIN_OPTION, ScGetHubExtOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+DECLARE_SC_EX("SetHubExtOptions", RPC_ADMIN_OPTION, ScSetHubExtOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+DECLARE_SC_EX("GetDefaultHubAdminOptions", RPC_ADMIN_OPTION, ScGetDefaultHubAdminOptions, InRpcAdminOption, OutRpcAdminOption, FreeRpcAdminOption)
+DECLARE_SC("AddL3Switch", RPC_L3SW, ScAddL3Switch, InRpcL3Sw, OutRpcL3Sw)
+DECLARE_SC("DelL3Switch", RPC_L3SW, ScDelL3Switch, InRpcL3Sw, OutRpcL3Sw)
+DECLARE_SC_EX("EnumL3Switch", RPC_ENUM_L3SW, ScEnumL3Switch, InRpcEnumL3Sw, OutRpcEnumL3Sw, FreeRpcEnumL3Sw)
+DECLARE_SC("StartL3Switch", RPC_L3SW, ScStartL3Switch, InRpcL3Sw, OutRpcL3Sw)
+DECLARE_SC("StopL3Switch", RPC_L3SW, ScStopL3Switch, InRpcL3Sw, OutRpcL3Sw)
+DECLARE_SC("AddL3If", RPC_L3IF, ScAddL3If, InRpcL3If, OutRpcL3If)
+DECLARE_SC("DelL3If", RPC_L3IF, ScDelL3If, InRpcL3If, OutRpcL3If)
+DECLARE_SC_EX("EnumL3If", RPC_ENUM_L3IF, ScEnumL3If, InRpcEnumL3If, OutRpcEnumL3If, FreeRpcEnumL3If)
+DECLARE_SC("AddL3Table", RPC_L3TABLE, ScAddL3Table, InRpcL3Table, OutRpcL3Table)
+DECLARE_SC("DelL3Table", RPC_L3TABLE, ScDelL3Table, InRpcL3Table, OutRpcL3Table)
+DECLARE_SC_EX("EnumL3Table", RPC_ENUM_L3TABLE, ScEnumL3Table, InRpcEnumL3Table, OutRpcEnumL3Table, FreeRpcEnumL3Table)
+DECLARE_SC_EX("EnumCrl", RPC_ENUM_CRL, ScEnumCrl, InRpcEnumCrl, OutRpcEnumCrl, FreeRpcEnumCrl)
+DECLARE_SC_EX("AddCrl", RPC_CRL, ScAddCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+DECLARE_SC_EX("DelCrl", RPC_CRL, ScDelCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+DECLARE_SC_EX("GetCrl", RPC_CRL, ScGetCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+DECLARE_SC_EX("SetCrl", RPC_CRL, ScSetCrl, InRpcCrl, OutRpcCrl, FreeRpcCrl)
+DECLARE_SC_EX("SetAcList", RPC_AC_LIST, ScSetAcList, InRpcAcList, OutRpcAcList, FreeRpcAcList)
+DECLARE_SC_EX("GetAcList", RPC_AC_LIST, ScGetAcList, InRpcAcList, OutRpcAcList, FreeRpcAcList)
+DECLARE_SC_EX("EnumLogFile", RPC_ENUM_LOG_FILE, ScEnumLogFile, InRpcEnumLogFile, OutRpcEnumLogFile, FreeRpcEnumLogFile)
+DECLARE_SC_EX("ReadLogFile", RPC_READ_LOG_FILE, ScReadLogFile, InRpcReadLogFile, OutRpcReadLogFile, FreeRpcReadLogFile)
+DECLARE_SC("AddLicenseKey", RPC_TEST, ScAddLicenseKey, InRpcTest, OutRpcTest)
+DECLARE_SC("DelLicenseKey", RPC_TEST, ScDelLicenseKey, InRpcTest, OutRpcTest)
+DECLARE_SC_EX("EnumLicenseKey", RPC_ENUM_LICENSE_KEY, ScEnumLicenseKey, InRpcEnumLicenseKey, OutRpcEnumLicenseKey, FreeRpcEnumLicenseKey)
+DECLARE_SC("GetLicenseStatus", RPC_LICENSE_STATUS, ScGetLicenseStatus, InRpcLicenseStatus, OutRpcLicenseStatus)
+DECLARE_SC("SetSysLog", SYSLOG_SETTING, ScSetSysLog, InRpcSysLogSetting, OutRpcSysLogSetting)
+DECLARE_SC("GetSysLog", SYSLOG_SETTING, ScGetSysLog, InRpcSysLogSetting, OutRpcSysLogSetting)
+DECLARE_SC_EX("EnumEthVLan", RPC_ENUM_ETH_VLAN, ScEnumEthVLan, InRpcEnumEthVLan, OutRpcEnumEthVLan, FreeRpcEnumEthVLan)
+DECLARE_SC("SetEnableEthVLan", RPC_TEST, ScSetEnableEthVLan, InRpcTest, OutRpcTest)
+DECLARE_SC_EX("SetHubMsg", RPC_MSG, ScSetHubMsg, InRpcMsg, OutRpcMsg, FreeRpcMsg)
+DECLARE_SC_EX("GetHubMsg", RPC_MSG, ScGetHubMsg, InRpcMsg, OutRpcMsg, FreeRpcMsg)
+DECLARE_SC("Crash", RPC_TEST, ScCrash, InRpcTest, OutRpcTest)
+DECLARE_SC_EX("GetAdminMsg", RPC_MSG, ScGetAdminMsg, InRpcMsg, OutRpcMsg, FreeRpcMsg)
+DECLARE_SC("Flush", RPC_TEST, ScFlush, InRpcTest, OutRpcTest)
+DECLARE_SC("Debug", RPC_TEST, ScDebug, InRpcTest, OutRpcTest)
+DECLARE_SC("SetIPsecServices", IPSEC_SERVICES, ScSetIPsecServices, InIPsecServices, OutIPsecServices)
+DECLARE_SC("GetIPsecServices", IPSEC_SERVICES, ScGetIPsecServices, InIPsecServices, OutIPsecServices)
+DECLARE_SC("AddEtherIpId", ETHERIP_ID, ScAddEtherIpId, InEtherIpId, OutEtherIpId)
+DECLARE_SC("GetEtherIpId", ETHERIP_ID, ScGetEtherIpId, InEtherIpId, OutEtherIpId)
+DECLARE_SC("DeleteEtherIpId", ETHERIP_ID, ScDeleteEtherIpId, InEtherIpId, OutEtherIpId)
+DECLARE_SC_EX("EnumEtherIpId", RPC_ENUM_ETHERIP_ID, ScEnumEtherIpId, InRpcEnumEtherIpId, OutRpcEnumEtherIpId, FreeRpcEnumEtherIpId)
+DECLARE_SC("SetOpenVpnSstpConfig", OPENVPN_SSTP_CONFIG, ScSetOpenVpnSstpConfig, InOpenVpnSstpConfig, OutOpenVpnSstpConfig)
+DECLARE_SC("GetOpenVpnSstpConfig", OPENVPN_SSTP_CONFIG, ScGetOpenVpnSstpConfig, InOpenVpnSstpConfig, OutOpenVpnSstpConfig)
+DECLARE_SC("GetDDnsClientStatus", DDNS_CLIENT_STATUS, ScGetDDnsClientStatus, InDDnsClientStatus, OutDDnsClientStatus)
+DECLARE_SC("ChangeDDnsClientHostname", RPC_TEST, ScChangeDDnsClientHostname, InRpcTest, OutRpcTest)
+DECLARE_SC("RegenerateServerCert", RPC_TEST, ScRegenerateServerCert, InRpcTest, OutRpcTest)
+DECLARE_SC_EX("MakeOpenVpnConfigFile", RPC_READ_LOG_FILE, ScMakeOpenVpnConfigFile, InRpcReadLogFile, OutRpcReadLogFile, FreeRpcReadLogFile)
+DECLARE_SC("SetSpecialListener", RPC_SPECIAL_LISTENER, ScSetSpecialListener, InRpcSpecialListener, OutRpcSpecialListener)
+DECLARE_SC("GetSpecialListener", RPC_SPECIAL_LISTENER, ScGetSpecialListener, InRpcSpecialListener, OutRpcSpecialListener)
+DECLARE_SC("GetAzureStatus", RPC_AZURE_STATUS, ScGetAzureStatus, InRpcAzureStatus, OutRpcAzureStatus)
+DECLARE_SC("SetAzureStatus", RPC_AZURE_STATUS, ScSetAzureStatus, InRpcAzureStatus, OutRpcAzureStatus)
+DECLARE_SC("GetDDnsInternetSettng", INTERNET_SETTING, ScGetDDnsInternetSetting, InRpcInternetSetting, OutRpcInternetSetting)
+DECLARE_SC("SetDDnsInternetSettng", INTERNET_SETTING, ScSetDDnsInternetSetting, InRpcInternetSetting, OutRpcInternetSetting)
+// RPC call function declaration: till here
+
+// Setting VPN Gate Server Configuration
+UINT StSetVgsConfig(ADMIN *a, VGS_CONFIG *t)
+{
+ return ERR_NOT_SUPPORTED;
+}
+
+// Get VPN Gate configuration
+UINT StGetVgsConfig(ADMIN *a, VGS_CONFIG *t)
+{
+ return ERR_NOT_SUPPORTED;
+}
+
+// Get DDNS proxy configuration
+UINT StGetDDnsInternetSetting(ADMIN *a, INTERNET_SETTING *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (s->DDnsClient == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ Zero(t, sizeof(INTERNET_SETTING));
+
+ DCGetInternetSetting(s->DDnsClient, t);
+
+ return ret;
+}
+
+// Set DDNS proxy configuration
+UINT StSetDDnsInternetSetting(ADMIN *a, INTERNET_SETTING *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (s->DDnsClient == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ DCSetInternetSetting(s->DDnsClient, t);
+
+ IncrementServerConfigRevision(s);
+
+ return ret;
+}
+
+// Get Azure status
+UINT StGetAzureStatus(ADMIN *a, RPC_AZURE_STATUS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ AZURE_CLIENT *ac;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (SiIsAzureSupported(s) == false)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ ac = s->AzureClient;
+ if (ac == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ Zero(t, sizeof(RPC_AZURE_STATUS));
+
+ Lock(ac->Lock);
+ {
+ t->IsConnected = ac->IsConnected;
+ t->IsEnabled = ac->IsEnabled;
+ }
+ Unlock(ac->Lock);
+
+ return ERR_NO_ERROR;
+}
+
+// Set Azure status
+UINT StSetAzureStatus(ADMIN *a, RPC_AZURE_STATUS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (SiIsAzureSupported(s) == false)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ SiSetAzureEnable(s, t->IsEnabled);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get special listener status
+UINT StGetSpecialListener(ADMIN *a, RPC_SPECIAL_LISTENER *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ Zero(t, sizeof(RPC_SPECIAL_LISTENER));
+ t->VpnOverDnsListener = s->EnableVpnOverDns;
+ t->VpnOverIcmpListener = s->EnableVpnOverIcmp;
+
+ return ERR_NO_ERROR;
+}
+
+// Set special listener status
+UINT StSetSpecialListener(ADMIN *a, RPC_SPECIAL_LISTENER *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ // Check ports
+ if (t->VpnOverDnsListener && (MAKEBOOL(s->EnableVpnOverDns) != MAKEBOOL(t->VpnOverDnsListener)))
+ {
+ if (SiCanOpenVpnOverDnsPort() == false)
+ {
+ return ERR_SPECIAL_LISTENER_DNS_ERROR;
+ }
+ }
+
+ if (t->VpnOverIcmpListener && (MAKEBOOL(s->EnableVpnOverIcmp) != MAKEBOOL(t->VpnOverIcmpListener)))
+ {
+ if (SiCanOpenVpnOverIcmpPort() == false)
+ {
+ return ERR_SPECIAL_LISTENER_ICMP_ERROR;
+ }
+ }
+
+ s->EnableVpnOverDns = t->VpnOverDnsListener;
+ s->EnableVpnOverIcmp = t->VpnOverIcmpListener;
+
+ SiApplySpecialListenerStatus(s);
+
+ ALog(a, NULL, "LA_SET_SPECIAL_LISTENER");
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Set configurations for OpenVPN and SSTP
+UINT StSetOpenVpnSstpConfig(ADMIN *a, OPENVPN_SSTP_CONFIG *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ SiSetOpenVPNAndSSTPConfig(s, t);
+
+ ALog(a, NULL, "LA_SET_OVPN_SSTP_CONFIG");
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get configurations for OpenVPN and SSTP
+UINT StGetOpenVpnSstpConfig(ADMIN *a, OPENVPN_SSTP_CONFIG *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ Zero(t, sizeof(OPENVPN_SSTP_CONFIG));
+ SiGetOpenVPNAndSSTPConfig(s, t);
+
+ return ERR_NO_ERROR;
+}
+
+// Get status of DDNS client
+UINT StGetDDnsClientStatus(ADMIN *a, DDNS_CLIENT_STATUS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (s->DDnsClient == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ Zero(t, sizeof(DDNS_CLIENT_STATUS));
+ DCGetStatus(s->DDnsClient, t);
+
+ return ERR_NO_ERROR;
+}
+
+// Change host-name for DDNS client
+UINT StChangeDDnsClientHostname(ADMIN *a, RPC_TEST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (s->DDnsClient == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ ret = DCChangeHostName(s->DDnsClient, t->StrValue);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ ALog(a, NULL, "LA_DDNS_HOSTNAME_CHANGED", t->StrValue);
+ }
+
+ IncrementServerConfigRevision(s);
+
+ return ret;
+}
+
+// Regenerate server certification
+UINT StRegenerateServerCert(ADMIN *a, RPC_TEST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ X *x;
+ K *k;
+
+ SERVER_ADMIN_ONLY;
+
+ SiGenerateDefaultCertEx(&x, &k, t->StrValue);
+
+ SetCedarCert(c, x, k);
+
+ ALog(a, NULL, "LA_REGENERATE_SERVER_CERT", t->StrValue);
+
+ IncrementServerConfigRevision(s);
+
+ FreeX(x);
+ FreeK(k);
+
+ return ERR_NO_ERROR;
+}
+
+// Generate OpenVPN configuration files
+UINT StMakeOpenVpnConfigFile(ADMIN *a, RPC_READ_LOG_FILE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ ZIP_PACKER *p;
+ FIFO *f;
+ BUF *readme_buf;
+ BUF *readme_pdf_buf;
+ BUF *sample_buf;
+ OPENVPN_SSTP_CONFIG config;
+ LIST *port_list;
+ char my_hostname[MAX_SIZE];
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ SiGetOpenVPNAndSSTPConfig(s, &config);
+
+ if (config.EnableOpenVPN == false)
+ {
+ return ERR_OPENVPN_IS_NOT_ENABLED;
+ }
+
+ port_list = StrToIntList(config.OpenVPNPortList, true);
+
+ FreeRpcReadLogFile(t);
+ Zero(t, sizeof(RPC_READ_LOG_FILE));
+
+ p = NewZipPacker();
+
+ // readme.txt
+ readme_buf = ReadDump("|openvpn_readme.txt");
+
+ // readme.pdf
+ readme_pdf_buf = ReadDump("|openvpn_readme.pdf");
+
+ // sample.ovpn
+ sample_buf = ReadDump("|openvpn_sample.ovpn");
+
+ // host name
+ GetMachineHostName(my_hostname, sizeof(my_hostname));
+ my_hostname[16] = 0;
+
+ if (readme_buf == NULL || sample_buf == NULL || readme_pdf_buf == NULL)
+ {
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ BUF *config_l3_buf, *config_l2_buf;
+ X *x = NULL;
+ BUF *x_buf;
+ char protocol[MAX_SIZE];
+ UINT port = OPENVPN_UDP_PORT;
+ char port_str[MAX_SIZE];
+ char hostname[MAX_SIZE];
+ char tag_before_hostname[MAX_SIZE];
+ DDNS_CLIENT_STATUS ddns;
+ UCHAR *zero_buffer;
+ UINT zero_buffer_size = 128 * 1024;
+ char name_tmp[MAX_SIZE];
+ X *dummy_x = NULL;
+ K *dummy_private_k = NULL;
+ K *dummy_public_k = NULL;
+ BUF *dummy_x_buf = NULL;
+ BUF *dummy_k_buf = NULL;
+
+ zero_buffer = ZeroMalloc(zero_buffer_size);
+
+
+ if (x == NULL)
+ {
+ Lock(c->lock);
+ {
+ x = CloneX(c->ServerX);
+ }
+ Unlock(c->lock);
+ }
+
+ x_buf = XToBuf(x, true);
+
+ SeekBufToEnd(x_buf);
+ WriteBufChar(x_buf, 0);
+ SeekBufToBegin(x_buf);
+
+ // Generate dummy certification
+ if (x != NULL)
+ {
+ if (RsaGen(&dummy_private_k, &dummy_public_k, x->bits))
+ {
+ NAME *name;
+ wchar_t cn[128];
+
+ UniToStr64(cn, Rand64());
+
+ name = NewName(cn, cn, cn, L"US", NULL, NULL);
+
+ dummy_x = NewRootX(dummy_public_k, dummy_private_k, name, MAX(GetDaysUntil2038(), SERVER_DEFAULT_CERT_DAYS), NULL);
+
+ FreeName(name);
+
+ dummy_x_buf = XToBuf(dummy_x, true);
+ SeekBufToEnd(dummy_x_buf);
+ WriteBufChar(dummy_x_buf, 0);
+ SeekBufToBegin(dummy_x_buf);
+
+ dummy_k_buf = KToBuf(dummy_private_k, true, NULL);
+ SeekBufToEnd(dummy_k_buf);
+ WriteBufChar(dummy_k_buf, 0);
+ SeekBufToBegin(dummy_k_buf);
+ }
+ }
+
+ FreeX(x);
+ Zero(hostname, sizeof(hostname));
+ Zero(tag_before_hostname, sizeof(tag_before_hostname));
+
+ Zero(&ddns, sizeof(ddns));
+ if (s->DDnsClient != NULL)
+ {
+ DCGetStatus(s->DDnsClient, &ddns);
+
+ if (IsEmptyStr(ddns.CurrentHostName) == false && IsEmptyStr(ddns.DnsSuffix) == false &&
+ ddns.Err_IPv4 == ERR_NO_ERROR)
+ {
+ StrCpy(tag_before_hostname, sizeof(tag_before_hostname),
+ "# Note: The below hostname is came from the Dynamic DNS Client function\r\n"
+ "# which is running on the VPN Server. If you don't want to use\r\n"
+ "# the Dynamic DNS hostname, replace it to either IP address or\r\n"
+ "# other domain's hostname.\r\n\r\n");
+
+ Format(hostname, sizeof(hostname), "%s.v4%s", ddns.CurrentHostName, ddns.DnsSuffix);
+ }
+ }
+
+ if (IsEmptyStr(hostname))
+ {
+ IP myip;
+
+ Zero(&myip, sizeof(myip));
+ GetCurrentGlobalIP(&myip, false);
+
+ if (IsZeroIP(&myip))
+ {
+ GetCurrentGlobalIPGuess(&myip, false);
+ }
+
+ IPToStr(hostname, sizeof(hostname), &myip);
+ }
+
+ SeekBuf(sample_buf, sample_buf->Size, 0);
+ WriteBuf(sample_buf, zero_buffer, zero_buffer_size);
+
+ config_l3_buf = CloneBuf(sample_buf);
+ config_l2_buf = CloneBuf(sample_buf);
+
+ // Generate contents of configuration
+ if (LIST_NUM(port_list) >= 1)
+ {
+ StrCpy(protocol, sizeof(protocol), "udp");
+
+ if (IsIntInList(port_list, OPENVPN_UDP_PORT))
+ {
+ port = OPENVPN_UDP_PORT;
+ }
+ else
+ {
+ port = *((UINT *)(LIST_DATA(port_list, 0)));
+ }
+ }
+ else
+ {
+ RPC_LISTENER_LIST tt;
+ UINT i;
+
+ port = 0;
+
+ StrCpy(protocol, sizeof(protocol), "tcp");
+
+ Zero(&tt, sizeof(tt));
+
+ StEnumListener(a, &tt);
+
+ for (i = 0;i < tt.NumPort;i++)
+ {
+ if (tt.Enables[i] && tt.Errors[i] == false)
+ {
+ port = tt.Ports[i];
+ break;
+ }
+ }
+
+ FreeRpcListenerList(&tt);
+
+ if (port == 0)
+ {
+ StrCpy(protocol, sizeof(protocol), "udp");
+ port = OPENVPN_UDP_PORT;
+ }
+ }
+
+ ToStr(port_str, port);
+
+ if (IsEmptyStr(my_hostname) == false)
+ {
+ StrCat(my_hostname, sizeof(my_hostname), "_");
+
+ StrLower(my_hostname);
+ }
+
+ ZipAddFileSimple(p, "readme.txt", LocalTime64(), 0, readme_buf->Buf, readme_buf->Size);
+ ZipAddFileSimple(p, "readme.pdf", LocalTime64(), 0, readme_pdf_buf->Buf, readme_pdf_buf->Size);
+
+ ReplaceStrEx((char *)config_l3_buf->Buf, config_l3_buf->Size, (char *)config_l3_buf->Buf,
+ "$TAG_TUN_TAP$", "tun", false);
+ ReplaceStrEx((char *)config_l3_buf->Buf, config_l3_buf->Size, (char *)config_l3_buf->Buf,
+ "$TAG_PROTO$", protocol, false);
+ ReplaceStrEx((char *)config_l3_buf->Buf, config_l3_buf->Size, (char *)config_l3_buf->Buf,
+ "$TAG_HOSTNAME$", hostname, false);
+ ReplaceStrEx((char *)config_l3_buf->Buf, config_l3_buf->Size, (char *)config_l3_buf->Buf,
+ "$TAG_BEFORE_REMOTE$", tag_before_hostname, false);
+ ReplaceStrEx((char *)config_l3_buf->Buf, config_l3_buf->Size, (char *)config_l3_buf->Buf,
+ "$TAG_PORT$", port_str, false);
+
+ if (x_buf != NULL)
+ {
+ ReplaceStrEx((char *)config_l3_buf->Buf, config_l3_buf->Size, (char *)config_l3_buf->Buf,
+ "$CA$", x_buf->Buf, false);
+ }
+
+ if (dummy_x_buf != NULL)
+ {
+ ReplaceStrEx((char *)config_l3_buf->Buf, config_l3_buf->Size, (char *)config_l3_buf->Buf,
+ "$CERT$", dummy_x_buf->Buf, false);
+ }
+
+ if (dummy_k_buf != NULL)
+ {
+ ReplaceStrEx((char *)config_l3_buf->Buf, config_l3_buf->Size, (char *)config_l3_buf->Buf,
+ "$KEY$", dummy_k_buf->Buf, false);
+ }
+
+ Format(name_tmp, sizeof(name_tmp), "%sopenvpn_remote_access_l3.ovpn", my_hostname);
+ ZipAddFileSimple(p, name_tmp, LocalTime64(), 0, config_l3_buf->Buf, StrLen(config_l3_buf->Buf));
+
+ ReplaceStrEx((char *)config_l2_buf->Buf, config_l2_buf->Size, (char *)config_l2_buf->Buf,
+ "$TAG_TUN_TAP$", "tap", false);
+ ReplaceStrEx((char *)config_l2_buf->Buf, config_l2_buf->Size, (char *)config_l2_buf->Buf,
+ "$TAG_PROTO$", protocol, false);
+ ReplaceStrEx((char *)config_l2_buf->Buf, config_l2_buf->Size, (char *)config_l2_buf->Buf,
+ "$TAG_HOSTNAME$", hostname, false);
+ ReplaceStrEx((char *)config_l2_buf->Buf, config_l2_buf->Size, (char *)config_l2_buf->Buf,
+ "$TAG_BEFORE_REMOTE$", tag_before_hostname, false);
+ ReplaceStrEx((char *)config_l2_buf->Buf, config_l2_buf->Size, (char *)config_l2_buf->Buf,
+ "$TAG_PORT$", port_str, false);
+
+ if (x_buf != NULL)
+ {
+ ReplaceStrEx((char *)config_l2_buf->Buf, config_l2_buf->Size, (char *)config_l2_buf->Buf,
+ "$CA$", x_buf->Buf, false);
+ }
+
+ if (dummy_x_buf != NULL)
+ {
+ ReplaceStrEx((char *)config_l2_buf->Buf, config_l2_buf->Size, (char *)config_l2_buf->Buf,
+ "$CERT$", dummy_x_buf->Buf, false);
+ }
+
+ if (dummy_k_buf != NULL)
+ {
+ ReplaceStrEx((char *)config_l2_buf->Buf, config_l2_buf->Size, (char *)config_l2_buf->Buf,
+ "$KEY$", dummy_k_buf->Buf, false);
+ }
+
+ Format(name_tmp, sizeof(name_tmp), "%sopenvpn_site_to_site_bridge_l2.ovpn", my_hostname);
+ ZipAddFileSimple(p, name_tmp, LocalTime64(), 0, config_l2_buf->Buf, StrLen(config_l2_buf->Buf));
+
+ FreeBuf(config_l3_buf);
+ FreeBuf(config_l2_buf);
+
+ f = ZipFinish(p);
+
+ if (f != NULL)
+ {
+ t->Buffer = NewBuf();
+ WriteBuf(t->Buffer, FifoPtr(f), FifoSize(f));
+ SeekBuf(t->Buffer, 0, 0);
+ }
+
+ FreeBuf(readme_buf);
+ FreeBuf(sample_buf);
+ FreeBuf(readme_pdf_buf);
+ FreeBuf(x_buf);
+
+ FreeX(dummy_x);
+ FreeK(dummy_private_k);
+ FreeK(dummy_public_k);
+
+ FreeBuf(dummy_k_buf);
+ FreeBuf(dummy_x_buf);
+
+ Free(zero_buffer);
+ }
+
+ FreeStrList(port_list);
+
+ FreeZipPacker(p);
+
+ return ERR_NO_ERROR;
+}
+
+// Set IPsec service configuration
+UINT StSetIPsecServices(ADMIN *a, IPSEC_SERVICES *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (GetServerCapsBool(s, "b_support_ipsec") == false || s->IPsecServer == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ IPsecServerSetServices(s->IPsecServer, t);
+
+ ALog(a, NULL, "LA_SET_IPSEC_CONFIG");
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get IPsec service configuration
+UINT StGetIPsecServices(ADMIN *a, IPSEC_SERVICES *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (GetServerCapsBool(s, "b_support_ipsec") == false || s->IPsecServer == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ Zero(t, sizeof(IPSEC_SERVICES));
+ IPsecServerGetServices(s->IPsecServer, t);
+
+ return ERR_NO_ERROR;
+}
+
+// Add EtherIP ID setting
+UINT StAddEtherIpId(ADMIN *a, ETHERIP_ID *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (GetServerCapsBool(s, "b_support_ipsec") == false || s->IPsecServer == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ AddEtherIPId(s->IPsecServer, t);
+
+ ALog(a, NULL, "LA_ADD_ETHERIP_ID", t->Id);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get EtherIP ID setting
+UINT StGetEtherIpId(ADMIN *a, ETHERIP_ID *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ char id[MAX_SIZE];
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (GetServerCapsBool(s, "b_support_ipsec") == false || s->IPsecServer == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ StrCpy(id, sizeof(id), t->Id);
+
+ Zero(t, sizeof(ETHERIP_ID));
+ if (SearchEtherIPId(s->IPsecServer, t, id) == false)
+ {
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ return ERR_NO_ERROR;
+}
+
+// Delete EtherIP ID setting
+UINT StDeleteEtherIpId(ADMIN *a, ETHERIP_ID *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ char id[MAX_SIZE];
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (GetServerCapsBool(s, "b_support_ipsec") == false || s->IPsecServer == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ StrCpy(id, sizeof(id), t->Id);
+
+ if (DeleteEtherIPId(s->IPsecServer, id) == false)
+ {
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ ALog(a, NULL, "LA_DEL_ETHERIP_ID", id);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate EtherIP ID settings
+UINT StEnumEtherIpId(ADMIN *a, RPC_ENUM_ETHERIP_ID *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (GetServerCapsBool(s, "b_support_ipsec") == false || s->IPsecServer == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ FreeRpcEnumEtherIpId(t);
+ Zero(t, sizeof(RPC_ENUM_ETHERIP_ID));
+
+ Lock(s->IPsecServer->LockSettings);
+ {
+ UINT i;
+ UINT num;
+
+ num = LIST_NUM(s->IPsecServer->EtherIPIdList);
+
+ t->NumItem = num;
+ t->IdList = ZeroMalloc(sizeof(ETHERIP_ID) * num);
+
+ for (i = 0;i < num;i++)
+ {
+ ETHERIP_ID *d = &t->IdList[i];
+ ETHERIP_ID *src = LIST_DATA(s->IPsecServer->EtherIPIdList, i);
+
+ Copy(d, src, sizeof(ETHERIP_ID));
+ }
+ }
+ Unlock(s->IPsecServer->LockSettings);
+
+ return ERR_NO_ERROR;
+}
+
+// Set message of today on hub
+UINT StSetHubMsg(ADMIN *a, RPC_MSG *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+ if (UniStrLen(t->Msg) > HUB_MAXMSG_LEN)
+ {
+ return ERR_MEMORY_NOT_ENOUGH;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ h = GetHub(c, hubname);
+
+ if (h == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_msg") != 0)
+ {
+ ret = ERR_NOT_ENOUGH_RIGHT;
+ }
+ else
+ {
+ SetHubMsg(h, t->Msg);
+ }
+
+ ReleaseHub(h);
+ }
+
+ IncrementServerConfigRevision(s);
+
+ return ret;
+}
+
+// Get message of today on hub
+UINT StGetHubMsg(ADMIN *a, RPC_MSG *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+ if (UniStrLen(t->Msg) > HUB_MAXMSG_LEN)
+ {
+ return ERR_MEMORY_NOT_ENOUGH;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ h = GetHub(c, hubname);
+
+ if (h == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ FreeRpcMsg(t);
+ Zero(t, sizeof(t));
+
+ t->Msg = GetHubMsg(h);
+
+ ReleaseHub(h);
+ }
+
+ return ret;
+}
+
+// Do debug function
+UINT StDebug(ADMIN *a, RPC_TEST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ RPC_TEST t2;
+
+ SERVER_ADMIN_ONLY;
+
+ Zero(&t2, sizeof(t2));
+
+ ret = SiDebug(s, &t2, t->IntValue, t->StrValue);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ Copy(t, &t2, sizeof(RPC_TEST));
+ }
+ else
+ {
+ Zero(t, sizeof(RPC_TEST));
+ }
+
+ return ret;
+}
+
+// Flush configuration file
+UINT StFlush(ADMIN *a, RPC_TEST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ UINT size;
+
+ SERVER_ADMIN_ONLY;
+
+ size = SiWriteConfigurationFile(s);
+
+ t->IntValue = size;
+
+ return ERR_NO_ERROR;
+}
+
+// Do Crash
+UINT StCrash(ADMIN *a, RPC_TEST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+
+#ifdef OS_WIN32
+ MsSetEnableMinidump(false);
+#endif // OS_WIN32
+
+ CrashNow();
+
+ return ERR_NO_ERROR;
+}
+
+// Get message for administrators
+UINT StGetAdminMsg(ADMIN *a, RPC_MSG *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ RPC_WINVER server_ver;
+ RPC_WINVER client_ver;
+ wchar_t winver_msg_client[3800];
+ wchar_t winver_msg_server[3800];
+ UINT tmpsize;
+ wchar_t *tmp;
+
+ FreeRpcMsg(t);
+ Zero(t, sizeof(RPC_MSG));
+
+ // Check for Windows version
+ GetWinVer(&server_ver);
+ Copy(&client_ver, &a->ClientWinVer, sizeof(RPC_WINVER));
+
+ Zero(winver_msg_client, sizeof(winver_msg_client));
+ Zero(winver_msg_server, sizeof(winver_msg_server));
+
+ if (IsSupportedWinVer(&client_ver) == false)
+ {
+ SYSTEMTIME st;
+
+ LocalTime(&st);
+
+ UniFormat(winver_msg_client, sizeof(winver_msg_client), _UU("WINVER_ERROR_FORMAT"),
+ _UU("WINVER_ERROR_PC_LOCAL"),
+ client_ver.Title,
+ _UU("WINVER_ERROR_VPNSERVER"),
+ SUPPORTED_WINDOWS_LIST,
+ _UU("WINVER_ERROR_PC_LOCAL"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ st.wYear, st.wMonth);
+ }
+
+ if (IsSupportedWinVer(&server_ver) == false)
+ {
+ SYSTEMTIME st;
+
+ LocalTime(&st);
+
+ UniFormat(winver_msg_server, sizeof(winver_msg_server), _UU("WINVER_ERROR_FORMAT"),
+ _UU("WINVER_ERROR_PC_REMOTE"),
+ server_ver.Title,
+ _UU("WINVER_ERROR_VPNSERVER"),
+ SUPPORTED_WINDOWS_LIST,
+ _UU("WINVER_ERROR_PC_REMOTE"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ st.wYear, st.wMonth);
+ }
+
+ tmpsize = UniStrSize(winver_msg_client) + UniStrSize(winver_msg_server) + 10000;
+
+ tmp = ZeroMalloc(tmpsize);
+
+ if (
+ c->Bridge == false)
+ {
+ if (GetCurrentLangId() != SE_LANG_ENGLISH)
+ {
+ UniStrCat(tmp, tmpsize, _UU("OSS_MSG"));
+ }
+ }
+
+ UniStrCat(tmp, tmpsize, winver_msg_client);
+ UniStrCat(tmp, tmpsize, winver_msg_server);
+
+ t->Msg = tmp;
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate VLAN tag transparent setting
+UINT StEnumEthVLan(ADMIN *a, RPC_ENUM_ETH_VLAN *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+
+#ifdef OS_WIN32
+ if (GetServerCapsBool(s, "b_support_eth_vlan") == false)
+ {
+ ret = ERR_NOT_SUPPORTED;
+ }
+ else
+ {
+ FreeRpcEnumEthVLan(t);
+ Zero(t, sizeof(RPC_ENUM_ETH_VLAN));
+
+ if (EnumEthVLanWin32(t) == false)
+ {
+ ret = ERR_INTERNAL_ERROR;
+ }
+ }
+#else // OS_WIN32
+ ret = ERR_NOT_SUPPORTED;
+#endif // OS_WIN32
+
+ return ret;
+}
+
+// Set VLAN tag transparent setting
+UINT StSetEnableEthVLan(ADMIN *a, RPC_TEST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+
+#ifdef OS_WIN32
+ if (GetServerCapsBool(s, "b_support_eth_vlan") == false)
+ {
+ ret = ERR_NOT_SUPPORTED;
+ }
+ else if (MsIsAdmin() == false)
+ {
+ ret = ERR_NOT_ENOUGH_RIGHT;
+ }
+ else
+ {
+ if (SetVLanEnableStatus(t->StrValue, MAKEBOOL(t->IntValue)) == false)
+ {
+ ret = ERR_INTERNAL_ERROR;
+ }
+ }
+#else // OS_WIN32
+ ret = ERR_NOT_SUPPORTED;
+#endif // OS_WIN32
+
+ return ret;
+}
+
+// Get license status
+UINT StGetLicenseStatus(ADMIN *a, RPC_LICENSE_STATUS *t)
+{
+ return ERR_NOT_SUPPORTED;
+}
+
+// Enumerate license key
+UINT StEnumLicenseKey(ADMIN *a, RPC_ENUM_LICENSE_KEY *t)
+{
+ return ERR_NOT_SUPPORTED;
+}
+
+// Add new license key
+UINT StAddLicenseKey(ADMIN *a, RPC_TEST *t)
+{
+ return ERR_NOT_SUPPORTED;
+}
+
+// Delete a license key
+UINT StDelLicenseKey(ADMIN *a, RPC_TEST *t)
+{
+ return ERR_NOT_SUPPORTED;
+}
+
+// Download a log file
+BUF *DownloadFileFromServer(RPC *r, char *server_name, char *filepath, UINT total_size, DOWNLOAD_PROC *proc, void *param)
+{
+ UINT offset;
+ BUF *buf;
+ // Validate arguments
+ if (r == NULL || filepath == NULL)
+ {
+ return NULL;
+ }
+
+ if (server_name == NULL)
+ {
+ server_name = "";
+ }
+
+ offset = 0;
+
+ buf = NewBuf();
+
+ while (true)
+ {
+ DOWNLOAD_PROGRESS g;
+ RPC_READ_LOG_FILE t;
+ UINT ret;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.FilePath, sizeof(t.FilePath), filepath);
+ t.Offset = offset;
+ StrCpy(t.ServerName, sizeof(t.ServerName), server_name);
+
+ ret = ScReadLogFile(r, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Failed
+ FreeRpcReadLogFile(&t);
+ FreeBuf(buf);
+ return NULL;
+ }
+
+ if (t.Buffer == NULL)
+ {
+ // read to the end
+ break;
+ }
+
+ // Update current progress
+ offset += t.Buffer->Size;
+ Zero(&g, sizeof(g));
+ g.Param = param;
+ g.CurrentSize = offset;
+ g.TotalSize = MAX(total_size, offset);
+ g.ProgressPercent = (UINT)(MAKESURE((UINT64)g.CurrentSize * 100ULL / (UINT64)(MAX(g.TotalSize, 1)), 0, 100ULL));
+
+ WriteBuf(buf, t.Buffer->Buf, t.Buffer->Size);
+
+ FreeRpcReadLogFile(&t);
+
+ if (proc != NULL)
+ {
+ if (proc(&g) == false)
+ {
+ // Canceled by user
+ FreeBuf(buf);
+ return NULL;
+ }
+ }
+ }
+
+ if (buf->Size == 0)
+ {
+ // Downloading failed
+ FreeBuf(buf);
+ return NULL;
+ }
+
+ return buf;
+}
+
+// Read a log file
+UINT StReadLogFile(ADMIN *a, RPC_READ_LOG_FILE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ char logfilename[MAX_PATH];
+ char servername[MAX_HOST_NAME_LEN + 1];
+ UINT offset;
+ bool local = true;
+
+ if (IsEmptyStr(t->FilePath))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ StrCpy(logfilename, sizeof(logfilename), t->FilePath);
+ StrCpy(servername, sizeof(servername), t->ServerName);
+ offset = t->Offset;
+
+ if (s->ServerType != SERVER_TYPE_FARM_CONTROLLER)
+ {
+ GetMachineName(servername, sizeof(servername));
+ }
+
+ // Check the permission to read the log file
+ if (a->LogFileList == NULL)
+ {
+ // Cache not found
+ return ERR_OBJECT_NOT_FOUND;
+ }
+ if (CheckLogFileNameFromEnumList(a->LogFileList, logfilename, servername) == false)
+ {
+ // There is no such file in the log file list
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ FreeRpcReadLogFile(t);
+ Zero(t, sizeof(RPC_READ_LOG_FILE));
+
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ UINT i;
+
+ // When the host name in request is a cluster member, redirect the request
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+
+ if (f->Me == false)
+ {
+ if (StrCmpi(f->hostname, servername) == 0)
+ {
+ RPC_READ_LOG_FILE tt;
+
+ Zero(&tt, sizeof(tt));
+ local = false;
+
+ StrCpy(tt.ServerName, sizeof(tt.ServerName), servername);
+ StrCpy(tt.FilePath, sizeof(tt.FilePath), logfilename);
+ tt.Offset = offset;
+
+ if (SiCallReadLogFile(s, f, &tt))
+ {
+ if (tt.Buffer != NULL && tt.Buffer->Size > 0)
+ {
+ t->Buffer = NewBuf();
+ WriteBuf(t->Buffer, tt.Buffer->Buf, tt.Buffer->Size);
+ }
+ }
+
+ FreeRpcReadLogFile(&tt);
+
+ break;
+ }
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+
+ // Read a local file
+ if (local)
+ {
+ SiReadLocalLogFile(s, logfilename, offset, t);
+ }
+
+ if (offset == 0)
+ {
+ ALog(a, NULL, "LA_READ_LOG_FILE", servername, logfilename);
+ }
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate log files
+UINT StEnumLogFile(ADMIN *a, RPC_ENUM_LOG_FILE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT i;
+ bool no_access = false;
+
+ HUB *h;
+
+ if (a->ServerAdmin == false)
+ {
+ h = GetHub(c, a->HubName);
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_read_log_file") != 0)
+ {
+ no_access = true;
+ }
+
+ ReleaseHub(h);
+ }
+ else
+ {
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ // Since Management session will become unstable if log files are
+ // enumerated on a cluster controller, it forbids.
+ return ERR_NOT_SUPPORTED;
+ }
+ }
+
+ if (no_access)
+ {
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ FreeRpcEnumLogFile(t);
+ Zero(t, sizeof(RPC_ENUM_LOG_FILE));
+
+ // Enumerate local log files
+ SiEnumLocalLogFileList(s, a->ServerAdmin ? NULL : a->HubName, t);
+
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ UINT i;
+ LIST *tt_list = NewListFast(NULL);
+
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+
+ if (f->Me == false)
+ {
+ // Enumerate log files on other cluster members.
+ RPC_ENUM_LOG_FILE *tt;
+ tt = ZeroMalloc(sizeof(RPC_ENUM_LOG_FILE));
+
+ if (SiCallEnumLogFileList(s, f, tt, a->ServerAdmin ? "" : a->HubName))
+ {
+ UINT i;
+ for (i = 0;i < tt->NumItem;i++)
+ {
+ RPC_ENUM_LOG_FILE_ITEM *e = &tt->Items[i];
+
+ StrCpy(e->ServerName, sizeof(e->ServerName), f->hostname);
+ }
+
+ Add(tt_list, tt);
+ }
+ else
+ {
+ Free(tt);
+ }
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+
+ for (i = 0;i < LIST_NUM(tt_list);i++)
+ {
+ RPC_ENUM_LOG_FILE *tt = LIST_DATA(tt_list, i);
+
+ AdjoinRpcEnumLogFile(t, tt);
+ FreeRpcEnumLogFile(tt);
+
+ Free(tt);
+ }
+
+ ReleaseList(tt_list);
+ }
+
+ // Cache the last list of log files on RPC session
+ if (a->LogFileList != NULL)
+ {
+ FreeEnumLogFile(a->LogFileList);
+ }
+
+ a->LogFileList = NewListFast(CmpLogFile);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_LOG_FILE_ITEM *e = &t->Items[i];
+ LOG_FILE *f = ZeroMalloc(sizeof(LOG_FILE));
+
+ f->FileSize = e->FileSize;
+ f->UpdatedTime = e->UpdatedTime;
+ StrCpy(f->Path, sizeof(f->Path), e->FilePath);
+ StrCpy(f->ServerName, sizeof(f->ServerName), e->ServerName);
+
+ Insert(a->LogFileList, f);
+ }
+
+ return ERR_NO_ERROR;
+}
+
+
+// Get access control list
+UINT StGetAcList(ADMIN *a, RPC_AC_LIST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ FreeRpcAcList(t);
+ Zero(t, sizeof(RPC_AC_LIST));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ h = GetHub(c, hubname);
+
+ if (h == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ if (h->HubDb == NULL)
+ {
+ ret = ERR_NOT_SUPPORTED;
+ }
+ else
+ {
+ HUBDB *db = h->HubDb;
+
+ LockList(db->AcList);
+ {
+ t->o = NewAcList();
+
+ SetAcList(t->o, db->AcList);
+ }
+ UnlockList(db->AcList);
+ }
+ ReleaseHub(h);
+ }
+
+ return ret;
+}
+
+// Set access control list
+UINT StSetAcList(ADMIN *a, RPC_AC_LIST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+
+ if (c->Bridge)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ h = GetHub(c, hubname);
+
+ if (h == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_access_control_list") != 0)
+ {
+ ret = ERR_NOT_ENOUGH_RIGHT;
+ }
+ else
+ {
+ if (h->HubDb == NULL)
+ {
+ ret = ERR_NOT_SUPPORTED;
+ }
+ else
+ {
+ HUBDB *db = h->HubDb;
+
+ LockList(db->AcList);
+ {
+ SetAcList(db->AcList, t->o);
+
+ {
+ ALog(a, h, "LA_SET_AC_LIST", LIST_NUM(t->o));
+
+ IncrementServerConfigRevision(s);
+ }
+ }
+ UnlockList(db->AcList);
+ }
+ }
+ ReleaseHub(h);
+ }
+
+ return ret;
+}
+
+// Set CRL (Certificate Revocation List) entry
+UINT StSetCrl(ADMIN *a, RPC_CRL *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ UINT key;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ key = t->Key;
+
+ h = GetHub(c, hubname);
+
+ if (h == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_crl_list") != 0)
+ {
+ ret = ERR_NOT_ENOUGH_RIGHT;
+ }
+ else
+ {
+ if (h->HubDb == NULL)
+ {
+ ret = ERR_NOT_SUPPORTED;
+ }
+ else
+ {
+ LockList(h->HubDb->CrlList);
+ {
+ CRL *crl = ListKeyToPointer(h->HubDb->CrlList, t->Key);
+
+ if (crl == NULL)
+ {
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ CRL *new_crl = CopyCrl(t->Crl);
+ if (ReplaceListPointer(h->HubDb->CrlList, crl, new_crl))
+ {
+ ALog(a, h, "LA_ADD_CRL");
+ FreeCrl(crl);
+
+ IncrementServerConfigRevision(s);
+ }
+ }
+ }
+ UnlockList(h->HubDb->CrlList);
+ }
+ }
+
+ ReleaseHub(h);
+ }
+
+ return ret;
+}
+
+// Get CRL (Certificate Revocation List) entry
+UINT StGetCrl(ADMIN *a, RPC_CRL *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ UINT key;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ key = t->Key;
+
+ FreeRpcCrl(t);
+ Zero(t, sizeof(RPC_CRL));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+ t->Key = key;
+
+ h = GetHub(c, hubname);
+
+ if (h == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ if (h->HubDb == NULL)
+ {
+ ret = ERR_NOT_SUPPORTED;
+ }
+ else
+ {
+ LockList(h->HubDb->CrlList);
+ {
+ CRL *crl = ListKeyToPointer(h->HubDb->CrlList, t->Key);
+
+ if (crl == NULL)
+ {
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ t->Crl = CopyCrl(crl);
+ }
+ }
+ UnlockList(h->HubDb->CrlList);
+ }
+
+ ReleaseHub(h);
+ }
+
+ return ret;
+}
+
+// Delete CRL (Certificate Revocation List) entry
+UINT StDelCrl(ADMIN *a, RPC_CRL *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ h = GetHub(c, hubname);
+
+ if (h == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_crl_list") != 0)
+ {
+ ret = ERR_NOT_ENOUGH_RIGHT;
+ }
+ else
+ {
+ if (h->HubDb == NULL)
+ {
+ ret = ERR_NOT_SUPPORTED;
+ }
+ else
+ {
+ LockList(h->HubDb->CrlList);
+ {
+ CRL *crl = ListKeyToPointer(h->HubDb->CrlList, t->Key);
+
+ if (crl == NULL)
+ {
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ ALog(a, h, "LA_DEL_CRL");
+ FreeCrl(crl);
+ Delete(h->HubDb->CrlList, crl);
+ }
+ }
+ UnlockList(h->HubDb->CrlList);
+ }
+ }
+
+ ReleaseHub(h);
+ }
+
+ return ret;
+}
+
+// Add new CRL (Certificate Revocation List) entry
+UINT StAddCrl(ADMIN *a, RPC_CRL *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ if (c->Bridge)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ h = GetHub(c, hubname);
+
+ if (h == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_crl_list") != 0)
+ {
+ ret = ERR_NOT_ENOUGH_RIGHT;
+ }
+ else
+ {
+ if (h->HubDb == NULL)
+ {
+ ret = ERR_NOT_SUPPORTED;
+ }
+ else
+ {
+ LockList(h->HubDb->CrlList);
+ {
+ if (LIST_NUM(h->HubDb->CrlList) < MAX_HUB_CRLS)
+ {
+ CRL *crl = CopyCrl(t->Crl);
+
+ Insert(h->HubDb->CrlList, crl);
+
+ ALog(a, h, "LA_SET_CRL");
+
+ IncrementServerConfigRevision(s);
+ }
+ }
+ UnlockList(h->HubDb->CrlList);
+ }
+ }
+
+ ReleaseHub(h);
+ }
+
+ return ret;
+}
+
+// Get CRL (Certificate Revocation List) index
+UINT StEnumCrl(ADMIN *a, RPC_ENUM_CRL *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ FreeRpcEnumCrl(t);
+ Zero(t, sizeof(RPC_ENUM_CRL));
+
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ h = GetHub(c, hubname);
+
+ if (h == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ if (h->HubDb == NULL)
+ {
+ ret = ERR_NOT_SUPPORTED;
+ }
+ else
+ {
+ LockList(h->HubDb->CrlList);
+ {
+ UINT i;
+
+ t->NumItem = LIST_NUM(h->HubDb->CrlList);
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_CRL_ITEM) * t->NumItem);
+
+ for (i = 0;i < LIST_NUM(h->HubDb->CrlList);i++)
+ {
+ CRL *crl = LIST_DATA(h->HubDb->CrlList, i);
+ wchar_t *info = GenerateCrlStr(crl);
+
+ UniStrCpy(t->Items[i].CrlInfo, sizeof(t->Items[i].CrlInfo), info);
+ Free(info);
+
+ t->Items[i].Key = POINTER_TO_KEY(crl);
+ }
+ }
+ UnlockList(h->HubDb->CrlList);
+ }
+
+ ReleaseHub(h);
+ }
+
+ return ret;
+}
+
+// Get routing table on virtual L3 switch
+UINT StEnumL3Table(ADMIN *a, RPC_ENUM_L3TABLE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ L3SW *sw;
+ char name[MAX_HUBNAME_LEN + 1];
+
+ if (IsEmptyStr(t->Name))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ StrCpy(name, sizeof(name), t->Name);
+ FreeRpcEnumL3Table(t);
+ Zero(t, sizeof(RPC_ENUM_L3TABLE));
+ StrCpy(t->Name, sizeof(t->Name), name);
+
+ sw = L3GetSw(c, t->Name);
+
+ if (sw == NULL)
+ {
+ ret = ERR_LAYER3_SW_NOT_FOUND;
+ }
+ else
+ {
+ UINT i;
+
+ Lock(sw->lock);
+ {
+ t->NumItem = LIST_NUM(sw->TableList);
+ t->Items = ZeroMalloc(sizeof(RPC_L3TABLE) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ L3TABLE *tbl = LIST_DATA(sw->TableList, i);
+ RPC_L3TABLE *e = &t->Items[i];
+
+ StrCpy(e->Name, sizeof(e->Name), name);
+ e->NetworkAddress = tbl->NetworkAddress;
+ e->SubnetMask = tbl->SubnetMask;
+ e->GatewayAddress = tbl->GatewayAddress;
+ e->Metric = tbl->Metric;
+ }
+ }
+ Unlock(sw->lock);
+
+ ReleaseL3Sw(sw);
+ }
+
+ return ret;
+}
+
+// Delete routing table entry on virtual L3 switch
+UINT StDelL3Table(ADMIN *a, RPC_L3TABLE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ L3SW *sw;
+
+ SERVER_ADMIN_ONLY;
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ sw = L3GetSw(c, t->Name);
+
+ if (sw == NULL)
+ {
+ ret = ERR_LAYER3_SW_NOT_FOUND;
+ }
+ else
+ {
+ L3TABLE tbl;
+
+ Zero(&tbl, sizeof(tbl));
+ tbl.NetworkAddress = t->NetworkAddress;
+ tbl.SubnetMask = t->SubnetMask;
+ tbl.GatewayAddress = t->GatewayAddress;
+ tbl.Metric = t->Metric;
+
+ if (L3DelTable(sw, &tbl) == false)
+ {
+ ret = ERR_LAYER3_TABLE_DEL_FAILED;
+ }
+ else
+ {
+ char tmp[MAX_SIZE];
+ IPToStr32(tmp, sizeof(tmp), tbl.NetworkAddress);
+ ALog(a, NULL, "LA_DEL_L3_TABLE", tmp, t->Name);
+
+ IncrementServerConfigRevision(s);
+ }
+
+ ReleaseL3Sw(sw);
+ }
+
+ return ret;
+}
+
+// Add new routing table entry on virtual L3 switch
+UINT StAddL3Table(ADMIN *a, RPC_L3TABLE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ L3SW *sw;
+
+ if (IsNetworkAddress32(t->NetworkAddress, t->SubnetMask) == false ||
+ IsHostIPAddress32(t->GatewayAddress) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ SERVER_ADMIN_ONLY;
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ sw = L3GetSw(c, t->Name);
+
+ if (sw == NULL)
+ {
+ ret = ERR_LAYER3_SW_NOT_FOUND;
+ }
+ else
+ {
+ L3TABLE tbl;
+
+ Zero(&tbl, sizeof(tbl));
+ tbl.NetworkAddress = t->NetworkAddress;
+ tbl.SubnetMask = t->SubnetMask;
+ tbl.GatewayAddress = t->GatewayAddress;
+ tbl.Metric = t->Metric;
+
+ if (L3AddTable(sw, &tbl) == false)
+ {
+ ret = ERR_LAYER3_TABLE_ADD_FAILED;
+ }
+ else
+ {
+ char tmp[MAX_SIZE];
+ IPToStr32(tmp, sizeof(tmp), tbl.NetworkAddress);
+ ALog(a, NULL, "LA_ADD_L3_TABLE", tmp, t->Name);
+
+ IncrementServerConfigRevision(s);
+ }
+
+ ReleaseL3Sw(sw);
+ }
+
+ return ret;
+}
+
+// Enumerate virtual interfaces on virtual L3 switch
+UINT StEnumL3If(ADMIN *a, RPC_ENUM_L3IF *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ L3SW *sw;
+ char name[MAX_HUBNAME_LEN + 1];
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ StrCpy(name, sizeof(name), t->Name);
+
+ FreeRpcEnumL3If(t);
+ Zero(t, sizeof(RPC_ENUM_L3IF));
+
+ StrCpy(t->Name, sizeof(t->Name), name);
+
+ sw = L3GetSw(c, t->Name);
+
+ if (sw == NULL)
+ {
+ ret = ERR_LAYER3_SW_NOT_FOUND;
+ }
+ else
+ {
+ Lock(sw->lock);
+ {
+ UINT i;
+
+ t->NumItem = LIST_NUM(sw->IfList);
+ t->Items = ZeroMalloc(sizeof(RPC_L3IF) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ L3IF *f = LIST_DATA(sw->IfList, i);
+ RPC_L3IF *e = &t->Items[i];
+
+ StrCpy(e->Name, sizeof(e->Name), sw->Name);
+ StrCpy(e->HubName, sizeof(e->HubName), f->HubName);
+ e->IpAddress = f->IpAddress;
+ e->SubnetMask = f->SubnetMask;
+ }
+ }
+ Unlock(sw->lock);
+
+ ReleaseL3Sw(sw);
+ }
+
+ return ret;
+}
+
+// Delete a virtual interface on virtual L3 switch
+UINT StDelL3If(ADMIN *a, RPC_L3IF *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ L3SW *sw;
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ SERVER_ADMIN_ONLY;
+
+ sw = L3GetSw(c, t->Name);
+
+ if (sw == NULL)
+ {
+ ret = ERR_LAYER3_SW_NOT_FOUND;
+ }
+ else
+ {
+ if (L3DelIf(sw, t->HubName) == false)
+ {
+ ret = ERR_LAYER3_IF_DEL_FAILED;
+ }
+ else
+ {
+ ALog(a, NULL, "LA_DEL_L3_IF", t->HubName, t->Name);
+
+ IncrementServerConfigRevision(s);
+ }
+ ReleaseL3Sw(sw);
+ }
+
+ return ret;
+}
+
+// Add new virtual interface on virtual L3 switch
+UINT StAddL3If(ADMIN *a, RPC_L3IF *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ L3SW *sw;
+
+
+ if (IsSubnetMask32(t->SubnetMask) == false || IsHostIPAddress32(t->IpAddress) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ if ((t->IpAddress & (~t->SubnetMask)) == 0)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ SERVER_ADMIN_ONLY;
+
+ sw = L3GetSw(c, t->Name);
+
+ if (sw == NULL)
+ {
+ ret = ERR_LAYER3_SW_NOT_FOUND;
+ }
+ else
+ {
+ Lock(sw->lock);
+ {
+ if (L3SearchIf(sw, t->HubName) != NULL)
+ {
+ // Already exists
+ ret = ERR_LAYER3_IF_EXISTS;
+ }
+ else
+ {
+ if (L3AddIf(sw, t->HubName, t->IpAddress, t->SubnetMask) == false)
+ {
+ ret = ERR_LAYER3_IF_ADD_FAILED;
+ }
+ else
+ {
+ ALog(a, NULL, "LA_ADD_L3_IF", t->HubName, t->Name);
+
+ IncrementServerConfigRevision(s);
+ }
+ }
+ }
+ Unlock(sw->lock);
+ ReleaseL3Sw(sw);
+ }
+
+ return ret;
+}
+
+// Stop a virtual layer-3 switch
+UINT StStopL3Switch(ADMIN *a, RPC_L3SW *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ L3SW *sw;
+
+ if (IsEmptyStr(t->Name))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ SERVER_ADMIN_ONLY;
+
+ sw = L3GetSw(c, t->Name);
+
+ if (sw == NULL)
+ {
+ ret = ERR_LAYER3_SW_NOT_FOUND;
+ }
+ else
+ {
+ L3SwStop(sw);
+ ALog(a, NULL, "LA_STOP_L3_SW", sw->Name);
+ ReleaseL3Sw(sw);
+
+ IncrementServerConfigRevision(s);
+ }
+
+ return ret;
+}
+
+// Start a virtual layer-3 switch
+UINT StStartL3Switch(ADMIN *a, RPC_L3SW *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ L3SW *sw;
+
+ if (IsEmptyStr(t->Name))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ SERVER_ADMIN_ONLY;
+
+ sw = L3GetSw(c, t->Name);
+
+ if (sw == NULL)
+ {
+ ret = ERR_LAYER3_SW_NOT_FOUND;
+ }
+ else
+ {
+ Lock(sw->lock);
+ {
+ // Count the registered virtual interfaces
+ if (LIST_NUM(sw->IfList) >= 1)
+ {
+ L3SwStart(sw);
+
+ ALog(a, NULL, "LA_START_L3_SW", sw->Name);
+
+ IncrementServerConfigRevision(s);
+ }
+ else
+ {
+ ret = ERR_LAYER3_CANT_START_SWITCH;
+ }
+ }
+ Unlock(sw->lock);
+
+ ReleaseL3Sw(sw);
+ }
+
+ return ret;
+}
+
+// Enumerate virtual layer-3 switches
+UINT StEnumL3Switch(ADMIN *a, RPC_ENUM_L3SW *t)
+{
+ UINT i;
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ FreeRpcEnumL3Sw(t);
+ Zero(t, sizeof(RPC_ENUM_L3SW));
+
+ LockList(c->L3SwList);
+ {
+ t->NumItem = LIST_NUM(c->L3SwList);
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_L3SW_ITEM) * t->NumItem);
+ for (i = 0;i < LIST_NUM(c->L3SwList);i++)
+ {
+ L3SW *sw = LIST_DATA(c->L3SwList, i);
+ RPC_ENUM_L3SW_ITEM *e = &t->Items[i];
+
+ Lock(sw->lock);
+ {
+ StrCpy(e->Name, sizeof(e->Name), sw->Name);
+ e->NumInterfaces = LIST_NUM(sw->IfList);
+ e->NumTables = LIST_NUM(sw->TableList);
+ e->Active = sw->Active;
+ e->Online = sw->Online;
+ }
+ Unlock(sw->lock);
+ }
+ }
+ UnlockList(c->L3SwList);
+
+ return ret;
+}
+
+// Delete a virtual layer-3 switch
+UINT StDelL3Switch(ADMIN *a, RPC_L3SW *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+
+ if (IsEmptyStr(t->Name))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ SERVER_ADMIN_ONLY;
+
+ if (L3DelSw(c, t->Name) == false)
+ {
+ ret = ERR_LAYER3_SW_NOT_FOUND;
+ }
+ else
+ {
+ ALog(a, NULL, "LA_DEL_L3_SW", t->Name);
+
+ IncrementServerConfigRevision(s);
+ }
+
+ return ret;
+}
+
+// Add a new virtual layer-3 switch
+UINT StAddL3Switch(ADMIN *a, RPC_L3SW *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ L3SW *sw;
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (IsEmptyStr(t->Name))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (IsSafeStr(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ SERVER_ADMIN_ONLY;
+
+ // Duplication check
+ sw = L3GetSw(c, t->Name);
+ if (sw != NULL)
+ {
+ // Already exists
+ ReleaseL3Sw(sw);
+ ret = ERR_LAYER3_SW_EXISTS;
+ }
+ else
+ {
+ LockList(c->L3SwList);
+ {
+ if (LIST_NUM(c->L3SwList) >= GetServerCapsInt(s, "i_max_l3_sw"))
+ {
+ // No more virtual interfaces
+ sw = NULL;
+ }
+ else
+ {
+ // Create
+ sw = L3AddSw(c, t->Name);
+
+ if (sw != NULL)
+ {
+ ALog(a, NULL, "LA_ADD_L3_SW", t->Name);
+
+ IncrementServerConfigRevision(s);
+ }
+ }
+ }
+ UnlockList(c->L3SwList);
+
+ if (sw == NULL)
+ {
+ // Failed
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ // Success
+ ReleaseL3Sw(sw);
+ }
+ }
+
+ return ret;
+}
+
+// Set hub extended options
+UINT StSetHubExtOptions(ADMIN *a, RPC_ADMIN_OPTION *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ bool not_server_admin = false;
+
+ if (t->NumItem > MAX_HUB_ADMIN_OPTIONS)
+ {
+ return ERR_TOO_MANT_ITEMS;
+ }
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+
+ CHECK_RIGHT;
+
+ if (a->ServerAdmin == false)
+ {
+ not_server_admin = true;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (GetHubAdminOption(h, "deny_hub_admin_change_ext_option") && not_server_admin)
+ {
+ // Insufficient permission
+ ReleaseHub(h);
+
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ // Update setting
+ Lock(h->lock);
+ {
+ DataToHubOptionStruct(h->Option, t);
+ }
+ Unlock(h->lock);
+
+ ALog(a, NULL, "LA_SET_HUB_EXT_OPTION", h->Name);
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get hub extended options
+UINT StGetHubExtOptions(ADMIN *a, RPC_ADMIN_OPTION *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ FreeRpcAdminOption(t);
+ Zero(t, sizeof(RPC_ADMIN_OPTION));
+
+ StrCpy(t->HubName, sizeof(t->HubName), h->Name);
+
+ // Get options
+ Lock(h->lock);
+ {
+ HubOptionStructToData(t, h->Option, h->Name);
+ }
+ Unlock(h->lock);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Set hub administration options
+UINT StSetHubAdminOptions(ADMIN *a, RPC_ADMIN_OPTION *t)
+{
+ UINT i;
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ bool not_server_admin = false;
+
+
+ if (t->NumItem > MAX_HUB_ADMIN_OPTIONS)
+ {
+ return ERR_TOO_MANT_ITEMS;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ if (a->ServerAdmin == false)
+ {
+ not_server_admin = true;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (GetHubAdminOption(h, "allow_hub_admin_change_option") == false
+ && not_server_admin)
+ {
+ // Insufficient permission
+ ReleaseHub(h);
+
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ LockList(h->AdminOptionList);
+ {
+ DeleteAllHubAdminOption(h, false);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ ADMIN_OPTION *e = &t->Items[i];
+ ADMIN_OPTION *a = ZeroMalloc(sizeof(ADMIN_OPTION));
+
+ StrCpy(a->Name, sizeof(a->Name), e->Name);
+ a->Value = e->Value;
+
+ Insert(h->AdminOptionList, a);
+ }
+
+ AddHubAdminOptionsDefaults(h, false);
+ }
+ UnlockList(h->AdminOptionList);
+
+ ALog(a, NULL, "LA_SET_HUB_ADMIN_OPTION", h->Name);
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get hub administration options
+UINT StGetHubAdminOptions(ADMIN *a, RPC_ADMIN_OPTION *t)
+{
+ UINT i;
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ CHECK_RIGHT;
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ FreeRpcAdminOption(t);
+ Zero(t, sizeof(RPC_ADMIN_OPTION));
+
+ StrCpy(t->HubName, sizeof(t->HubName), h->Name);
+
+ LockList(h->AdminOptionList);
+ {
+ t->NumItem = LIST_NUM(h->AdminOptionList);
+ t->Items = ZeroMalloc(sizeof(ADMIN_OPTION) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ ADMIN_OPTION *a = LIST_DATA(h->AdminOptionList, i);
+ ADMIN_OPTION *e = &t->Items[i];
+
+ StrCpy(e->Name, sizeof(e->Name), a->Name);
+ e->Value = a->Value;
+ }
+ }
+ UnlockList(h->AdminOptionList);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Get default hub administration options
+UINT StGetDefaultHubAdminOptions(ADMIN *a, RPC_ADMIN_OPTION *t)
+{
+ UINT i;
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (a->Server->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ FreeRpcAdminOption(t);
+ Zero(t, sizeof(RPC_ADMIN_OPTION));
+
+ t->NumItem = num_admin_options;
+ t->Items = ZeroMalloc(sizeof(ADMIN_OPTION) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ ADMIN_OPTION *a = &t->Items[i];
+
+ StrCpy(a->Name, sizeof(a->Name), admin_options[i].Name);
+ a->Value = admin_options[i].Value;
+ }
+
+ return ERR_NO_ERROR;
+}
+
+// Get configuration file stream
+UINT StGetConfig(ADMIN *a, RPC_CONFIG *t)
+{
+ SERVER *s;
+
+ SERVER_ADMIN_ONLY;
+
+ FreeRpcConfig(t);
+ Zero(t, sizeof(RPC_CONFIG));
+
+ s = a->Server;
+
+ ALog(a, NULL, "LA_GET_CONFIG");
+
+ if (s->CfgRw != NULL)
+ {
+ FOLDER *f = SiWriteConfigurationToCfg(s);
+ BUF *b = CfgFolderToBuf(f, true);
+
+ StrCpy(t->FileName, sizeof(t->FileName), s->CfgRw->FileName + (s->CfgRw->FileName[0] == '@' ? 1 : 0));
+
+ t->FileData = ZeroMalloc(b->Size + 1);
+ Copy(t->FileData, b->Buf, b->Size);
+
+ CfgDeleteFolder(f);
+ FreeBuf(b);
+
+ return ERR_NO_ERROR;
+ }
+ else
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+}
+
+// Overwrite configuration file by specified data
+UINT StSetConfig(ADMIN *a, RPC_CONFIG *t)
+{
+ SERVER *s;
+ IO *o;
+ char filename[MAX_PATH];
+
+ SERVER_ADMIN_ONLY;
+
+ s = a->Server;
+ if (s->CfgRw == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ // Write new configuration file
+ Format(filename, sizeof(filename), "%s.new", s->CfgRw->FileName);
+
+ o = FileCreate(filename);
+
+ FileWrite(o, t->FileData, StrLen(t->FileData));
+
+ FileClose(o);
+
+ IncrementServerConfigRevision(s);
+
+ ALog(a, NULL, "LA_SET_CONFIG");
+
+ // Reboot server itself
+ SiRebootServer(s->Cedar->Bridge);
+
+ return ERR_NO_ERROR;
+}
+
+// Get capabilities
+UINT StGetCaps(ADMIN *a, CAPSLIST *t)
+{
+ FreeRpcCapsList(t);
+ Zero(t, sizeof(CAPSLIST));
+
+ GetServerCapsMain(a->Server, t);
+
+ return ERR_NO_ERROR;
+}
+
+// Reboot server itself
+UINT StRebootServer(ADMIN *a, RPC_TEST *t)
+{
+ SERVER_ADMIN_ONLY;
+
+ ALog(a, NULL, "LA_REBOOT_SERVER");
+
+ SiRebootServerEx(a->Server->Cedar->Bridge, t->IntValue);
+
+ return ERR_NO_ERROR;
+}
+
+// Get availability to localbridge function
+UINT StGetBridgeSupport(ADMIN *a, RPC_BRIDGE_SUPPORT *t)
+{
+ Zero(t, sizeof(RPC_BRIDGE_SUPPORT));
+
+ t->IsBridgeSupportedOs = IsBridgeSupported();
+ t->IsWinPcapNeeded = IsNeedWinPcap();
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate Ethernet devices
+UINT StEnumEthernet(ADMIN *a, RPC_ENUM_ETH *t)
+{
+ TOKEN_LIST *o;
+ UINT i;
+ char tmp[MAX_SIZE];
+ bool unix_support = false;
+
+ SERVER_ADMIN_ONLY;
+
+#ifdef OS_UNIX
+ unix_support = EthIsInterfaceDescriptionSupportedUnix();
+#endif // OS_UNIX
+
+ o = GetEthList();
+ if (o == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ FreeRpcEnumEth(t);
+ Zero(t, sizeof(RPC_ENUM_ETH));
+
+ t->NumItem = o->NumTokens;
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_ETH_ITEM) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_ETH_ITEM *e = &t->Items[i];
+
+ StrCpy(e->DeviceName, sizeof(e->DeviceName), o->Token[i]);
+
+ StrCpy(tmp, sizeof(tmp), e->DeviceName);
+
+#ifdef OS_WIN32
+ GetEthNetworkConnectionName(e->NetworkConnectionName, sizeof(e->NetworkConnectionName), e->DeviceName);
+#else
+ if (unix_support == false)
+ {
+ StrCpy(tmp, sizeof(tmp), "");
+ }
+ else
+ {
+ if (EthGetInterfaceDescriptionUnix(e->DeviceName, tmp, sizeof(tmp)) == false)
+ {
+ StrCpy(tmp, sizeof(tmp), e->DeviceName);
+ }
+ }
+
+ StrToUni(e->NetworkConnectionName, sizeof(e->NetworkConnectionName), tmp);
+#endif
+ }
+
+ FreeToken(o);
+
+ return ERR_NO_ERROR;
+}
+
+// Add a new local bridge
+UINT StAddLocalBridge(ADMIN *a, RPC_LOCALBRIDGE *t)
+{
+ if (IsEmptyStr(t->DeviceName) || IsEmptyStr(t->HubName))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ SERVER_ADMIN_ONLY;
+
+
+ if (IsEthSupported() == false)
+ {
+ return ERR_LOCAL_BRIDGE_UNSUPPORTED;
+ }
+
+#ifdef OS_WIN32
+ if (true)
+ {
+ char tmp[MAX_SIZE];
+ UINT id = Win32EthGetNameAndIdFromCombinedName(tmp, sizeof(tmp), t->DeviceName);
+
+ if (id == 0)
+ {
+ // If a ID is not specified in Win32, adding will fail
+ return ERR_OBJECT_NOT_FOUND;
+ }
+ }
+#endif // OS_WIN32
+
+ ALog(a, NULL, "LA_ADD_BRIDGE", t->HubName, t->DeviceName);
+
+ AddLocalBridge(a->Server->Cedar, t->HubName, t->DeviceName, false, false, t->TapMode, NULL, false);
+
+ IncrementServerConfigRevision(a->Server);
+
+ return ERR_NO_ERROR;
+}
+
+// Delete a local bridge
+UINT StDeleteLocalBridge(ADMIN *a, RPC_LOCALBRIDGE *t)
+{
+ if (IsEmptyStr(t->DeviceName) || IsEmptyStr(t->HubName))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ SERVER_ADMIN_ONLY;
+
+ ALog(a, NULL, "LA_DELETE_BRIDGE", t->HubName, t->DeviceName);
+
+ if (DeleteLocalBridge(a->Server->Cedar, t->HubName, t->DeviceName) == false)
+ {
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ IncrementServerConfigRevision(a->Server);
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate local bridges
+UINT StEnumLocalBridge(ADMIN *a, RPC_ENUM_LOCALBRIDGE *t)
+{
+ UINT i;
+ CEDAR *c;
+
+ if (IsEthSupported() == false)
+ {
+ return ERR_LOCAL_BRIDGE_UNSUPPORTED;
+ }
+
+ FreeRpcEnumLocalBridge(t);
+ Zero(t, sizeof(RPC_ENUM_LOCALBRIDGE));
+
+ c = a->Server->Cedar;
+
+ LockList(c->LocalBridgeList);
+ {
+ t->NumItem = LIST_NUM(c->LocalBridgeList);
+ t->Items = ZeroMalloc(sizeof(RPC_LOCALBRIDGE) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_LOCALBRIDGE *e = &t->Items[i];
+ LOCALBRIDGE *br = LIST_DATA(c->LocalBridgeList, i);
+
+ if (br->Bridge == false)
+ {
+ e->Online = e->Active = false;
+ }
+ else
+ {
+ e->Online = true;
+ if (br->Bridge->Active)
+ {
+ e->Active = true;
+ }
+ else
+ {
+ e->Active = false;
+ }
+ }
+ StrCpy(e->DeviceName, sizeof(e->DeviceName), br->DeviceName);
+ StrCpy(e->HubName, sizeof(e->HubName), br->HubName);
+
+ e->TapMode = br->TapMode;
+ }
+ }
+ UnlockList(c->LocalBridgeList);
+
+ return ERR_NO_ERROR;
+}
+
+// Set syslog function setting
+UINT StSetSysLog(ADMIN *a, SYSLOG_SETTING *t)
+{
+ SERVER *s = a->Server;
+
+ SERVER_ADMIN_ONLY;
+
+ if (GetServerCapsBool(s, "b_support_syslog") == false)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ SiSetSysLogSetting(s, t);
+
+ IncrementServerConfigRevision(s);
+ ALog(a, NULL, "LA_SET_SYSLOG");
+
+ return ERR_NO_ERROR;
+}
+
+// Get syslog function setting
+UINT StGetSysLog(ADMIN *a, SYSLOG_SETTING *t)
+{
+ SERVER *s = a->Server;
+
+ SiGetSysLogSetting(s, t);
+
+ if (a->ServerAdmin == false)
+ {
+ // Hide server name for non-administrator
+ if (t->SaveType == SYSLOG_NONE)
+ {
+ StrCpy(t->Hostname, sizeof(t->Hostname), "");
+ t->Port = 0;
+ }
+ else
+ {
+ StrCpy(t->Hostname, sizeof(t->Hostname), "Secret");
+ t->Port = 0;
+ }
+ }
+
+ return ERR_NO_ERROR;
+}
+
+// Set keep-alive function setting
+UINT StSetKeep(ADMIN *a, RPC_KEEP *t)
+{
+ SERVER *s = a->Server;
+
+ if (t->UseKeepConnect)
+ {
+ if (IsEmptyStr(t->KeepConnectHost) ||
+ t->KeepConnectPort == 0 ||
+ t->KeepConnectPort >= 65536)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+
+ SERVER_ADMIN_ONLY;
+
+ Lock(s->Keep->lock);
+ {
+ KEEP *keep = s->Keep;
+ keep->Enable = t->UseKeepConnect;
+ keep->Server = true;
+ StrCpy(keep->ServerName, sizeof(keep->ServerName), t->KeepConnectHost);
+ keep->ServerPort = t->KeepConnectPort;
+ keep->UdpMode = t->KeepConnectProtocol;
+ keep->Interval = t->KeepConnectInterval * 1000;
+ if (keep->Interval < 5000)
+ {
+ keep->Interval = 5000;
+ }
+ else if (keep->Interval > 600000)
+ {
+ keep->Interval = 600000;
+ }
+ }
+ Unlock(s->Keep->lock);
+
+ ALog(a, NULL, "LA_SET_KEEP");
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get keep-alive function setting
+UINT StGetKeep(ADMIN *a, RPC_KEEP *t)
+{
+ SERVER *s = a->Server;
+
+ Zero(t, sizeof(RPC_KEEP));
+
+ Lock(s->Keep->lock);
+ {
+ KEEP *k = s->Keep;
+ t->UseKeepConnect = k->Enable;
+ StrCpy(t->KeepConnectHost, sizeof(t->KeepConnectHost), k->ServerName);
+ t->KeepConnectPort = k->ServerPort;
+ t->KeepConnectProtocol = k->UdpMode;
+ t->KeepConnectInterval = k->Interval / 1000;
+ }
+ Unlock(s->Keep->lock);
+
+ return ERR_NO_ERROR;
+}
+
+// Delete IP address table entry
+UINT StDeleteIpTable(ADMIN *a, RPC_DELETE_TABLE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_delete_iptable") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ LockList(h->IpTable);
+ {
+ if (IsInListKey(h->IpTable, t->Key))
+ {
+ IP_TABLE_ENTRY *e = ListKeyToPointer(h->IpTable, t->Key);
+ Free(e);
+ Delete(h->IpTable, e);
+ }
+ else
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ }
+ UnlockList(h->IpTable);
+
+ if (ret == ERR_OBJECT_NOT_FOUND)
+ {
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ UINT i;
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ if (f->Me == false)
+ {
+ SiCallDeleteIpTable(s, f, t->HubName, t->Key);
+ ret = ERR_NO_ERROR;
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+ }
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Get local IP address table
+UINT SiEnumIpTable(SERVER *s, char *hubname, RPC_ENUM_IP_TABLE *t)
+{
+ CEDAR *c;
+ UINT i;
+ HUB *h = NULL;
+ // Validate arguments
+ if (s == NULL || hubname == NULL || t == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ c = s->Cedar;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, hubname);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ LockList(h->IpTable);
+ {
+ t->NumIpTable = LIST_NUM(h->IpTable);
+ t->IpTables = ZeroMalloc(sizeof(RPC_ENUM_IP_TABLE_ITEM) * t->NumIpTable);
+
+ for (i = 0;i < t->NumIpTable;i++)
+ {
+ RPC_ENUM_IP_TABLE_ITEM *e = &t->IpTables[i];
+ IP_TABLE_ENTRY *table = LIST_DATA(h->IpTable, i);
+
+ e->Key = POINTER_TO_KEY(table);
+ StrCpy(e->SessionName, sizeof(e->SessionName), table->Session->Name);
+ e->Ip = IPToUINT(&table->Ip);
+ Copy(&e->IpV6, &table->Ip, sizeof(IP));
+ e->DhcpAllocated = table->DhcpAllocated;
+ e->CreatedTime = TickToTime(table->CreatedTime);
+ e->UpdatedTime = TickToTime(table->UpdatedTime);
+
+ GetMachineName(e->RemoteHostname, sizeof(e->RemoteHostname));
+ }
+ }
+ UnlockList(h->IpTable);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Get IP address table
+UINT StEnumIpTable(ADMIN *a, RPC_ENUM_IP_TABLE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT i;
+
+ CHECK_RIGHT;
+
+ // Get local IP address table
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ FreeRpcEnumIpTable(t);
+ Zero(t, sizeof(RPC_ENUM_IP_TABLE));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ ret = SiEnumIpTable(s, hubname, t);
+ if (ret != ERR_NO_ERROR)
+ {
+ return ret;
+ }
+
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ // Get remote IP address table
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ if (f->Me == false)
+ {
+ RPC_ENUM_IP_TABLE tmp;
+
+ Zero(&tmp, sizeof(tmp));
+
+ SiCallEnumIpTable(s, f, hubname, &tmp);
+
+ AdjoinRpcEnumIpTable(t, &tmp);
+ FreeRpcEnumIpTable(&tmp);
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+
+ return ret;
+}
+
+// Delete MAC address table entry
+UINT StDeleteMacTable(ADMIN *a, RPC_DELETE_TABLE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_delete_mactable") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ LockList(h->MacTable);
+ {
+ if (IsInListKey(h->MacTable, t->Key))
+ {
+ MAC_TABLE_ENTRY *e = ListKeyToPointer(h->MacTable, t->Key);
+ Free(e);
+ Delete(h->MacTable, e);
+ }
+ else
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ }
+ UnlockList(h->MacTable);
+
+ if (ret == ERR_OBJECT_NOT_FOUND)
+ {
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ UINT i;
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ if (f->Me == false)
+ {
+ SiCallDeleteMacTable(s, f, t->HubName, t->Key);
+ ret = ERR_NO_ERROR;
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+ }
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Get local MAC address table
+UINT SiEnumMacTable(SERVER *s, char *hubname, RPC_ENUM_MAC_TABLE *t)
+{
+ CEDAR *c;
+ UINT i;
+ HUB *h = NULL;
+ // Validate arguments
+ if (s == NULL || hubname == NULL || t == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ c = s->Cedar;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, hubname);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ LockList(h->MacTable);
+ {
+ t->NumMacTable = LIST_NUM(h->MacTable);
+ t->MacTables = ZeroMalloc(sizeof(RPC_ENUM_MAC_TABLE_ITEM) * t->NumMacTable);
+
+ for (i = 0;i < t->NumMacTable;i++)
+ {
+ RPC_ENUM_MAC_TABLE_ITEM *e = &t->MacTables[i];
+ MAC_TABLE_ENTRY *mac = LIST_DATA(h->MacTable, i);
+
+ e->Key = POINTER_TO_KEY(mac);
+ StrCpy(e->SessionName, sizeof(e->SessionName), mac->Session->Name);
+ Copy(e->MacAddress, mac->MacAddress, sizeof(e->MacAddress));
+ e->CreatedTime = TickToTime(mac->CreatedTime);
+ e->UpdatedTime = TickToTime(mac->UpdatedTime);
+ e->VlanId = mac->VlanId;
+
+ GetMachineName(e->RemoteHostname, sizeof(e->RemoteHostname));
+ }
+ }
+ UnlockList(h->MacTable);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Get MAC address table
+UINT StEnumMacTable(ADMIN *a, RPC_ENUM_MAC_TABLE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT i;
+
+ CHECK_RIGHT;
+
+ // Get local MAC address table
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ FreeRpcEnumMacTable(t);
+ Zero(t, sizeof(RPC_ENUM_MAC_TABLE));
+
+ ret = SiEnumMacTable(s, hubname, t);
+ if (ret != ERR_NO_ERROR)
+ {
+ return ret;
+ }
+
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ // Get remote MAC address table
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ if (f->Me == false)
+ {
+ RPC_ENUM_MAC_TABLE tmp;
+
+ Zero(&tmp, sizeof(tmp));
+
+ SiCallEnumMacTable(s, f, hubname, &tmp);
+
+ AdjoinRpcEnumMacTable(t, &tmp);
+ FreeRpcEnumMacTable(&tmp);
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+
+ return ret;
+}
+
+// Delete a session
+UINT StDeleteSession(ADMIN *a, RPC_DELETE_SESSION *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ char name[MAX_SESSION_NAME_LEN + 1];
+ SESSION *sess;
+
+ if (IsEmptyStr(t->Name))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ StrCpy(name, sizeof(name), t->Name);
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_disconnect_session") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ sess = GetSessionByName(h, name);
+
+ if (sess == NULL)
+ {
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ // Cluster controller
+ UINT i;
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ if (f->Me == false)
+ {
+ // Try to disconnect
+ SiCallDeleteSession(s, f, t->HubName, t->Name);
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+ else
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ }
+ else
+ {
+ if (sess->LinkModeServer)
+ {
+ ret = ERR_LINK_CANT_DISCONNECT;
+ }
+ else if (sess->SecureNATMode)
+ {
+ ret = ERR_SNAT_CANT_DISCONNECT;
+ }
+ else if (sess->BridgeMode)
+ {
+ ret = ERR_BRIDGE_CANT_DISCONNECT;
+ }
+ else if (sess->L3SwitchMode)
+ {
+ ret = ERR_LAYER3_CANT_DISCONNECT;
+ }
+ else
+ {
+ StopSession(sess);
+ }
+ ReleaseSession(sess);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ ALog(a, h, "LA_DELETE_SESSION", t->Name);
+ }
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Get session status
+UINT StGetSessionStatus(ADMIN *a, RPC_SESSION_STATUS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ char name[MAX_SESSION_NAME_LEN + 1];
+ SESSION *sess;
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ StrCpy(name, sizeof(name), t->Name);
+
+ if (IsEmptyStr(t->Name))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_query_session") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ FreeRpcSessionStatus(t);
+ Zero(t, sizeof(RPC_SESSION_STATUS));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+ StrCpy(t->Name, sizeof(t->Name), name);
+
+ sess = GetSessionByName(h, t->Name);
+
+ if (sess == NULL)
+ {
+ if (s->ServerType != SERVER_TYPE_FARM_CONTROLLER)
+ {
+ // Session is not found
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ else
+ {
+ UINT i;
+ // Try to find the session on other cluster member
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ if (f->Me == false)
+ {
+ RPC_SESSION_STATUS tmp;
+ Zero(&tmp, sizeof(tmp));
+ StrCpy(tmp.HubName, sizeof(tmp.HubName), t->HubName);
+ StrCpy(tmp.Name, sizeof(tmp.Name), t->Name);
+
+ if (SiCallGetSessionStatus(s, f, &tmp))
+ {
+ if (StrLen(tmp.HubName) != 0)
+ {
+ // Success to get session status
+ Copy(t, &tmp, sizeof(RPC_SESSION_STATUS));
+ break;
+ }
+ else
+ {
+ FreeRpcSessionStatus(&tmp);
+ }
+ }
+ }
+ }
+
+ if (i == LIST_NUM(s->FarmMemberList))
+ {
+ // not found after all
+ //
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+ }
+ else
+ {
+ SESSION *s = sess;
+
+ Lock(s->lock);
+ {
+ StrCpy(t->Username, sizeof(t->Username), s->Username);
+ StrCpy(t->RealUsername, sizeof(t->RealUsername), s->UserNameReal);
+ StrCpy(t->GroupName, sizeof(t->GroupName), s->GroupName);
+ Copy(&t->NodeInfo, &s->NodeInfo, sizeof(NODE_INFO));
+
+ if (s->Connection != NULL)
+ {
+ t->ClientIp = IPToUINT(&s->Connection->ClientIp);
+ if (IsIP6(&s->Connection->ClientIp))
+ {
+ Copy(&t->ClientIp6, &s->Connection->ClientIp.ipv6_addr, sizeof(t->ClientIp6));
+ }
+
+ StrCpy(t->ClientHostName, sizeof(t->ClientHostName), s->Connection->ClientHostname);
+ }
+ }
+ Unlock(s->lock);
+
+ CiGetSessionStatus(&t->Status, s);
+
+ ReleaseSession(s);
+ }
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Main routine of session enumeration
+void SiEnumSessionMain(SERVER *s, RPC_ENUM_SESSION *t)
+{
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT ret = ERR_NO_ERROR;
+ UINT num;
+ UINT i;
+ // Validate arguments
+ if (s == NULL || t == NULL)
+ {
+ return;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ FreeRpcEnumSession(t);
+ Zero(t, sizeof(RPC_ENUM_SESSION));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ // Local session enumeration
+ num = 0;
+ SiEnumLocalSession(s, hubname, t);
+
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ LIST *fm_list;
+
+ fm_list = NewListFast(NULL);
+
+ // Remote session enumeration
+ LockList(s->FarmMemberList);
+ {
+ 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)
+ {
+ Add(fm_list, f);
+ escape = false;
+
+ if (f->Me == false)
+ {
+ RPC_ENUM_SESSION tmp;
+
+ Zero(&tmp, sizeof(tmp));
+
+ SiCallEnumSession(s, f, hubname, &tmp);
+
+ AdjoinRpcEnumSession(t, &tmp);
+ FreeRpcEnumSession(&tmp);
+ }
+
+ break;
+ }
+ }
+
+ if (escape)
+ {
+ break;
+ }
+
+ UnlockList(s->FarmMemberList);
+ LockList(s->FarmMemberList);
+ }
+ }
+ UnlockList(s->FarmMemberList);
+
+ ReleaseList(fm_list);
+ }
+}
+
+// Enumerate sessions
+UINT StEnumSession(ADMIN *a, RPC_ENUM_SESSION *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_enum_session") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ SiEnumSessionMain(s, t);
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Enumerate groups
+UINT StEnumGroup(ADMIN *a, RPC_ENUM_GROUP *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ CHECK_RIGHT;
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ AcLock(h);
+ {
+ UINT i, j;
+
+ FreeRpcEnumGroup(t);
+ Zero(t, sizeof(RPC_ENUM_GROUP));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ t->NumGroup = LIST_NUM(h->HubDb->GroupList);
+ t->Groups = ZeroMalloc(sizeof(RPC_ENUM_GROUP_ITEM) * t->NumGroup);
+
+ for (i = 0;i < t->NumGroup;i++)
+ {
+ RPC_ENUM_GROUP_ITEM *e = &t->Groups[i];
+ USERGROUP *g = LIST_DATA(h->HubDb->GroupList, i);
+
+ Lock(g->lock);
+ {
+ StrCpy(e->Name, sizeof(e->Name), g->Name);
+ UniStrCpy(e->Realname, sizeof(e->Realname), g->RealName);
+ UniStrCpy(e->Note, sizeof(e->Note), g->Note);
+ if (g->Policy != NULL)
+ {
+ if (g->Policy->Access == false)
+ {
+ e->DenyAccess = true;
+ }
+ }
+ }
+ Unlock(g->lock);
+
+ e->NumUsers = 0;
+
+
+ LockList(h->HubDb->UserList);
+ {
+ for (j = 0;j < LIST_NUM(h->HubDb->UserList);j++)
+ {
+ USER *u = LIST_DATA(h->HubDb->UserList, j);
+
+ Lock(u->lock);
+ {
+ if (u->Group == g)
+ {
+ e->NumUsers++;
+ }
+ }
+ Unlock(u->lock);
+ }
+ }
+ UnlockList(h->HubDb->UserList);
+ }
+ }
+ AcUnlock(h);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Delete a group
+UINT StDeleteGroup(ADMIN *a, RPC_DELETE_USER *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+
+ if (IsEmptyStr(t->Name) || IsSafeStr(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ CHECK_RIGHT;
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_groups") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ AcLock(h);
+ {
+ if (AcDeleteGroup(h, t->Name) == false)
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ }
+ AcUnlock(h);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ ALog(a, h, "LA_DELETE_GROUP", t->Name);
+ }
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ret;
+}
+
+// Get group information
+UINT StGetGroup(ADMIN *a, RPC_SET_GROUP *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ if (IsEmptyStr(t->Name) || IsSafeStr(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ AcLock(h);
+ {
+ USERGROUP *g = AcGetGroup(h, t->Name);
+
+ if (g == NULL)
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ else
+ {
+ FreeRpcSetGroup(t);
+ Zero(t, sizeof(RPC_SET_GROUP));
+
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ Lock(g->lock);
+ {
+ StrCpy(t->Name, sizeof(t->Name), g->Name);
+ UniStrCpy(t->Realname, sizeof(t->Realname), g->RealName);
+ UniStrCpy(t->Note, sizeof(t->Note), g->Note);
+ Copy(&t->Traffic, g->Traffic, sizeof(TRAFFIC));
+ }
+ Unlock(g->lock);
+
+ t->Policy = GetGroupPolicy(g);
+
+ ReleaseGroup(g);
+ }
+ }
+ AcUnlock(h);
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Set group setting
+UINT StSetGroup(ADMIN *a, RPC_SET_GROUP *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+
+ if (IsEmptyStr(t->Name) || IsSafeStr(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_groups") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ AcLock(h);
+ {
+ USERGROUP *g = AcGetGroup(h, t->Name);
+ if (g == NULL)
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ else
+ {
+ Lock(g->lock);
+ {
+ Free(g->RealName);
+ Free(g->Note);
+ g->RealName = UniCopyStr(t->Realname);
+ g->Note = UniCopyStr(t->Note);
+ }
+ Unlock(g->lock);
+
+ SetGroupPolicy(g, t->Policy);
+
+ ReleaseGroup(g);
+
+ ALog(a, h, "LA_SET_GROUP", t->Name);
+ }
+ }
+ AcUnlock(h);
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ret;
+}
+
+// Create a group
+UINT StCreateGroup(ADMIN *a, RPC_SET_GROUP *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+
+ if (IsEmptyStr(t->Name) || IsSafeStr(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ CHECK_RIGHT;
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_groups") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ AcLock(h);
+ {
+ if (AcIsGroup(h, t->Name))
+ {
+ ret = ERR_GROUP_ALREADY_EXISTS;
+ }
+ else
+ {
+ USERGROUP *g = NewGroup(t->Name, t->Realname, t->Note);
+ SetGroupPolicy(g, t->Policy);
+
+ if ((LIST_NUM(h->HubDb->GroupList) >= GetServerCapsInt(a->Server, "i_max_users_per_hub")) ||
+ ((GetHubAdminOption(h, "max_groups") != 0) && (LIST_NUM(h->HubDb->GroupList) >= GetHubAdminOption(h, "max_groups"))))
+ {
+ ret = ERR_TOO_MANY_GROUP;
+ }
+ else
+ {
+ AcAddGroup(h, g);
+ }
+
+ ReleaseGroup(g);
+
+ ALog(a, h, "LA_CREATE_GROUP", t->Name);
+ }
+ }
+ AcUnlock(h);
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ret;
+}
+
+// Enumerate users
+UINT StEnumUser(ADMIN *a, RPC_ENUM_USER *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT i, num;
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ FreeRpcEnumUser(t);
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ Zero(t, sizeof(RPC_ENUM_USER));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ LockList(h->HubDb->UserList);
+ {
+ num = LIST_NUM(h->HubDb->UserList);
+
+ t->NumUser = num;
+ t->Users = ZeroMalloc(sizeof(RPC_ENUM_USER_ITEM) * num);
+
+ for (i = 0;i < num;i++)
+ {
+ USER *u = LIST_DATA(h->HubDb->UserList, i);
+
+ Lock(u->lock);
+ {
+ RPC_ENUM_USER_ITEM *e = &t->Users[i];
+
+ StrCpy(e->Name, sizeof(e->Name), u->Name);
+ StrCpy(e->GroupName, sizeof(e->GroupName), u->GroupName);
+ UniStrCpy(e->Realname, sizeof(e->Realname), u->RealName);
+ UniStrCpy(e->Note, sizeof(e->Note), u->Note);
+ e->AuthType = u->AuthType;
+ e->LastLoginTime = u->LastLoginTime;
+ e->NumLogin = u->NumLogin;
+
+ if (u->Policy != NULL)
+ {
+ e->DenyAccess = u->Policy->Access ? false : true;
+ }
+
+ Copy(&e->Traffic, u->Traffic, sizeof(TRAFFIC));
+ e->IsTrafficFilled = true;
+
+ e->Expires = u->ExpireTime;
+ e->IsExpiresFilled = true;
+ }
+ Unlock(u->lock);
+ }
+ }
+ UnlockList(h->HubDb->UserList);
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Delete a user
+UINT StDeleteUser(ADMIN *a, RPC_DELETE_USER *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+
+
+ if (IsEmptyStr(t->Name) || IsUserName(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_users") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ ALog(a, h, "LA_DELETE_USER", t->Name);
+
+ AcLock(h);
+ {
+ if (AcDeleteUser(h, t->Name) == false)
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ }
+ AcUnlock(h);
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ret;
+}
+
+// Get user setting
+UINT StGetUser(ADMIN *a, RPC_SET_USER *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+ USER *u = NULL;
+ USERGROUP *g = NULL;
+ char name[MAX_USERNAME_LEN + 1];
+ char hubname[MAX_HUBNAME_LEN + 1];
+ StrCpy(name, sizeof(name), t->Name);
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ if (IsEmptyStr(t->Name) || IsUserName(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ FreeRpcSetUser(t);
+ Zero(t, sizeof(RPC_SET_USER));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+ StrCpy(t->Name, sizeof(t->Name), name);
+
+ LockHubList(c);
+ {
+ h = GetHub(c, hubname);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ AcLock(h);
+ {
+ u = AcGetUser(h, name);
+ if (u == NULL)
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ else
+ {
+ Lock(u->lock);
+ {
+ StrCpy(t->GroupName, sizeof(t->GroupName), u->GroupName);
+ UniStrCpy(t->Realname, sizeof(t->Realname), u->RealName);
+ UniStrCpy(t->Note, sizeof(t->Note), u->Note);
+ t->CreatedTime = u->CreatedTime;
+ t->UpdatedTime = u->UpdatedTime;
+ t->ExpireTime = u->ExpireTime;
+
+ t->AuthType = u->AuthType;
+ t->AuthData = CopyAuthData(u->AuthData, t->AuthType);
+ t->NumLogin = u->NumLogin;
+ Copy(&t->Traffic, u->Traffic, sizeof(TRAFFIC));
+ if (u->Policy != NULL)
+ {
+ t->Policy = ClonePolicy(u->Policy);
+ }
+ }
+ Unlock(u->lock);
+
+ ReleaseUser(u);
+ }
+ }
+ AcUnlock(h);
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Set user setting
+UINT StSetUser(ADMIN *a, RPC_SET_USER *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+ USER *u = NULL;
+ USERGROUP *g = NULL;
+
+
+ if (IsEmptyStr(t->Name) || IsUserName(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ if (t->AuthType == AUTHTYPE_USERCERT || t->AuthType == AUTHTYPE_RADIUS || t->AuthType == AUTHTYPE_ROOTCERT || t->AuthType == AUTHTYPE_NT)
+ {
+ return ERR_NOT_SUPPORTED_AUTH_ON_OPENSOURCE;
+ }
+
+ if (StrCmpi(t->Name, "*") == 0)
+ {
+ if (t->AuthType != AUTHTYPE_RADIUS && t->AuthType != AUTHTYPE_NT)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+
+ if (t->AuthType == AUTHTYPE_USERCERT)
+ {
+ AUTHUSERCERT *c = t->AuthData;
+ if (c != NULL && c->UserX != NULL &&
+ c->UserX->is_compatible_bit == false)
+ {
+ return ERR_NOT_RSA_1024;
+ }
+ if (c == NULL || c->UserX == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_users") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ AcLock(h);
+ {
+ u = AcGetUser(h, t->Name);
+ if (u == NULL)
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ else
+ {
+ Lock(u->lock);
+ {
+ if (StrLen(t->GroupName) != 0)
+ {
+ g = AcGetGroup(h, t->GroupName);
+
+ if (g != NULL)
+ {
+ JoinUserToGroup(u, g);
+ ReleaseGroup(g);
+ }
+ else
+ {
+ ret = ERR_GROUP_NOT_FOUND;
+ }
+ }
+ else
+ {
+ JoinUserToGroup(u, NULL);
+ }
+
+ if (ret != ERR_GROUP_NOT_FOUND)
+ {
+ Free(u->RealName);
+ Free(u->Note);
+ u->RealName = UniCopyStr(t->Realname);
+ u->Note = UniCopyStr(t->Note);
+ SetUserAuthData(u, t->AuthType, CopyAuthData(t->AuthData, t->AuthType));
+ u->ExpireTime = t->ExpireTime;
+ u->UpdatedTime = SystemTime64();
+
+ SetUserPolicy(u, t->Policy);
+ }
+ }
+ Unlock(u->lock);
+
+ IncrementServerConfigRevision(s);
+
+ ReleaseUser(u);
+ }
+ }
+ AcUnlock(h);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ ALog(a, h, "LA_SET_USER", t->Name);
+ }
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Create a user
+UINT StCreateUser(ADMIN *a, RPC_SET_USER *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+ UINT ret = ERR_NO_ERROR;
+ USER *u;
+ USERGROUP *g = NULL;
+
+
+ if (IsEmptyStr(t->Name) || IsUserName(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ if (t->AuthType == AUTHTYPE_USERCERT || t->AuthType == AUTHTYPE_RADIUS || t->AuthType == AUTHTYPE_ROOTCERT || t->AuthType == AUTHTYPE_NT)
+ {
+ return ERR_NOT_SUPPORTED_AUTH_ON_OPENSOURCE;
+ }
+
+ if (t->AuthType == AUTHTYPE_USERCERT)
+ {
+ AUTHUSERCERT *c = t->AuthData;
+ if (c != NULL && c->UserX != NULL &&
+ c->UserX->is_compatible_bit == false)
+ {
+ return ERR_NOT_RSA_1024;
+ }
+ if (c == NULL || c->UserX == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+
+ if (IsUserName(t->Name) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (StrCmpi(t->Name, "*") == 0)
+ {
+ if (t->AuthType != AUTHTYPE_RADIUS && t->AuthType != AUTHTYPE_NT)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_users") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ u = NewUser(t->Name, t->Realname, t->Note, t->AuthType, CopyAuthData(t->AuthData, t->AuthType));
+ if (u == NULL)
+ {
+ ReleaseHub(h);
+ return ERR_INTERNAL_ERROR;
+ }
+
+ u->ExpireTime = t->ExpireTime;
+
+ SetUserPolicy(u, t->Policy);
+
+ AcLock(h);
+ {
+ if ((LIST_NUM(h->HubDb->UserList) >= GetServerCapsInt(a->Server, "i_max_users_per_hub")) ||
+ ((GetHubAdminOption(h, "max_users") != 0) && (LIST_NUM(h->HubDb->UserList) >= GetHubAdminOption(h, "max_users"))))
+ {
+ ret = ERR_TOO_MANY_USER;
+ }
+ else if (SiTooManyUserObjectsInServer(s, false))
+ {
+ ret = ERR_TOO_MANY_USERS_CREATED;
+ ALog(a, h, "ERR_128");
+ }
+ else if (AcIsUser(h, t->Name))
+ {
+ ret = ERR_USER_ALREADY_EXISTS;
+ }
+ else
+ {
+ if (StrLen(t->GroupName) != 0)
+ {
+ g = AcGetGroup(h, t->GroupName);
+ if (g == NULL)
+ {
+ ret = ERR_GROUP_NOT_FOUND;
+ }
+ }
+
+ if (ret != ERR_GROUP_NOT_FOUND)
+ {
+ if (g != NULL)
+ {
+ JoinUserToGroup(u, g);
+ ReleaseGroup(g);
+ }
+
+ AcAddUser(h, u);
+ ALog(a, h, "LA_CREATE_USER", t->Name);
+
+ IncrementServerConfigRevision(s);
+ }
+ }
+ }
+ AcUnlock(h);
+
+ ReleaseUser(u);
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Get access list
+UINT StEnumAccess(ADMIN *a, RPC_ENUM_ACCESS_LIST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT i;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ FreeRpcEnumAccessList(t);
+ Zero(t, sizeof(RPC_ENUM_ACCESS_LIST));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ LockList(h->AccessList);
+ {
+ t->NumAccess = LIST_NUM(h->AccessList);
+ t->Accesses = ZeroMalloc(sizeof(ACCESS) * t->NumAccess);
+
+ for (i = 0;i < LIST_NUM(h->AccessList);i++)
+ {
+ ACCESS *a = &t->Accesses[i];
+ Copy(a, LIST_DATA(h->AccessList, i), sizeof(ACCESS));
+ a->UniqueId = HashPtrToUINT(LIST_DATA(h->AccessList, i));
+ }
+ }
+ UnlockList(h->AccessList);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Delete access list entry
+UINT StDeleteAccess(ADMIN *a, RPC_DELETE_ACCESS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT i;
+ bool exists;
+
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_access_list") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ exists = false;
+
+ LockList(h->AccessList);
+ {
+ for (i = 0;i < LIST_NUM(h->AccessList);i++)
+ {
+ ACCESS *access = LIST_DATA(h->AccessList, i);
+
+ if ((t->Id < MAX_ACCESSLISTS && access->Id == t->Id) ||
+ (t->Id >= MAX_ACCESSLISTS && HashPtrToUINT(access) == t->Id))
+ {
+ Free(access);
+ Delete(h->AccessList, access);
+ exists = true;
+
+ break;
+ }
+ }
+ }
+ UnlockList(h->AccessList);
+
+ if (exists == false)
+ {
+ ReleaseHub(h);
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ ALog(a, h, "LA_DELETE_ACCESS");
+
+ IncrementServerConfigRevision(s);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Set access list
+UINT StSetAccessList(ADMIN *a, RPC_ENUM_ACCESS_LIST *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT i;
+ bool no_jitter = false;
+ bool no_include = false;
+ UINT ret = ERR_NO_ERROR;
+
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ if (t->NumAccess > GetServerCapsInt(a->Server, "i_max_access_lists"))
+ {
+ return ERR_TOO_MANY_ACCESS_LIST;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ no_jitter = GetHubAdminOption(h, "no_delay_jitter_packet_loss");
+ no_include = GetHubAdminOption(h, "no_access_list_include_file");
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_access_list") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "max_accesslists") != 0 &&
+ t->NumAccess > GetHubAdminOption(h, "max_accesslists"))
+ {
+ ReleaseHub(h);
+ return ERR_TOO_MANY_ACCESS_LIST;
+ }
+
+ LockList(h->AccessList);
+ {
+ UINT i;
+
+ // Confirm whether the access list of form which cannot handle by the old client already exists
+ if (a->ClientBuild < 6560)
+ {
+ for (i = 0;i < LIST_NUM(h->AccessList);i++)
+ {
+ ACCESS *access = LIST_DATA(h->AccessList, i);
+ if (access->IsIPv6 ||
+ access->Jitter != 0 || access->Loss != 0 || access->Delay != 0)
+ {
+ ret = ERR_VERSION_INVALID;
+ break;
+ }
+ }
+ }
+
+ if (a->ClientBuild < 8234)
+ {
+ for (i = 0;i < LIST_NUM(h->AccessList);i++)
+ {
+ ACCESS *access = LIST_DATA(h->AccessList, i);
+
+ if (IsEmptyStr(access->RedirectUrl) == false)
+ {
+ ret = ERR_VERSION_INVALID;
+ break;
+ }
+ }
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Delete whole access list
+ for (i = 0;i < LIST_NUM(h->AccessList);i++)
+ {
+ ACCESS *access = LIST_DATA(h->AccessList, i);
+ Free(access);
+ }
+
+ DeleteAll(h->AccessList);
+ }
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ ALog(a, h, "LA_SET_ACCESS_LIST", t->NumAccess);
+
+ // Add whole access list
+ for (i = 0;i < t->NumAccess;i++)
+ {
+ ACCESS *a = &t->Accesses[i];
+
+ if (no_jitter)
+ {
+ a->Jitter = a->Loss = a->Delay = 0;
+ }
+
+ if (no_include)
+ {
+ if (StartWith(a->SrcUsername, ACCESS_LIST_INCLUDED_PREFIX) ||
+ StartWith(a->SrcUsername, ACCESS_LIST_EXCLUDED_PREFIX))
+ {
+ ClearStr(a->SrcUsername, sizeof(a->SrcUsername));
+ }
+
+ if (StartWith(a->DestUsername, ACCESS_LIST_INCLUDED_PREFIX) ||
+ StartWith(a->DestUsername, ACCESS_LIST_EXCLUDED_PREFIX))
+ {
+ ClearStr(a->DestUsername, sizeof(a->DestUsername));
+ }
+ }
+
+ if (i == (t->NumAccess - 1))
+ {
+ Sort(h->AccessList);
+ }
+
+ AddAccessListEx(h, a, ((i != (t->NumAccess - 1)) ? true : false), ((i != (t->NumAccess - 1)) ? true : false));
+ }
+
+ UnlockList(h->AccessList);
+
+ IncrementServerConfigRevision(s);
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+ }
+ else
+ {
+ UnlockList(h->AccessList);
+ }
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Add access list entry
+UINT StAddAccess(ADMIN *a, RPC_ADD_ACCESS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ bool no_jitter = false;
+ bool no_include = false;
+
+
+ NO_SUPPORT_FOR_BRIDGE;
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ no_jitter = GetHubAdminOption(h, "no_delay_jitter_packet_loss");
+ no_include = GetHubAdminOption(h, "no_access_list_include_file");
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_access_list") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ if ((LIST_NUM(h->AccessList) >= GetServerCapsInt(a->Server, "i_max_access_lists") ||
+ (GetHubAdminOption(h, "max_accesslists") != 0) && (LIST_NUM(h->AccessList) >= GetHubAdminOption(h, "max_accesslists"))))
+ {
+ ReleaseHub(h);
+ return ERR_TOO_MANY_ACCESS_LIST;
+ }
+
+ ALog(a, h, "LA_ADD_ACCESS");
+
+ if (no_jitter)
+ {
+ t->Access.Jitter = t->Access.Delay = t->Access.Loss = 0;
+ }
+
+ if (no_include)
+ {
+ if (no_include)
+ {
+ if (StartWith(t->Access.SrcUsername, ACCESS_LIST_INCLUDED_PREFIX) ||
+ StartWith(t->Access.SrcUsername, ACCESS_LIST_EXCLUDED_PREFIX))
+ {
+ ClearStr(t->Access.SrcUsername, sizeof(t->Access.SrcUsername));
+ }
+
+ if (StartWith(t->Access.DestUsername, ACCESS_LIST_INCLUDED_PREFIX) ||
+ StartWith(t->Access.DestUsername, ACCESS_LIST_EXCLUDED_PREFIX))
+ {
+ ClearStr(t->Access.DestUsername, sizeof(t->Access.DestUsername));
+ }
+ }
+ }
+
+ AddAccessList(h, &t->Access);
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Rename link (cascade connection)
+UINT StRenameLink(ADMIN *a, RPC_RENAME_LINK *t)
+{
+ UINT i;
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ LINK *k;
+ bool exists = false;
+
+ if (UniIsEmptyStr(t->OldAccountName) || UniIsEmptyStr(t->NewAccountName))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ if (UniStrCmpi(t->NewAccountName, t->OldAccountName) == 0)
+ {
+ // Noop if new name is same to old name
+ return ERR_NO_ERROR;
+ }
+
+ h = GetHub(c, t->HubName);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_cascade") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ k = NULL;
+
+ // Find specified link
+ LockList(h->LinkList);
+ {
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *kk = LIST_DATA(h->LinkList, i);
+ Lock(kk->lock);
+ {
+ if (UniStrCmpi(kk->Option->AccountName, t->OldAccountName) == 0)
+ {
+ k = kk;
+ AddRef(kk->ref);
+ }
+ }
+ Unlock(kk->lock);
+
+ if (k != NULL)
+ {
+ break;
+ }
+ }
+
+ exists = false;
+
+ if (k != NULL)
+ {
+ // Check whether the new link name is same to other links
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *kk = LIST_DATA(h->LinkList, i);
+ Lock(kk->lock);
+ {
+ if (UniStrCmpi(kk->Option->AccountName, t->NewAccountName) == 0)
+ {
+ // duplicated
+ exists = true;
+ }
+ }
+ Unlock(kk->lock);
+ }
+
+ if (exists)
+ {
+ // Already same name exists
+ ret = ERR_LINK_ALREADY_EXISTS;
+ }
+ else
+ {
+ // Do rename
+ UniStrCpy(k->Option->AccountName, sizeof(k->Option->AccountName), t->NewAccountName);
+
+ ALog(a, h, "LA_RENAME_LINK", t->OldAccountName, t->NewAccountName);
+
+ IncrementServerConfigRevision(s);
+ }
+ }
+ }
+ UnlockList(h->LinkList);
+
+ if (k == NULL)
+ {
+ // specified link is not found
+ ReleaseHub(h);
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ ReleaseLink(k);
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Delete a link
+UINT StDeleteLink(ADMIN *a, RPC_LINK *t)
+{
+ UINT i;
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ wchar_t accountname[MAX_ACCOUNT_NAME_LEN + 1];
+ LINK *k;
+
+ if (UniIsEmptyStr(t->AccountName))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_cascade") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ UniStrCpy(accountname, sizeof(accountname), t->AccountName);
+ k = NULL;
+
+ // Find specified link
+ LockList(h->LinkList);
+ {
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *kk = LIST_DATA(h->LinkList, i);
+ Lock(kk->lock);
+ {
+ if (UniStrCmpi(kk->Option->AccountName, accountname) == 0)
+ {
+ k = kk;
+ AddRef(kk->ref);
+ }
+ }
+ Unlock(kk->lock);
+
+ if (k != NULL)
+ {
+ break;
+ }
+ }
+ }
+ UnlockList(h->LinkList);
+
+ if (k == NULL)
+ {
+ // Specified link is not found
+ ReleaseHub(h);
+
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ ALog(a, h, "LA_DELETE_LINK", t->AccountName);
+
+ SetLinkOffline(k);
+
+ IncrementServerConfigRevision(s);
+
+ DelLink(h, k);
+
+ ReleaseLink(k);
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Make a link into off-line
+UINT StSetLinkOffline(ADMIN *a, RPC_LINK *t)
+{
+ UINT i;
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ wchar_t accountname[MAX_ACCOUNT_NAME_LEN + 1];
+ LINK *k;
+
+
+ if (UniIsEmptyStr(t->AccountName))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_cascade") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ UniStrCpy(accountname, sizeof(accountname), t->AccountName);
+ k = NULL;
+
+ // Find specified link
+ LockList(h->LinkList);
+ {
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *kk = LIST_DATA(h->LinkList, i);
+ Lock(kk->lock);
+ {
+ if (UniStrCmpi(kk->Option->AccountName, accountname) == 0)
+ {
+ k = kk;
+ AddRef(kk->ref);
+ }
+ }
+ Unlock(kk->lock);
+
+ if (k != NULL)
+ {
+ break;
+ }
+ }
+ }
+ UnlockList(h->LinkList);
+
+ if (k == NULL)
+ {
+ // Link is not found
+ ReleaseHub(h);
+
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ ALog(a, h, "LA_SET_LINK_OFFLINE", t->AccountName);
+
+ SetLinkOffline(k);
+
+ IncrementServerConfigRevision(s);
+
+ ReleaseLink(k);
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Make a link into on-line
+UINT StSetLinkOnline(ADMIN *a, RPC_LINK *t)
+{
+ UINT i;
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ wchar_t accountname[MAX_ACCOUNT_NAME_LEN + 1];
+ LINK *k;
+
+
+ if (UniIsEmptyStr(t->AccountName))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_cascade") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ UniStrCpy(accountname, sizeof(accountname), t->AccountName);
+ k = NULL;
+
+ // Find specified link
+ LockList(h->LinkList);
+ {
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *kk = LIST_DATA(h->LinkList, i);
+ Lock(kk->lock);
+ {
+ if (UniStrCmpi(kk->Option->AccountName, accountname) == 0)
+ {
+ k = kk;
+ AddRef(kk->ref);
+ }
+ }
+ Unlock(kk->lock);
+
+ if (k != NULL)
+ {
+ break;
+ }
+ }
+ }
+ UnlockList(h->LinkList);
+
+ if (k == NULL)
+ {
+ // Specified link is not found
+ ReleaseHub(h);
+
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ ALog(a, h, "LA_SET_LINK_ONLINE", t->AccountName);
+
+ SetLinkOnline(k);
+
+ ReleaseLink(k);
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ret;
+}
+
+// Get link status
+UINT StGetLinkStatus(ADMIN *a, RPC_LINK_STATUS *t)
+{
+ UINT i;
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ wchar_t accountname[MAX_ACCOUNT_NAME_LEN + 1];
+ LINK *k;
+ SESSION *sess;
+
+ if (UniIsEmptyStr(t->AccountName))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ UniStrCpy(accountname, sizeof(accountname), t->AccountName);
+ FreeRpcLinkStatus(t);
+ Zero(t, sizeof(RPC_LINK_STATUS));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+ UniStrCpy(t->AccountName, sizeof(t->AccountName), accountname);
+
+ k = NULL;
+
+ // Find the link
+ LockList(h->LinkList);
+ {
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *kk = LIST_DATA(h->LinkList, i);
+ Lock(kk->lock);
+ {
+ if (UniStrCmpi(kk->Option->AccountName, accountname) == 0)
+ {
+ k = kk;
+ AddRef(kk->ref);
+ }
+ }
+ Unlock(kk->lock);
+
+ if (k != NULL)
+ {
+ break;
+ }
+ }
+ }
+ UnlockList(h->LinkList);
+
+ if (k == NULL)
+ {
+ // Specified link is not found
+ ReleaseHub(h);
+
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ // Get status infomation from session
+ Lock(k->lock);
+ {
+ sess = k->ClientSession;
+ if (sess != NULL)
+ {
+ AddRef(sess->ref);
+ }
+ }
+ Unlock(k->lock);
+
+ if (sess != NULL && k->Offline == false)
+ {
+ CiGetSessionStatus(&t->Status, sess);
+ }
+ else
+ {
+ ret = ERR_LINK_IS_OFFLINE;
+ }
+ ReleaseSession(sess);
+
+ ReleaseLink(k);
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Enumerate links
+UINT StEnumLink(ADMIN *a, RPC_ENUM_LINK *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT i;
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ FreeRpcEnumLink(t);
+ Zero(t, sizeof(RPC_ENUM_LINK));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ LockList(h->LinkList);
+ {
+ t->NumLink = LIST_NUM(h->LinkList);
+ t->Links = ZeroMalloc(sizeof(RPC_ENUM_LINK_ITEM) * t->NumLink);
+
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *k = LIST_DATA(h->LinkList, i);
+ RPC_ENUM_LINK_ITEM *e = &t->Links[i];
+
+ Lock(k->lock);
+ {
+ UniStrCpy(e->AccountName, sizeof(e->AccountName), k->Option->AccountName);
+ StrCpy(e->Hostname, sizeof(e->Hostname), k->Option->Hostname);
+ StrCpy(e->HubName, sizeof(e->HubName), k->Option->HubName);
+ e->Online = k->Offline ? false : true;
+
+ if (e->Online)
+ {
+ if (k->ClientSession != NULL)
+ {
+ e->ConnectedTime = TickToTime(k->ClientSession->CurrentConnectionEstablishTime);
+ e->Connected = (k->ClientSession->ClientStatus == CLIENT_STATUS_ESTABLISHED);
+ e->LastError = k->ClientSession->Err;
+ }
+ }
+ }
+ Unlock(k->lock);
+ }
+ }
+ UnlockList(h->LinkList);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Get link configuration
+UINT StGetLink(ADMIN *a, RPC_CREATE_LINK *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ UINT i;
+ char hubname[MAX_SIZE];
+ LINK *k;
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_LINK_CANT_CREATE_ON_FARM;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ k = NULL;
+
+ // Find the link
+ LockList(h->LinkList);
+ {
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *kk = LIST_DATA(h->LinkList, i);
+ Lock(kk->lock);
+ {
+ if (UniStrCmpi(kk->Option->AccountName, t->ClientOption->AccountName) == 0)
+ {
+ k = kk;
+ AddRef(kk->ref);
+ }
+ }
+ Unlock(kk->lock);
+
+ if (k != NULL)
+ {
+ break;
+ }
+ }
+ }
+ UnlockList(h->LinkList);
+
+ if (k == NULL)
+ {
+ // The link is not found
+ ReleaseHub(h);
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ FreeRpcCreateLink(t);
+ Zero(t, sizeof(t));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ Lock(k->lock);
+ {
+ // Get configuration
+ t->Online = k->Offline ? false : true;
+ t->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(t->ClientOption, k->Option, sizeof(CLIENT_OPTION));
+ t->ClientAuth = CopyClientAuth(k->Auth);
+ Copy(&t->Policy, k->Policy, sizeof(POLICY));
+
+ t->CheckServerCert = k->CheckServerCert;
+ t->ServerCert = CloneX(k->ServerCert);
+ }
+ Unlock(k->lock);
+
+ ReleaseLink(k);
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Set link configuration
+UINT StSetLink(ADMIN *a, RPC_CREATE_LINK *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ UINT i;
+ LINK *k;
+
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_LINK_CANT_CREATE_ON_FARM;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_cascade") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ k = NULL;
+
+ // Find the link
+ LockList(h->LinkList);
+ {
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *kk = LIST_DATA(h->LinkList, i);
+ Lock(kk->lock);
+ {
+ if (UniStrCmpi(kk->Option->AccountName, t->ClientOption->AccountName) == 0)
+ {
+ k = kk;
+ AddRef(kk->ref);
+ }
+ }
+ Unlock(kk->lock);
+
+ if (k != NULL)
+ {
+ break;
+ }
+ }
+ }
+ UnlockList(h->LinkList);
+
+ if (k == NULL)
+ {
+ // The link is not found
+ ReleaseHub(h);
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ ALog(a, h, "LA_SET_LINK", t->ClientOption->AccountName);
+
+ Lock(k->lock);
+ {
+ // Update the configuration of the link
+ if (k->ServerCert != NULL)
+ {
+ FreeX(k->ServerCert);
+ k->ServerCert = NULL;
+ }
+
+ Copy(k->Option, t->ClientOption, sizeof(CLIENT_OPTION));
+ StrCpy(k->Option->DeviceName, sizeof(k->Option->DeviceName), LINK_DEVICE_NAME);
+ k->Option->NumRetry = INFINITE;
+ k->Option->RetryInterval = 10;
+ k->Option->NoRoutingTracking = true;
+ CiFreeClientAuth(k->Auth);
+ k->Auth = CopyClientAuth(t->ClientAuth);
+
+ if (t->Policy.Ver3 == false)
+ {
+ Copy(k->Policy, &t->Policy, sizeof(UINT) * NUM_POLICY_ITEM_FOR_VER2);
+ }
+ else
+ {
+ Copy(k->Policy, &t->Policy, sizeof(POLICY));
+ }
+
+ k->Option->RequireBridgeRoutingMode = true; // Enable Bridge / Routing mode
+ k->Option->RequireMonitorMode = false; // Disable monitor mode
+
+ k->CheckServerCert = t->CheckServerCert;
+ k->ServerCert = CloneX(t->ServerCert);
+ }
+ Unlock(k->lock);
+
+ IncrementServerConfigRevision(s);
+
+ ReleaseLink(k);
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Create a new link(cascade)
+UINT StCreateLink(ADMIN *a, RPC_CREATE_LINK *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ UINT i;
+ LINK *k;
+
+ CHECK_RIGHT;
+
+
+ if (s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ return ERR_LINK_CANT_CREATE_ON_FARM;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_cascade") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ k = NULL;
+
+ // Check for existing a link which has same name
+ LockList(h->LinkList);
+ {
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *kk = LIST_DATA(h->LinkList, i);
+ Lock(kk->lock);
+ {
+ if (UniStrCmpi(kk->Option->AccountName, t->ClientOption->AccountName) == 0)
+ {
+ k = kk;
+ AddRef(kk->ref);
+ }
+ }
+ Unlock(kk->lock);
+
+ if (k != NULL)
+ {
+ break;
+ }
+ }
+ }
+ UnlockList(h->LinkList);
+
+ if (k != NULL)
+ {
+ // There is a link which has same name
+ ReleaseLink(k);
+ ReleaseHub(h);
+ return ERR_LINK_ALREADY_EXISTS;
+ }
+
+ ALog(a, h, "LA_CREATE_LINK", t->ClientOption->AccountName);
+
+ // Create a new link
+ k = NewLink(c, h, t->ClientOption, t->ClientAuth, &t->Policy);
+
+ if (k == NULL)
+ {
+ // Link creation failed
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ // setting of verifying server certification
+ //
+ k->CheckServerCert = t->CheckServerCert;
+ k->ServerCert = CloneX(t->ServerCert);
+
+ // stay this off-line
+ k->Offline = false;
+ SetLinkOffline(k);
+ ReleaseLink(k);
+
+ IncrementServerConfigRevision(s);
+ }
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Delete a CA(Certificate Authority) setting from the hub
+UINT StDeleteCa(ADMIN *a, RPC_HUB_DELETE_CA *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_cert_list") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ LockList(h->HubDb->RootCertList);
+ {
+ if (IsInListKey(h->HubDb->RootCertList, t->Key))
+ {
+ X *x = ListKeyToPointer(h->HubDb->RootCertList, t->Key);
+ Delete(h->HubDb->RootCertList, x);
+ FreeX(x);
+
+ ALog(a, h, "LA_DELETE_CA");
+
+ IncrementServerConfigRevision(s);
+ }
+ else
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ }
+ UnlockList(h->HubDb->RootCertList);
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Get CA(Certificate Authority) setting from the hub
+UINT StGetCa(ADMIN *a, RPC_HUB_GET_CA *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT key;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+ key = t->Key;
+
+ FreeRpcHubGetCa(t);
+ Zero(t, sizeof(RPC_HUB_GET_CA));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ LockList(h->HubDb->RootCertList);
+ {
+ if (IsInListKey(h->HubDb->RootCertList, key))
+ {
+ X *x = ListKeyToPointer(h->HubDb->RootCertList, key);
+
+ t->Cert = CloneX(x);
+ }
+ else
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ }
+ UnlockList(h->HubDb->RootCertList);
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Enumerate CA(Certificate Authority) in the hub
+UINT StEnumCa(ADMIN *a, RPC_HUB_ENUM_CA *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT i;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ FreeRpcHubEnumCa(t);
+ Zero(t, sizeof(RPC_HUB_ENUM_CA));
+
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, hubname);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ Zero(t, sizeof(RPC_HUB_ENUM_CA));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+
+ if (h->HubDb->RootCertList != NULL)
+ {
+ LockList(h->HubDb->RootCertList);
+ {
+ t->NumCa = LIST_NUM(h->HubDb->RootCertList);
+ t->Ca = ZeroMalloc(sizeof(RPC_HUB_ENUM_CA_ITEM) * t->NumCa);
+
+ for (i = 0;i < t->NumCa;i++)
+ {
+ RPC_HUB_ENUM_CA_ITEM *e = &t->Ca[i];
+ X *x = LIST_DATA(h->HubDb->RootCertList, i);
+
+ e->Key = POINTER_TO_KEY(x);
+ GetAllNameFromNameEx(e->SubjectName, sizeof(e->SubjectName), x->subject_name);
+ GetAllNameFromNameEx(e->IssuerName, sizeof(e->IssuerName), x->issuer_name);
+ e->Expires = x->notAfter;
+ }
+ }
+ UnlockList(h->HubDb->RootCertList);
+ }
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Add CA(Certificate Authority) into the hub
+UINT StAddCa(ADMIN *a, RPC_HUB_ADD_CA *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ if (c->Bridge)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ if (t->Cert == NULL)
+ {
+ ERR_INVALID_PARAMETER;
+ }
+
+ if (t->Cert->is_compatible_bit == false)
+ {
+ return ERR_NOT_RSA_1024;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_cert_list") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ IncrementServerConfigRevision(s);
+
+ ALog(a, h, "LA_ADD_CA");
+
+ AddRootCert(h, t->Cert);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Get logging configuration of the hub
+UINT StGetHubLog(ADMIN *a, RPC_HUB_LOG *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ GetHubLogSetting(h, &t->LogSetting);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Set logging configuration into the hub
+UINT StSetHubLog(ADMIN *a, RPC_HUB_LOG *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ CHECK_RIGHT;
+
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_log_config") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ ALog(a, h, "LA_SET_HUB_LOG");
+
+ SetHubLogSettingEx(h, &t->LogSetting,
+ (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_log_switch_type") != 0));
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get hub status
+UINT StGetHubStatus(ADMIN *a, RPC_HUB_STATUS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ Zero(t, sizeof(RPC_HUB_STATUS));
+
+ Lock(h->lock);
+ {
+ StrCpy(t->HubName, sizeof(t->HubName), h->Name);
+ t->HubType = h->Type;
+ t->Online = h->Offline ? false : true;
+ t->NumSessions = LIST_NUM(h->SessionList);
+ t->NumSessionsClient = Count(h->NumSessionsClient);
+ t->NumSessionsBridge = Count(h->NumSessionsBridge);
+ t->NumAccessLists = LIST_NUM(h->AccessList);
+
+ if (h->HubDb != NULL)
+ {
+ t->NumUsers = LIST_NUM(h->HubDb->UserList);
+ t->NumGroups = LIST_NUM(h->HubDb->GroupList);
+ }
+
+ t->NumMacTables = LIST_NUM(h->MacTable);
+ t->NumIpTables = LIST_NUM(h->IpTable);
+
+ Lock(h->TrafficLock);
+ {
+ Copy(&t->Traffic, h->Traffic, sizeof(TRAFFIC));
+ }
+ Unlock(h->TrafficLock);
+
+ t->NumLogin = h->NumLogin;
+ t->LastCommTime = h->LastCommTime;
+ t->LastLoginTime = h->LastLoginTime;
+ t->CreatedTime = h->CreatedTime;
+ }
+ Unlock(h->lock);
+
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ UINT i;
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ UINT k;
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+
+ if (f->Me == false)
+ {
+ LockList(f->HubList);
+ {
+ for (k = 0;k < LIST_NUM(f->HubList);k++)
+ {
+ HUB_LIST *h = LIST_DATA(f->HubList, k);
+
+ if (StrCmpi(h->Name, t->HubName) == 0)
+ {
+ t->NumSessions += h->NumSessions;
+ t->NumSessionsClient += h->NumSessionsClient;
+ t->NumSessionsBridge += h->NumSessionsBridge;
+ t->NumMacTables += h->NumMacTables;
+ t->NumIpTables += h->NumIpTables;
+ }
+ }
+ }
+ UnlockList(f->HubList);
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+
+ if (h->Type != HUB_TYPE_FARM_STATIC)
+ {
+ t->SecureNATEnabled = h->EnableSecureNAT;
+ }
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Enable SecureNAT function of the hub
+UINT StEnableSecureNAT(ADMIN *a, RPC_HUB *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ CHECK_RIGHT;
+
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_SUPPORTED;
+ }
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_securenat") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ ALog(a, h, "LA_ENABLE_SNAT");
+
+ EnableSecureNAT(h, true);
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+
+ IncrementServerConfigRevision(s);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Disable the SecureNAT function of the hub
+UINT StDisableSecureNAT(ADMIN *a, RPC_HUB *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ CHECK_RIGHT;
+
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_SUPPORTED;
+ }
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_securenat") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ ALog(a, h, "LA_DISABLE_SNAT");
+
+ EnableSecureNAT(h, false);
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+
+ IncrementServerConfigRevision(s);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate NAT entries of the SecureNAT
+UINT StEnumNAT(ADMIN *a, RPC_ENUM_NAT *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT i;
+
+ CHECK_RIGHT;
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_SUPPORTED;
+ }
+
+ Lock(h->lock_online);
+ {
+ if (h->SecureNAT == NULL)
+ {
+ ret = ERR_SNAT_NOT_RUNNING;
+ }
+ else
+ {
+ NtEnumNatList(h->SecureNAT->Nat, t);
+ }
+ }
+ Unlock(h->lock_online);
+
+ if (h->Type == HUB_TYPE_FARM_DYNAMIC)
+ {
+ if (ret == ERR_SNAT_NOT_RUNNING)
+ {
+ // Get status of remote SecureNAT
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ if (f->Me == false)
+ {
+ RPC_ENUM_NAT tmp;
+
+ Zero(&tmp, sizeof(tmp));
+
+ SiCallEnumNat(s, f, hubname, &tmp);
+
+ if (tmp.NumItem >= 1)
+ {
+ FreeRpcEnumNat(t);
+ Copy(t, &tmp, sizeof(RPC_ENUM_NAT));
+ ret = ERR_NO_ERROR;
+ break;
+ }
+ else
+ {
+ FreeRpcEnumNat(&tmp);
+ }
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+ }
+
+ ReleaseHub(h);
+
+ ret = ERR_NO_ERROR;
+
+ return ret;
+}
+
+// Get status of the SecureNAT
+UINT StGetSecureNATStatus(ADMIN *a, RPC_NAT_STATUS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT i;
+
+ CHECK_RIGHT;
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_SUPPORTED;
+ }
+
+ Lock(h->lock_online);
+ {
+ if (h->SecureNAT == NULL)
+ {
+ ret = ERR_SNAT_NOT_RUNNING;
+ }
+ else
+ {
+ NtGetStatus(h->SecureNAT->Nat, t);
+ }
+ }
+ Unlock(h->lock_online);
+
+ if (h->Type == HUB_TYPE_FARM_DYNAMIC)
+ {
+ if (ret == ERR_SNAT_NOT_RUNNING)
+ {
+ // Get status of remote secureNAT
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ if (f->Me == false)
+ {
+ RPC_NAT_STATUS tmp;
+
+ Zero(&tmp, sizeof(tmp));
+
+ SiCallGetNatStatus(s, f, hubname, &tmp);
+
+ if (tmp.NumDhcpClients == 0 && tmp.NumTcpSessions == 0 && tmp.NumUdpSessions == 0)
+ {
+ }
+ else
+ {
+ Copy(t, &tmp, sizeof(RPC_NAT_STATUS));
+ ret = ERR_NO_ERROR;
+ break;
+ }
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+ }
+
+ ReleaseHub(h);
+
+ ret = ERR_NO_ERROR;
+
+ return ret;
+}
+
+// Enumerate DHCP entries
+UINT StEnumDHCP(ADMIN *a, RPC_ENUM_DHCP *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ UINT i;
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_SUPPORTED;
+ }
+
+ Lock(h->lock_online);
+ {
+ if (h->SecureNAT == NULL)
+ {
+ ret = ERR_SNAT_NOT_RUNNING;
+ }
+ else
+ {
+ NtEnumDhcpList(h->SecureNAT->Nat, t);
+ }
+ }
+ Unlock(h->lock_online);
+
+ if (h->Type == HUB_TYPE_FARM_DYNAMIC)
+ {
+ if (ret == ERR_SNAT_NOT_RUNNING)
+ {
+ // Get status of remote DHCP service
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ if (f->Me == false)
+ {
+ RPC_ENUM_DHCP tmp;
+
+ Zero(&tmp, sizeof(tmp));
+
+ SiCallEnumDhcp(s, f, hubname, &tmp);
+
+ if (tmp.NumItem >= 1)
+ {
+ FreeRpcEnumDhcp(t);
+ Copy(t, &tmp, sizeof(RPC_ENUM_DHCP));
+ ret = ERR_NO_ERROR;
+ break;
+ }
+ else
+ {
+ FreeRpcEnumDhcp(&tmp);
+ }
+ }
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+ }
+
+ ReleaseHub(h);
+
+ ret = ERR_NO_ERROR;
+
+ return ret;
+}
+
+// Set SecureNAT options
+UINT StSetSecureNATOption(ADMIN *a, VH_OPTION *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+
+ if (IsZero(t->MacAddress, sizeof(t->MacAddress)) ||
+ IsHostIPAddress4(&t->Ip) == false ||
+ IsSubnetMask4(&t->Mask) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ if ((IPToUINT(&t->Ip) & (~(IPToUINT(&t->Mask)))) == 0)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_SUPPORTED;
+ }
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_securenat") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ if (h->SecureNATOption->UseNat == false && t->UseNat)
+ {
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_securenat_enablenat") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+ }
+
+ if (h->SecureNATOption->UseDhcp == false && t->UseDhcp)
+ {
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_securenat_enabledhcp") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+ }
+
+ Copy(h->SecureNATOption, t, sizeof(VH_OPTION));
+
+ if (h->Type != HUB_TYPE_STANDALONE && h->Cedar != NULL && h->Cedar->Server != NULL &&
+ h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ NiClearUnsupportedVhOptionForDynamicHub(h->SecureNATOption, false);
+ }
+
+ Lock(h->lock_online);
+ {
+ if (h->SecureNAT != NULL)
+ {
+ SetVirtualHostOption(h->SecureNAT->Nat->Virtual, t);
+ }
+ }
+ Unlock(h->lock_online);
+
+ ALog(a, h, "LA_SET_SNAT_OPTION");
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+
+ IncrementServerConfigRevision(s);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Get SecureNAT options
+UINT StGetSecureNATOption(ADMIN *a, VH_OPTION *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ char hubname[MAX_HUBNAME_LEN + 1];
+
+ StrCpy(hubname, sizeof(hubname), t->HubName);
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (h->Type == HUB_TYPE_FARM_STATIC || GetServerCapsBool(s, "b_support_securenat") == false)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_SUPPORTED;
+ }
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ Zero(t, sizeof(VH_OPTION));
+ StrCpy(t->HubName, sizeof(t->HubName), hubname);
+ Copy(t, h->SecureNATOption, sizeof(VH_OPTION));
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Make a hub on-line or off-line
+UINT StSetHubOnline(ADMIN *a, RPC_SET_HUB_ONLINE *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (a->ServerAdmin == false && t->Online && GetHubAdminOption(h, "no_online") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ if (a->ServerAdmin == false && t->Online == false && GetHubAdminOption(h, "no_offline") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ if (t->Online)
+ {
+ ALog(a, h, "LA_SET_HUB_ONLINE");
+ SetHubOnline(h);
+ }
+ else
+ {
+ ALog(a, h, "LA_SET_HUB_OFFLINE");
+ SetHubOffline(h);
+ }
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+
+ IncrementServerConfigRevision(s);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Get connection information
+UINT StGetConnectionInfo(ADMIN *a, RPC_CONNECTION_INFO *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ CONNECTION *connection;
+ char name[MAX_CONNECTION_NAME_LEN + 1];
+
+ if (IsEmptyStr(t->Name))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ SERVER_ADMIN_ONLY;
+
+ LockList(c->ConnectionList);
+ {
+ CONNECTION tt;
+ Zero(&tt, sizeof(tt));
+ tt.Name = t->Name;
+ StrCpy(name, sizeof(name), t->Name);
+
+ connection = Search(c->ConnectionList, &tt);
+
+ if (connection != NULL)
+ {
+ AddRef(connection->ref);
+ }
+ }
+ UnlockList(c->ConnectionList);
+
+ if (connection == NULL)
+ {
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ Zero(t, sizeof(RPC_CONNECTION_INFO));
+ StrCpy(t->Name, sizeof(t->Name), name);
+
+ Lock(connection->lock);
+ {
+ SOCK *s = connection->FirstSock;
+
+ if (s != NULL)
+ {
+ t->Ip = IPToUINT(&s->RemoteIP);
+ t->Port = s->RemotePort;
+ StrCpy(t->Hostname, sizeof(t->Hostname), s->RemoteHostname);
+ }
+
+ StrCpy(t->Name, sizeof(t->Name), connection->Name);
+ t->ConnectedTime = TickToTime(connection->ConnectedTick);
+ t->Type = connection->Type;
+
+ StrCpy(t->ServerStr, sizeof(t->ServerStr), connection->ServerStr);
+ StrCpy(t->ClientStr, sizeof(t->ClientStr), connection->ClientStr);
+ t->ServerVer = connection->ServerVer;
+ t->ServerBuild = connection->ServerBuild;
+ t->ClientVer = connection->ClientVer;
+ t->ClientBuild = connection->ClientBuild;
+ }
+ Unlock(connection->lock);
+
+ ReleaseConnection(connection);
+
+ return ERR_NO_ERROR;
+}
+
+// Disconnect a connection
+UINT StDisconnectConnection(ADMIN *a, RPC_DISCONNECT_CONNECTION *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ CONNECTION *connection;
+
+ if (IsEmptyStr(t->Name))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ SERVER_ADMIN_ONLY;
+
+ LockList(c->ConnectionList);
+ {
+ CONNECTION tt;
+ Zero(&tt, sizeof(tt));
+ tt.Name = t->Name;
+
+ connection = Search(c->ConnectionList, &tt);
+ if (connection != NULL)
+ {
+ AddRef(connection->ref);
+ }
+ }
+ UnlockList(c->ConnectionList);
+
+ if (connection == NULL)
+ {
+ return ERR_OBJECT_NOT_FOUND;
+ }
+
+ StopConnection(connection, true);
+
+ ReleaseConnection(connection);
+
+ ALog(a, NULL, "LA_DISCONNECT_CONN", t->Name);
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate connections
+UINT StEnumConnection(ADMIN *a, RPC_ENUM_CONNECTION *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+
+ SERVER_ADMIN_ONLY;
+
+ FreeRpcEnumConnetion(t);
+ Zero(t, sizeof(RPC_ENUM_CONNECTION));
+
+ LockList(c->ConnectionList);
+ {
+ UINT i;
+ t->NumConnection = LIST_NUM(c->ConnectionList);
+ t->Connections = ZeroMalloc(sizeof(RPC_ENUM_CONNECTION_ITEM) * t->NumConnection);
+
+ for (i = 0;i < t->NumConnection;i++)
+ {
+ RPC_ENUM_CONNECTION_ITEM *e = &t->Connections[i];
+ CONNECTION *connection = LIST_DATA(c->ConnectionList, i);
+
+ Lock(connection->lock);
+ {
+ SOCK *s = connection->FirstSock;
+
+ if (s != NULL)
+ {
+ e->Ip = IPToUINT(&s->RemoteIP);
+ e->Port = s->RemotePort;
+ StrCpy(e->Hostname, sizeof(e->Hostname), s->RemoteHostname);
+ }
+
+ StrCpy(e->Name, sizeof(e->Name), connection->Name);
+ e->ConnectedTime = TickToTime(connection->ConnectedTick);
+ e->Type = connection->Type;
+ }
+ Unlock(connection->lock);
+ }
+ }
+ UnlockList(c->ConnectionList);
+
+ return ERR_NO_ERROR;
+}
+
+// Set Radius options of the hub
+UINT StSetHubRadius(ADMIN *a, RPC_RADIUS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ //SetRadiusServer(h, t->RadiusServerName, t->RadiusPort, t->RadiusSecret);
+ SetRadiusServerEx(h, t->RadiusServerName, t->RadiusPort, t->RadiusSecret, t->RadiusRetryInterval);
+
+ ALog(a, h, "LA_SET_HUB_RADIUS");
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get Radius options of the hub
+UINT StGetHubRadius(ADMIN *a, RPC_RADIUS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+
+ CHECK_RIGHT;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ Zero(t, sizeof(t));
+ //GetRadiusServer(h, t->RadiusServerName, sizeof(t->RadiusServerName),
+ // &t->RadiusPort, t->RadiusSecret, sizeof(t->RadiusSecret));
+ GetRadiusServerEx(h, t->RadiusServerName, sizeof(t->RadiusServerName),
+ &t->RadiusPort, t->RadiusSecret, sizeof(t->RadiusSecret), &t->RadiusRetryInterval);
+
+ ReleaseHub(h);
+
+ return ERR_NO_ERROR;
+}
+
+// Delete a hub
+UINT StDeleteHub(ADMIN *a, RPC_DELETE_HUB *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+
+ if (IsEmptyStr(t->HubName) || IsSafeStr(t->HubName) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ SERVER_ADMIN_ONLY;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ StopHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ DelHub(c, h);
+ ReleaseHub(h);
+
+ ALog(a, NULL, "LA_DELETE_HUB", t->HubName);
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate hubs
+UINT StEnumHub(ADMIN *a, RPC_ENUM_HUB *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h = NULL;
+
+ FreeRpcEnumHub(t);
+
+ Zero(t, sizeof(RPC_ENUM_HUB));
+
+ LockHubList(c);
+ {
+ UINT i, num, j;
+
+ num = 0;
+
+ for (i = 0;i < LIST_NUM(c->HubList);i++)
+ {
+ HUB *h = LIST_DATA(c->HubList, i);
+
+ Lock(h->lock);
+
+ if (a->ServerAdmin == false &&
+ h->Option != NULL &&
+ StrCmpi(h->Name, a->HubName) != 0)
+ {
+ // This hub is not listed
+ }
+ else
+ {
+ // This hub is listed
+ num++;
+ }
+ }
+
+ t->NumHub = num;
+
+ t->Hubs = ZeroMalloc(sizeof(RPC_ENUM_HUB_ITEM) * num);
+
+ i = 0;
+ for (j = 0;j < LIST_NUM(c->HubList);j++)
+ {
+ HUB *h = LIST_DATA(c->HubList, j);
+
+ if (a->ServerAdmin == false &&
+ h->Option != NULL &&
+ StrCmpi(h->Name, a->HubName) != 0)
+ {
+ // This hub is not listed
+ }
+ else
+ {
+ // This hub is listed
+ RPC_ENUM_HUB_ITEM *e = &t->Hubs[i++];
+
+ StrCpy(e->HubName, sizeof(e->HubName), h->Name);
+ e->Online = h->Offline ? false : true;
+ e->HubType = h->Type;
+
+ e->NumSessions = LIST_NUM(h->SessionList);
+
+ LockList(h->MacTable);
+ {
+ e->NumMacTables = LIST_NUM(h->MacTable);
+ }
+ UnlockList(h->MacTable);
+
+ LockList(h->IpTable);
+ {
+ e->NumIpTables = LIST_NUM(h->IpTable);
+ }
+ UnlockList(h->IpTable);
+
+ if (h->HubDb != NULL)
+ {
+ LockList(h->HubDb->UserList);
+ {
+ e->NumUsers = LIST_NUM(h->HubDb->UserList);
+ }
+ UnlockList(h->HubDb->UserList);
+
+ LockList(h->HubDb->GroupList);
+ {
+ e->NumGroups = LIST_NUM(h->HubDb->GroupList);
+ }
+ UnlockList(h->HubDb->GroupList);
+ }
+
+ e->LastCommTime = h->LastCommTime;
+ e->LastLoginTime = h->LastLoginTime;
+ e->NumLogin = h->NumLogin;
+ e->CreatedTime = h->CreatedTime;
+
+ Lock(h->TrafficLock);
+ {
+ Copy(&e->Traffic, h->Traffic, sizeof(TRAFFIC));
+ }
+ Unlock(h->TrafficLock);
+
+ e->IsTrafficFilled = true;
+ }
+
+ Unlock(h->lock);
+ }
+ }
+ UnlockHubList(c);
+
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ UINT i, j, k;
+ LockList(s->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(s->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+
+ LockList(f->HubList);
+ {
+ if (f->Me == false)
+ {
+ for (j = 0;j < LIST_NUM(f->HubList);j++)
+ {
+ HUB_LIST *o = LIST_DATA(f->HubList, j);
+
+ for (k = 0;k < t->NumHub;k++)
+ {
+ RPC_ENUM_HUB_ITEM *e = &t->Hubs[k];
+
+ if (StrCmpi(e->HubName, o->Name) == 0)
+ {
+ e->NumIpTables += o->NumIpTables;
+ e->NumMacTables += o->NumMacTables;
+ e->NumSessions += o->NumSessions;
+ }
+ }
+ }
+ }
+ }
+ UnlockList(f->HubList);
+ }
+ }
+ UnlockList(s->FarmMemberList);
+ }
+
+ return ERR_NO_ERROR;
+}
+
+// Get hub configuration
+UINT StGetHub(ADMIN *a, RPC_CREATE_HUB *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT ret = ERR_NO_ERROR;
+ HUB *h;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ if (IsEmptyStr(t->HubName) || IsSafeStr(t->HubName) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+ CHECK_RIGHT;
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ Zero(t, sizeof(RPC_CREATE_HUB));
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ Lock(h->lock);
+ {
+ StrCpy(t->HubName, sizeof(t->HubName), h->Name);
+ t->Online = h->Offline ? false : true;
+ t->HubOption.MaxSession = h->Option->MaxSession;
+ t->HubOption.NoEnum = h->Option->NoEnum;
+ t->HubType = h->Type;
+ }
+ Unlock(h->lock);
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Set hub configuration
+UINT StSetHub(ADMIN *a, RPC_CREATE_HUB *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ UINT ret = ERR_NO_ERROR;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ if (IsEmptyStr(t->HubName) || IsSafeStr(t->HubName) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+
+ CHECK_RIGHT;
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ if (s->ServerType == SERVER_TYPE_STANDALONE)
+ {
+ if (t->HubType != HUB_TYPE_STANDALONE)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ if (t->HubType == HUB_TYPE_STANDALONE)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+
+ LockHubList(c);
+ {
+ h = GetHub(c, t->HubName);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ if (h->Type != t->HubType)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_SUPPORTED;
+ }
+
+ if (IsZero(t->HashedPassword, sizeof(t->HashedPassword)) == false &&
+ IsZero(t->SecurePassword, sizeof(t->SecurePassword)) == false)
+ {
+ if (a->ServerAdmin == false && GetHubAdminOption(h, "no_change_admin_password") != 0)
+ {
+ ReleaseHub(h);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+ }
+
+ // Is the password to be set blank
+ {
+ UCHAR hash1[SHA1_SIZE], hash2[SHA1_SIZE];
+ HashPassword(hash1, ADMINISTRATOR_USERNAME, "");
+ Hash(hash2, "", 0, true);
+
+ if (Cmp(t->HashedPassword, hash2, SHA1_SIZE) == 0 || Cmp(t->SecurePassword, hash1, SHA1_SIZE) == 0)
+ {
+ if (a->ServerAdmin == false && a->Rpc->Sock->RemoteIP.addr[0] != 127)
+ {
+ // Refuse to set a blank password to hub admin from remote host
+ ReleaseHub(h);
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ Lock(h->lock);
+ {
+ if (a->ServerAdmin == false && h->Type != t->HubType)
+ {
+ ret = ERR_NOT_ENOUGH_RIGHT;
+ }
+ else
+ {
+ h->Type = t->HubType;
+ h->Option->MaxSession = t->HubOption.MaxSession;
+ h->Option->NoEnum = t->HubOption.NoEnum;
+ if (IsZero(t->HashedPassword, sizeof(t->HashedPassword)) == false &&
+ IsZero(t->SecurePassword, sizeof(t->SecurePassword)) == false)
+ {
+ Copy(h->HashedPassword, t->HashedPassword, SHA1_SIZE);
+ Copy(h->SecurePassword, t->SecurePassword, SHA1_SIZE);
+ }
+ }
+ }
+ Unlock(h->lock);
+
+ if (t->Online)
+ {
+ if (a->ServerAdmin || GetHubAdminOption(h, "no_online") == 0)
+ {
+ SetHubOnline(h);
+ }
+ }
+ else
+ {
+ if (a->ServerAdmin || GetHubAdminOption(h, "no_offline") == 0)
+ {
+ SetHubOffline(h);
+ }
+ }
+
+ if (h->Type == HUB_TYPE_FARM_STATIC)
+ {
+ EnableSecureNAT(h, false);
+ }
+
+ h->CurrentVersion++;
+ SiHubUpdateProc(h);
+
+ IncrementServerConfigRevision(s);
+
+ ALog(a, h, "LA_SET_HUB");
+
+ ReleaseHub(h);
+
+ return ret;
+}
+
+// Create a hub
+UINT StCreateHub(ADMIN *a, RPC_CREATE_HUB *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ HUB *h;
+ HUB_OPTION o;
+ UINT current_hub_num;
+ bool b;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+
+
+ if (IsEmptyStr(t->HubName) || IsSafeStr(t->HubName) == false)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ NO_SUPPORT_FOR_BRIDGE;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ SERVER_ADMIN_ONLY;
+
+ Trim(t->HubName);
+ if (StrLen(t->HubName) == 0)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ if (StartWith(t->HubName, ".") || EndWith(t->HubName, "."))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ if (s->ServerType == SERVER_TYPE_STANDALONE)
+ {
+ if (t->HubType != HUB_TYPE_STANDALONE)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+ else if (t->HubType != HUB_TYPE_FARM_DYNAMIC && t->HubType != HUB_TYPE_FARM_STATIC)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Create a hub object
+ Zero(&o, sizeof(o));
+ o.MaxSession = t->HubOption.MaxSession;
+ o.NoEnum = t->HubOption.NoEnum;
+
+ // Default setting for hub admin options
+ SiSetDefaultHubOption(&o);
+
+ LockList(c->HubList);
+ {
+ current_hub_num = LIST_NUM(c->HubList);
+ }
+ UnlockList(c->HubList);
+
+ if (current_hub_num > GetServerCapsInt(a->Server, "i_max_hubs"))
+ {
+ return ERR_TOO_MANY_HUBS;
+ }
+
+ LockList(c->HubList);
+ {
+ b = IsHub(c, t->HubName);
+ }
+ UnlockList(c->HubList);
+
+ if (b)
+ {
+ return ERR_HUB_ALREADY_EXISTS;
+ }
+
+ ALog(a, NULL, "LA_CREATE_HUB", t->HubName);
+
+ h = NewHub(c, t->HubName, &o);
+ Copy(h->HashedPassword, t->HashedPassword, SHA1_SIZE);
+ Copy(h->SecurePassword, t->SecurePassword, SHA1_SIZE);
+
+ h->Type = t->HubType;
+
+ AddHub(c, h);
+
+ if (t->Online)
+ {
+ h->Offline = true;
+ SetHubOnline(h);
+ }
+ else
+ {
+ h->Offline = false;
+ SetHubOffline(h);
+ }
+
+ h->CreatedTime = SystemTime64();
+
+ ReleaseHub(h);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Set cipher for SSL to the server
+UINT StSetServerCipher(ADMIN *a, RPC_STR *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+
+ if (IsEmptyStr(t->String))
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ SERVER_ADMIN_ONLY;
+
+ StrUpper(t->String);
+
+ if (CheckCipherListName(t->String) == false)
+ {
+ return ERR_CIPHER_NOT_SUPPORTED;
+ }
+ else
+ {
+ ALog(a, NULL, "LA_SET_SERVER_CIPHER", t->String);
+ }
+
+ Lock(c->lock);
+ {
+ SetCedarCipherList(c, t->String);
+ }
+ Unlock(c->lock);
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get cipher for SSL
+UINT StGetServerCipher(ADMIN *a, RPC_STR *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+
+ FreeRpcStr(t);
+ Zero(t, sizeof(RPC_STR));
+
+ Lock(c->lock);
+ {
+ t->String = CopyStr(c->CipherList);
+ }
+ Unlock(c->lock);
+
+ return ERR_NO_ERROR;
+}
+
+// Get the server certification
+UINT StGetServerCert(ADMIN *a, RPC_KEY_PAIR *t)
+{
+ bool admin;
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ bool is_vgs_cert = false;
+
+ admin = a->ServerAdmin;
+
+ FreeRpcKeyPair(t);
+ Zero(t, sizeof(RPC_KEY_PAIR));
+
+ Lock(c->lock);
+ {
+
+ t->Cert = CloneX(c->ServerX);
+ if (admin && is_vgs_cert == false)
+ {
+ t->Key = CloneK(c->ServerK);
+ }
+ }
+ Unlock(c->lock);
+
+ return ERR_NO_ERROR;
+}
+
+// Set the server certification
+UINT StSetServerCert(ADMIN *a, RPC_KEY_PAIR *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+
+ SERVER_ADMIN_ONLY;
+
+ if (t->Cert == NULL || t->Key == NULL)
+ {
+ return ERR_PROTOCOL_ERROR;
+ }
+
+ if (t->Cert->is_compatible_bit == false)
+ {
+ return ERR_NOT_RSA_1024;
+ }
+
+ if (CheckXandK(t->Cert, t->Key) == false)
+ {
+ return ERR_PROTOCOL_ERROR;
+ }
+
+ SetCedarCert(c, t->Cert, t->Key);
+
+ ALog(a, NULL, "LA_SET_SERVER_CERT");
+
+ IncrementServerConfigRevision(s);
+
+ return ERR_NO_ERROR;
+}
+
+// Get status of connection to cluster controller
+UINT StGetFarmConnectionStatus(ADMIN *a, RPC_FARM_CONNECTION_STATUS *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ FARM_CONTROLLER *fc;
+
+ if (s->ServerType != SERVER_TYPE_FARM_MEMBER)
+ {
+ return ERR_NOT_FARM_MEMBER;
+ }
+
+ Zero(t, sizeof(RPC_FARM_CONNECTION_STATUS));
+
+ fc = s->FarmController;
+
+ Lock(fc->lock);
+ {
+ if (fc->Sock != NULL)
+ {
+ t->Ip = IPToUINT(&fc->Sock->RemoteIP);
+ t->Port = fc->Sock->RemotePort;
+ }
+
+ t->Online = fc->Online;
+ t->LastError = ERR_NO_ERROR;
+
+ if (t->Online == false)
+ {
+ t->LastError = fc->LastError;
+ }
+ else
+ {
+ t->CurrentConnectedTime = fc->CurrentConnectedTime;
+ }
+
+ t->StartedTime = fc->StartedTime;
+ t->FirstConnectedTime = fc->FirstConnectedTime;
+
+ t->NumConnected = fc->NumConnected;
+ t->NumTry = fc->NumTry;
+ t->NumFailed = fc->NumFailed;
+ }
+ Unlock(fc->lock);
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate cluster members
+UINT StEnumFarmMember(ADMIN *a, RPC_ENUM_FARM *t)
+{
+ SERVER *s = a->Server;
+ CEDAR *c = s->Cedar;
+ UINT i;
+
+ FreeRpcEnumFarm(t);
+ Zero(t, sizeof(RPC_ENUM_FARM));
+
+ if (s->ServerType != SERVER_TYPE_FARM_CONTROLLER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_FARM));
+
+ LockList(s->FarmMemberList);
+ {
+ t->NumFarm = LIST_NUM(s->FarmMemberList);
+ t->Farms = ZeroMalloc(sizeof(RPC_ENUM_FARM_ITEM) * t->NumFarm);
+
+ for (i = 0;i < t->NumFarm;i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(s->FarmMemberList, i);
+ RPC_ENUM_FARM_ITEM *e = &t->Farms[i];
+
+ e->Id = POINTER_TO_KEY(f);
+ e->Controller = f->Me;
+
+ if (e->Controller)
+ {
+ e->ConnectedTime = TickToTime(c->CreatedTick);
+ e->Ip = 0x0100007f;
+ GetMachineName(e->Hostname, sizeof(e->Hostname));
+ e->Point = f->Point;
+ e->NumSessions = Count(c->CurrentSessions);
+ e->NumTcpConnections = Count(c->CurrentTcpConnections);
+
+ e->AssignedBridgeLicense = Count(c->AssignedBridgeLicense);
+ e->AssignedClientLicense = Count(c->AssignedClientLicense);
+ }
+ else
+ {
+ e->ConnectedTime = f->ConnectedTime;
+ e->Ip = f->Ip;
+ StrCpy(e->Hostname, sizeof(e->Hostname), f->hostname);
+ e->Point = f->Point;
+ e->NumSessions = f->NumSessions;
+ e->NumTcpConnections = f->NumTcpConnections;
+
+ e->AssignedBridgeLicense = f->AssignedBridgeLicense;
+ e->AssignedClientLicense = f->AssignedClientLicense;
+ }
+ e->NumHubs = LIST_NUM(f->HubList);
+ }
+ }
+ UnlockList(s->FarmMemberList);
+
+ return ERR_NO_ERROR;
+}
+
+// Get cluster member information
+UINT StGetFarmInfo(ADMIN *a, RPC_FARM_INFO *t)
+{
+ SERVER *s = a->Server;
+ UINT id = t->Id;
+ UINT i;
+ UINT ret = ERR_NO_ERROR;
+
+ FreeRpcFarmInfo(t);
+ Zero(t, sizeof(RPC_FARM_INFO));
+
+ if (s->ServerType != SERVER_TYPE_FARM_CONTROLLER)
+ {
+ return ERR_NOT_FARM_CONTROLLER;
+ }
+
+ LockList(s->FarmMemberList);
+ {
+ if (IsInListKey(s->FarmMemberList, id))
+ {
+ FARM_MEMBER *f = ListKeyToPointer(s->FarmMemberList, id);
+
+ t->Id = id;
+ t->Controller = f->Me;
+ t->Weight = f->Weight;
+
+ LockList(f->HubList);
+ {
+ t->NumFarmHub = LIST_NUM(f->HubList);
+ t->FarmHubs = ZeroMalloc(sizeof(RPC_FARM_HUB) * t->NumFarmHub);
+
+ for (i = 0;i < t->NumFarmHub;i++)
+ {
+ RPC_FARM_HUB *h = &t->FarmHubs[i];
+ HUB_LIST *hh = LIST_DATA(f->HubList, i);
+
+ h->DynamicHub = hh->DynamicHub;
+ StrCpy(h->HubName, sizeof(h->HubName), hh->Name);
+ }
+ }
+ UnlockList(f->HubList);
+
+ if (t->Controller)
+ {
+ t->ConnectedTime = TickToTime(s->Cedar->CreatedTick);
+ t->Ip = 0x0100007f;
+ GetMachineName(t->Hostname, sizeof(t->Hostname));
+ t->Point = f->Point;
+
+ LockList(s->ServerListenerList);
+ {
+ UINT i, n;
+ t->NumPort = 0;
+ for (i = 0;i < LIST_NUM(s->ServerListenerList);i++)
+ {
+ SERVER_LISTENER *o = LIST_DATA(s->ServerListenerList, i);
+ if (o->Enabled)
+ {
+ t->NumPort++;
+ }
+ }
+ t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+ n = 0;
+ for (i = 0;i < LIST_NUM(s->ServerListenerList);i++)
+ {
+ SERVER_LISTENER *o = LIST_DATA(s->ServerListenerList, i);
+ if (o->Enabled)
+ {
+ t->Ports[n++] = o->Port;
+ }
+ }
+ }
+ UnlockList(s->ServerListenerList);
+
+ t->ServerCert = CloneX(s->Cedar->ServerX);
+ t->NumSessions = Count(s->Cedar->CurrentSessions);
+ t->NumTcpConnections = Count(s->Cedar->CurrentTcpConnections);
+ }
+ else
+ {
+ t->ConnectedTime = f->ConnectedTime;
+ t->Ip = f->Ip;
+ StrCpy(t->Hostname, sizeof(t->Hostname), f->hostname);
+ t->Point = f->Point;
+ t->NumPort = f->NumPort;
+ t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+ Copy(t->Ports, f->Ports, sizeof(UINT) * t->NumPort);
+ t->ServerCert = CloneX(f->ServerCert);
+ t->NumSessions = f->NumSessions;
+ t->NumTcpConnections = f->NumTcpConnections;
+ }
+ }
+ else
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ }
+ }
+ UnlockList(s->FarmMemberList);
+
+ return ret;
+}
+
+// Get clustering configuration
+UINT StGetFarmSetting(ADMIN *a, RPC_FARM *t)
+{
+ SERVER *s;
+ FreeRpcFarm(t);
+ Zero(t, sizeof(RPC_FARM));
+
+ s = a->Server;
+ t->ServerType = s->ServerType;
+ t->ControllerOnly = s->ControllerOnly;
+ t->Weight = s->Weight;
+
+ if (t->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ t->NumPort = s->NumPublicPort;
+ t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+ Copy(t->Ports, s->PublicPorts, sizeof(UINT) * t->NumPort);
+ t->PublicIp = s->PublicIp;
+ StrCpy(t->ControllerName, sizeof(t->ControllerName), s->ControllerName);
+ t->ControllerPort = s->ControllerPort;
+ }
+ else
+ {
+ t->NumPort = 0;
+ t->Ports = ZeroMalloc(0);
+ }
+
+ return ERR_NO_ERROR;
+}
+
+// Set clustering configuration
+UINT StSetFarmSetting(ADMIN *a, RPC_FARM *t)
+{
+ bool cluster_allowed = false;
+
+ SERVER_ADMIN_ONLY;
+ NO_SUPPORT_FOR_BRIDGE;
+
+
+ cluster_allowed = GetServerCapsInt(a->Server, "b_support_cluster");
+
+ if (t->ServerType != SERVER_TYPE_STANDALONE && cluster_allowed == false)
+ {
+ // When clustering function is disabled, deny turning into clustering mode
+ return ERR_NOT_SUPPORTED;
+ }
+
+ ALog(a, NULL, "LA_SET_FARM_SETTING");
+
+ IncrementServerConfigRevision(a->Server);
+
+ SiSetServerType(a->Server, t->ServerType, t->PublicIp, t->NumPort, t->Ports,
+ t->ControllerName, t->ControllerPort, t->MemberPassword, t->Weight, t->ControllerOnly);
+
+ return ERR_NO_ERROR;
+}
+
+// Set server password
+UINT StSetServerPassword(ADMIN *a, RPC_SET_PASSWORD *t)
+{
+ SERVER_ADMIN_ONLY;
+
+
+ Copy(a->Server->HashedPassword, t->HashedPassword, SHA1_SIZE);
+
+ ALog(a, NULL, "LA_SET_SERVER_PASSWORD");
+
+ IncrementServerConfigRevision(a->Server);
+
+ return ERR_NO_ERROR;
+}
+
+// Enable / Disable listener
+UINT StEnableListener(ADMIN *a, RPC_LISTENER *t)
+{
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+
+
+ LockList(a->Server->ServerListenerList);
+ {
+ if (t->Enable)
+ {
+ if (SiEnableListener(a->Server, t->Port) == false)
+ {
+ ret = ERR_LISTENER_NOT_FOUND;
+ }
+ else
+ {
+ ALog(a, NULL, "LA_ENABLE_LISTENER", t->Port);
+ }
+ }
+ else
+ {
+ if (SiDisableListener(a->Server, t->Port) == false)
+ {
+ ret = ERR_LISTENER_NOT_FOUND;
+ }
+ else
+ {
+ ALog(a, NULL, "LA_DISABLE_LISTENER", t->Port);
+ }
+ }
+ }
+ UnlockList(a->Server->ServerListenerList);
+
+ IncrementServerConfigRevision(a->Server);
+
+ SleepThread(250);
+
+ return ret;
+}
+
+// Delete a listener
+UINT StDeleteListener(ADMIN *a, RPC_LISTENER *t)
+{
+ UINT ret = ERR_NO_ERROR;
+
+ SERVER_ADMIN_ONLY;
+
+
+ LockList(a->Server->ServerListenerList);
+ {
+ if (SiDeleteListener(a->Server, t->Port) == false)
+ {
+ ret = ERR_LISTENER_NOT_FOUND;
+ }
+ else
+ {
+ ALog(a, NULL, "LA_DELETE_LISTENER", t->Port);
+
+ IncrementServerConfigRevision(a->Server);
+ }
+ }
+ UnlockList(a->Server->ServerListenerList);
+
+ return ret;
+}
+
+// Enumerating listeners
+UINT StEnumListener(ADMIN *a, RPC_LISTENER_LIST *t)
+{
+ CEDAR *c = a->Server->Cedar;
+ UINT i;
+
+ FreeRpcListenerList(t);
+ Zero(t, sizeof(RPC_LISTENER_LIST));
+
+ LockList(a->Server->ServerListenerList);
+ {
+ t->NumPort = LIST_NUM(a->Server->ServerListenerList);
+ t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+ t->Enables = ZeroMalloc(sizeof(bool) * t->NumPort);
+ t->Errors = ZeroMalloc(sizeof(bool) * t->NumPort);
+
+ for (i = 0;i < t->NumPort;i++)
+ {
+ SERVER_LISTENER *o = LIST_DATA(a->Server->ServerListenerList, i);
+
+ t->Ports[i] = o->Port;
+ t->Enables[i] = o->Enabled;
+ if (t->Enables[i])
+ {
+ if (o->Listener->Status == LISTENER_STATUS_TRYING)
+ {
+ t->Errors[i] = true;
+ }
+ }
+ }
+ }
+ UnlockList(a->Server->ServerListenerList);
+
+ return ERR_NO_ERROR;
+}
+
+// Create a listener
+UINT StCreateListener(ADMIN *a, RPC_LISTENER *t)
+{
+ UINT ret = ERR_NO_ERROR;
+ CEDAR *c = a->Server->Cedar;
+
+ if (t->Port == 0 || t->Port > 65535)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ SERVER_ADMIN_ONLY;
+
+ LockList(a->Server->ServerListenerList);
+ {
+ if (SiAddListener(a->Server, t->Port, t->Enable) == false)
+ {
+ ret = ERR_LISTENER_ALREADY_EXISTS;
+ }
+ else
+ {
+ ALog(a, NULL, "LA_CREATE_LISTENER", t->Port);
+
+ IncrementServerConfigRevision(a->Server);
+ }
+ }
+ UnlockList(a->Server->ServerListenerList);
+
+ SleepThread(250);
+
+ return ret;
+}
+
+// Get server status
+UINT StGetServerStatus(ADMIN *a, RPC_SERVER_STATUS *t)
+{
+ CEDAR *c;
+ UINT i;
+
+ c = a->Server->Cedar;
+
+ Zero(t, sizeof(RPC_SERVER_STATUS));
+
+ Lock(c->TrafficLock);
+ {
+ Copy(&t->Traffic, c->Traffic, sizeof(TRAFFIC));
+ }
+ Unlock(c->TrafficLock);
+
+ GetMemInfo(&t->MemInfo);
+
+ t->ServerType = a->Server->ServerType;
+ t->NumTcpConnections = t->NumTcpConnectionsLocal = t->NumTcpConnectionsRemote = 0;
+ t->NumSessionsTotal = t->NumSessionsLocal = t->NumSessionsRemote = 0;
+
+ t->NumTcpConnectionsLocal = Count(c->CurrentTcpConnections);
+
+ if (a->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ LockList(a->Server->FarmMemberList);
+ {
+ for (i = 0;i < LIST_NUM(a->Server->FarmMemberList);i++)
+ {
+ FARM_MEMBER *f = LIST_DATA(a->Server->FarmMemberList, i);
+
+ if (f->Me == false)
+ {
+ t->NumTcpConnectionsRemote += f->NumTcpConnections;
+ t->NumSessionsRemote += f->NumSessions;
+ AddTraffic(&t->Traffic, &f->Traffic);
+ }
+ }
+ }
+ UnlockList(a->Server->FarmMemberList);
+ }
+
+ t->NumMacTables = t->NumIpTables = t->NumUsers = t->NumGroups = 0;
+
+ // The number of hubs
+ LockList(c->HubList);
+ {
+ t->NumHubTotal = LIST_NUM(c->HubList);
+
+ t->NumHubStandalone = t->NumHubDynamic = t->NumHubStatic = 0;
+
+ for (i = 0;i < LIST_NUM(c->HubList);i++)
+ {
+ HUB *h = LIST_DATA(c->HubList, i);
+ Lock(h->lock);
+ {
+ switch (h->Type)
+ {
+ case HUB_TYPE_STANDALONE:
+ t->NumHubStandalone++;
+ break;
+
+ case HUB_TYPE_FARM_STATIC:
+ t->NumHubStatic++;
+ break;
+
+ case HUB_TYPE_FARM_DYNAMIC:
+ t->NumHubDynamic++;
+ break;
+ }
+ }
+
+ t->NumMacTables += LIST_NUM(h->MacTable);
+ t->NumIpTables += LIST_NUM(h->IpTable);
+
+ if (h->HubDb != NULL)
+ {
+ t->NumUsers += LIST_NUM(h->HubDb->UserList);
+ t->NumGroups += LIST_NUM(h->HubDb->GroupList);
+ }
+
+ Unlock(h->lock);
+ }
+ }
+ UnlockList(c->HubList);
+
+ // The number of sessions
+ t->NumSessionsLocal = Count(c->CurrentSessions);
+ t->NumSessionsTotal = t->NumSessionsLocal + t->NumSessionsRemote;
+ t->NumTcpConnections = t->NumTcpConnectionsLocal + t->NumTcpConnectionsRemote;
+
+ t->AssignedBridgeLicenses = Count(c->AssignedBridgeLicense);
+ t->AssignedClientLicenses = Count(c->AssignedClientLicense);
+
+ t->AssignedBridgeLicensesTotal = a->Server->CurrentAssignedBridgeLicense;
+ t->AssignedClientLicensesTotal = a->Server->CurrentAssignedClientLicense;
+
+ t->CurrentTick = Tick64();
+ t->CurrentTime = SystemTime64();
+
+ t->StartTime = a->Server->StartTime;
+
+ return ERR_NO_ERROR;
+}
+
+// Get server information
+UINT StGetServerInfo(ADMIN *a, RPC_SERVER_INFO *t)
+{
+ CEDAR *c;
+ OS_INFO *info;
+ SYSTEMTIME st;
+ // Validate arguments
+ if (a == NULL || t == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ FreeRpcServerInfo(t);
+ Zero(t, sizeof(RPC_SERVER_INFO));
+
+ c = a->Server->Cedar;
+
+ GetServerProductName(a->Server, t->ServerProductName, sizeof(t->ServerProductName));
+
+ StrCpy(t->ServerVersionString, sizeof(t->ServerVersionString), c->VerString);
+ StrCpy(t->ServerBuildInfoString, sizeof(t->ServerBuildInfoString), c->BuildInfo);
+ t->ServerVerInt = c->Version;
+ t->ServerBuildInt = c->Build;
+ GetMachineName(t->ServerHostName, sizeof(t->ServerHostName));
+ t->ServerType = c->Server->ServerType;
+
+ Zero(&st, sizeof(st));
+ st.wYear = BUILD_DATE_Y;
+ st.wMonth = BUILD_DATE_M;
+ st.wDay = BUILD_DATE_D;
+ st.wHour = BUILD_DATE_HO;
+ st.wMinute = BUILD_DATE_MI;
+ st.wSecond = BUILD_DATE_SE;
+
+ t->ServerBuildDate = SystemToUINT64(&st);
+ StrCpy(t->ServerFamilyName, sizeof(t->ServerFamilyName), UPDATE_FAMILY_NAME);
+
+ info = GetOsInfo();
+ if (info != NULL)
+ {
+ CopyOsInfo(&t->OsInfo, info);
+ }
+
+ return ERR_NO_ERROR;
+}
+
+// Copy OS_INFO
+void CopyOsInfo(OS_INFO *dst, OS_INFO *info)
+{
+ // Validate arguments
+ if (info == NULL || dst == NULL)
+ {
+ return;
+ }
+
+ dst->OsType = info->OsType;
+ dst->OsServicePack = info->OsServicePack;
+ dst->OsSystemName = CopyStr(info->OsSystemName);
+ dst->OsProductName = CopyStr(info->OsProductName);
+ dst->OsVendorName = CopyStr(info->OsVendorName);
+ dst->OsVersion = CopyStr(info->OsVersion);
+ dst->KernelName = CopyStr(info->KernelName);
+ dst->KernelVersion = CopyStr(info->KernelVersion);
+}
+
+// OPENVPN_SSTP_CONFIG
+void InOpenVpnSstpConfig(OPENVPN_SSTP_CONFIG *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(OPENVPN_SSTP_CONFIG));
+
+ t->EnableOpenVPN = PackGetBool(p, "EnableOpenVPN");
+ t->EnableSSTP = PackGetBool(p, "EnableSSTP");
+ PackGetStr(p, "OpenVPNPortList", t->OpenVPNPortList, sizeof(t->OpenVPNPortList));
+}
+void OutOpenVpnSstpConfig(PACK *p, OPENVPN_SSTP_CONFIG *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "EnableOpenVPN", t->EnableOpenVPN);
+ PackAddBool(p, "EnableSSTP", t->EnableSSTP);
+ PackAddStr(p, "OpenVPNPortList", t->OpenVPNPortList);
+}
+
+// DDNS_CLIENT_STATUS
+void InDDnsClientStatus(DDNS_CLIENT_STATUS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(DDNS_CLIENT_STATUS));
+
+ t->Err_IPv4 = PackGetInt(p, "Err_IPv4");
+ t->Err_IPv6 = PackGetInt(p, "Err_IPv6");
+
+ PackGetStr(p, "CurrentHostName", t->CurrentHostName, sizeof(t->CurrentHostName));
+ PackGetStr(p, "CurrentFqdn", t->CurrentFqdn, sizeof(t->CurrentFqdn));
+ PackGetStr(p, "DnsSuffix", t->DnsSuffix, sizeof(t->DnsSuffix));
+ PackGetStr(p, "CurrentIPv4", t->CurrentIPv4, sizeof(t->CurrentIPv4));
+ PackGetStr(p, "CurrentIPv6", t->CurrentIPv6, sizeof(t->CurrentIPv6));
+}
+void OutDDnsClientStatus(PACK *p, DDNS_CLIENT_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "Err_IPv4", t->Err_IPv4);
+ PackAddInt(p, "Err_IPv6", t->Err_IPv6);
+ PackAddStr(p, "CurrentHostName", t->CurrentHostName);
+ PackAddStr(p, "CurrentFqdn", t->CurrentFqdn);
+ PackAddStr(p, "DnsSuffix", t->DnsSuffix);
+ PackAddStr(p, "CurrentIPv4", t->CurrentIPv4);
+ PackAddStr(p, "CurrentIPv6", t->CurrentIPv6);
+}
+
+// INTERNET_SETTING
+void InRpcInternetSetting(INTERNET_SETTING *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ t->ProxyType = PackGetInt(p, "ProxyType");
+ PackGetStr(p, "ProxyHostName", t->ProxyHostName, sizeof(t->ProxyHostName));
+ t->ProxyPort = PackGetInt(p, "ProxyPort");
+ PackGetStr(p, "ProxyUsername", t->ProxyUsername, sizeof(t->ProxyUsername));
+ PackGetStr(p, "ProxyPassword", t->ProxyPassword, sizeof(t->ProxyPassword));
+}
+void OutRpcInternetSetting(PACK *p, INTERNET_SETTING *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "ProxyType", t->ProxyType);
+ PackAddStr(p, "ProxyHostName", t->ProxyHostName);
+ PackAddInt(p, "ProxyPort", t->ProxyPort);
+ PackAddStr(p, "ProxyUsername", t->ProxyUsername);
+ PackAddStr(p, "ProxyPassword", t->ProxyPassword);
+}
+
+// RPC_AZURE_STATUS
+void InRpcAzureStatus(RPC_AZURE_STATUS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_AZURE_STATUS));
+
+ t->IsConnected = PackGetBool(p, "IsConnected");
+ t->IsEnabled = PackGetBool(p, "IsEnabled");
+}
+void OutRpcAzureStatus(PACK *p, RPC_AZURE_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "IsConnected", t->IsConnected);
+ PackAddBool(p, "IsEnabled", t->IsEnabled);
+}
+
+// RPC_SPECIAL_LISTENER
+void InRpcSpecialListener(RPC_SPECIAL_LISTENER *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_SPECIAL_LISTENER));
+
+ t->VpnOverIcmpListener = PackGetBool(p, "VpnOverIcmpListener");
+ t->VpnOverDnsListener = PackGetBool(p, "VpnOverDnsListener");
+}
+void OutRpcSpecialListener(PACK *p, RPC_SPECIAL_LISTENER *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "VpnOverIcmpListener", t->VpnOverIcmpListener);
+ PackAddBool(p, "VpnOverDnsListener", t->VpnOverDnsListener);
+}
+
+
+// ETHERIP_ID
+void InEtherIpId(ETHERIP_ID *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(ETHERIP_ID));
+
+ PackGetStr(p, "Id", t->Id, sizeof(t->Id));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetStr(p, "UserName", t->UserName, sizeof(t->UserName));
+ PackGetStr(p, "Password", t->Password, sizeof(t->Password));
+}
+void OutEtherIpId(PACK *p, ETHERIP_ID *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "Id", t->Id);
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddStr(p, "UserName", t->UserName);
+ PackAddStr(p, "Password", t->Password);
+}
+
+// RPC_ENUM_ETHERIP_ID
+void InRpcEnumEtherIpId(RPC_ENUM_ETHERIP_ID *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_ETHERIP_ID));
+
+ t->NumItem = PackGetInt(p, "NumItem");
+ t->IdList = ZeroMalloc(sizeof(ETHERIP_ID) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ ETHERIP_ID *e = &t->IdList[i];
+
+ PackGetStrEx(p, "Id", e->Id, sizeof(e->Id), i);
+ PackGetStrEx(p, "HubName", e->HubName, sizeof(e->HubName), i);
+ PackGetStrEx(p, "UserName", e->UserName, sizeof(e->UserName), i);
+ PackGetStrEx(p, "Password", e->Password, sizeof(e->Password), i);
+ }
+}
+void OutRpcEnumEtherIpId(PACK *p, RPC_ENUM_ETHERIP_ID *t)
+{
+ UINT i;
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ ETHERIP_ID *e = &t->IdList[i];
+
+ PackAddStrEx(p, "Id", e->Id, i, t->NumItem);
+ PackAddStrEx(p, "HubName", e->HubName, i, t->NumItem);
+ PackAddStrEx(p, "UserName", e->UserName, i, t->NumItem);
+ PackAddStrEx(p, "Password", e->Password, i, t->NumItem);
+ }
+}
+void FreeRpcEnumEtherIpId(RPC_ENUM_ETHERIP_ID *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->IdList);
+}
+
+// IPSEC_SERVICES
+void InIPsecServices(IPSEC_SERVICES *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(IPSEC_SERVICES));
+
+ t->L2TP_Raw = PackGetBool(p, "L2TP_Raw");
+ t->L2TP_IPsec = PackGetBool(p, "L2TP_IPsec");
+ t->EtherIP_IPsec = PackGetBool(p, "EtherIP_IPsec");
+
+ PackGetStr(p, "IPsec_Secret", t->IPsec_Secret, sizeof(t->IPsec_Secret));
+ PackGetStr(p, "L2TP_DefaultHub", t->L2TP_DefaultHub, sizeof(t->L2TP_DefaultHub));
+}
+void OutIPsecServices(PACK *p, IPSEC_SERVICES *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "L2TP_Raw", t->L2TP_Raw);
+ PackAddBool(p, "L2TP_IPsec", t->L2TP_IPsec);
+ PackAddBool(p, "EtherIP_IPsec", t->EtherIP_IPsec);
+
+ PackAddStr(p, "IPsec_Secret", t->IPsec_Secret);
+ PackAddStr(p, "L2TP_DefaultHub", t->L2TP_DefaultHub);
+}
+
+// RPC_WINVER
+void InRpcWinVer(RPC_WINVER *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_WINVER));
+
+ t->IsWindows = PackGetBool(p, "V_IsWindows");
+ t->IsNT = PackGetBool(p, "V_IsNT");
+ t->IsServer = PackGetBool(p, "V_IsServer");
+ t->IsBeta = PackGetBool(p, "V_IsBeta");
+ t->VerMajor = PackGetInt(p, "V_VerMajor");
+ t->VerMinor = PackGetInt(p, "V_VerMinor");
+ t->Build = PackGetInt(p, "V_Build");
+ t->ServicePack = PackGetInt(p, "V_ServicePack");
+ PackGetStr(p, "V_Title", t->Title, sizeof(t->Title));
+}
+void OutRpcWinVer(PACK *p, RPC_WINVER *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "V_IsWindows", t->IsWindows);
+ PackAddBool(p, "V_IsNT", t->IsNT);
+ PackAddBool(p, "V_IsServer", t->IsServer);
+ PackAddBool(p, "V_IsBeta", t->IsBeta);
+ PackAddInt(p, "V_VerMajor", t->VerMajor);
+ PackAddInt(p, "V_VerMinor", t->VerMinor);
+ PackAddInt(p, "V_Build", t->Build);
+ PackAddInt(p, "V_ServicePack", t->ServicePack);
+ PackAddStr(p, "V_Title", t->Title);
+}
+
+// RPC_MSG
+void InRpcMsg(RPC_MSG *t, PACK *p)
+{
+ UINT size;
+ char *utf8;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_MSG));
+
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ size = PackGetDataSize(p, "Msg");
+ utf8 = ZeroMalloc(size + 8);
+ PackGetData(p, "Msg", utf8);
+ t->Msg = CopyUtfToUni(utf8);
+ Free(utf8);
+}
+void OutRpcMsg(PACK *p, RPC_MSG *t)
+{
+ UINT size;
+ char *utf8;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ utf8 = CopyUniToUtf(t->Msg);
+ size = StrLen(utf8);
+ PackAddData(p, "Msg", utf8, size);
+ Free(utf8);
+}
+void FreeRpcMsg(RPC_MSG *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Msg);
+}
+
+// RPC_ENUM_ETH_VLAN
+void InRpcEnumEthVLan(RPC_ENUM_ETH_VLAN *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_ETH_VLAN));
+
+ t->NumItem = PackGetIndexCount(p, "DeviceName");
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_ETH_VLAN_ITEM) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_ETH_VLAN_ITEM *e = &t->Items[i];
+
+ PackGetStrEx(p, "DeviceName", e->DeviceName, sizeof(e->DeviceName), i);
+ PackGetStrEx(p, "Guid", e->Guid, sizeof(e->Guid), i);
+ PackGetStrEx(p, "DeviceInstanceId", e->DeviceInstanceId, sizeof(e->DeviceInstanceId), i);
+ PackGetStrEx(p, "DriverName", e->DriverName, sizeof(e->DriverName), i);
+ PackGetStrEx(p, "DriverType", e->DriverType, sizeof(e->DriverType), i);
+ e->Support = PackGetBoolEx(p, "Support", i);
+ e->Enabled = PackGetBoolEx(p, "Enabled", i);
+ }
+}
+void OutRpcEnumEthVLan(PACK *p, RPC_ENUM_ETH_VLAN *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_ETH_VLAN_ITEM *e = &t->Items[i];
+
+ PackAddStrEx(p, "DeviceName", e->DeviceName, i, t->NumItem);
+ PackAddStrEx(p, "Guid", e->Guid, i, t->NumItem);
+ PackAddStrEx(p, "DeviceInstanceId", e->DeviceInstanceId, i, t->NumItem);
+ PackAddStrEx(p, "DriverName", e->DriverName, i, t->NumItem);
+ PackAddStrEx(p, "DriverType", e->DriverType, i, t->NumItem);
+ PackAddBoolEx(p, "Support", e->Support, i, t->NumItem);
+ PackAddBoolEx(p, "Enabled", e->Enabled, i, t->NumItem);
+ }
+}
+void FreeRpcEnumEthVLan(RPC_ENUM_ETH_VLAN *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_ENUM_LOG_FILE
+void InRpcEnumLogFile(RPC_ENUM_LOG_FILE *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_LOG_FILE));
+ t->NumItem = PackGetInt(p, "NumItem");
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_LOG_FILE_ITEM) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_LOG_FILE_ITEM *e = &t->Items[i];
+
+ PackGetStrEx(p, "FilePath", e->FilePath, sizeof(e->FilePath), i);
+ PackGetStrEx(p, "ServerName", e->ServerName, sizeof(e->ServerName), i);
+ e->FileSize = PackGetIntEx(p, "FileSize", i);
+ e->UpdatedTime = PackGetInt64Ex(p, "UpdatedTime", i);
+ }
+}
+void OutRpcEnumLogFile(PACK *p, RPC_ENUM_LOG_FILE *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_LOG_FILE_ITEM *e = &t->Items[i];
+
+ PackAddStrEx(p, "FilePath", e->FilePath, i, t->NumItem);
+ PackAddStrEx(p, "ServerName", e->ServerName, i, t->NumItem);
+ PackAddIntEx(p, "FileSize", e->FileSize, i, t->NumItem);
+ PackAddInt64Ex(p, "UpdatedTime", e->UpdatedTime, i, t->NumItem);
+ }
+}
+void FreeRpcEnumLogFile(RPC_ENUM_LOG_FILE *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+void AdjoinRpcEnumLogFile(RPC_ENUM_LOG_FILE *t, RPC_ENUM_LOG_FILE *src)
+{
+ LIST *o;
+ UINT i;
+ // Validate arguments
+ if (t == NULL || src == NULL)
+ {
+ return;
+ }
+
+ o = NewListFast(CmpLogFile);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_LOG_FILE_ITEM *e = &t->Items[i];
+ LOG_FILE *f = ZeroMalloc(sizeof(LOG_FILE));
+
+ f->FileSize = e->FileSize;
+ StrCpy(f->Path, sizeof(f->Path), e->FilePath);
+ StrCpy(f->ServerName, sizeof(f->ServerName), e->ServerName);
+ f->UpdatedTime = e->UpdatedTime;
+
+ Add(o, f);
+ }
+
+ for (i = 0;i < src->NumItem;i++)
+ {
+ RPC_ENUM_LOG_FILE_ITEM *e = &src->Items[i];
+ LOG_FILE *f = ZeroMalloc(sizeof(LOG_FILE));
+
+ f->FileSize = e->FileSize;
+ StrCpy(f->Path, sizeof(f->Path), e->FilePath);
+ StrCpy(f->ServerName, sizeof(f->ServerName), e->ServerName);
+ f->UpdatedTime = e->UpdatedTime;
+
+ Add(o, f);
+ }
+
+ FreeRpcEnumLogFile(t);
+
+ Sort(o);
+
+ Zero(t, sizeof(RPC_ENUM_LOG_FILE));
+ t->NumItem = LIST_NUM(o);
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_LOG_FILE_ITEM) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ LOG_FILE *f = LIST_DATA(o, i);
+ RPC_ENUM_LOG_FILE_ITEM *e = &t->Items[i];
+
+ StrCpy(e->FilePath, sizeof(e->FilePath), f->Path);
+ StrCpy(e->ServerName, sizeof(e->ServerName), f->ServerName);
+ e->FileSize = f->FileSize;
+ e->UpdatedTime = f->UpdatedTime;
+ }
+
+ FreeEnumLogFile(o);
+}
+
+// RPC_READ_LOG_FILE
+void InRpcReadLogFile(RPC_READ_LOG_FILE *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_READ_LOG_FILE));
+ PackGetStr(p, "FilePath", t->FilePath, sizeof(t->FilePath));
+ PackGetStr(p, "ServerName", t->ServerName, sizeof(t->ServerName));
+ t->Offset = PackGetInt(p, "Offset");
+
+ t->Buffer = PackGetBuf(p, "Buffer");
+}
+void OutRpcReadLogFile(PACK *p, RPC_READ_LOG_FILE *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "FilePath", t->FilePath);
+ PackAddStr(p, "ServerName", t->ServerName);
+ PackAddInt(p, "Offset", t->Offset);
+
+ if (t->Buffer != NULL)
+ {
+ PackAddBuf(p, "Buffer", t->Buffer);
+ }
+}
+void FreeRpcReadLogFile(RPC_READ_LOG_FILE *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->Buffer != NULL)
+ {
+ FreeBuf(t->Buffer);
+ }
+}
+
+// RPC_AC_LIST
+void InRpcAcList(RPC_AC_LIST *t, PACK *p)
+{
+ UINT i;
+ LIST *o;
+ UINT num;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_AC_LIST));
+ o = NewAcList();
+
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ num = PackGetInt(p, "NumItem");
+
+ for (i = 0;i < num;i++)
+ {
+ AC *ac = ZeroMalloc(sizeof(AC));
+
+ ac->Deny = PackGetBoolEx(p, "Deny", i);
+ PackGetIpEx(p, "IpAddress", &ac->IpAddress, i);
+ ac->Masked = PackGetBoolEx(p, "Masked", i);
+
+ if (ac->Masked)
+ {
+ PackGetIpEx(p, "SubnetMask", &ac->SubnetMask, i);
+ }
+
+ ac->Priority = PackGetIntEx(p, "Priority", i);
+
+ AddAc(o, ac);
+
+ Free(ac);
+ }
+
+ t->o = o;
+}
+void OutRpcAcList(PACK *p, RPC_AC_LIST *t)
+{
+ UINT i, num;
+ LIST *o;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ o = t->o;
+ num = LIST_NUM(o);
+
+ PackAddInt(p, "NumItem", num);
+
+ PackAddStr(p, "HubName", t->HubName);
+
+ for (i = 0;i < num;i++)
+ {
+ AC *ac = LIST_DATA(o, i);
+
+ PackAddBoolEx(p, "Deny", ac->Deny, i, num);
+ PackAddIpEx(p, "IpAddress", &ac->IpAddress, i, num);
+ PackAddBoolEx(p, "Masked", ac->Masked, i, num);
+
+ PackAddIpEx(p, "SubnetMask", &ac->SubnetMask, i, num);
+
+ PackAddIntEx(p, "Priority", ac->Priority, i, num);
+ }
+}
+void FreeRpcAcList(RPC_AC_LIST *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FreeAcList(t->o);
+}
+
+// RPC_INT
+void InRpcInt(RPC_INT *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_INT));
+ t->IntValue = PackGetInt(p, "IntValue");
+}
+void OutRpcInt(PACK *p, RPC_INT *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "IntValue", t->IntValue);
+}
+
+// RPC_ENUM_CRL
+void InRpcEnumCrl(RPC_ENUM_CRL *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_CRL));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->NumItem = PackGetInt(p, "NumItem");
+
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_CRL_ITEM) * t->NumItem);
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_CRL_ITEM *e = &t->Items[i];
+
+ e->Key = PackGetIntEx(p, "Key", i);
+ PackGetUniStrEx(p, "CrlInfo", e->CrlInfo, sizeof(e->CrlInfo), i);
+ }
+}
+void OutRpcEnumCrl(PACK *p, RPC_ENUM_CRL *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddInt(p, "NumItem", t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_CRL_ITEM *e = &t->Items[i];
+
+ PackAddIntEx(p, "Key", e->Key, i, t->NumItem);
+ PackAddUniStrEx(p, "CrlInfo", e->CrlInfo, i, t->NumItem);
+ }
+}
+void FreeRpcEnumCrl(RPC_ENUM_CRL *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_CRL
+void InRpcCrl(RPC_CRL *t, PACK *p)
+{
+ BUF *b;
+ NAME *n;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_CRL));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->Key = PackGetInt(p, "Key");
+ b = PackGetBuf(p, "Serial");
+ t->Crl = ZeroMalloc(sizeof(CRL));
+ if (b != NULL)
+ {
+ t->Crl->Serial = NewXSerial(b->Buf, b->Size);
+ FreeBuf(b);
+ }
+ t->Crl->Name = ZeroMalloc(sizeof(NAME));
+ n = t->Crl->Name;
+ if (PackGetUniStr(p, "CommonName", tmp, sizeof(tmp)))
+ {
+ n->CommonName = CopyUniStr(tmp);
+ }
+ if (PackGetUniStr(p, "Organization", tmp, sizeof(tmp)))
+ {
+ n->Organization = CopyUniStr(tmp);
+ }
+ if (PackGetUniStr(p, "Unit", tmp, sizeof(tmp)))
+ {
+ n->Unit = CopyUniStr(tmp);
+ }
+ if (PackGetUniStr(p, "Country", tmp, sizeof(tmp)))
+ {
+ n->Country = CopyUniStr(tmp);
+ }
+ if (PackGetUniStr(p, "State", tmp, sizeof(tmp)))
+ {
+ n->State = CopyUniStr(tmp);
+ }
+ if (PackGetUniStr(p, "Local", tmp, sizeof(tmp)))
+ {
+ n->Local = CopyUniStr(tmp);
+ }
+ if (PackGetDataSize(p, "DigestMD5") == MD5_SIZE)
+ {
+ PackGetData(p, "DigestMD5", t->Crl->DigestMD5);
+ }
+ if (PackGetDataSize(p, "DigestSHA1") == SHA1_SIZE)
+ {
+ PackGetData(p, "DigestSHA1", t->Crl->DigestSHA1);
+ }
+}
+void OutRpcCrl(PACK *p, RPC_CRL *t)
+{
+ NAME *n;
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddInt(p, "Key", t->Key);
+
+ if (t->Crl == NULL)
+ {
+ return;
+ }
+
+ if (t->Crl->Serial != NULL)
+ {
+ PackAddData(p, "Serial", t->Crl->Serial->data, t->Crl->Serial->size);
+ }
+ n = t->Crl->Name;
+ if (n->CommonName != NULL)
+ {
+ PackAddUniStr(p, "CommonName", n->CommonName);
+ }
+ if (n->Organization != NULL)
+ {
+ PackAddUniStr(p, "Organization", n->Organization);
+ }
+ if (n->Unit != NULL)
+ {
+ PackAddUniStr(p, "Unit", n->Unit);
+ }
+ if (n->Country != NULL)
+ {
+ PackAddUniStr(p, "Country", n->Country);
+ }
+ if (n->State != NULL)
+ {
+ PackAddUniStr(p, "State", n->State);
+ }
+ if (n->Local != NULL)
+ {
+ PackAddUniStr(p, "Local", n->Local);
+ }
+ if (IsZero(t->Crl->DigestMD5, MD5_SIZE) == false)
+ {
+ PackAddData(p, "DigestMD5", t->Crl->DigestMD5, MD5_SIZE);
+ }
+ if (IsZero(t->Crl->DigestSHA1, SHA1_SIZE) == false)
+ {
+ PackAddData(p, "DigestSHA1", t->Crl->DigestSHA1, SHA1_SIZE);
+ }
+}
+void FreeRpcCrl(RPC_CRL *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FreeCrl(t->Crl);
+}
+
+// RPC_ENUM_L3TABLE
+void InRpcEnumL3Table(RPC_ENUM_L3TABLE *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_L3TABLE));
+ t->NumItem = PackGetInt(p, "NumItem");
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+ t->Items = ZeroMalloc(sizeof(RPC_L3TABLE) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_L3TABLE *e = &t->Items[i];
+
+ e->NetworkAddress = PackGetIp32Ex(p, "NetworkAddress", i);
+ e->SubnetMask = PackGetIp32Ex(p, "SubnetMask", i);
+ e->GatewayAddress = PackGetIp32Ex(p, "GatewayAddress", i);
+ e->Metric = PackGetIntEx(p, "Metric", i);
+ }
+}
+void OutRpcEnumL3Table(PACK *p, RPC_ENUM_L3TABLE *t)
+{
+ UINT i;
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+ PackAddStr(p, "Name", t->Name);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_L3TABLE *e = &t->Items[i];
+
+ PackAddIp32Ex(p, "NetworkAddress", e->NetworkAddress, i, t->NumItem);
+ PackAddIp32Ex(p, "SubnetMask", e->SubnetMask, i, t->NumItem);
+ PackAddIp32Ex(p, "GatewayAddress", e->GatewayAddress, i, t->NumItem);
+ PackAddIntEx(p, "Metric", e->Metric, i, t->NumItem);
+ }
+}
+void FreeRpcEnumL3Table(RPC_ENUM_L3TABLE *t)
+{
+ Free(t->Items);
+}
+
+// RPC_L3TABLE
+void InRpcL3Table(RPC_L3TABLE *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_L3TABLE));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+ t->NetworkAddress = PackGetIp32(p, "NetworkAddress");
+ t->SubnetMask = PackGetIp32(p, "SubnetMask");
+ t->GatewayAddress = PackGetIp32(p, "GatewayAddress");
+ t->Metric = PackGetInt(p, "Metric");
+}
+void OutRpcL3Table(PACK *p, RPC_L3TABLE *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "Name", t->Name);
+ PackAddIp32(p, "NetworkAddress", t->NetworkAddress);
+ PackAddIp32(p, "SubnetMask", t->SubnetMask);
+ PackAddIp32(p, "GatewayAddress", t->GatewayAddress);
+ PackAddInt(p, "Metric", t->Metric);
+}
+
+// RPC_ENUM_L3IF
+void InRpcEnumL3If(RPC_ENUM_L3IF *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_L3IF));
+ t->NumItem = PackGetInt(p, "NumItem");
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+ t->Items = ZeroMalloc(sizeof(RPC_L3IF) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_L3IF *f = &t->Items[i];
+
+ PackGetStrEx(p, "HubName", f->HubName, sizeof(f->HubName), i);
+ f->IpAddress = PackGetIp32Ex(p, "IpAddress", i);
+ f->SubnetMask = PackGetIp32Ex(p, "SubnetMask", i);
+ }
+}
+void OutRpcEnumL3If(PACK *p, RPC_ENUM_L3IF *t)
+{
+ UINT i;
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+ PackAddStr(p, "Name", t->Name);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_L3IF *f = &t->Items[i];
+
+ PackAddStrEx(p, "HubName", f->HubName, i, t->NumItem);
+ PackAddIp32Ex(p, "IpAddress", f->IpAddress, i, t->NumItem);
+ PackAddIp32Ex(p, "SubnetMask", f->SubnetMask, i, t->NumItem);
+ }
+}
+void FreeRpcEnumL3If(RPC_ENUM_L3IF *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_L3IF
+void InRpcL3If(RPC_L3IF *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_L3IF));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->IpAddress = PackGetIp32(p, "IpAddress");
+ t->SubnetMask = PackGetIp32(p, "SubnetMask");
+}
+void OutRpcL3If(PACK *p, RPC_L3IF *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "Name", t->Name);
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddIp32(p, "IpAddress", t->IpAddress);
+ PackAddIp32(p, "SubnetMask", t->SubnetMask);
+}
+
+// RPC_L3SW
+void InRpcL3Sw(RPC_L3SW *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_L3SW));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+}
+void OutRpcL3Sw(PACK *p, RPC_L3SW *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "Name", t->Name);
+}
+
+// RPC_ENUM_L3SW
+void InRpcEnumL3Sw(RPC_ENUM_L3SW *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_L3SW));
+ t->NumItem = PackGetInt(p, "NumItem");
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_L3SW_ITEM) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_L3SW_ITEM *s = &t->Items[i];
+
+ PackGetStrEx(p, "Name", s->Name, sizeof(s->Name), i);
+ s->NumInterfaces = PackGetIntEx(p, "NumInterfaces", i);
+ s->NumTables = PackGetIntEx(p, "NumTables", i);
+ s->Active = PackGetBoolEx(p, "Active", i);
+ s->Online = PackGetBoolEx(p, "Online", i);
+ }
+}
+void OutRpcEnumL3Sw(PACK *p, RPC_ENUM_L3SW *t)
+{
+ UINT i;
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_L3SW_ITEM *s = &t->Items[i];
+
+ PackAddStrEx(p, "Name", s->Name, i, t->NumItem);
+ PackAddIntEx(p, "NumInterfaces", s->NumInterfaces, i, t->NumItem);
+ PackAddIntEx(p, "NumTables", s->NumTables, i, t->NumItem);
+ PackAddBoolEx(p, "Active", s->Active, i, t->NumItem);
+ PackAddBoolEx(p, "Online", s->Online, i, t->NumItem);
+ }
+}
+void FreeRpcEnumL3Sw(RPC_ENUM_L3SW *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_ENUM_ETH
+void InRpcEnumEth(RPC_ENUM_ETH *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_ETH));
+ t->NumItem = PackGetInt(p, "NumItem");
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_ETH_ITEM) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_ETH_ITEM *e = &t->Items[i];
+ PackGetStrEx(p, "DeviceName", e->DeviceName, sizeof(e->DeviceName), i);
+ PackGetUniStrEx(p, "NetworkConnectionName", e->NetworkConnectionName, sizeof(e->NetworkConnectionName), i);
+ }
+}
+void OutRpcEnumEth(PACK *p, RPC_ENUM_ETH *t)
+{
+ UINT i;
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_ETH_ITEM *e = &t->Items[i];
+ PackAddStrEx(p, "DeviceName", e->DeviceName, i, t->NumItem);
+ PackAddUniStrEx(p, "NetworkConnectionName", e->NetworkConnectionName, i, t->NumItem);
+ }
+}
+void FreeRpcEnumEth(RPC_ENUM_ETH *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_LOCALBRIDGE
+void InRpcLocalBridge(RPC_LOCALBRIDGE *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_LOCALBRIDGE));
+ PackGetStr(p, "DeviceName", t->DeviceName, sizeof(t->DeviceName));
+ PackGetStr(p, "HubNameLB", t->HubName, sizeof(t->HubName));
+ t->TapMode = PackGetBool(p, "TapMode");
+}
+void OutRpcLocalBridge(PACK *p, RPC_LOCALBRIDGE *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "DeviceName", t->DeviceName);
+ PackAddStr(p, "HubNameLB", t->HubName);
+ PackAddBool(p, "TapMode", t->TapMode);
+}
+
+// RPC_ENUM_LOCALBRIDGE
+void InRpcEnumLocalBridge(RPC_ENUM_LOCALBRIDGE *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_LOCALBRIDGE));
+ t->NumItem = PackGetInt(p, "NumItem");
+ t->Items = ZeroMalloc(sizeof(RPC_LOCALBRIDGE) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_LOCALBRIDGE *e = &t->Items[i];
+
+ PackGetStrEx(p, "DeviceName", e->DeviceName, sizeof(e->DeviceName), i);
+ PackGetStrEx(p, "HubNameLB", e->HubName, sizeof(e->HubName), i);
+ e->Online = PackGetBoolEx(p, "Online", i);
+ e->Active = PackGetBoolEx(p, "Active", i);
+ e->TapMode = PackGetBoolEx(p, "TapMode", i);
+ }
+}
+void OutRpcEnumLocalBridge(PACK *p, RPC_ENUM_LOCALBRIDGE *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_LOCALBRIDGE *e = &t->Items[i];
+
+ PackAddStrEx(p, "DeviceName", e->DeviceName, i, t->NumItem);
+ PackAddStrEx(p, "HubNameLB", e->HubName, i, t->NumItem);
+ PackAddBoolEx(p, "Online", e->Online, i, t->NumItem);
+ PackAddBoolEx(p, "Active", e->Active, i, t->NumItem);
+ PackAddBoolEx(p, "TapMode", e->TapMode, i, t->NumItem);
+ }
+}
+void FreeRpcEnumLocalBridge(RPC_ENUM_LOCALBRIDGE *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+ Free(t->Items);
+}
+
+// MEMINFO
+void InRpcMemInfo(MEMINFO *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(MEMINFO));
+ t->TotalMemory = PackGetInt64(p, "TotalMemory");
+ t->UsedMemory = PackGetInt64(p, "UsedMemory");
+ t->FreeMemory = PackGetInt64(p, "FreeMemory");
+ t->TotalPhys = PackGetInt64(p, "TotalPhys");
+ t->UsedPhys = PackGetInt64(p, "UsedPhys");
+ t->FreePhys = PackGetInt64(p, "FreePhys");
+}
+void OutRpcMemInfo(PACK *p, MEMINFO *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt64(p, "TotalMemory", t->TotalMemory);
+ PackAddInt64(p, "UsedMemory", t->UsedMemory);
+ PackAddInt64(p, "FreeMemory", t->FreeMemory);
+ PackAddInt64(p, "TotalPhys", t->TotalPhys);
+ PackAddInt64(p, "UsedPhys", t->UsedPhys);
+ PackAddInt64(p, "FreePhys", t->FreePhys);
+}
+
+// OS_INFO
+void InRpcOsInfo(OS_INFO *t, PACK *p)
+{
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(OS_INFO));
+ t->OsType = PackGetInt(p, "OsType");
+ t->OsServicePack = PackGetInt(p, "OsServicePack");
+ if (PackGetStr(p, "OsSystemName", tmp, sizeof(tmp)))
+ {
+ t->OsSystemName = CopyStr(tmp);
+ }
+ if (PackGetStr(p, "OsProductName", tmp, sizeof(tmp)))
+ {
+ t->OsProductName = CopyStr(tmp);
+ }
+ if (PackGetStr(p, "OsVendorName", tmp, sizeof(tmp)))
+ {
+ t->OsVendorName = CopyStr(tmp);
+ }
+ if (PackGetStr(p, "OsVersion", tmp, sizeof(tmp)))
+ {
+ t->OsVersion = CopyStr(tmp);
+ }
+ if (PackGetStr(p, "KernelName", tmp, sizeof(tmp)))
+ {
+ t->KernelName = CopyStr(tmp);
+ }
+ if (PackGetStr(p, "KernelVersion", tmp, sizeof(tmp)))
+ {
+ t->KernelVersion = CopyStr(tmp);
+ }
+}
+void OutRpcOsInfo(PACK *p, OS_INFO *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "OsType", t->OsType);
+ PackAddInt(p, "OsServicePack", t->OsServicePack);
+ PackAddStr(p, "OsSystemName", t->OsSystemName);
+ PackAddStr(p, "OsProductName", t->OsProductName);
+ PackAddStr(p, "OsVendorName", t->OsVendorName);
+ PackAddStr(p, "OsVersion", t->OsVersion);
+ PackAddStr(p, "KernelName", t->KernelName);
+ PackAddStr(p, "KernelVersion", t->KernelVersion);
+}
+void FreeRpcOsInfo(OS_INFO *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->OsSystemName);
+ Free(t->OsProductName);
+ Free(t->OsVendorName);
+ Free(t->OsVersion);
+ Free(t->KernelName);
+ Free(t->KernelVersion);
+}
+
+// Read a local log file
+void SiReadLocalLogFile(SERVER *s, char *filepath, UINT offset, RPC_READ_LOG_FILE *t)
+{
+ char exe_dir[MAX_PATH], full_path[MAX_PATH];
+ IO *o;
+ // Validate arguments
+ if (s == NULL || t == NULL || filepath == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_READ_LOG_FILE));
+
+ GetExeDir(exe_dir, sizeof(exe_dir));
+ Format(full_path, sizeof(full_path), "%s/%s", exe_dir, filepath);
+
+ // Read file
+ o = FileOpenEx(full_path, false, false);
+ if (o != NULL)
+ {
+ UINT filesize = FileSize(o);
+
+ if (offset < filesize)
+ {
+ UINT readsize = MIN(filesize - offset, FTP_BLOCK_SIZE);
+ void *buf = ZeroMalloc(readsize);
+
+ FileSeek(o, FILE_BEGIN, offset);
+ FileRead(o, buf, readsize);
+
+ t->Buffer = NewBuf();
+ WriteBuf(t->Buffer, buf, readsize);
+ Free(buf);
+ }
+
+ FileClose(o);
+ }
+}
+
+// Enumerate local log files
+void SiEnumLocalLogFileList(SERVER *s, char *hubname, RPC_ENUM_LOG_FILE *t)
+{
+ LIST *o;
+ UINT i;
+ // Validate arguments
+ if (s == NULL || t == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_LOG_FILE));
+
+ o = EnumLogFile(hubname);
+
+ t->NumItem = LIST_NUM(o);
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_LOG_FILE_ITEM) * t->NumItem);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ LOG_FILE *f = LIST_DATA(o, i);
+ RPC_ENUM_LOG_FILE_ITEM *e = &t->Items[i];
+
+ StrCpy(e->FilePath, sizeof(e->FilePath), f->Path);
+ StrCpy(e->ServerName, sizeof(e->ServerName), f->ServerName);
+ e->FileSize = f->FileSize;
+ e->UpdatedTime = f->UpdatedTime;
+ }
+
+ FreeEnumLogFile(o);
+}
+
+// Enumerate local sessions
+void SiEnumLocalSession(SERVER *s, char *hubname, RPC_ENUM_SESSION *t)
+{
+ HUB *h;
+ // Validate arguments
+ if (s == NULL || hubname == NULL || t == NULL)
+ {
+ return;
+ }
+
+ LockHubList(s->Cedar);
+ h = GetHub(s->Cedar, hubname);
+ UnlockHubList(s->Cedar);
+
+ if (h == NULL)
+ {
+ t->NumSession = 0;
+ t->Sessions = ZeroMalloc(0);
+ return;
+ }
+
+ LockList(h->SessionList);
+ {
+ UINT i;
+ t->NumSession = LIST_NUM(h->SessionList);
+ t->Sessions = ZeroMalloc(sizeof(RPC_ENUM_SESSION_ITEM) * t->NumSession);
+
+ for (i = 0;i < t->NumSession;i++)
+ {
+ SESSION *s = LIST_DATA(h->SessionList, i);
+ RPC_ENUM_SESSION_ITEM *e = &t->Sessions[i];
+ Lock(s->lock);
+ {
+ StrCpy(e->Name, sizeof(e->Name), s->Name);
+ StrCpy(e->Username, sizeof(e->Username), s->Username);
+ e->Ip = IPToUINT(&s->Connection->ClientIp);
+ StrCpy(e->Hostname, sizeof(e->Hostname), s->Connection->ClientHostname);
+ e->MaxNumTcp = s->MaxConnection;
+ e->LinkMode = s->LinkModeServer;
+ e->SecureNATMode = s->SecureNATMode;
+ e->BridgeMode = s->BridgeMode;
+ e->Layer3Mode = s->L3SwitchMode;
+ e->VLanId = s->VLanId;
+ LockList(s->Connection->Tcp->TcpSockList);
+ {
+ e->CurrentNumTcp = s->Connection->Tcp->TcpSockList->num_item;
+ }
+ UnlockList(s->Connection->Tcp->TcpSockList);
+ Lock(s->TrafficLock);
+ {
+ e->PacketSize = GetTrafficPacketSize(s->Traffic);
+ e->PacketNum = GetTrafficPacketNum(s->Traffic);
+ }
+ Unlock(s->TrafficLock);
+ e->Client_BridgeMode = s->IsBridgeMode;
+ e->Client_MonitorMode = s->IsMonitorMode;
+ Copy(e->UniqueId, s->NodeInfo.UniqueId, 16);
+ }
+ Unlock(s->lock);
+ GetMachineName(e->RemoteHostname, sizeof(e->RemoteHostname));
+ }
+ }
+ UnlockList(h->SessionList);
+
+ ReleaseHub(h);
+}
+
+// RPC_ENUM_LICENSE_KEY
+void InRpcEnumLicenseKey(RPC_ENUM_LICENSE_KEY *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_LICENSE_KEY));
+ t->NumItem = PackGetInt(p, "NumItem");
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_LICENSE_KEY_ITEM) * t->NumItem);
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_LICENSE_KEY_ITEM *e = &t->Items[i];
+
+ e->Id = PackGetIntEx(p, "Id", i);
+ PackGetStrEx(p, "LicenseKey", e->LicenseKey, sizeof(e->LicenseKey), i);
+ PackGetStrEx(p, "LicenseId", e->LicenseId, sizeof(e->LicenseId), i);
+ PackGetStrEx(p, "LicenseName", e->LicenseName, sizeof(e->LicenseName), i);
+ e->Expires = PackGetInt64Ex(p, "Expires", i);
+ e->Status = PackGetIntEx(p, "Status", i);
+ e->ProductId = PackGetIntEx(p, "ProductId", i);
+ e->SystemId = PackGetInt64Ex(p, "SystemId", i);
+ e->SerialId = PackGetIntEx(p, "SerialId", i);
+ }
+}
+void OutRpcEnumLicenseKey(PACK *p, RPC_ENUM_LICENSE_KEY *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_LICENSE_KEY_ITEM *e = &t->Items[i];
+
+ PackAddIntEx(p, "Id", e->Id, i, t->NumItem);
+ PackAddStrEx(p, "LicenseKey", e->LicenseKey, i, t->NumItem);
+ PackAddStrEx(p, "LicenseId", e->LicenseId, i, t->NumItem);
+ PackAddStrEx(p, "LicenseName", e->LicenseName, i, t->NumItem);
+ PackAddInt64Ex(p, "Expires", e->Expires, i, t->NumItem);
+ PackAddIntEx(p, "Status", e->Status, i, t->NumItem);
+ PackAddIntEx(p, "ProductId", e->ProductId, i, t->NumItem);
+ PackAddInt64Ex(p, "SystemId", e->SystemId, i, t->NumItem);
+ PackAddIntEx(p, "SerialId", e->SerialId, i, t->NumItem);
+ }
+}
+void FreeRpcEnumLicenseKey(RPC_ENUM_LICENSE_KEY *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_LICENSE_STATUS
+void InRpcLicenseStatus(RPC_LICENSE_STATUS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_LICENSE_STATUS));
+
+ t->EditionId = PackGetInt(p, "EditionId");
+ PackGetStr(p, "EditionStr", t->EditionStr, sizeof(t->EditionStr) );
+ t->SystemId = PackGetInt64(p, "SystemId");
+ t->SystemExpires = PackGetInt64(p, "SystemExpires");
+ t->NumClientConnectLicense = PackGetInt(p, "NumClientConnectLicense");
+ t->NumBridgeConnectLicense = PackGetInt(p, "NumBridgeConnectLicense");
+
+ // v3.0
+ t->NeedSubscription = PackGetBool(p, "NeedSubscription");
+ t->AllowEnterpriseFunction = PackGetBool(p, "AllowEnterpriseFunction");
+ t->SubscriptionExpires = PackGetInt64(p, "SubscriptionExpires");
+ t->IsSubscriptionExpired = PackGetBool(p, "IsSubscriptionExpired");
+ t->NumUserCreationLicense = PackGetInt(p, "NumUserCreationLicense");
+ t->ReleaseDate = PackGetInt64(p, "ReleaseDate");
+}
+void OutRpcLicenseStatus(PACK *p, RPC_LICENSE_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "EditionId", t->EditionId);
+ PackAddStr(p, "EditionStr", t->EditionStr);
+ PackAddInt64(p, "SystemId", t->SystemId);
+ PackAddInt64(p, "SystemExpires", t->SystemExpires);
+ PackAddInt(p, "NumClientConnectLicense", t->NumClientConnectLicense);
+ PackAddInt(p, "NumBridgeConnectLicense", t->NumBridgeConnectLicense);
+
+ // v3.0
+ PackAddBool(p, "NeedSubscription", t->NeedSubscription);
+ PackAddBool(p, "AllowEnterpriseFunction", t->AllowEnterpriseFunction);
+ PackAddInt64(p, "SubscriptionExpires", t->SubscriptionExpires);
+ PackAddBool(p, "IsSubscriptionExpired", t->IsSubscriptionExpired);
+ PackAddInt(p, "NumUserCreationLicense", t->NumUserCreationLicense);
+ PackAddInt64(p, "ReleaseDate", t->ReleaseDate);
+}
+
+// RPC_ADMIN_OPTION
+void InRpcAdminOption(RPC_ADMIN_OPTION *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ADMIN_OPTION));
+ t->NumItem = PackGetInt(p, "NumItem");
+ t->Items = ZeroMalloc(sizeof(ADMIN_OPTION) * t->NumItem);
+
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ ADMIN_OPTION *o = &t->Items[i];
+
+ PackGetStrEx(p, "Name", o->Name, sizeof(o->Name), i);
+ o->Value = PackGetIntEx(p, "Value", i);
+ }
+}
+void OutRpcAdminOption(PACK *p, RPC_ADMIN_OPTION *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+
+ PackAddStr(p, "HubName", t->HubName);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ ADMIN_OPTION *o = &t->Items[i];
+
+ PackAddStrEx(p, "Name", o->Name, i, t->NumItem);
+ PackAddIntEx(p, "Value", o->Value, i, t->NumItem);
+ }
+}
+void FreeRpcAdminOption(RPC_ADMIN_OPTION *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_CONFIG
+void InRpcConfig(RPC_CONFIG *t, PACK *p)
+{
+ UINT size;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_CONFIG));
+ PackGetStr(p, "FileName", t->FileName, sizeof(t->FileName));
+ size = PackGetDataSize(p, "FileData");
+ t->FileData = ZeroMalloc(size + 1);
+ PackGetData(p, "FileData", t->FileData);
+}
+void OutRpcConfig(PACK *p, RPC_CONFIG *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "FileName", t->FileName);
+ PackAddData(p, "FileData", t->FileData, StrLen(t->FileData));
+}
+void FreeRpcConfig(RPC_CONFIG *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->FileData);
+}
+
+// RPC_BRIDGE_SUPPORT
+void InRpcBridgeSupport(RPC_BRIDGE_SUPPORT *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_BRIDGE_SUPPORT));
+
+ t->IsBridgeSupportedOs = PackGetBool(p, "IsBridgeSupportedOs");
+ t->IsWinPcapNeeded = PackGetBool(p, "IsWinPcapNeeded");
+}
+void OutRpcBridgeSupport(PACK *p, RPC_BRIDGE_SUPPORT *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "IsBridgeSupportedOs", t->IsBridgeSupportedOs);
+ PackAddBool(p, "IsWinPcapNeeded",t->IsWinPcapNeeded);
+}
+
+// RPC_ADD_ACCESS
+void InRpcAddAccess(RPC_ADD_ACCESS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ADD_ACCESS));
+
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ InRpcAccess(&t->Access, p);
+}
+void OutRpcAddAccess(PACK *p, RPC_ADD_ACCESS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ OutRpcAccess(p, &t->Access);
+}
+
+// RPC_DELETE_ACCESS
+void InRpcDeleteAccess(RPC_DELETE_ACCESS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_DELETE_ACCESS));
+
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->Id = PackGetInt(p, "Id");
+}
+void OutRpcDeleteAccess(PACK *p, RPC_DELETE_ACCESS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddInt(p, "Id", t->Id);
+}
+
+
+// RPC_SERVER_INFO
+void InRpcServerInfo(RPC_SERVER_INFO *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_SERVER_INFO));
+
+ PackGetStr(p, "ServerProductName", t->ServerProductName, sizeof(t->ServerProductName));
+ PackGetStr(p, "ServerVersionString", t->ServerVersionString, sizeof(t->ServerVersionString));
+ PackGetStr(p, "ServerBuildInfoString", t->ServerBuildInfoString, sizeof(t->ServerBuildInfoString));
+ t->ServerVerInt = PackGetInt(p, "ServerVerInt");
+ t->ServerBuildInt = PackGetInt(p, "ServerBuildInt");
+ PackGetStr(p, "ServerHostName", t->ServerHostName, sizeof(t->ServerHostName));
+ t->ServerType = PackGetInt(p, "ServerType");
+ t->ServerBuildDate = PackGetInt64(p, "ServerBuildDate");
+ PackGetStr(p, "ServerFamilyName", t->ServerFamilyName, sizeof(t->ServerFamilyName));
+ InRpcOsInfo(&t->OsInfo, p);
+}
+void OutRpcServerInfo(PACK *p, RPC_SERVER_INFO *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "ServerProductName", t->ServerProductName);
+ PackAddStr(p, "ServerVersionString", t->ServerVersionString);
+ PackAddStr(p, "ServerBuildInfoString", t->ServerBuildInfoString);
+ PackAddInt(p, "ServerVerInt", t->ServerVerInt);
+ PackAddInt(p, "ServerBuildInt", t->ServerBuildInt);
+ PackAddStr(p, "ServerHostName", t->ServerHostName);
+ PackAddInt(p, "ServerType", t->ServerType);
+ PackAddInt64(p, "ServerBuildDate", t->ServerBuildDate);
+ PackAddStr(p, "ServerFamilyName", t->ServerFamilyName);
+ OutRpcOsInfo(p, &t->OsInfo);
+}
+void FreeRpcServerInfo(RPC_SERVER_INFO *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FreeRpcOsInfo(&t->OsInfo);
+}
+
+// RPC_SERVER_STATUS
+void InRpcServerStatus(RPC_SERVER_STATUS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_SERVER_STATUS));
+ t->ServerType = PackGetInt(p, "ServerType");
+ t->NumTcpConnections = PackGetInt(p, "NumTcpConnections");
+ t->NumTcpConnectionsLocal = PackGetInt(p, "NumTcpConnectionsLocal");
+ t->NumTcpConnectionsRemote = PackGetInt(p, "NumTcpConnectionsRemote");
+ t->NumHubTotal = PackGetInt(p, "NumHubTotal");
+ t->NumHubStandalone = PackGetInt(p, "NumHubStandalone");
+ t->NumHubStatic = PackGetInt(p, "NumHubStatic");
+ t->NumHubDynamic = PackGetInt(p, "NumHubDynamic");
+ t->NumSessionsTotal = PackGetInt(p, "NumSessionsTotal");
+ t->NumSessionsLocal = PackGetInt(p, "NumSessionsLocal");
+ t->NumSessionsRemote = PackGetInt(p, "NumSessionsRemote");
+ t->NumMacTables = PackGetInt(p, "NumMacTables");
+ t->NumIpTables = PackGetInt(p, "NumIpTables");
+ t->NumUsers = PackGetInt(p, "NumUsers");
+ t->NumGroups = PackGetInt(p, "NumGroups");
+ t->CurrentTime = PackGetInt64(p, "CurrentTime");
+ t->CurrentTick = PackGetInt64(p, "CurrentTick");
+ t->AssignedBridgeLicenses = PackGetInt(p, "AssignedBridgeLicenses");
+ t->AssignedClientLicenses = PackGetInt(p, "AssignedClientLicenses");
+ t->AssignedBridgeLicensesTotal = PackGetInt(p, "AssignedBridgeLicensesTotal");
+ t->AssignedClientLicensesTotal = PackGetInt(p, "AssignedClientLicensesTotal");
+ t->StartTime = PackGetInt64(p, "StartTime");
+
+ InRpcTraffic(&t->Traffic, p);
+
+ InRpcMemInfo(&t->MemInfo, p);
+}
+void OutRpcServerStatus(PACK *p, RPC_SERVER_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "ServerType", t->ServerType);
+ PackAddInt(p, "NumHubTotal", t->NumHubTotal);
+ PackAddInt(p, "NumHubStandalone", t->NumHubStandalone);
+ PackAddInt(p, "NumHubStatic", t->NumHubStatic);
+ PackAddInt(p, "NumHubDynamic", t->NumHubDynamic);
+ PackAddInt(p, "NumSessionsTotal", t->NumSessionsTotal);
+ PackAddInt(p, "NumSessionsLocal", t->NumSessionsLocal);
+ PackAddInt(p, "NumSessionsRemote", t->NumSessionsRemote);
+ PackAddInt(p, "NumTcpConnections", t->NumTcpConnections);
+ PackAddInt(p, "NumTcpConnectionsLocal", t->NumTcpConnectionsLocal);
+ PackAddInt(p, "NumTcpConnectionsRemote", t->NumTcpConnectionsRemote);
+ PackAddInt(p, "NumMacTables", t->NumMacTables);
+ PackAddInt(p, "NumIpTables", t->NumIpTables);
+ PackAddInt(p, "NumUsers", t->NumUsers);
+ PackAddInt(p, "NumGroups", t->NumGroups);
+ PackAddInt64(p, "CurrentTime", t->CurrentTime);
+ PackAddInt64(p, "CurrentTick", t->CurrentTick);
+ PackAddInt(p, "AssignedBridgeLicenses", t->AssignedBridgeLicenses);
+ PackAddInt(p, "AssignedClientLicenses", t->AssignedClientLicenses);
+ PackAddInt(p, "AssignedBridgeLicensesTotal", t->AssignedBridgeLicensesTotal);
+ PackAddInt(p, "AssignedClientLicensesTotal", t->AssignedClientLicensesTotal);
+ PackAddInt64(p, "StartTime", t->StartTime);
+
+ OutRpcTraffic(p, &t->Traffic);
+
+ OutRpcMemInfo(p, &t->MemInfo);
+}
+
+// RPC_LISTENER
+void InRpcListener(RPC_LISTENER *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_LISTENER));
+ t->Port = PackGetInt(p, "Port");
+ t->Enable = PackGetBool(p, "Enable");
+}
+void OutRpcListener(PACK *p, RPC_LISTENER *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "Port", t->Port);
+ PackAddBool(p, "Enable", t->Enable);
+}
+
+// RPC_LISTENER_LIST
+void InRpcListenerList(RPC_LISTENER_LIST *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_LISTENER_LIST));
+ t->NumPort = PackGetIndexCount(p, "Ports");
+ t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+ t->Enables = ZeroMalloc(sizeof(UINT) * t->NumPort);
+ t->Errors = ZeroMalloc(sizeof(UINT) * t->NumPort);
+ for (i = 0;i < t->NumPort;i++)
+ {
+ t->Ports[i] = PackGetIntEx(p, "Ports", i);
+ t->Enables[i] = PackGetBoolEx(p, "Enables", i);
+ t->Errors[i] = PackGetBoolEx(p, "Errors", i);
+ }
+}
+void OutRpcListenerList(PACK *p, RPC_LISTENER_LIST *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < t->NumPort;i++)
+ {
+ PackAddIntEx(p, "Ports", t->Ports[i], i, t->NumPort);
+ PackAddBoolEx(p, "Enables", t->Enables[i], i, t->NumPort);
+ PackAddBoolEx(p, "Errors", t->Errors[i], i, t->NumPort);
+ }
+}
+void FreeRpcListenerList(RPC_LISTENER_LIST *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Ports);
+ Free(t->Enables);
+ Free(t->Errors);
+}
+
+// RPC_STR
+void InRpcStr(RPC_STR *t, PACK *p)
+{
+ UINT size = 65536;
+ char *tmp = Malloc(size);
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_STR));
+ if (PackGetStr(p, "String", tmp, size) == false)
+ {
+ t->String = CopyStr("");
+ }
+ else
+ {
+ t->String = CopyStr(tmp);
+ }
+ Free(tmp);
+}
+void OutRpcStr(PACK *p, RPC_STR *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "String", t->String);
+}
+void FreeRpcStr(RPC_STR *t)
+{
+ // Validate arguments
+ if (t == NULL )
+ {
+ return;
+ }
+
+ Free(t->String);
+}
+
+// RPC_SET_PASSWORD
+void InRpcSetPassword(RPC_SET_PASSWORD *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_SET_PASSWORD));
+ PackGetData2(p, "HashedPassword", t->HashedPassword, sizeof(t->HashedPassword));
+}
+void OutRpcSetPassword(PACK *p, RPC_SET_PASSWORD *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddData(p, "HashedPassword", t->HashedPassword, sizeof(t->HashedPassword));
+}
+
+// RPC_FARM
+void InRpcFarm(RPC_FARM *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_FARM));
+ t->ServerType = PackGetInt(p, "ServerType");
+ t->NumPort = PackGetIndexCount(p, "Ports");
+ t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+ for (i = 0;i < t->NumPort;i++)
+ {
+ t->Ports[i] = PackGetIntEx(p, "Ports", i);
+ }
+ t->PublicIp = PackGetIp32(p, "PublicIp");
+ PackGetStr(p, "ControllerName", t->ControllerName, sizeof(t->ControllerName));
+ t->ControllerPort = PackGetInt(p, "ControllerPort");
+ PackGetData2(p, "MemberPassword", t->MemberPassword, sizeof(t->MemberPassword));
+ t->Weight = PackGetInt(p, "Weight");
+ t->ControllerOnly = PackGetBool(p, "ControllerOnly");
+}
+void OutRpcFarm(PACK *p, RPC_FARM *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "ServerType", t->ServerType);
+ for (i = 0;i < t->NumPort;i++)
+ {
+ PackAddIntEx(p, "Ports", t->Ports[i], i, t->NumPort);
+ }
+ PackAddIp32(p, "PublicIp", t->PublicIp);
+ PackAddStr(p, "ControllerName", t->ControllerName);
+ PackAddInt(p, "ControllerPort", t->ControllerPort);
+ PackAddData(p, "MemberPassword", t->MemberPassword, sizeof(t->MemberPassword));
+ PackAddInt(p, "Weight", t->Weight);
+ PackAddBool(p, "ControllerOnly", t->ControllerOnly);
+}
+void FreeRpcFarm(RPC_FARM *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Ports);
+}
+
+// RPC_FARM_HUB
+void InRpcFarmHub(RPC_FARM_HUB *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_FARM_HUB));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->DynamicHub = PackGetBool(p, "DynamicHub");
+}
+void OutRpcFarmHub(PACK *p, RPC_FARM_HUB *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddBool(p, "DynamicHub", t->DynamicHub);
+}
+
+// RPC_FARM_INFO
+void InRpcFarmInfo(RPC_FARM_INFO *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_FARM_INFO));
+ t->Id = PackGetInt(p, "Id");
+ t->Controller = PackGetBool(p, "Controller");
+ t->ConnectedTime = PackGetInt64(p, "ConnectedTime");
+ t->Ip = PackGetIp32(p, "Ip");
+ PackGetStr(p, "Hostname", t->Hostname, sizeof(t->Hostname));
+ t->Point = PackGetInt(p, "Point");
+ t->NumPort = PackGetIndexCount(p, "Ports");
+ t->Ports = ZeroMalloc(sizeof(UINT) * t->NumPort);
+ for (i = 0;i < t->NumPort;i++)
+ {
+ t->Ports[i] = PackGetIntEx(p, "Ports", i);
+ }
+ t->ServerCert = PackGetX(p, "ServerCert");
+ t->NumFarmHub = PackGetIndexCount(p, "HubName");
+ t->FarmHubs = ZeroMalloc(sizeof(RPC_FARM_HUB) * t->NumFarmHub);
+ for (i = 0;i < t->NumFarmHub;i++)
+ {
+ PackGetStrEx(p, "HubName", t->FarmHubs[i].HubName, sizeof(t->FarmHubs[i].HubName), i);
+ t->FarmHubs[i].DynamicHub = PackGetBoolEx(p, "DynamicHub", i);
+ }
+ t->NumSessions = PackGetInt(p, "NumSessions");
+ t->NumTcpConnections = PackGetInt(p, "NumTcpConnections");
+ t->Weight = PackGetInt(p, "Weight");
+}
+void OutRpcFarmInfo(PACK *p, RPC_FARM_INFO *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "Id", t->Id);
+ PackAddBool(p, "Controller", t->Controller);
+ PackAddInt64(p, "ConnectedTime", t->ConnectedTime);
+ PackAddIp32(p, "Ip", t->Ip);
+ PackAddStr(p, "Hostname", t->Hostname);
+ PackAddInt(p, "Point", t->Point);
+ for (i = 0;i < t->NumPort;i++)
+ {
+ PackAddIntEx(p, "Ports", t->Ports[i], i, t->NumPort);
+ }
+ PackAddX(p, "ServerCert", t->ServerCert);
+ for (i = 0;i < t->NumFarmHub;i++)
+ {
+ PackAddStrEx(p, "HubName", t->FarmHubs[i].HubName, i, t->NumFarmHub);
+ PackAddBoolEx(p, "DynamicHub", t->FarmHubs[i].DynamicHub, i, t->NumFarmHub);
+ }
+ PackAddInt(p, "NumSessions", t->NumSessions);
+ PackAddInt(p, "NumTcpConnections", t->NumTcpConnections);
+ PackAddInt(p, "Weight", t->Weight);
+}
+void FreeRpcFarmInfo(RPC_FARM_INFO *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Ports);
+ Free(t->FarmHubs);
+ FreeX(t->ServerCert);
+}
+
+void InRpcEnumFarm(RPC_ENUM_FARM *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_FARM));
+ t->NumFarm = PackGetIndexCount(p, "Id");
+ t->Farms = ZeroMalloc(sizeof(RPC_ENUM_FARM_ITEM) * t->NumFarm);
+
+ for (i = 0;i < t->NumFarm;i++)
+ {
+ RPC_ENUM_FARM_ITEM *e = &t->Farms[i];
+
+ e->Id = PackGetIntEx(p, "Id", i);
+ e->Controller = PackGetBoolEx(p, "Controller", i);
+ e->ConnectedTime = PackGetInt64Ex(p, "ConnectedTime", i);
+ e->Ip = PackGetIp32Ex(p, "Ip", i);
+ PackGetStrEx(p, "Hostname", e->Hostname, sizeof(e->Hostname), i);
+ e->Point = PackGetIntEx(p, "Point", i);
+ e->NumSessions = PackGetIntEx(p, "NumSessions", i);
+ e->NumTcpConnections = PackGetIntEx(p, "NumTcpConnections", i);
+ e->NumHubs = PackGetIntEx(p, "NumHubs", i);
+ e->AssignedClientLicense = PackGetIntEx(p, "AssignedClientLicense", i);
+ e->AssignedBridgeLicense = PackGetIntEx(p, "AssignedBridgeLicense", i);
+ }
+}
+void OutRpcEnumFarm(PACK *p, RPC_ENUM_FARM *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < t->NumFarm;i++)
+ {
+ RPC_ENUM_FARM_ITEM *e = &t->Farms[i];
+
+ PackAddIntEx(p, "Id", e->Id, i, t->NumFarm);
+ PackAddBoolEx(p, "Controller", e->Controller, i, t->NumFarm);
+ PackAddInt64Ex(p, "ConnectedTime", e->ConnectedTime, i, t->NumFarm);
+ PackAddIp32Ex(p, "Ip", e->Ip, i, t->NumFarm);
+ PackAddStrEx(p, "Hostname", e->Hostname, i, t->NumFarm);
+ PackAddIntEx(p, "Point", e->Point, i, t->NumFarm);
+ PackAddIntEx(p, "NumSessions", e->NumSessions, i, t->NumFarm);
+ PackAddIntEx(p, "NumTcpConnections", e->NumTcpConnections, i, t->NumFarm);
+ PackAddIntEx(p, "NumHubs", e->NumHubs, i, t->NumFarm);
+ PackAddIntEx(p, "AssignedClientLicense", e->AssignedClientLicense, i, t->NumFarm);
+ PackAddIntEx(p, "AssignedBridgeLicense", e->AssignedBridgeLicense, i, t->NumFarm);
+ }
+}
+void FreeRpcEnumFarm(RPC_ENUM_FARM *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Farms);
+}
+
+// RPC_FARM_CONNECTION_STATUS
+void InRpcFarmConnectionStatus(RPC_FARM_CONNECTION_STATUS *t, PACK *p)
+{
+ Zero(t, sizeof(RPC_FARM_CONNECTION_STATUS));
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ t->Ip = PackGetIp32(p, "Ip");
+ t->Port = PackGetInt(p, "Port");
+ t->Online = PackGetBool(p, "Online");
+ t->LastError = PackGetInt(p, "LastError");
+ t->StartedTime = PackGetInt64(p, "StartedTime");
+ t->CurrentConnectedTime = PackGetInt64(p, "CurrentConnectedTime");
+ t->FirstConnectedTime = PackGetInt64(p, "FirstConnectedTime");
+ t->NumConnected = PackGetInt(p, "NumConnected");
+ t->NumTry = PackGetInt(p, "NumTry");
+ t->NumFailed = PackGetInt(p, "NumFailed");
+}
+void OutRpcFarmConnectionStatus(PACK *p, RPC_FARM_CONNECTION_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddIp32(p, "Ip", t->Ip);
+ PackAddInt(p, "Port", t->Port);
+ PackAddBool(p, "Online", t->Online);
+ PackAddInt(p, "LastError", t->LastError);
+ PackAddInt64(p, "StartedTime", t->StartedTime);
+ PackAddInt64(p, "CurrentConnectedTime", t->CurrentConnectedTime);
+ PackAddInt64(p, "FirstConnectedTime", t->FirstConnectedTime);
+ PackAddInt(p, "NumConnected", t->NumConnected);
+ PackAddInt(p, "NumTry", t->NumTry);
+ PackAddInt(p, "NumFailed", t->NumFailed);
+}
+
+// RPC_HUB_OPTION
+void InRpcHubOption(RPC_HUB_OPTION *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_HUB_OPTION));
+ t->MaxSession = PackGetInt(p, "MaxSession");
+ t->NoEnum = PackGetBool(p, "NoEnum");
+}
+void OutRpcHubOption(PACK *p, RPC_HUB_OPTION *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "MaxSession", t->MaxSession);
+ PackAddBool(p, "NoEnum", t->NoEnum);
+}
+
+// RPC_RADIUS
+void InRpcRadius(RPC_RADIUS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_RADIUS));
+ PackGetStr(p, "RadiusServerName", t->RadiusServerName, sizeof(t->RadiusServerName));
+ t->RadiusPort = PackGetInt(p, "RadiusPort");
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetStr(p, "RadiusSecret", t->RadiusSecret, sizeof(t->RadiusSecret));
+ t->RadiusRetryInterval = PackGetInt(p, "RadiusRetryInterval");
+}
+void OutRpcRadius(PACK *p, RPC_RADIUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "RadiusServerName", t->RadiusServerName);
+ PackAddInt(p, "RadiusPort", t->RadiusPort);
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddStr(p, "RadiusSecret", t->RadiusSecret);
+ PackAddInt(p, "RadiusRetryInterval", t->RadiusRetryInterval);
+}
+
+// RPC_HUB
+void InRpcHub(RPC_HUB *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_HUB));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+}
+void OutRpcHub(PACK *p, RPC_HUB *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+}
+
+// RPC_CREATE_HUB
+void InRpcCreateHub(RPC_CREATE_HUB *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_CREATE_HUB));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetData2(p, "HashedPassword", t->HashedPassword, sizeof(t->HashedPassword));
+ PackGetData2(p, "SecurePassword", t->SecurePassword, sizeof(t->SecurePassword));
+ t->Online = PackGetBool(p, "Online");
+ InRpcHubOption(&t->HubOption, p);
+ t->HubType = PackGetInt(p, "HubType");
+}
+void OutRpcCreateHub(PACK *p, RPC_CREATE_HUB *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddData(p, "HashedPassword", t->HashedPassword, sizeof(t->HashedPassword));
+ PackAddData(p, "SecurePassword", t->SecurePassword, sizeof(t->SecurePassword));
+ PackAddBool(p, "Online", t->Online);
+ OutRpcHubOption(p, &t->HubOption);
+ PackAddInt(p, "HubType", t->HubType);
+}
+
+// RPC_ENUM_HUB
+void InRpcEnumHub(RPC_ENUM_HUB *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_HUB));
+ t->NumHub = PackGetIndexCount(p, "HubName");
+ t->Hubs = ZeroMalloc(sizeof(RPC_ENUM_HUB_ITEM) * t->NumHub);
+
+ for (i = 0;i < t->NumHub;i++)
+ {
+ RPC_ENUM_HUB_ITEM *e = &t->Hubs[i];
+
+ PackGetStrEx(p, "HubName", e->HubName, sizeof(e->HubName), i);
+ e->Online = PackGetBoolEx(p, "Online", i);
+ e->HubType = PackGetIntEx(p, "HubType", i);
+ e->NumSessions = PackGetIntEx(p, "NumSessions", i);
+ e->NumUsers = PackGetIntEx(p, "NumUsers", i);
+ e->NumGroups = PackGetIntEx(p, "NumGroups", i);
+ e->NumMacTables = PackGetIntEx(p, "NumMacTables", i);
+ e->NumIpTables = PackGetIntEx(p, "NumIpTables", i);
+ e->LastCommTime = PackGetInt64Ex(p, "LastCommTime", i);
+ e->CreatedTime = PackGetInt64Ex(p, "CreatedTime", i);
+ e->LastLoginTime = PackGetInt64Ex(p, "LastLoginTime", i);
+ e->NumLogin = PackGetIntEx(p, "NumLogin", i);
+ e->IsTrafficFilled = PackGetBoolEx(p, "IsTrafficFilled", i);
+
+ InRpcTrafficEx(&e->Traffic, p, i);
+ }
+}
+void OutRpcEnumHub(PACK *p, RPC_ENUM_HUB *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < t->NumHub;i++)
+ {
+ RPC_ENUM_HUB_ITEM *e = &t->Hubs[i];
+
+ PackAddStrEx(p, "HubName", e->HubName, i, t->NumHub);
+ PackAddBoolEx(p, "Online", e->Online, i, t->NumHub);
+ PackAddIntEx(p, "HubType", e->HubType, i, t->NumHub);
+ PackAddIntEx(p, "NumSessions", e->NumSessions, i, t->NumHub);
+ PackAddIntEx(p, "NumUsers", e->NumUsers, i, t->NumHub);
+ PackAddIntEx(p, "NumGroups", e->NumGroups, i, t->NumHub);
+ PackAddIntEx(p, "NumMacTables", e->NumMacTables, i, t->NumHub);
+ PackAddIntEx(p, "NumIpTables", e->NumIpTables, i, t->NumHub);
+ PackAddInt64Ex(p, "LastCommTime", e->LastCommTime, i, t->NumHub);
+ PackAddInt64Ex(p, "CreatedTime", e->CreatedTime, i, t->NumHub);
+ PackAddInt64Ex(p, "LastLoginTime", e->LastLoginTime, i, t->NumHub);
+ PackAddIntEx(p, "NumLogin", e->NumLogin, i, t->NumHub);
+ PackAddBoolEx(p, "IsTrafficFilled", e->IsTrafficFilled, i, t->NumHub);
+
+ OutRpcTrafficEx(&e->Traffic, p, i, t->NumHub);
+ }
+}
+void FreeRpcEnumHub(RPC_ENUM_HUB *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Hubs);
+}
+
+// RPC_DELETE_HUB
+void InRpcDeleteHub(RPC_DELETE_HUB *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_DELETE_HUB));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+}
+void OutRpcDeleteHub(PACK *p, RPC_DELETE_HUB *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+}
+
+// RPC_ENUM_CONNECTION
+void InRpcEnumConnection(RPC_ENUM_CONNECTION *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_CONNECTION));
+ t->NumConnection = PackGetIndexCount(p, "Name");
+ t->Connections = ZeroMalloc(sizeof(RPC_ENUM_CONNECTION_ITEM) * t->NumConnection);
+
+ for (i = 0;i < t->NumConnection;i++)
+ {
+ RPC_ENUM_CONNECTION_ITEM *e = &t->Connections[i];
+
+ e->Ip = PackGetIp32Ex(p, "Ip", i);
+ e->Port = PackGetIntEx(p, "Port", i);
+ PackGetStrEx(p, "Name", e->Name, sizeof(e->Name), i);
+ PackGetStrEx(p, "Hostname", e->Hostname, sizeof(e->Hostname), i);
+ e->ConnectedTime = PackGetInt64Ex(p, "ConnectedTime", i);
+ e->Type = PackGetIntEx(p, "Type", i);
+ }
+}
+void OutRpcEnumConnection(PACK *p, RPC_ENUM_CONNECTION *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < t->NumConnection;i++)
+ {
+ RPC_ENUM_CONNECTION_ITEM *e = &t->Connections[i];
+
+ PackAddIp32Ex(p, "Ip", e->Ip, i, t->NumConnection);
+ PackAddIntEx(p, "Port", e->Port, i, t->NumConnection);
+ PackAddStrEx(p, "Name", e->Name, i, t->NumConnection);
+ PackAddStrEx(p, "Hostname", e->Hostname, i, t->NumConnection);
+ PackAddInt64Ex(p, "ConnectedTime", e->ConnectedTime, i, t->NumConnection);
+ PackAddIntEx(p, "Type", e->Type, i, t->NumConnection);
+ }
+}
+void FreeRpcEnumConnetion(RPC_ENUM_CONNECTION *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Connections);
+}
+
+// RPC_DISCONNECT_CONNECTION
+void InRpcDisconnectConnection(RPC_DISCONNECT_CONNECTION *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_DISCONNECT_CONNECTION));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+}
+void OutRpcDisconnectConnection(PACK *p, RPC_DISCONNECT_CONNECTION *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "Name", t->Name);
+}
+
+// RPC_CONNECTION_INFO
+void InRpcConnectionInfo(RPC_CONNECTION_INFO *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_CONNECTION_INFO));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+ t->Ip = PackGetIp32(p, "Ip");
+ t->Port = PackGetInt(p, "Port");
+ t->ConnectedTime = PackGetInt64(p, "ConnectedTime");
+ PackGetStr(p, "Hostname", t->Hostname, sizeof(t->Hostname));
+ PackGetStr(p, "ServerStr", t->ServerStr, sizeof(t->ServerStr));
+ PackGetStr(p, "ClientStr", t->ClientStr, sizeof(t->ClientStr));
+ t->ServerVer = PackGetInt(p, "ServerVer");
+ t->ServerBuild = PackGetInt(p, "ServerBuild");
+ t->ClientVer = PackGetInt(p, "ClientVer");
+ t->ClientBuild = PackGetInt(p, "ClientBuild");
+ t->Type = PackGetInt(p, "Type");
+}
+void OutRpcConnectionInfo(PACK *p, RPC_CONNECTION_INFO *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "Name", t->Name);
+ PackAddIp32(p, "Ip", t->Ip);
+ PackAddInt(p, "Port", t->Port);
+ PackAddInt64(p, "ConnectedTime", t->ConnectedTime);
+ PackAddStr(p, "Hostname", t->Hostname);
+ PackAddStr(p, "ServerStr", t->ServerStr);
+ PackAddStr(p, "ClientStr", t->ClientStr);
+ PackAddInt(p, "ServerVer", t->ServerVer);
+ PackAddInt(p, "ServerBuild", t->ServerBuild);
+ PackAddInt(p, "ClientVer", t->ClientVer);
+ PackAddInt(p, "ClientBuild", t->ClientBuild);
+ PackAddInt(p, "Type", t->Type);
+}
+
+// RPC_SET_HUB_ONLINE
+void InRpcSetHubOnline(RPC_SET_HUB_ONLINE *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_SET_HUB_ONLINE));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->Online = PackGetBool(p, "Online");
+}
+void OutRpcSetHubOnline(PACK *p, RPC_SET_HUB_ONLINE *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddBool(p, "Online", t->Online);
+}
+
+// RPC_HUB_STATUS
+void InRpcHubStatus(RPC_HUB_STATUS *t, PACK *p)
+{
+ Zero(t, sizeof(RPC_HUB_STATUS));
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->Online = PackGetBool(p, "Online");
+ t->HubType = PackGetInt(p, "HubType");
+ t->NumSessions = PackGetInt(p, "NumSessions");
+ t->NumSessionsClient = PackGetInt(p, "NumSessionsClient");
+ t->NumSessionsBridge = PackGetInt(p, "NumSessionsBridge");
+ t->NumAccessLists = PackGetInt(p, "NumAccessLists");
+ t->NumUsers = PackGetInt(p, "NumUsers");
+ t->NumGroups = PackGetInt(p, "NumGroups");
+ t->NumMacTables = PackGetInt(p, "NumMacTables");
+ t->NumIpTables = PackGetInt(p, "NumIpTables");
+ t->SecureNATEnabled = PackGetBool(p, "SecureNATEnabled");
+ InRpcTraffic(&t->Traffic, p);
+ t->LastCommTime = PackGetInt64(p, "LastCommTime");
+ t->CreatedTime = PackGetInt64(p, "CreatedTime");
+ t->LastLoginTime = PackGetInt64(p, "LastLoginTime");
+ t->NumLogin = PackGetInt(p, "NumLogin");
+}
+void OutRpcHubStatus(PACK *p, RPC_HUB_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddBool(p, "Online", t->Online);
+ PackAddInt(p, "HubType", t->HubType);
+ PackAddInt(p, "NumSessions", t->NumSessions);
+ PackAddInt(p, "NumSessionsClient", t->NumSessionsClient);
+ PackAddInt(p, "NumSessionsBridge", t->NumSessionsBridge);
+ PackAddInt(p, "NumAccessLists", t->NumAccessLists);
+ PackAddInt(p, "NumUsers", t->NumUsers);
+ PackAddInt(p, "NumGroups", t->NumGroups);
+ PackAddInt(p, "NumMacTables", t->NumMacTables);
+ PackAddInt(p, "NumIpTables", t->NumIpTables);
+ PackAddBool(p, "SecureNATEnabled", t->SecureNATEnabled);
+ OutRpcTraffic(p, &t->Traffic);
+ PackAddInt64(p, "LastCommTime", t->LastCommTime);
+ PackAddInt64(p, "CreatedTime", t->CreatedTime);
+ PackAddInt64(p, "LastLoginTime", t->LastLoginTime);
+ PackAddInt(p, "NumLogin", t->NumLogin);
+}
+
+// RPC_HUB_LOG
+void InRpcHubLog(RPC_HUB_LOG *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_HUB_LOG));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->LogSetting.SaveSecurityLog = PackGetBool(p, "SaveSecurityLog");
+ t->LogSetting.SecurityLogSwitchType = PackGetInt(p, "SecurityLogSwitchType");
+ t->LogSetting.SavePacketLog = PackGetBool(p, "SavePacketLog");
+ t->LogSetting.PacketLogSwitchType = PackGetInt(p, "PacketLogSwitchType");
+ for (i = 0;i < NUM_PACKET_LOG;i++)
+ {
+ t->LogSetting.PacketLogConfig[i] = PackGetIntEx(p, "PacketLogConfig", i);
+ }
+}
+void OutRpcHubLog(PACK *p, RPC_HUB_LOG *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddBool(p, "SaveSecurityLog", t->LogSetting.SaveSecurityLog);
+ PackAddInt(p, "SecurityLogSwitchType", t->LogSetting.SecurityLogSwitchType);
+ PackAddBool(p, "SavePacketLog", t->LogSetting.SavePacketLog);
+ PackAddInt(p, "PacketLogSwitchType", t->LogSetting.PacketLogSwitchType);
+ for (i = 0;i < NUM_PACKET_LOG;i++)
+ {
+ PackAddIntEx(p, "PacketLogConfig", t->LogSetting.PacketLogConfig[i], i, NUM_PACKET_LOG);
+ }
+}
+
+// RPC_HUB_ADD_CA
+void InRpcHubAddCa(RPC_HUB_ADD_CA *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_HUB_ADD_CA));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->Cert = PackGetX(p, "Cert");
+}
+void OutRpcHubAddCa(PACK *p, RPC_HUB_ADD_CA *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddX(p, "Cert", t->Cert);
+}
+void FreeRpcHubAddCa(RPC_HUB_ADD_CA *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FreeX(t->Cert);
+}
+
+// RPC_HUB_ENUM_CA
+void InRpcHubEnumCa(RPC_HUB_ENUM_CA *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_HUB_ENUM_CA));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->NumCa = PackGetIndexCount(p, "Key");
+ t->Ca = ZeroMalloc(sizeof(RPC_HUB_ENUM_CA_ITEM) * t->NumCa);
+
+ for (i = 0;i < t->NumCa;i++)
+ {
+ RPC_HUB_ENUM_CA_ITEM *e = &t->Ca[i];
+
+ e->Key = PackGetIntEx(p, "Key", i);
+ PackGetUniStrEx(p, "SubjectName", e->SubjectName, sizeof(e->SubjectName), i);
+ PackGetUniStrEx(p, "IssuerName", e->IssuerName, sizeof(e->IssuerName), i);
+ e->Expires = PackGetInt64Ex(p, "Expires", i);
+ }
+}
+void OutRpcHubEnumCa(PACK *p, RPC_HUB_ENUM_CA *t)
+{
+ UINT i;
+ PackAddStr(p, "HubName", t->HubName);
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < t->NumCa;i++)
+ {
+ RPC_HUB_ENUM_CA_ITEM *e = &t->Ca[i];
+
+ PackAddIntEx(p, "Key", e->Key, i, t->NumCa);
+ PackAddUniStrEx(p, "SubjectName", e->SubjectName, i, t->NumCa);
+ PackAddUniStrEx(p, "IssuerName", e->IssuerName, i, t->NumCa);
+ PackAddInt64Ex(p, "Expires", e->Expires, i, t->NumCa);
+ }
+}
+void FreeRpcHubEnumCa(RPC_HUB_ENUM_CA *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Ca);
+}
+
+// RPC_HUB_GET_CA
+void InRpcHubGetCa(RPC_HUB_GET_CA *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_HUB_GET_CA));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->Key = PackGetInt(p, "Key");
+ t->Cert = PackGetX(p, "Cert");
+}
+void OutRpcHubGetCa(PACK *p, RPC_HUB_GET_CA *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddInt(p, "Key", t->Key);
+ PackAddX(p, "Cert", t->Cert);
+}
+void FreeRpcHubGetCa(RPC_HUB_GET_CA *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FreeX(t->Cert);
+}
+
+// RPC_HUB_DELETE_CA
+void InRpcHubDeleteCa(RPC_HUB_DELETE_CA *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_HUB_DELETE_CA));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->Key = PackGetInt(p, "Key");
+}
+void OutRpcHubDeleteCa(PACK *p, RPC_HUB_DELETE_CA *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddInt(p, "Key", t->Key);
+}
+
+// RPC_CREATE_LINK
+void InRpcCreateLink(RPC_CREATE_LINK *t, PACK *p)
+{
+ BUF *b;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_CREATE_LINK));
+ PackGetStr(p, "HubName_Ex", t->HubName, sizeof(t->HubName));
+ t->Online = PackGetBool(p, "Online");
+ t->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ InRpcClientOption(t->ClientOption, p);
+ t->ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+ InRpcClientAuth(t->ClientAuth, p);
+ InRpcPolicy(&t->Policy, p);
+
+ t->CheckServerCert = PackGetBool(p, "CheckServerCert");
+ b = PackGetBuf(p, "ServerCert");
+ if (b != NULL)
+ {
+ t->ServerCert = BufToX(b, false);
+ FreeBuf(b);
+ }
+}
+void OutRpcCreateLink(PACK *p, RPC_CREATE_LINK *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName_Ex",t->HubName);
+ PackAddBool(p, "Online", t->Online);
+ OutRpcClientOption(p, t->ClientOption);
+ OutRpcClientAuth(p, t->ClientAuth);
+ OutRpcPolicy(p, &t->Policy);
+
+ PackAddBool(p, "CheckServerCert", t->CheckServerCert);
+ if (t->ServerCert != NULL)
+ {
+ BUF *b;
+ b = XToBuf(t->ServerCert, false);
+ PackAddBuf(p, "ServerCert", b);
+ FreeBuf(b);
+ }
+}
+void FreeRpcCreateLink(RPC_CREATE_LINK *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->ServerCert != NULL)
+ {
+ FreeX(t->ServerCert);
+ }
+ Free(t->ClientOption);
+ CiFreeClientAuth(t->ClientAuth);
+}
+
+// RPC_ENUM_LINK
+void InRpcEnumLink(RPC_ENUM_LINK *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_LINK));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->NumLink = PackGetIndexCount(p, "AccountName");
+ t->Links = ZeroMalloc(sizeof(RPC_ENUM_LINK_ITEM) * t->NumLink);
+
+ for (i = 0;i < t->NumLink;i++)
+ {
+ RPC_ENUM_LINK_ITEM *e = &t->Links[i];
+
+ PackGetUniStrEx(p, "AccountName", e->AccountName, sizeof(e->AccountName), i);
+ PackGetStrEx(p, "Hostname", e->Hostname, sizeof(e->Hostname), i);
+ PackGetStrEx(p, "ConnectedHubName", e->HubName, sizeof(e->HubName), i);
+ e->Online = PackGetBoolEx(p, "Online", i);
+ e->ConnectedTime = PackGetInt64Ex(p, "ConnectedTime", i);
+ e->Connected = PackGetBoolEx(p, "Connected", i);
+ e->LastError = PackGetIntEx(p, "LastError", i);
+ }
+}
+void OutRpcEnumLink(PACK *p, RPC_ENUM_LINK *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+
+ for (i = 0;i < t->NumLink;i++)
+ {
+ RPC_ENUM_LINK_ITEM *e = &t->Links[i];
+
+ PackAddUniStrEx(p, "AccountName", e->AccountName, i, t->NumLink);
+ PackAddStrEx(p, "ConnectedHubName", e->HubName, i, t->NumLink);
+ PackAddStrEx(p, "Hostname", e->Hostname, i, t->NumLink);
+ PackAddBoolEx(p, "Online", e->Online, i, t->NumLink);
+ PackAddInt64Ex(p, "ConnectedTime", e->ConnectedTime, i, t->NumLink);
+ PackAddBoolEx(p, "Connected", e->Connected, i, t->NumLink);
+ PackAddIntEx(p, "LastError", e->LastError, i, t->NumLink);
+ }
+}
+void FreeRpcEnumLink(RPC_ENUM_LINK *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Links);
+}
+
+// RPC_LINK_STATUS
+void InRpcLinkStatus(RPC_LINK_STATUS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_LINK_STATUS));
+ PackGetStr(p, "HubName_Ex", t->HubName, sizeof(t->HubName));
+ PackGetUniStr(p, "AccountName", t->AccountName, sizeof(t->AccountName));
+ InRpcClientGetConnectionStatus(&t->Status, p);
+}
+void OutRpcLinkStatus(PACK *p, RPC_LINK_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName_Ex", t->HubName);
+ PackAddUniStr(p, "AccountName", t->AccountName);
+ OutRpcClientGetConnectionStatus(p, &t->Status);
+}
+void FreeRpcLinkStatus(RPC_LINK_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ CiFreeClientGetConnectionStatus(&t->Status);
+}
+
+// RPC_LINK
+void InRpcLink(RPC_LINK *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_LINK));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetUniStr(p, "AccountName", t->AccountName, sizeof(t->AccountName));
+}
+void OutRpcLink(PACK *p, RPC_LINK *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddUniStr(p, "AccountName", t->AccountName);
+}
+
+// RPC_RENAME_LINK
+void InRpcRenameLink(RPC_RENAME_LINK *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_RENAME_LINK));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetUniStr(p, "OldAccountName", t->OldAccountName, sizeof(t->OldAccountName));
+ PackGetUniStr(p, "NewAccountName", t->NewAccountName, sizeof(t->NewAccountName));
+}
+void OutRpcRenameLink(PACK *p, RPC_RENAME_LINK *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddUniStr(p, "OldAccountName", t->OldAccountName);
+ PackAddUniStr(p, "NewAccountName", t->NewAccountName);
+}
+
+// ACCESS
+void InRpcAccessEx(ACCESS *a, PACK *p, UINT index)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(a, sizeof(ACCESS));
+ a->Id = PackGetIntEx(p, "Id", index);
+ PackGetUniStrEx(p, "Note", a->Note, sizeof(a->Note), index);
+ a->Active = PackGetBoolEx(p, "Active", index);
+ a->Priority = PackGetIntEx(p, "Priority", index);
+ a->Discard = PackGetBoolEx(p, "Discard", index);
+ a->SrcIpAddress = PackGetIp32Ex(p, "SrcIpAddress", index);
+ a->SrcSubnetMask = PackGetIp32Ex(p, "SrcSubnetMask", index);
+ a->DestIpAddress = PackGetIp32Ex(p, "DestIpAddress", index);
+ a->DestSubnetMask = PackGetIp32Ex(p, "DestSubnetMask", index);
+ a->Protocol = PackGetIntEx(p, "Protocol", index);
+ a->SrcPortStart = PackGetIntEx(p, "SrcPortStart", index);
+ a->SrcPortEnd = PackGetIntEx(p, "SrcPortEnd", index);
+ a->DestPortStart = PackGetIntEx(p, "DestPortStart", index);
+ a->DestPortEnd = PackGetIntEx(p, "DestPortEnd", index);
+ //a->SrcUsernameHash = PackGetIntEx(p, "SrcUsernameHash", index);
+ PackGetStrEx(p, "SrcUsername", a->SrcUsername, sizeof(a->SrcUsername), index);
+ //a->DestUsernameHash = PackGetIntEx(p, "DestUsernameHash", index);
+ PackGetStrEx(p, "DestUsername", a->DestUsername, sizeof(a->DestUsername), index);
+ a->CheckSrcMac = PackGetBoolEx(p, "CheckSrcMac", index);
+ PackGetDataEx2(p, "SrcMacAddress", a->SrcMacAddress, sizeof(a->SrcMacAddress), index);
+ PackGetDataEx2(p, "SrcMacMask", a->SrcMacMask, sizeof(a->SrcMacMask), index);
+ a->CheckDstMac = PackGetBoolEx(p, "CheckDstMac", index);
+ PackGetDataEx2(p, "DstMacAddress", a->DstMacAddress, sizeof(a->DstMacAddress), index);
+ PackGetDataEx2(p, "DstMacMask", a->DstMacMask, sizeof(a->DstMacMask), index);
+ a->CheckTcpState = PackGetBoolEx(p, "CheckTcpState", index);
+ a->Established = PackGetBoolEx(p, "Established", index);
+ a->Delay = PackGetIntEx(p, "Delay", index);
+ a->Jitter = PackGetIntEx(p, "Jitter", index);
+ a->Loss = PackGetIntEx(p, "Loss", index);
+ a->IsIPv6 = PackGetBoolEx(p, "IsIPv6", index);
+ a->UniqueId = PackGetIntEx(p, "UniqueId", index);
+ PackGetStrEx(p, "RedirectUrl", a->RedirectUrl, sizeof(a->RedirectUrl), index);
+ if (a->IsIPv6)
+ {
+ PackGetIp6AddrEx(p, "SrcIpAddress6", &a->SrcIpAddress6, index);
+ PackGetIp6AddrEx(p, "SrcSubnetMask6", &a->SrcSubnetMask6, index);
+ PackGetIp6AddrEx(p, "DestIpAddress6", &a->DestIpAddress6, index);
+ PackGetIp6AddrEx(p, "DestSubnetMask6", &a->DestSubnetMask6, index);
+ }
+}
+void InRpcAccess(ACCESS *a, PACK *p)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ InRpcAccessEx(a, p, 0);
+}
+void OutRpcAccessEx(PACK *p, ACCESS *a, UINT index, UINT total)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddIntEx(p, "Id", a->Id, index, total);
+ PackAddUniStrEx(p, "Note", a->Note, index, total);
+ PackAddBoolEx(p, "Active", a->Active, index, total);
+ PackAddIntEx(p, "Priority", a->Priority, index, total);
+ PackAddBoolEx(p, "Discard", a->Discard, index, total);
+ if (a->IsIPv6)
+ {
+ PackAddIp32Ex(p, "SrcIpAddress", 0xFDFFFFDF, index, total);
+ PackAddIp32Ex(p, "SrcSubnetMask", 0xFFFFFFFF, index, total);
+ PackAddIp32Ex(p, "DestIpAddress", 0xFDFFFFDF, index, total);
+ PackAddIp32Ex(p, "DestSubnetMask", 0xFFFFFFFF, index, total);
+ }
+ else
+ {
+ PackAddIp32Ex(p, "SrcIpAddress", a->SrcIpAddress, index, total);
+ PackAddIp32Ex(p, "SrcSubnetMask", a->SrcSubnetMask, index, total);
+ PackAddIp32Ex(p, "DestIpAddress", a->DestIpAddress, index, total);
+ PackAddIp32Ex(p, "DestSubnetMask", a->DestSubnetMask, index, total);
+ }
+ PackAddIntEx(p, "Protocol", a->Protocol, index, total);
+ PackAddIntEx(p, "SrcPortStart", a->SrcPortStart, index, total);
+ PackAddIntEx(p, "SrcPortEnd", a->SrcPortEnd, index, total);
+ PackAddIntEx(p, "DestPortStart", a->DestPortStart, index, total);
+ PackAddIntEx(p, "DestPortEnd", a->DestPortEnd, index, total);
+ //PackAddIntEx(p, "SrcUsernameHash", a->SrcUsernameHash, index, total);
+ PackAddStrEx(p, "SrcUsername", a->SrcUsername, index, total);
+ //PackAddIntEx(p, "DestUsernameHash", a->DestUsernameHash, index, total);
+ PackAddStrEx(p, "DestUsername", a->DestUsername, index, total);
+ PackAddBoolEx(p, "CheckSrcMac", a->CheckSrcMac, index, total);
+ PackAddDataEx(p, "SrcMacAddress", a->SrcMacAddress, sizeof(a->SrcMacAddress), index, total);
+ PackAddDataEx(p, "SrcMacMask", a->SrcMacMask, sizeof(a->SrcMacMask), index, total);
+ PackAddBoolEx(p, "CheckDstMac", a->CheckDstMac, index, total);
+ PackAddDataEx(p, "DstMacAddress", a->DstMacAddress, sizeof(a->DstMacAddress), index, total);
+ PackAddDataEx(p, "DstMacMask", a->DstMacMask, sizeof(a->DstMacMask), index, total);
+ PackAddBoolEx(p, "CheckTcpState", a->CheckTcpState, index, total);
+ PackAddBoolEx(p, "Established", a->Established, index, total);
+ PackAddIntEx(p, "Delay", a->Delay, index, total);
+ PackAddIntEx(p, "Jitter", a->Jitter, index, total);
+ PackAddIntEx(p, "Loss", a->Loss, index, total);
+ PackAddBoolEx(p, "IsIPv6", a->IsIPv6, index, total);
+ PackAddIntEx(p, "UniqueId", a->UniqueId, index, total);
+ PackAddStrEx(p, "RedirectUrl", a->RedirectUrl, index, total);
+ if (a->IsIPv6)
+ {
+ PackAddIp6AddrEx(p, "SrcIpAddress6", &a->SrcIpAddress6, index, total);
+ PackAddIp6AddrEx(p, "SrcSubnetMask6", &a->SrcSubnetMask6, index, total);
+ PackAddIp6AddrEx(p, "DestIpAddress6", &a->DestIpAddress6, index, total);
+ PackAddIp6AddrEx(p, "DestSubnetMask6", &a->DestSubnetMask6, index, total);
+ }
+ else
+ {
+ IPV6_ADDR zero;
+
+ Zero(&zero, sizeof(zero));
+
+ PackAddIp6AddrEx(p, "SrcIpAddress6", &zero, index, total);
+ PackAddIp6AddrEx(p, "SrcSubnetMask6", &zero, index, total);
+ PackAddIp6AddrEx(p, "DestIpAddress6", &zero, index, total);
+ PackAddIp6AddrEx(p, "DestSubnetMask6", &zero, index, total);
+ }
+}
+void OutRpcAccess(PACK *p, ACCESS *a)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ OutRpcAccessEx(p, a, 0, 1);
+}
+
+// RPC_ENUM_ACCESS_LIST
+void InRpcEnumAccessList(RPC_ENUM_ACCESS_LIST *a, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(a, sizeof(RPC_ENUM_ACCESS_LIST));
+ PackGetStr(p, "HubName", a->HubName, sizeof(a->HubName));
+ a->NumAccess = PackGetIndexCount(p, "Protocol");
+ a->Accesses = ZeroMalloc(sizeof(ACCESS) * a->NumAccess);
+
+ for (i = 0;i < a->NumAccess;i++)
+ {
+ ACCESS *e = &a->Accesses[i];
+
+ InRpcAccessEx(e, p, i);
+ }
+}
+void OutRpcEnumAccessList(PACK *p, RPC_ENUM_ACCESS_LIST *a)
+{
+ UINT i;
+ PackAddStr(p, "HubName", a->HubName);
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < a->NumAccess;i++)
+ {
+ ACCESS *e = &a->Accesses[i];
+
+ OutRpcAccessEx(p, e, i, a->NumAccess);
+ }
+}
+void FreeRpcEnumAccessList(RPC_ENUM_ACCESS_LIST *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ Free(a->Accesses);
+}
+
+// AUTHDATA
+void *InRpcAuthData(PACK *p, UINT *authtype)
+{
+ wchar_t tmp[MAX_SIZE];
+ AUTHPASSWORD *pw;
+ AUTHUSERCERT *usercert;
+ AUTHROOTCERT *rootcert;
+ AUTHRADIUS *radius;
+ AUTHNT *nt;
+ BUF *b;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+ if (authtype == NULL)
+ {
+ return NULL;
+ }
+
+ *authtype = PackGetInt(p, "AuthType");
+
+ switch (*authtype)
+ {
+ case AUTHTYPE_PASSWORD:
+ pw = ZeroMalloc(sizeof(AUTHPASSWORD));
+ PackGetData2(p, "HashedKey", pw->HashedKey, sizeof(pw->HashedKey));
+ PackGetData2(p, "NtLmSecureHash", pw->NtLmSecureHash, sizeof(pw->NtLmSecureHash));
+ return pw;
+
+ case AUTHTYPE_USERCERT:
+ usercert = ZeroMalloc(sizeof(AUTHUSERCERT));
+ usercert->UserX = PackGetX(p, "UserX");
+ return usercert;
+
+ case AUTHTYPE_ROOTCERT:
+ rootcert = ZeroMalloc(sizeof(AUTHROOTCERT));
+ b = PackGetBuf(p, "Serial");
+ if (b != NULL)
+ {
+ rootcert->Serial = NewXSerial(b->Buf, b->Size);
+ FreeBuf(b);
+ }
+ if (PackGetUniStr(p, "CommonName", tmp, sizeof(tmp)))
+ {
+ rootcert->CommonName = CopyUniStr(tmp);
+ }
+ return rootcert;
+
+ case AUTHTYPE_RADIUS:
+ radius = ZeroMalloc(sizeof(AUTHRADIUS));
+ if (PackGetUniStr(p, "RadiusUsername", tmp, sizeof(tmp)))
+ {
+ radius->RadiusUsername = CopyUniStr(tmp);
+ }
+ else
+ {
+ radius->RadiusUsername = CopyUniStr(L"");
+ }
+ return radius;
+
+ case AUTHTYPE_NT:
+ nt = ZeroMalloc(sizeof(AUTHNT));
+ if (PackGetUniStr(p, "NtUsername", tmp, sizeof(tmp)))
+ {
+ nt->NtUsername = CopyUniStr(tmp);
+ }
+ else
+ {
+ nt->NtUsername = CopyUniStr(L"");
+ }
+ return nt;
+ }
+
+ return NULL;
+}
+void OutRpcAuthData(PACK *p, void *authdata, UINT authtype)
+{
+ AUTHPASSWORD *pw = authdata;
+ AUTHUSERCERT *usercert = authdata;
+ AUTHROOTCERT *rootcert = authdata;
+ AUTHRADIUS *radius = authdata;
+ AUTHNT *nt = authdata;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "AuthType", authtype);
+
+ switch (authtype)
+ {
+ case AUTHTYPE_PASSWORD:
+ PackAddData(p, "HashedKey", pw->HashedKey, sizeof(pw->HashedKey));
+ PackAddData(p, "NtLmSecureHash", pw->NtLmSecureHash, sizeof(pw->NtLmSecureHash));
+ break;
+
+ case AUTHTYPE_USERCERT:
+ PackAddX(p, "UserX", usercert->UserX);
+ break;
+
+ case AUTHTYPE_ROOTCERT:
+ if (rootcert->Serial != NULL)
+ {
+ PackAddData(p, "Serial", rootcert->Serial->data, rootcert->Serial->size);
+ }
+ if (rootcert->CommonName != NULL)
+ {
+ PackAddUniStr(p, "CommonName", rootcert->CommonName);
+ }
+ break;
+
+ case AUTHTYPE_RADIUS:
+ PackAddUniStr(p, "RadiusUsername", radius->RadiusUsername);
+ break;
+
+ case AUTHTYPE_NT:
+ PackAddUniStr(p, "NtUsername", nt->NtUsername);
+ break;
+ }
+}
+void FreeRpcAuthData(void *authdata, UINT authtype)
+{
+ FreeAuthData(authtype, authdata);
+}
+
+// RPC_SET_USER
+void InRpcSetUser(RPC_SET_USER *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_SET_USER));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+ PackGetStr(p, "GroupName", t->GroupName, sizeof(t->GroupName));
+ PackGetUniStr(p, "Realname", t->Realname, sizeof(t->Realname));
+ PackGetUniStr(p, "Note", t->Note, sizeof(t->Note));
+ t->CreatedTime = PackGetInt64(p, "CreatedTime");
+ t->UpdatedTime = PackGetInt64(p, "UpdatedTime");
+ t->ExpireTime = PackGetInt64(p, "ExpireTime");
+ t->AuthData = InRpcAuthData(p, &t->AuthType);
+ t->NumLogin = PackGetInt(p, "NumLogin");
+ InRpcTraffic(&t->Traffic, p);
+
+ if (PackGetBool(p, "UsePolicy"))
+ {
+ t->Policy = ZeroMalloc(sizeof(POLICY));
+ InRpcPolicy(t->Policy, p);
+ }
+}
+
+void OutRpcSetUser(PACK *p, RPC_SET_USER *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddStr(p, "Name", t->Name);
+ PackAddStr(p, "GroupName", t->GroupName);
+ PackAddUniStr(p, "Realname", t->Realname);
+ PackAddUniStr(p, "Note", t->Note);
+ PackAddInt64(p, "CreatedTime", t->CreatedTime);
+ PackAddInt64(p, "UpdatedTime", t->UpdatedTime);
+ PackAddInt64(p, "ExpireTime", t->ExpireTime);
+ OutRpcAuthData(p, t->AuthData, t->AuthType);
+ PackAddInt(p, "NumLogin", t->NumLogin);
+ OutRpcTraffic(p, &t->Traffic);
+
+ if (t->Policy != NULL)
+ {
+ PackAddBool(p, "UsePolicy", true);
+ OutRpcPolicy(p, t->Policy);
+ }
+}
+void FreeRpcSetUser(RPC_SET_USER *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FreeRpcAuthData(t->AuthData, t->AuthType);
+ if (t->Policy)
+ {
+ Free(t->Policy);
+ }
+}
+
+// RPC_ENUM_USER
+void InRpcEnumUser(RPC_ENUM_USER *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_USER));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->NumUser = PackGetIndexCount(p, "Name");
+ t->Users = ZeroMalloc(sizeof(RPC_ENUM_USER_ITEM) * t->NumUser);
+
+ for (i = 0;i < t->NumUser;i++)
+ {
+ RPC_ENUM_USER_ITEM *e = &t->Users[i];
+
+ PackGetStrEx(p, "Name", e->Name, sizeof(e->Name), i);
+ PackGetStrEx(p, "GroupName", e->GroupName, sizeof(e->GroupName), i);
+ PackGetUniStrEx(p, "Realname", e->Realname, sizeof(e->Realname), i);
+ PackGetUniStrEx(p, "Note", e->Note, sizeof(e->Note), i);
+ e->AuthType = PackGetIntEx(p, "AuthType", i);
+ e->LastLoginTime = PackGetInt64Ex(p, "LastLoginTime", i);
+ e->NumLogin = PackGetIntEx(p, "NumLogin", i);
+ e->DenyAccess = PackGetBoolEx(p, "DenyAccess", i);
+
+ e->IsTrafficFilled = PackGetBoolEx(p, "IsTrafficFilled", i);
+ InRpcTrafficEx(&e->Traffic, p, i);
+
+ e->IsExpiresFilled = PackGetBoolEx(p, "IsExpiresFilled", i);
+ e->Expires = PackGetInt64Ex(p, "Expires", i);
+ }
+}
+void OutRpcEnumUser(PACK *p, RPC_ENUM_USER *t)
+{
+ UINT i;
+ PackAddStr(p, "HubName", t->HubName);
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < t->NumUser;i++)
+ {
+ RPC_ENUM_USER_ITEM *e = &t->Users[i];
+
+ PackAddStrEx(p, "Name", e->Name, i, t->NumUser);
+ PackAddStrEx(p, "GroupName", e->GroupName, i, t->NumUser);
+ PackAddUniStrEx(p, "Realname", e->Realname, i, t->NumUser);
+ PackAddUniStrEx(p, "Note", e->Note, i, t->NumUser);
+ PackAddIntEx(p, "AuthType", e->AuthType, i, t->NumUser);
+ PackAddInt64Ex(p, "LastLoginTime", e->LastLoginTime, i, t->NumUser);
+ PackAddIntEx(p, "NumLogin", e->NumLogin, i, t->NumUser);
+ PackAddBoolEx(p, "DenyAccess", e->DenyAccess, i, t->NumUser);
+
+ PackAddBoolEx(p, "IsTrafficFilled", e->IsTrafficFilled, i, t->NumUser);
+ OutRpcTrafficEx(&e->Traffic, p, i, t->NumUser);
+
+ PackAddBoolEx(p, "IsExpiresFilled", e->IsExpiresFilled, i, t->NumUser);
+ PackAddInt64Ex(p, "Expires", e->Expires, i, t->NumUser);
+ }
+}
+void FreeRpcEnumUser(RPC_ENUM_USER *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Users);
+}
+
+// RPC_SET_GROUP
+void InRpcSetGroup(RPC_SET_GROUP *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_SET_GROUP));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+ PackGetUniStr(p, "Realname", t->Realname, sizeof(t->Realname));
+ PackGetUniStr(p, "Note", t->Note, sizeof(t->Note));
+ InRpcTraffic(&t->Traffic, p);
+
+ if (PackGetBool(p, "UsePolicy"))
+ {
+ t->Policy = ZeroMalloc(sizeof(POLICY));
+ InRpcPolicy(t->Policy, p);
+ }
+}
+void OutRpcSetGroup(PACK *p, RPC_SET_GROUP *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddStr(p, "Name", t->Name);
+ PackAddUniStr(p, "Realname", t->Realname);
+ PackAddUniStr(p, "Note", t->Note);
+ OutRpcTraffic(p, &t->Traffic);
+
+ if (t->Policy != NULL)
+ {
+ PackAddBool(p, "UsePolicy", true);
+ OutRpcPolicy(p, t->Policy);
+ }
+}
+void FreeRpcSetGroup(RPC_SET_GROUP *t)
+{
+ Free(t->Policy);
+}
+
+// RPC_ENUM_GROUP
+void InRpcEnumGroup(RPC_ENUM_GROUP *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_GROUP));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->NumGroup = PackGetIndexCount(p, "Name");
+ t->Groups = ZeroMalloc(sizeof(RPC_ENUM_GROUP_ITEM) * t->NumGroup);
+
+ for (i = 0;i < t->NumGroup;i++)
+ {
+ RPC_ENUM_GROUP_ITEM *e = &t->Groups[i];
+
+ PackGetStrEx(p, "Name", e->Name, sizeof(e->Name), i);
+ PackGetUniStrEx(p, "Realname", e->Realname, sizeof(e->Realname), i);
+ PackGetUniStrEx(p, "Note", e->Note, sizeof(e->Note), i);
+ e->NumUsers = PackGetIntEx(p, "NumUsers", i);
+ e->DenyAccess = PackGetBoolEx(p, "DenyAccess", i);
+ }
+}
+void OutRpcEnumGroup(PACK *p, RPC_ENUM_GROUP *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+
+ for (i = 0;i < t->NumGroup;i++)
+ {
+ RPC_ENUM_GROUP_ITEM *e = &t->Groups[i];
+
+ PackAddStrEx(p, "Name", e->Name, i, t->NumGroup);
+ PackAddUniStrEx(p, "Realname", e->Realname, i, t->NumGroup);
+ PackAddUniStrEx(p, "Note", e->Note, i, t->NumGroup);
+ PackAddIntEx(p, "NumUsers", e->NumUsers, i, t->NumGroup);
+ PackAddBoolEx(p, "DenyAccess", e->DenyAccess, i, t->NumGroup);
+ }
+}
+void FreeRpcEnumGroup(RPC_ENUM_GROUP *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Groups);
+}
+
+// RPC_DELETE_USER
+void InRpcDeleteUser(RPC_DELETE_USER *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_DELETE_USER));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+}
+void OutRpcDeleteUser(PACK *p, RPC_DELETE_USER *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddStr(p, "Name", t->Name);
+}
+
+// RPC_ENUM_SESSION
+void InRpcEnumSession(RPC_ENUM_SESSION *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_SESSION));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->NumSession = PackGetIndexCount(p, "Name");
+ t->Sessions = ZeroMalloc(sizeof(RPC_ENUM_SESSION_ITEM) * t->NumSession);
+
+ for (i = 0;i < t->NumSession;i++)
+ {
+ RPC_ENUM_SESSION_ITEM *e = &t->Sessions[i];
+
+ PackGetStrEx(p, "Name", e->Name, sizeof(e->Name), i);
+ PackGetStrEx(p, "Username", e->Username, sizeof(e->Username), i);
+ e->Ip = PackGetIntEx(p, "Ip", i);
+ PackGetStrEx(p, "Hostname", e->Hostname, sizeof(e->Hostname), i);
+ e->MaxNumTcp = PackGetIntEx(p, "MaxNumTcp", i);
+ e->CurrentNumTcp = PackGetIntEx(p, "CurrentNumTcp", i);
+ e->PacketSize = PackGetInt64Ex(p, "PacketSize", i);
+ e->PacketNum = PackGetInt64Ex(p, "PacketNum", i);
+ e->RemoteSession = PackGetBoolEx(p, "RemoteSession", i);
+ e->LinkMode = PackGetBoolEx(p, "LinkMode", i);
+ e->SecureNATMode = PackGetBoolEx(p, "SecureNATMode", i);
+ e->BridgeMode = PackGetBoolEx(p, "BridgeMode", i);
+ e->Layer3Mode = PackGetBoolEx(p, "Layer3Mode", i);
+ e->Client_BridgeMode = PackGetBoolEx(p, "Client_BridgeMode", i);
+ e->Client_MonitorMode = PackGetBoolEx(p, "Client_MonitorMode", i);
+ PackGetStrEx(p, "RemoteHostname", e->RemoteHostname, sizeof(e->RemoteHostname), i);
+ e->VLanId = PackGetIntEx(p, "VLanId", i);
+ PackGetDataEx2(p, "UniqueId", e->UniqueId, sizeof(e->UniqueId), i);
+ }
+}
+void OutRpcEnumSession(PACK *p, RPC_ENUM_SESSION *t)
+{
+ UINT i;
+ PackAddStr(p, "HubName", t->HubName);
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < t->NumSession;i++)
+ {
+ RPC_ENUM_SESSION_ITEM *e = &t->Sessions[i];
+
+ PackAddStrEx(p, "Name", e->Name, i, t->NumSession);
+ PackAddStrEx(p, "Username", e->Username, i, t->NumSession);
+ PackAddIp32Ex(p, "Ip", e->Ip, i, t->NumSession);
+ PackAddStrEx(p, "Hostname", e->Hostname, i, t->NumSession);
+ PackAddIntEx(p, "MaxNumTcp", e->MaxNumTcp, i, t->NumSession);
+ PackAddIntEx(p, "CurrentNumTcp", e->CurrentNumTcp, i, t->NumSession);
+ PackAddInt64Ex(p, "PacketSize", e->PacketSize, i, t->NumSession);
+ PackAddInt64Ex(p, "PacketNum", e->PacketNum, i, t->NumSession);
+ PackAddBoolEx(p, "RemoteSession", e->RemoteSession, i, t->NumSession);
+ PackAddStrEx(p, "RemoteHostname", e->RemoteHostname, i, t->NumSession);
+ PackAddBoolEx(p, "LinkMode", e->LinkMode, i, t->NumSession);
+ PackAddBoolEx(p, "SecureNATMode", e->SecureNATMode, i, t->NumSession);
+ PackAddBoolEx(p, "BridgeMode", e->BridgeMode, i, t->NumSession);
+ PackAddBoolEx(p, "Layer3Mode", e->Layer3Mode, i, t->NumSession);
+ PackAddBoolEx(p, "Client_BridgeMode", e->Client_BridgeMode, i, t->NumSession);
+ PackAddBoolEx(p, "Client_MonitorMode", e->Client_MonitorMode, i, t->NumSession);
+ PackAddIntEx(p, "VLanId", e->VLanId, i, t->NumSession);
+ PackAddDataEx(p, "UniqueId", e->UniqueId, sizeof(e->UniqueId), i, t->NumSession);
+ }
+}
+void FreeRpcEnumSession(RPC_ENUM_SESSION *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Sessions);
+}
+
+// RPC_KEY_PAIR
+void InRpcKeyPair(RPC_KEY_PAIR *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ t->Cert = PackGetX(p, "Cert");
+ t->Key = PackGetK(p, "Key");
+}
+void OutRpcKeyPair(PACK *p, RPC_KEY_PAIR *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddX(p, "Cert", t->Cert);
+ PackAddK(p, "Key", t->Key);
+}
+void FreeRpcKeyPair(RPC_KEY_PAIR *t)
+{
+ FreeX(t->Cert);
+ FreeK(t->Key);
+}
+
+// NODE_INFO
+void InRpcNodeInfo(NODE_INFO *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(NODE_INFO));
+ PackGetStr(p, "ClientProductName", t->ClientProductName, sizeof(t->ClientProductName));
+ PackGetStr(p, "ServerProductName", t->ServerProductName, sizeof(t->ServerProductName));
+ PackGetStr(p, "ClientOsName", t->ClientOsName, sizeof(t->ClientOsName));
+ PackGetStr(p, "ClientOsVer", t->ClientOsVer, sizeof(t->ClientOsVer));
+ PackGetStr(p, "ClientOsProductId", t->ClientOsProductId, sizeof(t->ClientOsProductId));
+ PackGetStr(p, "ClientHostname", t->ClientHostname, sizeof(t->ClientHostname));
+ PackGetStr(p, "ServerHostname", t->ServerHostname, sizeof(t->ServerHostname));
+ PackGetStr(p, "ProxyHostname", t->ProxyHostname, sizeof(t->ProxyHostname));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetData2(p, "UniqueId", t->UniqueId, sizeof(t->UniqueId));
+
+ t->ClientProductVer = PackGetInt(p, "ClientProductVer");
+ t->ClientProductBuild = PackGetInt(p, "ClientProductBuild");
+ t->ServerProductVer = PackGetInt(p, "ServerProductVer");
+ t->ServerProductBuild = PackGetInt(p, "ServerProductBuild");
+ t->ClientIpAddress = PackGetIp32(p, "ClientIpAddress");
+ PackGetData2(p, "ClientIpAddress6", t->ClientIpAddress6, sizeof(t->ClientIpAddress6));
+ t->ClientPort = PackGetInt(p, "ClientPort");
+ t->ServerIpAddress = PackGetIp32(p, "ServerIpAddress");
+ PackGetData2(p, "ServerIpAddress6", t->ServerIpAddress6, sizeof(t->ServerIpAddress6));
+ t->ServerPort = PackGetInt(p, "ServerPort2");
+ t->ProxyIpAddress = PackGetIp32(p, "ProxyIpAddress");
+ PackGetData2(p, "ProxyIpAddress6", t->ProxyIpAddress6, sizeof(t->ProxyIpAddress6));
+ t->ProxyPort = PackGetInt(p, "ProxyPort");
+}
+void OutRpcNodeInfo(PACK *p, NODE_INFO *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "ClientProductName", t->ClientProductName);
+ PackAddStr(p, "ServerProductName", t->ServerProductName);
+ PackAddStr(p, "ClientOsName", t->ClientOsName);
+ PackAddStr(p, "ClientOsVer", t->ClientOsVer);
+ PackAddStr(p, "ClientOsProductId", t->ClientOsProductId);
+ PackAddStr(p, "ClientHostname", t->ClientHostname);
+ PackAddStr(p, "ServerHostname", t->ServerHostname);
+ PackAddStr(p, "ProxyHostname", t->ProxyHostname);
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddData(p, "UniqueId", t->UniqueId, sizeof(t->UniqueId));
+
+ PackAddInt(p, "ClientProductVer", t->ClientProductVer);
+ PackAddInt(p, "ClientProductBuild", t->ClientProductBuild);
+ PackAddInt(p, "ServerProductVer", t->ServerProductVer);
+ PackAddInt(p, "ServerProductBuild", t->ServerProductBuild);
+ PackAddIp32(p, "ClientIpAddress", t->ClientIpAddress);
+ PackAddData(p, "ClientIpAddress6", t->ClientIpAddress6, sizeof(t->ClientIpAddress6));
+ PackAddInt(p, "ClientPort", t->ClientPort);
+ PackAddIp32(p, "ServerIpAddress", t->ServerIpAddress);
+ PackAddData(p, "ServerIpAddress6", t->ServerIpAddress6, sizeof(t->ServerIpAddress6));
+ PackAddInt(p, "ServerPort2", t->ServerPort);
+ PackAddIp32(p, "ProxyIpAddress", t->ProxyIpAddress);
+ PackAddData(p, "ProxyIpAddress6", t->ProxyIpAddress6, sizeof(t->ProxyIpAddress6));
+ PackAddInt(p, "ProxyPort", t->ProxyPort);
+}
+
+// RPC_SESSION_STATUS
+void InRpcSessionStatus(RPC_SESSION_STATUS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_SESSION_STATUS));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+ PackGetStr(p, "Username", t->Username, sizeof(t->Username));
+ PackGetStr(p, "GroupName", t->GroupName, sizeof(t->GroupName));
+ PackGetStr(p, "RealUsername", t->RealUsername, sizeof(t->RealUsername));
+ t->ClientIp = PackGetIp32(p, "SessionStatus_ClientIp");
+ PackGetData2(p, "SessionStatus_ClientIp6", t->ClientIp6, sizeof(t->ClientIp6));
+ PackGetStr(p, "SessionStatus_ClientHostName", t->ClientHostName, sizeof(t->ClientHostName));
+
+ InRpcClientGetConnectionStatus(&t->Status, p);
+ InRpcNodeInfo(&t->NodeInfo, p);
+}
+void OutRpcSessionStatus(PACK *p, RPC_SESSION_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddStr(p, "Name", t->Name);
+ PackAddStr(p, "Username", t->Username);
+ PackAddStr(p, "GroupName", t->GroupName);
+ PackAddStr(p, "RealUsername", t->RealUsername);
+ PackAddIp32(p, "SessionStatus_ClientIp", t->ClientIp);
+ PackAddData(p, "SessionStatus_ClientIp6", t->ClientIp6, sizeof(t->ClientIp6));
+ PackAddStr(p, "SessionStatus_ClientHostName", t->ClientHostName);
+
+ OutRpcClientGetConnectionStatus(p, &t->Status);
+ OutRpcNodeInfo(p, &t->NodeInfo);
+}
+void FreeRpcSessionStatus(RPC_SESSION_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ CiFreeClientGetConnectionStatus(&t->Status);
+}
+
+// RPC_DELETE_SESSION
+void InRpcDeleteSession(RPC_DELETE_SESSION *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_DELETE_SESSION));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ PackGetStr(p, "Name", t->Name, sizeof(t->Name));
+}
+void OutRpcDeleteSession(PACK *p, RPC_DELETE_SESSION *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddStr(p, "Name", t->Name);
+}
+
+// RPC_ENUM_MAC_TABLE
+void InRpcEnumMacTable(RPC_ENUM_MAC_TABLE *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_MAC_TABLE));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->NumMacTable = PackGetIndexCount(p, "SessionName");
+ t->MacTables = ZeroMalloc(sizeof(RPC_ENUM_MAC_TABLE_ITEM) * t->NumMacTable);
+
+ for (i = 0;i < t->NumMacTable;i++)
+ {
+ RPC_ENUM_MAC_TABLE_ITEM *e = &t->MacTables[i];
+
+ e->Key = PackGetIntEx(p, "Key", i);
+ PackGetStrEx(p, "SessionName", e->SessionName, sizeof(e->SessionName), i);
+ PackGetDataEx2(p, "MacAddress", e->MacAddress, sizeof(e->MacAddress), i);
+ e->VlanId = PackGetIntEx(p, "VlanId", i);
+ e->CreatedTime = PackGetInt64Ex(p, "CreatedTime", i);
+ e->UpdatedTime = PackGetInt64Ex(p, "UpdatedTime", i);
+ e->RemoteItem = PackGetBoolEx(p, "RemoteItem", i);
+ PackGetStrEx(p, "RemoteHostname", e->RemoteHostname, sizeof(e->RemoteHostname), i);
+ }
+}
+void OutRpcEnumMacTable(PACK *p, RPC_ENUM_MAC_TABLE *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+
+ for (i = 0;i < t->NumMacTable;i++)
+ {
+ RPC_ENUM_MAC_TABLE_ITEM *e = &t->MacTables[i];
+
+ PackAddIntEx(p, "Key", e->Key, i, t->NumMacTable);
+ PackAddStrEx(p, "SessionName", e->SessionName, i, t->NumMacTable);
+ PackAddDataEx(p, "MacAddress", e->MacAddress, sizeof(e->MacAddress), i, t->NumMacTable);
+ PackAddIntEx(p, "VlanId", e->VlanId, i, t->NumMacTable);
+ PackAddInt64Ex(p, "CreatedTime", e->CreatedTime, i, t->NumMacTable);
+ PackAddInt64Ex(p, "UpdatedTime", e->UpdatedTime, i, t->NumMacTable);
+ PackAddBoolEx(p, "RemoteItem", e->RemoteItem, i, t->NumMacTable);
+ PackAddStrEx(p, "RemoteHostname", e->RemoteHostname, i, t->NumMacTable);
+ }
+}
+void FreeRpcEnumMacTable(RPC_ENUM_MAC_TABLE *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->MacTables);
+}
+
+// RPC_ENUM_IP_TABLE
+void InRpcEnumIpTable(RPC_ENUM_IP_TABLE *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_IP_TABLE));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->NumIpTable = PackGetIndexCount(p, "SessionName");
+ t->IpTables = ZeroMalloc(sizeof(RPC_ENUM_IP_TABLE_ITEM) * t->NumIpTable);
+
+ for (i = 0;i < t->NumIpTable;i++)
+ {
+ RPC_ENUM_IP_TABLE_ITEM *e = &t->IpTables[i];
+
+ e->Key = PackGetIntEx(p, "Key", i);
+ PackGetStrEx(p, "SessionName", e->SessionName, sizeof(e->SessionName), i);
+ e->Ip = PackGetIp32Ex(p, "Ip", i);
+ if (PackGetIpEx(p, "IpV6", &e->IpV6, i) == false)
+ {
+ UINTToIP(&e->IpV6, e->Ip);
+ }
+ e->DhcpAllocated = PackGetBoolEx(p, "DhcpAllocated", i);
+ e->CreatedTime = PackGetInt64Ex(p, "CreatedTime", i);
+ e->UpdatedTime = PackGetInt64Ex(p, "UpdatedTime", i);
+ e->RemoteItem = PackGetBoolEx(p, "RemoteItem", i);
+ PackGetStrEx(p, "RemoteHostname", e->RemoteHostname, sizeof(e->RemoteHostname), i);
+ }
+}
+void OutRpcEnumIpTable(PACK *p, RPC_ENUM_IP_TABLE *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+
+ for (i = 0;i < t->NumIpTable;i++)
+ {
+ RPC_ENUM_IP_TABLE_ITEM *e = &t->IpTables[i];
+
+ PackAddIntEx(p, "Key", e->Key, i, t->NumIpTable);
+ PackAddStrEx(p, "SessionName", e->SessionName, i, t->NumIpTable);
+ PackAddIp32Ex(p, "Ip", e->Ip, i, t->NumIpTable);
+ PackAddIpEx(p, "IpV6", &e->IpV6, i, t->NumIpTable);
+ PackAddBoolEx(p, "DhcpAllocated", e->DhcpAllocated, i, t->NumIpTable);
+ PackAddInt64Ex(p, "CreatedTime", e->CreatedTime, i, t->NumIpTable);
+ PackAddInt64Ex(p, "UpdatedTime", e->UpdatedTime, i, t->NumIpTable);
+ PackAddBoolEx(p, "RemoteItem", e->RemoteItem, i, t->NumIpTable);
+ PackAddStrEx(p, "RemoteHostname", e->RemoteHostname, i, t->NumIpTable);
+ }
+}
+void FreeRpcEnumIpTable(RPC_ENUM_IP_TABLE *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->IpTables);
+}
+
+// RPC_DELETE_TABLE
+void InRpcDeleteTable(RPC_DELETE_TABLE *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_DELETE_TABLE));
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->Key = PackGetInt(p, "Key");
+}
+void OutRpcDeleteTable(PACK *p, RPC_DELETE_TABLE *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddInt(p, "Key", t->Key);
+}
+
+// Adjoin RPC_ENUM_IP_TABLE
+void AdjoinRpcEnumIpTable(RPC_ENUM_IP_TABLE *dest, RPC_ENUM_IP_TABLE *src)
+{
+ UINT old_num;
+ UINT i, n;
+ if (dest == NULL || src == NULL)
+ {
+ return;
+ }
+
+ if (src->NumIpTable == 0)
+ {
+ return;
+ }
+
+ old_num = dest->NumIpTable;
+ dest->NumIpTable += src->NumIpTable;
+ dest->IpTables = ReAlloc(dest->IpTables, sizeof(RPC_ENUM_IP_TABLE_ITEM) * dest->NumIpTable);
+
+ n = 0;
+ for (i = old_num;i < dest->NumIpTable;i++)
+ {
+ Copy(&dest->IpTables[i], &src->IpTables[n++], sizeof(RPC_ENUM_IP_TABLE_ITEM));
+ }
+}
+
+// Adjoin RPC_ENUM_MAC_TABLE
+void AdjoinRpcEnumMacTable(RPC_ENUM_MAC_TABLE *dest, RPC_ENUM_MAC_TABLE *src)
+{
+ UINT old_num;
+ UINT i, n;
+ if (dest == NULL || src == NULL)
+ {
+ return;
+ }
+
+ if (src->NumMacTable == 0)
+ {
+ return;
+ }
+
+ old_num = dest->NumMacTable;
+ dest->NumMacTable += src->NumMacTable;
+ dest->MacTables = ReAlloc(dest->MacTables, sizeof(RPC_ENUM_MAC_TABLE_ITEM) * dest->NumMacTable);
+
+ n = 0;
+ for (i = old_num;i < dest->NumMacTable;i++)
+ {
+ Copy(&dest->MacTables[i], &src->MacTables[n++], sizeof(RPC_ENUM_MAC_TABLE_ITEM));
+ }
+}
+
+// Adjoin RPC_ENUM_SESSION
+void AdjoinRpcEnumSession(RPC_ENUM_SESSION *dest, RPC_ENUM_SESSION *src)
+{
+ UINT old_num;
+ UINT i, n;
+ if (dest == NULL || src == NULL)
+ {
+ return;
+ }
+
+ if (src->NumSession == 0)
+ {
+ return;
+ }
+
+ old_num = dest->NumSession;
+ dest->NumSession += src->NumSession;
+ dest->Sessions = ReAlloc(dest->Sessions, sizeof(RPC_ENUM_SESSION_ITEM) * dest->NumSession);
+
+ n = 0;
+ for (i = old_num;i < dest->NumSession;i++)
+ {
+ Copy(&dest->Sessions[i], &src->Sessions[n++], sizeof(RPC_ENUM_SESSION_ITEM));
+ }
+}
+
+// RPC_KEEP
+void InRpcKeep(RPC_KEEP *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_KEEP));
+ t->UseKeepConnect = PackGetBool(p, "UseKeepConnect");
+ PackGetStr(p, "KeepConnectHost", t->KeepConnectHost, sizeof(t->KeepConnectHost));
+ t->KeepConnectPort = PackGetInt(p, "KeepConnectPort");
+ t->KeepConnectProtocol = PackGetInt(p, "KeepConnectProtocol");
+ t->KeepConnectInterval = PackGetInt(p, "KeepConnectInterval");
+}
+void OutRpcKeep(PACK *p, RPC_KEEP *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "UseKeepConnect", t->UseKeepConnect);
+ PackAddStr(p, "KeepConnectHost", t->KeepConnectHost);
+ PackAddInt(p, "KeepConnectPort", t->KeepConnectPort);
+ PackAddInt(p, "KeepConnectProtocol", t->KeepConnectProtocol);
+ PackAddInt(p, "KeepConnectInterval", t->KeepConnectInterval);
+}
+
+// test RPC function
+UINT StTest(ADMIN *a, RPC_TEST *t)
+{
+ Format(t->StrValue, sizeof(t->StrValue), "%u", t->IntValue);
+
+ return ERR_NO_ERROR;
+}
+
+// RPC_TEST
+void InRpcTest(RPC_TEST *t, PACK *p)
+{
+ Zero(t, sizeof(RPC_TEST));
+ t->IntValue = PackGetInt(p, "IntValue");
+ t->Int64Value = PackGetInt64(p, "Int64Value");
+ PackGetStr(p, "StrValue", t->StrValue, sizeof(t->StrValue));
+ PackGetUniStr(p, "UniStrValue", t->UniStrValue, sizeof(t->UniStrValue));
+}
+void OutRpcTest(PACK *p, RPC_TEST *t)
+{
+ PackAddInt(p, "IntValue", t->IntValue);
+ PackAddInt64(p, "Int64Value", t->Int64Value);
+ PackAddStr(p, "StrValue", t->StrValue);
+ PackAddUniStr(p, "UniStrValue", t->UniStrValue);
+}
+void FreeRpcTest(RPC_TEST *t)
+{
+}
+
+// Admin RPC call
+PACK *AdminCall(RPC *rpc, char *function_name, PACK *p)
+{
+ // Validate arguments
+ if (rpc == NULL || function_name == NULL)
+ {
+ return NULL;
+ }
+ if (p == NULL)
+ {
+ p = NewPack();
+ }
+
+// Debug("Admin RPC Call: %s\n", function_name);
+
+ return RpcCall(rpc, function_name, p);
+}
+
+// Check whether the source IP address is permitted to admin connection
+bool CheckAdminSourceAddress(SOCK *sock, char *hubname)
+{
+ BUF *b;
+ char *s;
+ bool ok = false;
+ // Validate arguments
+ if (sock == NULL)
+ {
+ return false;
+ }
+
+ b = ReadDump(ADMINIP_TXT);
+ if (b == NULL)
+ {
+ return true;
+ }
+
+ while (true)
+ {
+ UINT i;
+ TOKEN_LIST *t;
+ IP ip;
+ s = CfgReadNextLine(b);
+
+ if (s == NULL)
+ {
+ break;
+ }
+
+ Trim(s);
+
+ i = SearchStrEx(s, "//", 0, false);
+ if (i != INFINITE)
+ {
+ s[i] = 0;
+ }
+
+ i = SearchStrEx(s, "#", 0, false);
+ if (i != INFINITE)
+ {
+ s[i] = 0;
+ }
+
+ Trim(s);
+
+ t = ParseToken(s, " \t");
+ if (t != NULL)
+ {
+ if (t->NumTokens >= 1)
+ {
+ if (t->NumTokens == 1 || StrCmpi(hubname, t->Token[1]) == 0)
+ {
+ if (StrToIP(&ip, t->Token[0]))
+ {
+ if (CmpIpAddr(&sock->RemoteIP, &ip) == 0)
+ {
+ ok = true;
+ }
+ }
+
+ if (StrCmpi(t->Token[0], "*") == 0)
+ {
+ ok = true;
+ }
+ }
+ }
+
+ FreeToken(t);
+ }
+
+ Free(s);
+ }
+
+ FreeBuf(b);
+
+ return ok;
+}
+
+// Accept admin connection
+UINT AdminAccept(CONNECTION *c, PACK *p)
+{
+ ADMIN *a;
+ UCHAR secure_password[SHA1_SIZE];
+ UCHAR null_password[SHA1_SIZE];
+ UCHAR secure_null_password[SHA1_SIZE];
+ char hubname[MAX_HUBNAME_LEN + 1];
+ CEDAR *cedar;
+ SOCK *sock;
+ RPC *rpc;
+ UINT err;
+ SERVER *server = NULL;
+ RPC_WINVER ver;
+ bool accept_empty_password;
+ bool is_empty_password = false;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ cedar = c->Cedar;
+ sock = c->FirstSock;
+
+ if (cedar != NULL)
+ {
+ server = cedar->Server;
+ }
+
+ accept_empty_password = PackGetBool(p, "accept_empty_password");
+
+ // Get client OS version
+ InRpcWinVer(&ver, p);
+
+ // Get hub name
+ if (PackGetStr(p, "hubname", hubname, sizeof(hubname)) == false)
+ {
+ // without hub name
+ StrCpy(hubname, sizeof(hubname), "");
+ }
+
+ // Cehck source IP address
+ if (CheckAdminSourceAddress(sock, hubname) == false)
+ {
+ SLog(c->Cedar, "LA_IP_DENIED", c->Name);
+ return ERR_IP_ADDRESS_DENIED;
+ }
+
+ // Get password information
+ if (PackGetDataSize(p, "secure_password") != SHA1_SIZE)
+ {
+ // Malformed information
+ return ERR_PROTOCOL_ERROR;
+ }
+ PackGetData(p, "secure_password", secure_password);
+
+ if (StrLen(hubname) == 0)
+ {
+ // Server admin mode
+ SLog(c->Cedar, "LA_CONNECTED_1", c->Name);
+ }
+ else
+ {
+ // Hub admin mode
+ if (cedar->Server != NULL && cedar->Server->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ // Connection with hub admin mode to cluster member is not permitted
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+ SLog(c->Cedar, "LA_CONNECTED_2", c->Name, hubname);
+ }
+
+ // Check password
+ err = AdminCheckPassword(cedar, c->Random, secure_password,
+ StrLen(hubname) != 0 ? hubname : NULL, accept_empty_password, &is_empty_password);
+
+ if (err != ERR_NO_ERROR)
+ {
+ // Error occured
+ SLog(c->Cedar, "LA_ERROR", c->Name, GetUniErrorStr(err), err);
+ return err;
+ }
+
+ SLog(c->Cedar, "LA_OK", c->Name);
+
+ HashAdminPassword(null_password, "");
+ SecurePassword(secure_null_password, null_password, c->Random);
+
+ if (Cmp(secure_null_password, secure_password, SHA1_SIZE) == 0)
+ {
+ if (sock->RemoteIP.addr[0] != 127)
+ {
+ // The client tried to use blank password for hub admin mode from remote
+ if (StrLen(hubname) != 0)
+ {
+ return ERR_NULL_PASSWORD_LOCAL_ONLY;
+ }
+ }
+ }
+
+
+ // Reply success result
+ p = NewPack();
+ if (accept_empty_password && is_empty_password)
+ {
+ PackAddBool(p, "empty_password", true);
+ }
+ HttpServerSend(sock, p);
+ FreePack(p);
+
+ // Construct ADMIN object
+ a = ZeroMalloc(sizeof(ADMIN));
+ a->ServerAdmin = ((StrLen(hubname) == 0) ? true : false);
+ a->HubName = (StrLen(hubname) != 0 ? hubname : NULL);
+ a->Server = c->Cedar->Server;
+ a->ClientBuild = c->ClientBuild;
+
+ Copy(&a->ClientWinVer, &ver, sizeof(RPC_WINVER));
+
+ // Timeout setting
+ SetTimeout(sock, INFINITE);
+
+ // RPC Server
+ rpc = StartRpcServer(sock, AdminDispatch, a);
+
+ a->Rpc = rpc;
+
+ SLog(c->Cedar, "LA_RPC_START", c->Name, rpc->Name);
+
+ RpcServer(rpc);
+ RpcFree(rpc);
+
+ if (a->LogFileList != NULL)
+ {
+ // Free cached log file list, if it exists
+ FreeEnumLogFile(a->LogFileList);
+ }
+
+ // Free ADMIN object
+ Free(a);
+
+ return ERR_NO_ERROR;
+}
+
+// Check for admin password
+UINT AdminCheckPassword(CEDAR *c, void *random, void *secure_password, char *hubname,
+ bool accept_empty_password, bool *is_password_empty)
+{
+ UCHAR check[SHA1_SIZE];
+ bool b_dummy;
+ // Validate arguments
+ if (c == NULL || random == NULL || secure_password == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+ if (is_password_empty == NULL)
+ {
+ is_password_empty = &b_dummy;
+ }
+
+ *is_password_empty = false;
+
+ if (hubname == NULL || StrLen(hubname) == 0)
+ {
+ // Server admin mode
+ Lock(c->lock);
+ {
+ if (accept_empty_password && SiIsEmptyPassword(c->Server->HashedPassword))
+ {
+ // blank password
+ *is_password_empty = true;
+ }
+
+ SecurePassword(check, c->Server->HashedPassword, random);
+ }
+ Unlock(c->lock);
+
+ if (Cmp(check, secure_password, SHA1_SIZE) != 0)
+ {
+ // Password incorrect
+ return ERR_ACCESS_DENIED;
+ }
+ }
+ else
+ {
+ HUB *h;
+
+#if 0
+ if (c->Server->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ // In cluster member mode, hub admin mode is disabled
+ return ERR_FARM_MEMBER_HUB_ADMIN;
+ }
+#endif
+
+ // Hub admin mode
+ LockHubList(c);
+ {
+ h = GetHub(c, hubname);
+ }
+ UnlockHubList(c);
+
+ if (h == NULL)
+ {
+ // Specified hub is not found
+ return ERR_HUB_NOT_FOUND;
+ }
+
+ Lock(h->lock);
+ {
+ if (accept_empty_password && SiIsEmptyPassword(h->HashedPassword))
+ {
+ // User specified blank password
+ *is_password_empty = true;
+ }
+
+ SecurePassword(check, h->HashedPassword, random);
+ }
+ Unlock(h->lock);
+
+ ReleaseHub(h);
+
+ if (Cmp(check, secure_password, SHA1_SIZE) != 0)
+ {
+ // Incorrect password
+ return ERR_ACCESS_DENIED;
+ }
+ }
+
+ return ERR_NO_ERROR;
+}
+
+// Hash admin password
+void HashAdminPassword(void *hash, char *password)
+{
+ // Validate arguments
+ if (hash == NULL || password == NULL)
+ {
+ return;
+ }
+
+ Hash(hash, password, StrLen(password), true);
+}
+
+// Disconnect admin connection
+void AdminDisconnect(RPC *rpc)
+{
+ SESSION *s;
+ SOCK *sock;
+ // Validate arguments
+ if (rpc == NULL)
+ {
+ return;
+ }
+
+ s = (SESSION *)rpc->Param;
+ sock = rpc->Sock;
+
+ EndRpc(rpc);
+
+ Disconnect(sock);
+ ReleaseSession(s);
+}
+
+// Admin connection main routine
+SESSION *AdminConnectMain(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err, char *client_name, void *hWnd, bool *empty_password)
+{
+ UCHAR secure_password[SHA1_SIZE];
+ SESSION *s;
+ SOCK *sock;
+ PACK *p;
+ RPC_WINVER ver;
+ // connect
+ s = NewRpcSessionEx2(cedar, o, err, client_name, hWnd);
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ // Get socket
+ sock = s->Connection->FirstSock;
+
+ // Generate connect method
+ p = NewPack();
+
+ PackAddClientVersion(p, s->Connection);
+
+ PackAddStr(p, "method", "admin");
+ PackAddBool(p, "accept_empty_password", true);
+
+ // Windows version on client
+ GetWinVer(&ver);
+ OutRpcWinVer(p, &ver);
+
+ // Secure Password
+ SecurePassword(secure_password, hashed_password, s->Connection->Random);
+
+ PackAddData(p, "secure_password", secure_password, sizeof(secure_password));
+
+ // HUB name
+ if (hubname != NULL)
+ {
+ PackAddStr(p, "hubname", hubname);
+ }
+
+ if (HttpClientSend(sock, p) == false)
+ {
+ // disconnect
+ FreePack(p);
+ ReleaseSession(s);
+ *err = ERR_DISCONNECTED;
+ return NULL;
+ }
+
+ FreePack(p);
+
+ p = HttpClientRecv(sock);
+ if (p == NULL)
+ {
+ // disconnect
+ ReleaseSession(s);
+ *err = ERR_DISCONNECTED;
+ return NULL;
+ }
+
+ if (GetErrorFromPack(p) != 0)
+ {
+ // error
+ ReleaseSession(s);
+ *err = GetErrorFromPack(p);
+ FreePack(p);
+ return NULL;
+ }
+
+ if (empty_password != NULL)
+ {
+ *empty_password = PackGetBool(p, "empty_password");
+ }
+
+ FreePack(p);
+
+ return s;
+}
+
+// Admin connection
+RPC *AdminConnect(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err)
+{
+ return AdminConnectEx(cedar, o, hubname, hashed_password, err, NULL);
+}
+RPC *AdminConnectEx(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err, char *client_name)
+{
+ return AdminConnectEx2(cedar, o, hubname, hashed_password, err, client_name, NULL);
+}
+RPC *AdminConnectEx2(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err, char *client_name, void *hWnd)
+{
+ SESSION *s;
+ SOCK *sock;
+ RPC *rpc;
+ UCHAR hashed_password_2[SHA1_SIZE];
+ bool empty_password = false;
+ // Validate arguments
+ if (cedar == NULL || o == NULL || hashed_password == NULL || err == NULL)
+ {
+ return NULL;
+ }
+
+ if (client_name == NULL)
+ {
+ client_name = CEDAR_MANAGER_STR;
+ }
+
+ Copy(hashed_password_2, hashed_password, SHA1_SIZE);
+
+ s = AdminConnectMain(cedar, o, hubname, hashed_password_2, err, client_name, hWnd, &empty_password);
+
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ sock = s->Connection->FirstSock;
+
+ // RPC start
+ rpc = StartRpcClient(sock, s);
+
+ rpc->IsVpnServer = true;
+ Copy(&rpc->VpnServerClientOption, o, sizeof(CLIENT_OPTION));
+ StrCpy(rpc->VpnServerHubName, sizeof(rpc->VpnServerHubName), hubname);
+ StrCpy(rpc->VpnServerClientName, sizeof(rpc->VpnServerClientName), client_name);
+
+ if (empty_password == false)
+ {
+ Copy(rpc->VpnServerHashedPassword, hashed_password_2, SHA1_SIZE);
+ }
+ else
+ {
+ HashAdminPassword(rpc->VpnServerHashedPassword, "");
+ }
+
+ // timeout setting
+ SetTimeout(sock, INFINITE);
+
+ return rpc;
+}
+
+// Reconnect admin connection
+UINT AdminReconnect(RPC *rpc)
+{
+ SESSION *s;
+ SOCK *sock;
+ CEDAR *cedar;
+ UINT err;
+ bool empty_password = false;
+ // Validate arguments
+ if (rpc == NULL || rpc->IsVpnServer == false)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ s = (SESSION *)rpc->Param;
+ cedar = s->Cedar;
+ AddRef(cedar->ref);
+
+ sock = rpc->Sock;
+ Disconnect(sock);
+ ReleaseSock(sock);
+ ReleaseSession(s);
+ rpc->Param = NULL;
+
+ rpc->Sock = NULL;
+
+ s = AdminConnectMain(cedar, &rpc->VpnServerClientOption,
+ rpc->VpnServerHubName,
+ rpc->VpnServerHashedPassword,
+ &err,
+ rpc->VpnServerClientName, NULL, &empty_password);
+
+ ReleaseCedar(cedar);
+
+ if (s == NULL)
+ {
+ return err;
+ }
+
+ if (empty_password)
+ {
+ HashAdminPassword(rpc->VpnServerHashedPassword, "");
+ }
+
+ rpc->Param = s;
+ rpc->Sock = s->Connection->FirstSock;
+ AddRef(rpc->Sock->ref);
+
+ return ERR_NO_ERROR;
+}
+
+// Identify blank password
+bool SiIsEmptyPassword(void *hash_password)
+{
+ UCHAR hash[SHA1_SIZE];
+ // Validate arguments
+ if (hash_password == NULL)
+ {
+ return false;
+ }
+
+ Hash(hash, "", 0, true);
+
+ if (Cmp(hash_password, hash, SHA1_SIZE) == 0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Admin.h b/src/Cedar/Admin.h
new file mode 100644
index 00000000..b667f609
--- /dev/null
+++ b/src/Cedar/Admin.h
@@ -0,0 +1,1505 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Admin.h
+// Header of Admin.c
+
+#ifndef ADMIN_H
+#define ADMIN_H
+
+// Windows version
+struct RPC_WINVER
+{
+ bool IsWindows;
+ bool IsNT;
+ bool IsServer;
+ bool IsBeta;
+ UINT VerMajor;
+ UINT VerMinor;
+ UINT Build;
+ UINT ServicePack;
+ char Title[128];
+};
+
+// Server-side structure
+struct ADMIN
+{
+ SERVER *Server; // Server
+ bool ServerAdmin; // Server Administrator
+ char *HubName; // HUB name that can be managed
+ RPC *Rpc; // RPC
+ LIST *LogFileList; // Accessible log file list
+ UINT ClientBuild; // Build number of the client
+ RPC_WINVER ClientWinVer; // Windows version of client
+};
+
+// Test
+struct RPC_TEST
+{
+ UINT IntValue;
+ UINT64 Int64Value;
+ char StrValue[1024];
+ wchar_t UniStrValue[1024];
+};
+
+// Server Information *
+struct RPC_SERVER_INFO
+{
+ char ServerProductName[128]; // Server product name
+ char ServerVersionString[128]; // Server version string
+ char ServerBuildInfoString[128]; // Server build information string
+ UINT ServerVerInt; // Server version integer value
+ UINT ServerBuildInt; // Server build number integer value
+ char ServerHostName[MAX_HOST_NAME_LEN + 1]; // Server host name
+ UINT ServerType; // Type of server
+ UINT64 ServerBuildDate; // Build date and time of the server
+ char ServerFamilyName[128]; // Family name
+ OS_INFO OsInfo; // OS information
+};
+
+// Server status
+struct RPC_SERVER_STATUS
+{
+ UINT ServerType; // Type of server
+ UINT NumTcpConnections; // Total number of TCP connections
+ UINT NumTcpConnectionsLocal; // Number of Local TCP connections
+ UINT NumTcpConnectionsRemote; // Number of remote TCP connections
+ UINT NumHubTotal; // Total number of HUBs
+ UINT NumHubStandalone; // Nymber of stand-alone HUB
+ UINT NumHubStatic; // Number of static HUBs
+ UINT NumHubDynamic; // Number of Dynamic HUBs
+ UINT NumSessionsTotal; // Total number of sessions
+ UINT NumSessionsLocal; // Number of Local sessions (only controller)
+ UINT NumSessionsRemote; // The number of remote sessions (other than the controller)
+ UINT NumMacTables; // Number of MAC table entries
+ UINT NumIpTables; // Number of IP table entries
+ UINT NumUsers; // Number of users
+ UINT NumGroups; // Number of groups
+ UINT AssignedBridgeLicenses; // Number of assigned bridge licenses
+ UINT AssignedClientLicenses; // Number of assigned client licenses
+ UINT AssignedBridgeLicensesTotal; // Number of Assigned bridge license (cluster-wide)
+ UINT AssignedClientLicensesTotal; // Number of assigned client licenses (cluster-wide)
+ TRAFFIC Traffic; // Traffic information
+ UINT64 CurrentTime; // Current time
+ UINT64 CurrentTick; // Current tick
+ UINT64 StartTime; // Start-up time
+ MEMINFO MemInfo; // Memory information
+};
+
+// Listener
+struct RPC_LISTENER
+{
+ UINT Port; // Port number
+ bool Enable; // Active state
+};
+
+// List of listeners *
+struct RPC_LISTENER_LIST
+{
+ UINT NumPort; // Number of ports
+ UINT *Ports; // Port List
+ bool *Enables; // Effective state
+ bool *Errors; // An error occurred
+};
+
+// String *
+struct RPC_STR
+{
+ char *String; // String
+};
+
+// Integer
+struct RPC_INT
+{
+ UINT IntValue; // Integer
+};
+
+// Set Password
+struct RPC_SET_PASSWORD
+{
+ UCHAR HashedPassword[SHA1_SIZE]; // Hashed password
+};
+
+// Server farm configuration *
+struct RPC_FARM
+{
+ UINT ServerType; // Type of server
+ UINT NumPort; // Number of public ports
+ UINT *Ports; // Public port list
+ UINT PublicIp; // Public IP
+ char ControllerName[MAX_HOST_NAME_LEN + 1]; // Controller name
+ UINT ControllerPort; // Controller port
+ UCHAR MemberPassword[SHA1_SIZE]; // Member password
+ UINT Weight; // Performance ratio
+ bool ControllerOnly; // Only controller function
+};
+
+// HUB item of each farm member
+struct RPC_FARM_HUB
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ bool DynamicHub; // Dynamic HUB
+};
+
+// Server farm member information acquisition *
+struct RPC_FARM_INFO
+{
+ UINT Id; // ID
+ bool Controller; // Controller
+ UINT64 ConnectedTime; // Connection time
+ UINT Ip; // IP address
+ char Hostname[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT Point; // Point
+ UINT NumPort; // Number of ports
+ UINT *Ports; // Port
+ X *ServerCert; // Server certificate
+ UINT NumFarmHub; // Number of farm HUB
+ RPC_FARM_HUB *FarmHubs; // Farm HUB
+ UINT NumSessions; // Number of sessions
+ UINT NumTcpConnections; // Number of TCP connections
+ UINT Weight; // Performance ratio
+};
+
+// Server farm members enumeration items
+struct RPC_ENUM_FARM_ITEM
+{
+ UINT Id; // ID
+ bool Controller; // Controller
+ UINT64 ConnectedTime; // Connection time
+ UINT Ip; // IP address
+ char Hostname[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT Point; // Point
+ UINT NumSessions; // Number of sessions
+ UINT NumTcpConnections; // Number of TCP connections
+ UINT NumHubs; // Number of HUBs
+ UINT AssignedClientLicense; // Number of assigned client licenses
+ UINT AssignedBridgeLicense; // Number of assigned bridge licenses
+};
+
+// Server farm member enumeration *
+struct RPC_ENUM_FARM
+{
+ UINT NumFarm; // Number of farm members
+ RPC_ENUM_FARM_ITEM *Farms; // Farm member list
+};
+
+// Connection state to the controller
+struct RPC_FARM_CONNECTION_STATUS
+{
+ UINT Ip; // IP address
+ UINT Port; // Port number
+ bool Online; // Online state
+ UINT LastError; // Last error
+ UINT64 StartedTime; // Connection start time
+ UINT64 FirstConnectedTime; // First connection time
+ UINT64 CurrentConnectedTime; // Connection time of this time
+ UINT NumTry; // Number of trials
+ UINT NumConnected; // Number of connection count
+ UINT NumFailed; // Connection failure count
+};
+
+// Key pair
+struct RPC_KEY_PAIR
+{
+ X *Cert; // Certificate
+ K *Key; // Secret key
+};
+
+// HUB option
+struct RPC_HUB_OPTION
+{
+ UINT MaxSession; // Maximum number of sessions
+ bool NoEnum; // Not listed
+};
+
+// Radius server options
+struct RPC_RADIUS
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ char RadiusServerName[MAX_HOST_NAME_LEN + 1]; // Radius server name
+ UINT RadiusPort; // Radius port number
+ char RadiusSecret[MAX_PASSWORD_LEN + 1]; // Secret key
+ UINT RadiusRetryInterval; // Radius retry interval
+};
+
+// Specify the HUB
+struct RPC_HUB
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+};
+
+// Create a HUB
+struct RPC_CREATE_HUB
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UCHAR HashedPassword[SHA1_SIZE]; // Administrative password
+ UCHAR SecurePassword[SHA1_SIZE]; // Administrator password
+ bool Online; // Online flag
+ RPC_HUB_OPTION HubOption; // HUB options
+ UINT HubType; // Type of HUB
+};
+
+// Enumeration items of HUB
+struct RPC_ENUM_HUB_ITEM
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ bool Online; // Online
+ UINT HubType; // Type of HUB
+ UINT NumUsers; // Number of users
+ UINT NumGroups; // Number of groups
+ UINT NumSessions; // Number of sessions
+ UINT NumMacTables; // Number of MAC table entries
+ UINT NumIpTables; // Number of IP table entries
+ UINT64 LastCommTime; // Last communication date and time
+ UINT64 LastLoginTime; // Last login date and time
+ UINT64 CreatedTime; // Creation date and time
+ UINT NumLogin; // Number of logins
+ bool IsTrafficFilled; // Whether the traffic information exists
+ TRAFFIC Traffic; // Traffic
+};
+
+// Enumeration of HUB
+struct RPC_ENUM_HUB
+{
+ UINT NumHub; // Number of HUBs
+ RPC_ENUM_HUB_ITEM *Hubs; // HUB
+};
+
+// Delete the HUB
+struct RPC_DELETE_HUB
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+};
+
+// Connection enumeration items
+struct RPC_ENUM_CONNECTION_ITEM
+{
+ char Name[MAX_SIZE]; // Connection name
+ char Hostname[MAX_SIZE]; // Host name
+ UINT Ip; // IP address
+ UINT Port; // Port number
+ UINT64 ConnectedTime; // Connected time
+ UINT Type; // Type
+};
+
+// Connection enumeration
+struct RPC_ENUM_CONNECTION
+{
+ UINT NumConnection; // Number of connections
+ RPC_ENUM_CONNECTION_ITEM *Connections; // Connection list
+};
+
+// Disconnection
+struct RPC_DISCONNECT_CONNECTION
+{
+ char Name[MAX_SIZE]; // Connection name
+};
+
+// Connection information
+struct RPC_CONNECTION_INFO
+{
+ char Name[MAX_SIZE]; // Connection name
+ UINT Type; // Type
+ char Hostname[MAX_SIZE]; // Host name
+ UINT Ip; // IP address
+ UINT Port; // Port number
+ UINT64 ConnectedTime; // Connected time
+ char ServerStr[MAX_SERVER_STR_LEN + 1]; // Server string
+ UINT ServerVer; // Server version
+ UINT ServerBuild; // Server build number
+ char ClientStr[MAX_CLIENT_STR_LEN + 1]; // Client string
+ UINT ClientVer; // Client version
+ UINT ClientBuild; // Client build number
+};
+
+// Online or offline the HUB
+struct RPC_SET_HUB_ONLINE
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ bool Online; // Online / offline flag
+};
+
+// Get the state HUB
+struct RPC_HUB_STATUS
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ bool Online; // Online
+ UINT HubType; // Type of HUB
+ UINT NumSessions; // Number of sessions
+ UINT NumSessionsClient; // Number of sessions (client)
+ UINT NumSessionsBridge; // Number of sessions (bridge)
+ UINT NumAccessLists; // Number of Access list entries
+ UINT NumUsers; // Number of users
+ UINT NumGroups; // Number of groups
+ UINT NumMacTables; // Number of MAC table entries
+ UINT NumIpTables; // Number of IP table entries
+ TRAFFIC Traffic; // Traffic
+ bool SecureNATEnabled; // Whether SecureNAT is enabled
+ UINT64 LastCommTime; // Last communication date and time
+ UINT64 LastLoginTime; // Last login date and time
+ UINT64 CreatedTime; // Creation date and time
+ UINT NumLogin; // Number of logins
+};
+
+// HUB log settings
+struct RPC_HUB_LOG
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ HUB_LOG LogSetting; // Log Settings
+};
+
+// Add CA to HUB *
+struct RPC_HUB_ADD_CA
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ X *Cert; // Certificate
+};
+
+// CA enumeration items of HUB
+struct RPC_HUB_ENUM_CA_ITEM
+{
+ UINT Key; // Certificate key
+ wchar_t SubjectName[MAX_SIZE]; // Issued to
+ wchar_t IssuerName[MAX_SIZE]; // Issuer
+ UINT64 Expires; // Expiration date
+};
+
+// CA enumeration of HUB *
+struct RPC_HUB_ENUM_CA
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT NumCa; // CA number
+ RPC_HUB_ENUM_CA_ITEM *Ca; // CA
+};
+
+// Get the CA of HUB *
+struct RPC_HUB_GET_CA
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT Key; // Certificate key
+ X *Cert; // Certificate
+};
+
+// Delete the CA of HUB
+struct RPC_HUB_DELETE_CA
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT Key; // Certificate key to be deleted
+};
+
+// Create and set of link *
+struct RPC_CREATE_LINK
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ bool Online; // Online flag
+ CLIENT_OPTION *ClientOption; // Client Option
+ CLIENT_AUTH *ClientAuth; // Client authentication data
+ POLICY Policy; // Policy
+ bool CheckServerCert; // Validate the server certificate
+ X *ServerCert; // Server certificate
+};
+
+// Enumeration items of link
+struct RPC_ENUM_LINK_ITEM
+{
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+ bool Online; // Online flag
+ bool Connected; // Connection completion flag
+ UINT LastError; // The error that last occurred
+ UINT64 ConnectedTime; // Connection completion time
+ char Hostname[MAX_HOST_NAME_LEN + 1]; // Host name
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+};
+
+// Enumeration of the link *
+struct RPC_ENUM_LINK
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT NumLink; // Number of links
+ RPC_ENUM_LINK_ITEM *Links; // Link List
+};
+
+// Get the link state *
+struct RPC_LINK_STATUS
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+ RPC_CLIENT_GET_CONNECTION_STATUS Status; // Status
+};
+
+// Specify the Link
+struct RPC_LINK
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+};
+
+// Rename link
+struct RPC_RENAME_LINK
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ wchar_t OldAccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Old account name
+ wchar_t NewAccountName[MAX_ACCOUNT_NAME_LEN + 1]; // New account name
+};
+
+// Enumeration of the access list *
+struct RPC_ENUM_ACCESS_LIST
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT NumAccess; // Number of Access list entries
+ ACCESS *Accesses; // Access list
+};
+
+// Add to Access List
+struct RPC_ADD_ACCESS
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ ACCESS Access; // Access list
+};
+
+// Delete the access list
+struct RPC_DELETE_ACCESS
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT Id; // ID
+};
+
+// Create, configure, and get the user *
+struct RPC_SET_USER
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ char Name[MAX_USERNAME_LEN + 1]; // User name
+ char GroupName[MAX_USERNAME_LEN + 1]; // Group name
+ wchar_t Realname[MAX_SIZE]; // Real name
+ wchar_t Note[MAX_SIZE]; // Note
+ UINT64 CreatedTime; // Creation date and time
+ UINT64 UpdatedTime; // Updating date
+ UINT64 ExpireTime; // Expiration date
+ UINT AuthType; // Authentication method
+ void *AuthData; // Authentication data
+ UINT NumLogin; // Number of logins
+ TRAFFIC Traffic; // Traffic data
+ POLICY *Policy; // Policy
+};
+
+// Enumeration item of user
+struct RPC_ENUM_USER_ITEM
+{
+ char Name[MAX_USERNAME_LEN + 1]; // User name
+ char GroupName[MAX_USERNAME_LEN + 1]; // Group name
+ wchar_t Realname[MAX_SIZE]; // Real name
+ wchar_t Note[MAX_SIZE]; // Note
+ UINT AuthType; // Authentication method
+ UINT NumLogin; // Number of logins
+ UINT64 LastLoginTime; // Last login date and time
+ bool DenyAccess; // Access denied
+ bool IsTrafficFilled; // Flag of whether the traffic variable is set
+ TRAFFIC Traffic; // Traffic
+ bool IsExpiresFilled; // Flag of whether expiration date variable is set
+ UINT64 Expires; // Expiration date
+};
+
+// Enumeration of user
+struct RPC_ENUM_USER
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT NumUser; // Number of users
+ RPC_ENUM_USER_ITEM *Users; // User
+};
+
+// Create, configure, and get the group *
+struct RPC_SET_GROUP
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ char Name[MAX_USERNAME_LEN + 1]; // User name
+ wchar_t Realname[MAX_SIZE]; // Real name
+ wchar_t Note[MAX_SIZE]; // Note
+ TRAFFIC Traffic; // Traffic data
+ POLICY *Policy; // Policy
+};
+
+// Enumeration items in the group
+struct RPC_ENUM_GROUP_ITEM
+{
+ char Name[MAX_USERNAME_LEN + 1]; // User name
+ wchar_t Realname[MAX_SIZE]; // Real name
+ wchar_t Note[MAX_SIZE]; // Note
+ UINT NumUsers; // Number of users
+ bool DenyAccess; // Access denied
+};
+
+// Group enumeration
+struct RPC_ENUM_GROUP
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT NumGroup; // Number of groups
+ RPC_ENUM_GROUP_ITEM *Groups; // Group
+};
+
+// Deleting a user or group
+struct RPC_DELETE_USER
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ char Name[MAX_USERNAME_LEN + 1]; // User or group name
+};
+
+// Enumeration items of session
+struct RPC_ENUM_SESSION_ITEM
+{
+ char Name[MAX_SESSION_NAME_LEN + 1]; // Session name
+ bool RemoteSession; // Remote session
+ char RemoteHostname[MAX_HOST_NAME_LEN + 1]; // Remote server name
+ char Username[MAX_USERNAME_LEN + 1]; // User name
+ UINT Ip; // IP address (IPv4)
+ char Hostname[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT MaxNumTcp; // Maximum number of TCP connections
+ UINT CurrentNumTcp; // Number of currentl TCP connections
+ UINT64 PacketSize; // Packet size
+ UINT64 PacketNum; // Number of packets
+ bool LinkMode; // Link mode
+ bool SecureNATMode; // SecureNAT mode
+ bool BridgeMode; // Bridge mode
+ bool Layer3Mode; // Layer 3 mode
+ bool Client_BridgeMode; // Client is bridge mode
+ bool Client_MonitorMode; // Client is monitoring mode
+ UINT VLanId; // VLAN ID
+ UCHAR UniqueId[16]; // Unique ID
+};
+
+// Disconnect the session
+struct RPC_DELETE_SESSION
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ char Name[MAX_SESSION_NAME_LEN + 1]; // Session name
+};
+
+// Enumeration items of the MAC table
+struct RPC_ENUM_MAC_TABLE_ITEM
+{
+ UINT Key; // Key
+ char SessionName[MAX_SESSION_NAME_LEN + 1]; // Session name
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2];
+ UINT64 CreatedTime; // Creation date and time
+ UINT64 UpdatedTime; // Updating date
+ bool RemoteItem; // Remote items
+ char RemoteHostname[MAX_HOST_NAME_LEN + 1]; // Remote host name
+ UINT VlanId; // VLAN ID
+};
+
+// Enumeration of the MAC table
+struct RPC_ENUM_MAC_TABLE
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT NumMacTable; // Number of tables
+ RPC_ENUM_MAC_TABLE_ITEM *MacTables; // MAC table
+};
+
+// Enumeration items of IP table
+struct RPC_ENUM_IP_TABLE_ITEM
+{
+ UINT Key; // Key
+ char SessionName[MAX_SESSION_NAME_LEN + 1]; // Session name
+ UINT Ip; // IP address
+ IP IpV6; // IPv6 address
+ bool DhcpAllocated; // Assigned by the DHCP
+ UINT64 CreatedTime; // Creation date and time
+ UINT64 UpdatedTime; // Updating date
+ bool RemoteItem; // Remote items
+ char RemoteHostname[MAX_HOST_NAME_LEN + 1]; // Remote host name
+};
+
+// Enumeration of IP table
+struct RPC_ENUM_IP_TABLE
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT NumIpTable; // Number of tables
+ RPC_ENUM_IP_TABLE_ITEM *IpTables; // MAC table
+};
+
+// Delete the table
+struct RPC_DELETE_TABLE
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT Key; // Key
+};
+
+// KEEP setting
+struct RPC_KEEP
+{
+ bool UseKeepConnect; // Keep connected to the Internet
+ char KeepConnectHost[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT KeepConnectPort; // Port number
+ UINT KeepConnectProtocol; // Protocol
+ UINT KeepConnectInterval; // Interval
+};
+
+// Ethernet enumeration item
+struct RPC_ENUM_ETH_ITEM
+{
+ char DeviceName[MAX_SIZE]; // Device name
+ wchar_t NetworkConnectionName[MAX_SIZE];// Network connection name
+};
+
+// Ethernet enumeration
+struct RPC_ENUM_ETH
+{
+ UINT NumItem; // Number of items
+ RPC_ENUM_ETH_ITEM *Items; // Item
+};
+
+// Bridge item
+struct RPC_LOCALBRIDGE
+{
+ char DeviceName[MAX_SIZE]; // Device name
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ bool Online; // Online flag
+ bool Active; // Running flag
+ bool TapMode; // Tap mode
+};
+
+// Bridge enumeration
+struct RPC_ENUM_LOCALBRIDGE
+{
+ UINT NumItem; // Number of items
+ RPC_LOCALBRIDGE *Items; // Item
+};
+
+// Bridge support information
+struct RPC_BRIDGE_SUPPORT
+{
+ bool IsBridgeSupportedOs; // Whether the OS supports the bridge
+ bool IsWinPcapNeeded; // Whether WinPcap is necessary
+};
+
+// Config operation
+struct RPC_CONFIG
+{
+ char FileName[MAX_PATH]; // File name
+ char *FileData; // File data
+};
+
+// Administration options list
+struct RPC_ADMIN_OPTION
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // Virtual HUB name
+ UINT NumItem; // Count
+ ADMIN_OPTION *Items; // Data
+};
+
+// Layer-3 switch
+struct RPC_L3SW
+{
+ char Name[MAX_HUBNAME_LEN + 1]; // L3 switch name
+};
+
+// Layer-3 switch enumeration
+struct RPC_ENUM_L3SW_ITEM
+{
+ char Name[MAX_HUBNAME_LEN + 1]; // Name
+ UINT NumInterfaces; // Number of interfaces
+ UINT NumTables; // Routing table number
+ bool Active; // In operation
+ bool Online; // Online
+};
+struct RPC_ENUM_L3SW
+{
+ UINT NumItem;
+ RPC_ENUM_L3SW_ITEM *Items;
+};
+
+// Layer-3 interface
+struct RPC_L3IF
+{
+ char Name[MAX_HUBNAME_LEN + 1]; // L3 switch name
+ char HubName[MAX_HUBNAME_LEN + 1]; // Virtual HUB name
+ UINT IpAddress; // IP address
+ UINT SubnetMask; // Subnet mask
+};
+
+// Layer-3 interface enumeration
+struct RPC_ENUM_L3IF
+{
+ char Name[MAX_HUBNAME_LEN + 1]; // L3 switch name
+ UINT NumItem;
+ RPC_L3IF *Items;
+};
+
+// Routing table
+struct RPC_L3TABLE
+{
+ char Name[MAX_HUBNAME_LEN + 1]; // L3 switch name
+ UINT NetworkAddress; // Network address
+ UINT SubnetMask; // Subnet mask
+ UINT GatewayAddress; // Gateway address
+ UINT Metric; // Metric
+};
+
+// Routing table enumeration
+struct RPC_ENUM_L3TABLE
+{
+ char Name[MAX_HUBNAME_LEN + 1]; // L3 switch name
+ UINT NumItem;
+ RPC_L3TABLE *Items;
+};
+
+// CRL entry
+struct RPC_CRL
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT Key; // Key
+ CRL *Crl; // CRL body
+};
+
+// CRL enumeration
+struct RPC_ENUM_CRL_ITEM
+{
+ UINT Key; // Key
+ wchar_t CrlInfo[MAX_SIZE]; // Information
+};
+struct RPC_ENUM_CRL
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT NumItem; // Number of items
+ RPC_ENUM_CRL_ITEM *Items; // List
+};
+
+// AC list
+struct RPC_AC_LIST
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ LIST *o; // List body
+ bool InternalFlag1;
+};
+
+// Log file enumeration
+struct RPC_ENUM_LOG_FILE_ITEM
+{
+ char ServerName[MAX_HOST_NAME_LEN + 1]; // Server name
+ char FilePath[MAX_PATH]; // File Path
+ UINT FileSize; // File size
+ UINT64 UpdatedTime; // Updating date
+};
+struct RPC_ENUM_LOG_FILE
+{
+ UINT NumItem; // Number of items
+ RPC_ENUM_LOG_FILE_ITEM *Items; // List
+};
+
+// Read a Log file
+struct RPC_READ_LOG_FILE
+{
+ char ServerName[MAX_HOST_NAME_LEN + 1]; // Server name
+ char FilePath[MAX_PATH]; // File Path
+ UINT Offset; // Offset
+ BUF *Buffer; // Buffer
+};
+
+// Download information
+struct DOWNLOAD_PROGRESS
+{
+ void *Param; // User define data
+ UINT TotalSize; // The total file size
+ UINT CurrentSize; // Size which has loaded
+ UINT ProgressPercent; // Percent Complete
+};
+
+// Enumerate the license keys
+struct RPC_ENUM_LICENSE_KEY_ITEM
+{
+ UINT Id; // ID
+ char LicenseKey[LICENSE_KEYSTR_LEN + 1]; // License key
+ char LicenseId[LICENSE_LICENSEID_STR_LEN + 1]; // License ID
+ char LicenseName[LICENSE_MAX_PRODUCT_NAME_LEN + 1]; // License name
+ UINT64 Expires; // Expiration date
+ UINT Status; // Situation
+ UINT ProductId; // Product ID
+ UINT64 SystemId; // System ID
+ UINT SerialId; // Serial ID
+};
+struct RPC_ENUM_LICENSE_KEY
+{
+ UINT NumItem; // Number of items
+ RPC_ENUM_LICENSE_KEY_ITEM *Items; // List
+};
+
+// License status of the server
+struct RPC_LICENSE_STATUS
+{
+ UINT EditionId; // Edition ID
+ char EditionStr[LICENSE_MAX_PRODUCT_NAME_LEN + 1]; // Edition name
+ UINT64 SystemId; // System ID
+ UINT64 SystemExpires; // System expiration date
+ UINT NumClientConnectLicense; // Maximum number of concurrent client connections
+ UINT NumBridgeConnectLicense; // Available number of concurrent bridge connections
+
+ // v3.0
+ bool NeedSubscription; // Subscription system is enabled
+ UINT64 SubscriptionExpires; // Subscription expiration date
+ bool IsSubscriptionExpired; // Whether the subscription is expired
+ UINT NumUserCreationLicense; // Maximum number of users
+ bool AllowEnterpriseFunction; // Operation of the enterprise function
+ UINT64 ReleaseDate; // Release date
+};
+
+// Enumeration of VLAN support status of physical LAN card
+struct RPC_ENUM_ETH_VLAN_ITEM
+{
+ char DeviceName[MAX_SIZE]; // Device name
+ char Guid[MAX_SIZE]; // GUID
+ char DeviceInstanceId[MAX_SIZE]; // Device Instance ID
+ char DriverName[MAX_SIZE]; // Driver file name
+ char DriverType[MAX_SIZE]; // Type of driver
+ bool Support; // Check whether it is supported
+ bool Enabled; // Whether it is enabled
+};
+struct RPC_ENUM_ETH_VLAN
+{
+ UINT NumItem; // Number of items
+ RPC_ENUM_ETH_VLAN_ITEM *Items; // List
+};
+
+// Message
+struct RPC_MSG
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ wchar_t *Msg; // Message
+};
+
+// EtherIP setting list
+struct RPC_ENUM_ETHERIP_ID
+{
+ UINT NumItem;
+ ETHERIP_ID *IdList;
+};
+
+// Set the special listener
+struct RPC_SPECIAL_LISTENER
+{
+ bool VpnOverIcmpListener; // VPN over ICMP
+ bool VpnOverDnsListener; // VPN over DNS
+};
+
+// Get / Set the Azure state
+struct RPC_AZURE_STATUS
+{
+ bool IsEnabled; // Whether enabled
+ bool IsConnected; // Whether it's connected
+};
+
+
+// Function prototype
+UINT AdminAccept(CONNECTION *c, PACK *p);
+void HashAdminPassword(void *hash, char *password);
+SESSION *AdminConnectMain(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err, char *client_name, void *hWnd, bool *empty_password);
+RPC *AdminConnect(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err);
+RPC *AdminConnectEx(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err, char *client_name);
+RPC *AdminConnectEx2(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, void *hashed_password, UINT *err, char *client_name, void *hWnd);
+void AdminDisconnect(RPC *rpc);
+UINT AdminReconnect(RPC *rpc);
+UINT AdminCheckPassword(CEDAR *c, void *random, void *secure_password, char *hubname, bool accept_empty_password, bool *is_password_empty);
+PACK *AdminDispatch(RPC *rpc, char *name, PACK *p);
+PACK *AdminCall(RPC *rpc, char *function_name, PACK *p);
+void SiEnumLocalSession(SERVER *s, char *hubname, RPC_ENUM_SESSION *t);
+void CopyOsInfo(OS_INFO *dst, OS_INFO *info);
+CAPSLIST *ScGetCapsEx(RPC *rpc);
+UINT SiEnumMacTable(SERVER *s, char *hubname, RPC_ENUM_MAC_TABLE *t);
+UINT SiEnumIpTable(SERVER *s, char *hubname, RPC_ENUM_IP_TABLE *t);
+void SiEnumLocalLogFileList(SERVER *s, char *hubname, RPC_ENUM_LOG_FILE *t);
+void SiReadLocalLogFile(SERVER *s, char *filepath, UINT offset, RPC_READ_LOG_FILE *t);
+typedef bool (DOWNLOAD_PROC)(DOWNLOAD_PROGRESS *progress);
+BUF *DownloadFileFromServer(RPC *r, char *server_name, char *filepath, UINT total_size, DOWNLOAD_PROC *proc, void *param);
+bool CheckAdminSourceAddress(SOCK *sock, char *hubname);
+void SiEnumSessionMain(SERVER *s, RPC_ENUM_SESSION *t);
+bool SiIsEmptyPassword(void *hash_password);
+
+UINT StTest(ADMIN *a, RPC_TEST *t);
+UINT StGetServerInfo(ADMIN *a, RPC_SERVER_INFO *t);
+UINT StGetServerStatus(ADMIN *a, RPC_SERVER_STATUS *t);
+UINT StCreateListener(ADMIN *a, RPC_LISTENER *t);
+UINT StEnumListener(ADMIN *a, RPC_LISTENER_LIST *t);
+UINT StDeleteListener(ADMIN *a, RPC_LISTENER *t);
+UINT StEnableListener(ADMIN *a, RPC_LISTENER *t);
+UINT StSetServerPassword(ADMIN *a, RPC_SET_PASSWORD *t);
+UINT StSetFarmSetting(ADMIN *a, RPC_FARM *t);
+UINT StGetFarmSetting(ADMIN *a, RPC_FARM *t);
+UINT StGetFarmInfo(ADMIN *a, RPC_FARM_INFO *t);
+UINT StEnumFarmMember(ADMIN *a, RPC_ENUM_FARM *t);
+UINT StGetFarmConnectionStatus(ADMIN *a, RPC_FARM_CONNECTION_STATUS *t);
+UINT StSetServerCert(ADMIN *a, RPC_KEY_PAIR *t);
+UINT StGetServerCert(ADMIN *a, RPC_KEY_PAIR *t);
+UINT StGetServerCipher(ADMIN *a, RPC_STR *t);
+UINT StSetServerCipher(ADMIN *a, RPC_STR *t);
+UINT StCreateHub(ADMIN *a, RPC_CREATE_HUB *t);
+UINT StSetHub(ADMIN *a, RPC_CREATE_HUB *t);
+UINT StGetHub(ADMIN *a, RPC_CREATE_HUB *t);
+UINT StEnumHub(ADMIN *a, RPC_ENUM_HUB *t);
+UINT StDeleteHub(ADMIN *a, RPC_DELETE_HUB *t);
+UINT StGetHubRadius(ADMIN *a, RPC_RADIUS *t);
+UINT StSetHubRadius(ADMIN *a, RPC_RADIUS *t);
+UINT StEnumConnection(ADMIN *a, RPC_ENUM_CONNECTION *t);
+UINT StDisconnectConnection(ADMIN *a, RPC_DISCONNECT_CONNECTION *t);
+UINT StGetConnectionInfo(ADMIN *a, RPC_CONNECTION_INFO *t);
+UINT StSetHubOnline(ADMIN *a, RPC_SET_HUB_ONLINE *t);
+UINT StGetHubStatus(ADMIN *a, RPC_HUB_STATUS *t);
+UINT StSetHubLog(ADMIN *a, RPC_HUB_LOG *t);
+UINT StGetHubLog(ADMIN *a, RPC_HUB_LOG *t);
+UINT StAddCa(ADMIN *a, RPC_HUB_ADD_CA *t);
+UINT StEnumCa(ADMIN *a, RPC_HUB_ENUM_CA *t);
+UINT StGetCa(ADMIN *a, RPC_HUB_GET_CA *t);
+UINT StDeleteCa(ADMIN *a, RPC_HUB_DELETE_CA *t);
+UINT StCreateLink(ADMIN *a, RPC_CREATE_LINK *t);
+UINT StEnumLink(ADMIN *a, RPC_ENUM_LINK *t);
+UINT StGetLinkStatus(ADMIN *a, RPC_LINK_STATUS *t);
+UINT StSetLinkOnline(ADMIN *a, RPC_LINK *t);
+UINT StSetLinkOffline(ADMIN *a, RPC_LINK *t);
+UINT StDeleteLink(ADMIN *a, RPC_LINK *t);
+UINT StRenameLink(ADMIN *a, RPC_RENAME_LINK *t);
+UINT StAddAccess(ADMIN *a, RPC_ADD_ACCESS *t);
+UINT StDeleteAccess(ADMIN *a, RPC_DELETE_ACCESS *t);
+UINT StEnumAccess(ADMIN *a, RPC_ENUM_ACCESS_LIST *t);
+UINT StCreateUser(ADMIN *a, RPC_SET_USER *t);
+UINT StSetUser(ADMIN *a, RPC_SET_USER *t);
+UINT StGetUser(ADMIN *a, RPC_SET_USER *t);
+UINT StDeleteUser(ADMIN *a, RPC_DELETE_USER *t);
+UINT StEnumUser(ADMIN *a, RPC_ENUM_USER *t);
+UINT StCreateGroup(ADMIN *a, RPC_SET_GROUP *t);
+UINT StSetGroup(ADMIN *a, RPC_SET_GROUP *t);
+UINT StGetGroup(ADMIN *a, RPC_SET_GROUP *t);
+UINT StDeleteGroup(ADMIN *a, RPC_DELETE_USER *t);
+UINT StEnumGroup(ADMIN *a, RPC_ENUM_GROUP *t);
+UINT StEnumSession(ADMIN *a, RPC_ENUM_SESSION *t);
+UINT StGetSessionStatus(ADMIN *a, RPC_SESSION_STATUS *t);
+UINT StDeleteSession(ADMIN *a, RPC_DELETE_SESSION *t);
+UINT StEnumMacTable(ADMIN *a, RPC_ENUM_MAC_TABLE *t);
+UINT StDeleteMacTable(ADMIN *a, RPC_DELETE_TABLE *t);
+UINT StEnumIpTable(ADMIN *a, RPC_ENUM_IP_TABLE *t);
+UINT StDeleteIpTable(ADMIN *a, RPC_DELETE_TABLE *t);
+UINT StGetLink(ADMIN *a, RPC_CREATE_LINK *t);
+UINT StSetLink(ADMIN *a, RPC_CREATE_LINK *t);
+UINT StSetAccessList(ADMIN *a, RPC_ENUM_ACCESS_LIST *t);
+UINT StSetKeep(ADMIN *a, RPC_KEEP *t);
+UINT StGetKeep(ADMIN *a, RPC_KEEP *t);
+UINT StEnableSecureNAT(ADMIN *a, RPC_HUB *t);
+UINT StDisableSecureNAT(ADMIN *a, RPC_HUB *t);
+UINT StSetSecureNATOption(ADMIN *a, VH_OPTION *t);
+UINT StGetSecureNATOption(ADMIN *a, VH_OPTION *t);
+UINT StEnumNAT(ADMIN *a, RPC_ENUM_NAT *t);
+UINT StEnumDHCP(ADMIN *a, RPC_ENUM_DHCP *t);
+UINT StGetSecureNATStatus(ADMIN *a, RPC_NAT_STATUS *t);
+UINT StEnumEthernet(ADMIN *a, RPC_ENUM_ETH *t);
+UINT StAddLocalBridge(ADMIN *a, RPC_LOCALBRIDGE *t);
+UINT StDeleteLocalBridge(ADMIN *a, RPC_LOCALBRIDGE *t);
+UINT StEnumLocalBridge(ADMIN *a, RPC_ENUM_LOCALBRIDGE *t);
+UINT StGetBridgeSupport(ADMIN *a, RPC_BRIDGE_SUPPORT *t);
+UINT StRebootServer(ADMIN *a, RPC_TEST *t);
+UINT StGetCaps(ADMIN *a, CAPSLIST *t);
+UINT StGetConfig(ADMIN *a, RPC_CONFIG *t);
+UINT StSetConfig(ADMIN *a, RPC_CONFIG *t);
+UINT StGetDefaultHubAdminOptions(ADMIN *a, RPC_ADMIN_OPTION *t);
+UINT StGetHubAdminOptions(ADMIN *a, RPC_ADMIN_OPTION *t);
+UINT StSetHubAdminOptions(ADMIN *a, RPC_ADMIN_OPTION *t);
+UINT StGetHubExtOptions(ADMIN *a, RPC_ADMIN_OPTION *t);
+UINT StSetHubExtOptions(ADMIN *a, RPC_ADMIN_OPTION *t);
+UINT StAddL3Switch(ADMIN *a, RPC_L3SW *t);
+UINT StDelL3Switch(ADMIN *a, RPC_L3SW *t);
+UINT StEnumL3Switch(ADMIN *a, RPC_ENUM_L3SW *t);
+UINT StStartL3Switch(ADMIN *a, RPC_L3SW *t);
+UINT StStopL3Switch(ADMIN *a, RPC_L3SW *t);
+UINT StAddL3If(ADMIN *a, RPC_L3IF *t);
+UINT StDelL3If(ADMIN *a, RPC_L3IF *t);
+UINT StEnumL3If(ADMIN *a, RPC_ENUM_L3IF *t);
+UINT StAddL3Table(ADMIN *a, RPC_L3TABLE *t);
+UINT StDelL3Table(ADMIN *a, RPC_L3TABLE *t);
+UINT StEnumL3Table(ADMIN *a, RPC_ENUM_L3TABLE *t);
+UINT StEnumCrl(ADMIN *a, RPC_ENUM_CRL *t);
+UINT StAddCrl(ADMIN *a, RPC_CRL *t);
+UINT StDelCrl(ADMIN *a, RPC_CRL *t);
+UINT StGetCrl(ADMIN *a, RPC_CRL *t);
+UINT StSetCrl(ADMIN *a, RPC_CRL *t);
+UINT StSetAcList(ADMIN *a, RPC_AC_LIST *t);
+UINT StGetAcList(ADMIN *a, RPC_AC_LIST *t);
+UINT StEnumLogFile(ADMIN *a, RPC_ENUM_LOG_FILE *t);
+UINT StReadLogFile(ADMIN *a, RPC_READ_LOG_FILE *t);
+UINT StAddLicenseKey(ADMIN *a, RPC_TEST *t);
+UINT StDelLicenseKey(ADMIN *a, RPC_TEST *t);
+UINT StEnumLicenseKey(ADMIN *a, RPC_ENUM_LICENSE_KEY *t);
+UINT StGetLicenseStatus(ADMIN *a, RPC_LICENSE_STATUS *t);
+UINT StSetSysLog(ADMIN *a, SYSLOG_SETTING *t);
+UINT StGetSysLog(ADMIN *a, SYSLOG_SETTING *t);
+UINT StEnumEthVLan(ADMIN *a, RPC_ENUM_ETH_VLAN *t);
+UINT StSetEnableEthVLan(ADMIN *a, RPC_TEST *t);
+UINT StSetHubMsg(ADMIN *a, RPC_MSG *t);
+UINT StGetHubMsg(ADMIN *a, RPC_MSG *t);
+UINT StCrash(ADMIN *a, RPC_TEST *t);
+UINT StGetAdminMsg(ADMIN *a, RPC_MSG *t);
+UINT StFlush(ADMIN *a, RPC_TEST *t);
+UINT StDebug(ADMIN *a, RPC_TEST *t);
+UINT StSetIPsecServices(ADMIN *a, IPSEC_SERVICES *t);
+UINT StGetIPsecServices(ADMIN *a, IPSEC_SERVICES *t);
+UINT StAddEtherIpId(ADMIN *a, ETHERIP_ID *t);
+UINT StGetEtherIpId(ADMIN *a, ETHERIP_ID *t);
+UINT StDeleteEtherIpId(ADMIN *a, ETHERIP_ID *t);
+UINT StEnumEtherIpId(ADMIN *a, RPC_ENUM_ETHERIP_ID *t);
+UINT StSetOpenVpnSstpConfig(ADMIN *a, OPENVPN_SSTP_CONFIG *t);
+UINT StGetOpenVpnSstpConfig(ADMIN *a, OPENVPN_SSTP_CONFIG *t);
+UINT StGetDDnsClientStatus(ADMIN *a, DDNS_CLIENT_STATUS *t);
+UINT StChangeDDnsClientHostname(ADMIN *a, RPC_TEST *t);
+UINT StRegenerateServerCert(ADMIN *a, RPC_TEST *t);
+UINT StMakeOpenVpnConfigFile(ADMIN *a, RPC_READ_LOG_FILE *t);
+UINT StSetSpecialListener(ADMIN *a, RPC_SPECIAL_LISTENER *t);
+UINT StGetSpecialListener(ADMIN *a, RPC_SPECIAL_LISTENER *t);
+UINT StGetAzureStatus(ADMIN *a, RPC_AZURE_STATUS *t);
+UINT StSetAzureStatus(ADMIN *a, RPC_AZURE_STATUS *t);
+UINT StGetDDnsInternetSetting(ADMIN *a, INTERNET_SETTING *t);
+UINT StSetDDnsInternetSetting(ADMIN *a, INTERNET_SETTING *t);
+UINT StSetVgsConfig(ADMIN *a, VGS_CONFIG *t);
+UINT StGetVgsConfig(ADMIN *a, VGS_CONFIG *t);
+
+UINT ScTest(RPC *r, RPC_TEST *t);
+UINT ScGetServerInfo(RPC *r, RPC_SERVER_INFO *t);
+UINT ScGetServerStatus(RPC *r, RPC_SERVER_STATUS *t);
+UINT ScCreateListener(RPC *r, RPC_LISTENER *t);
+UINT ScEnumListener(RPC *r, RPC_LISTENER_LIST *t);
+UINT ScDeleteListener(RPC *r, RPC_LISTENER *t);
+UINT ScEnableListener(RPC *r, RPC_LISTENER *t);
+UINT ScSetServerPassword(RPC *r, RPC_SET_PASSWORD *t);
+UINT ScSetFarmSetting(RPC *r, RPC_FARM *t);
+UINT ScGetFarmSetting(RPC *r, RPC_FARM *t);
+UINT ScGetFarmInfo(RPC *r, RPC_FARM_INFO *t);
+UINT ScEnumFarmMember(RPC *r, RPC_ENUM_FARM *t);
+UINT ScGetFarmConnectionStatus(RPC *r, RPC_FARM_CONNECTION_STATUS *t);
+UINT ScSetServerCert(RPC *r, RPC_KEY_PAIR *t);
+UINT ScGetServerCert(RPC *r, RPC_KEY_PAIR *t);
+UINT ScGetServerCipher(RPC *r, RPC_STR *t);
+UINT ScSetServerCipher(RPC *r, RPC_STR *t);
+UINT ScCreateHub(RPC *r, RPC_CREATE_HUB *t);
+UINT ScSetHub(RPC *r, RPC_CREATE_HUB *t);
+UINT ScGetHub(RPC *r, RPC_CREATE_HUB *t);
+UINT ScEnumHub(RPC *r, RPC_ENUM_HUB *t);
+UINT ScDeleteHub(RPC *r, RPC_DELETE_HUB *t);
+UINT ScGetHubRadius(RPC *r, RPC_RADIUS *t);
+UINT ScSetHubRadius(RPC *r, RPC_RADIUS *t);
+UINT ScEnumConnection(RPC *r, RPC_ENUM_CONNECTION *t);
+UINT ScDisconnectConnection(RPC *r, RPC_DISCONNECT_CONNECTION *t);
+UINT ScGetConnectionInfo(RPC *r, RPC_CONNECTION_INFO *t);
+UINT ScSetHubOnline(RPC *r, RPC_SET_HUB_ONLINE *t);
+UINT ScGetHubStatus(RPC *r, RPC_HUB_STATUS *t);
+UINT ScSetHubLog(RPC *r, RPC_HUB_LOG *t);
+UINT ScGetHubLog(RPC *r, RPC_HUB_LOG *t);
+UINT ScAddCa(RPC *r, RPC_HUB_ADD_CA *t);
+UINT ScEnumCa(RPC *r, RPC_HUB_ENUM_CA *t);
+UINT ScGetCa(RPC *r, RPC_HUB_GET_CA *t);
+UINT ScDeleteCa(RPC *r, RPC_HUB_DELETE_CA *t);
+UINT ScCreateLink(RPC *r, RPC_CREATE_LINK *t);
+UINT ScEnumLink(RPC *r, RPC_ENUM_LINK *t);
+UINT ScGetLinkStatus(RPC *r, RPC_LINK_STATUS *t);
+UINT ScSetLinkOnline(RPC *r, RPC_LINK *t);
+UINT ScSetLinkOffline(RPC *r, RPC_LINK *t);
+UINT ScDeleteLink(RPC *r, RPC_LINK *t);
+UINT ScRenameLink(RPC *r, RPC_RENAME_LINK *t);
+UINT ScAddAccess(RPC *r, RPC_ADD_ACCESS *t);
+UINT ScDeleteAccess(RPC *r, RPC_DELETE_ACCESS *t);
+UINT ScEnumAccess(RPC *r, RPC_ENUM_ACCESS_LIST *t);
+UINT ScCreateUser(RPC *r, RPC_SET_USER *t);
+UINT ScSetUser(RPC *r, RPC_SET_USER *t);
+UINT ScGetUser(RPC *r, RPC_SET_USER *t);
+UINT ScDeleteUser(RPC *r, RPC_DELETE_USER *t);
+UINT ScEnumUser(RPC *r, RPC_ENUM_USER *t);
+UINT ScCreateGroup(RPC *r, RPC_SET_GROUP *t);
+UINT ScSetGroup(RPC *r, RPC_SET_GROUP *t);
+UINT ScGetGroup(RPC *r, RPC_SET_GROUP *t);
+UINT ScDeleteGroup(RPC *r, RPC_DELETE_USER *t);
+UINT ScEnumGroup(RPC *r, RPC_ENUM_GROUP *t);
+UINT ScEnumSession(RPC *r, RPC_ENUM_SESSION *t);
+UINT ScGetSessionStatus(RPC *r, RPC_SESSION_STATUS *t);
+UINT ScDeleteSession(RPC *r, RPC_DELETE_SESSION *t);
+UINT ScEnumMacTable(RPC *r, RPC_ENUM_MAC_TABLE *t);
+UINT ScDeleteMacTable(RPC *r, RPC_DELETE_TABLE *t);
+UINT ScEnumIpTable(RPC *r, RPC_ENUM_IP_TABLE *t);
+UINT ScDeleteIpTable(RPC *r, RPC_DELETE_TABLE *t);
+UINT ScGetLink(RPC *a, RPC_CREATE_LINK *t);
+UINT ScSetLink(RPC *a, RPC_CREATE_LINK *t);
+UINT ScSetAccessList(RPC *r, RPC_ENUM_ACCESS_LIST *t);
+UINT ScSetKeep(RPC *r, RPC_KEEP *t);
+UINT ScGetKeep(RPC *r, RPC_KEEP *t);
+UINT ScEnableSecureNAT(RPC *r, RPC_HUB *t);
+UINT ScDisableSecureNAT(RPC *r, RPC_HUB *t);
+UINT ScSetSecureNATOption(RPC *r, VH_OPTION *t);
+UINT ScGetSecureNATOption(RPC *r, VH_OPTION *t);
+UINT ScEnumNAT(RPC *r, RPC_ENUM_NAT *t);
+UINT ScEnumDHCP(RPC *r, RPC_ENUM_DHCP *t);
+UINT ScGetSecureNATStatus(RPC *r, RPC_NAT_STATUS *t);
+UINT ScEnumEthernet(RPC *r, RPC_ENUM_ETH *t);
+UINT ScAddLocalBridge(RPC *r, RPC_LOCALBRIDGE *t);
+UINT ScDeleteLocalBridge(RPC *r, RPC_LOCALBRIDGE *t);
+UINT ScEnumLocalBridge(RPC *r, RPC_ENUM_LOCALBRIDGE *t);
+UINT ScGetBridgeSupport(RPC *r, RPC_BRIDGE_SUPPORT *t);
+UINT ScRebootServer(RPC *r, RPC_TEST *t);
+UINT ScGetCaps(RPC *r, CAPSLIST *t);
+UINT ScGetConfig(RPC *r, RPC_CONFIG *t);
+UINT ScSetConfig(RPC *r, RPC_CONFIG *t);
+UINT ScGetDefaultHubAdminOptions(RPC *r, RPC_ADMIN_OPTION *t);
+UINT ScGetHubAdminOptions(RPC *r, RPC_ADMIN_OPTION *t);
+UINT ScSetHubAdminOptions(RPC *r, RPC_ADMIN_OPTION *t);
+UINT ScGetHubExtOptions(RPC *r, RPC_ADMIN_OPTION *t);
+UINT ScSetHubExtOptions(RPC *r, RPC_ADMIN_OPTION *t);
+UINT ScAddL3Switch(RPC *r, RPC_L3SW *t);
+UINT ScDelL3Switch(RPC *r, RPC_L3SW *t);
+UINT ScEnumL3Switch(RPC *r, RPC_ENUM_L3SW *t);
+UINT ScStartL3Switch(RPC *r, RPC_L3SW *t);
+UINT ScStopL3Switch(RPC *r, RPC_L3SW *t);
+UINT ScAddL3If(RPC *r, RPC_L3IF *t);
+UINT ScDelL3If(RPC *r, RPC_L3IF *t);
+UINT ScEnumL3If(RPC *r, RPC_ENUM_L3IF *t);
+UINT ScAddL3Table(RPC *r, RPC_L3TABLE *t);
+UINT ScDelL3Table(RPC *r, RPC_L3TABLE *t);
+UINT ScEnumL3Table(RPC *r, RPC_ENUM_L3TABLE *t);
+UINT ScEnumCrl(RPC *r, RPC_ENUM_CRL *t);
+UINT ScAddCrl(RPC *r, RPC_CRL *t);
+UINT ScDelCrl(RPC *r, RPC_CRL *t);
+UINT ScGetCrl(RPC *r, RPC_CRL *t);
+UINT ScSetCrl(RPC *r, RPC_CRL *t);
+UINT ScSetAcList(RPC *r, RPC_AC_LIST *t);
+UINT ScGetAcList(RPC *r, RPC_AC_LIST *t);
+UINT ScEnumLogFile(RPC *r, RPC_ENUM_LOG_FILE *t);
+UINT ScReadLogFile(RPC *r, RPC_READ_LOG_FILE *t);
+UINT ScAddLicenseKey(RPC *r, RPC_TEST *t);
+UINT ScDelLicenseKey(RPC *r, RPC_TEST *t);
+UINT ScEnumLicenseKey(RPC *r, RPC_ENUM_LICENSE_KEY *t);
+UINT ScGetLicenseStatus(RPC *r, RPC_LICENSE_STATUS *t);
+UINT ScSetSysLog(RPC *r, SYSLOG_SETTING *t);
+UINT ScGetSysLog(RPC *r, SYSLOG_SETTING *t);
+UINT ScEnumEthVLan(RPC *r, RPC_ENUM_ETH_VLAN *t);
+UINT ScSetEnableEthVLan(RPC *r, RPC_TEST *t);
+UINT ScSetHubMsg(RPC *r, RPC_MSG *t);
+UINT ScGetHubMsg(RPC *r, RPC_MSG *t);
+UINT ScCrash(RPC *r, RPC_TEST *t);
+UINT ScGetAdminMsg(RPC *r, RPC_MSG *t);
+UINT ScFlush(RPC *r, RPC_TEST *t);
+UINT ScDebug(RPC *r, RPC_TEST *t);
+UINT ScSetIPsecServices(RPC *r, IPSEC_SERVICES *t);
+UINT ScGetIPsecServices(RPC *r, IPSEC_SERVICES *t);
+UINT ScAddEtherIpId(RPC *r, ETHERIP_ID *t);
+UINT ScGetEtherIpId(RPC *r, ETHERIP_ID *t);
+UINT ScDeleteEtherIpId(RPC *r, ETHERIP_ID *t);
+UINT ScEnumEtherIpId(RPC *r, RPC_ENUM_ETHERIP_ID *t);
+UINT ScSetOpenVpnSstpConfig(RPC *r, OPENVPN_SSTP_CONFIG *t);
+UINT ScGetOpenVpnSstpConfig(RPC *r, OPENVPN_SSTP_CONFIG *t);
+UINT ScGetDDnsClientStatus(RPC *r, DDNS_CLIENT_STATUS *t);
+UINT ScChangeDDnsClientHostname(RPC *r, RPC_TEST *t);
+UINT ScRegenerateServerCert(RPC *r, RPC_TEST *t);
+UINT ScMakeOpenVpnConfigFile(RPC *r, RPC_READ_LOG_FILE *t);
+UINT ScSetSpecialListener(RPC *r, RPC_SPECIAL_LISTENER *t);
+UINT ScGetSpecialListener(RPC *r, RPC_SPECIAL_LISTENER *t);
+UINT ScGetAzureStatus(RPC *r, RPC_AZURE_STATUS *t);
+UINT ScSetAzureStatus(RPC *r, RPC_AZURE_STATUS *t);
+UINT ScGetDDnsInternetSetting(RPC *r, INTERNET_SETTING *t);
+UINT ScSetDDnsInternetSetting(RPC *r, INTERNET_SETTING *t);
+UINT ScSetVgsConfig(RPC *r, VGS_CONFIG *t);
+UINT ScGetVgsConfig(RPC *r, VGS_CONFIG *t);
+
+void InRpcTest(RPC_TEST *t, PACK *p);
+void OutRpcTest(PACK *p, RPC_TEST *t);
+void FreeRpcTest(RPC_TEST *t);
+void InRpcServerInfo(RPC_SERVER_INFO *t, PACK *p);
+void OutRpcServerInfo(PACK *p, RPC_SERVER_INFO *t);
+void FreeRpcServerInfo(RPC_SERVER_INFO *t);
+void InRpcServerStatus(RPC_SERVER_STATUS *t, PACK *p);
+void OutRpcServerStatus(PACK *p, RPC_SERVER_STATUS *t);
+void InRpcListener(RPC_LISTENER *t, PACK *p);
+void OutRpcListener(PACK *p, RPC_LISTENER *t);
+void InRpcListenerList(RPC_LISTENER_LIST *t, PACK *p);
+void OutRpcListenerList(PACK *p, RPC_LISTENER_LIST *t);
+void FreeRpcListenerList(RPC_LISTENER_LIST *t);
+void InRpcStr(RPC_STR *t, PACK *p);
+void OutRpcStr(PACK *p, RPC_STR *t);
+void FreeRpcStr(RPC_STR *t);
+void InRpcSetPassword(RPC_SET_PASSWORD *t, PACK *p);
+void OutRpcSetPassword(PACK *p, RPC_SET_PASSWORD *t);
+void InRpcFarm(RPC_FARM *t, PACK *p);
+void OutRpcFarm(PACK *p, RPC_FARM *t);
+void FreeRpcFarm(RPC_FARM *t);
+void InRpcFarmHub(RPC_FARM_HUB *t, PACK *p);
+void OutRpcFarmHub(PACK *p, RPC_FARM_HUB *t);
+void InRpcFarmInfo(RPC_FARM_INFO *t, PACK *p);
+void OutRpcFarmInfo(PACK *p, RPC_FARM_INFO *t);
+void FreeRpcFarmInfo(RPC_FARM_INFO *t);
+void InRpcEnumFarm(RPC_ENUM_FARM *t, PACK *p);
+void OutRpcEnumFarm(PACK *p, RPC_ENUM_FARM *t);
+void FreeRpcEnumFarm(RPC_ENUM_FARM *t);
+void InRpcFarmConnectionStatus(RPC_FARM_CONNECTION_STATUS *t, PACK *p);
+void OutRpcFarmConnectionStatus(PACK *p, RPC_FARM_CONNECTION_STATUS *t);
+void InRpcHubOption(RPC_HUB_OPTION *t, PACK *p);
+void OutRpcHubOption(PACK *p, RPC_HUB_OPTION *t);
+void InRpcRadius(RPC_RADIUS *t, PACK *p);
+void OutRpcRadius(PACK *p, RPC_RADIUS *t);
+void InRpcHub(RPC_HUB *t, PACK *p);
+void OutRpcHub(PACK *p, RPC_HUB *t);
+void InRpcCreateHub(RPC_CREATE_HUB *t, PACK *p);
+void OutRpcCreateHub(PACK *p, RPC_CREATE_HUB *t);
+void InRpcEnumHub(RPC_ENUM_HUB *t, PACK *p);
+void OutRpcEnumHub(PACK *p, RPC_ENUM_HUB *t);
+void FreeRpcEnumHub(RPC_ENUM_HUB *t);
+void InRpcDeleteHub(RPC_DELETE_HUB *t, PACK *p);
+void OutRpcDeleteHub(PACK *p, RPC_DELETE_HUB *t);
+void InRpcEnumConnection(RPC_ENUM_CONNECTION *t, PACK *p);
+void OutRpcEnumConnection(PACK *p, RPC_ENUM_CONNECTION *t);
+void FreeRpcEnumConnetion(RPC_ENUM_CONNECTION *t);
+void InRpcDisconnectConnection(RPC_DISCONNECT_CONNECTION *t, PACK *p);
+void OutRpcDisconnectConnection(PACK *p, RPC_DISCONNECT_CONNECTION *t);
+void InRpcConnectionInfo(RPC_CONNECTION_INFO *t, PACK *p);
+void OutRpcConnectionInfo(PACK *p, RPC_CONNECTION_INFO *t);
+void InRpcSetHubOnline(RPC_SET_HUB_ONLINE *t, PACK *p);
+void OutRpcSetHubOnline(PACK *p, RPC_SET_HUB_ONLINE *t);
+void InRpcHubStatus(RPC_HUB_STATUS *t, PACK *p);
+void OutRpcHubStatus(PACK *p, RPC_HUB_STATUS *t);
+void InRpcHubLog(RPC_HUB_LOG *t, PACK *p);
+void OutRpcHubLog(PACK *p, RPC_HUB_LOG *t);
+void InRpcHubAddCa(RPC_HUB_ADD_CA *t, PACK *p);
+void OutRpcHubAddCa(PACK *p, RPC_HUB_ADD_CA *t);
+void FreeRpcHubAddCa(RPC_HUB_ADD_CA *t);
+void InRpcHubEnumCa(RPC_HUB_ENUM_CA *t, PACK *p);
+void OutRpcHubEnumCa(PACK *p, RPC_HUB_ENUM_CA *t);
+void FreeRpcHubEnumCa(RPC_HUB_ENUM_CA *t);
+void InRpcHubGetCa(RPC_HUB_GET_CA *t, PACK *p);
+void OutRpcHubGetCa(PACK *p, RPC_HUB_GET_CA *t);
+void FreeRpcHubGetCa(RPC_HUB_GET_CA *t);
+void InRpcHubDeleteCa(RPC_HUB_DELETE_CA *t, PACK *p);
+void OutRpcHubDeleteCa(PACK *p, RPC_HUB_DELETE_CA *t);
+void InRpcCreateLink(RPC_CREATE_LINK *t, PACK *p);
+void OutRpcCreateLink(PACK *p, RPC_CREATE_LINK *t);
+void FreeRpcCreateLink(RPC_CREATE_LINK *t);
+void InRpcEnumLink(RPC_ENUM_LINK *t, PACK *p);
+void OutRpcEnumLink(PACK *p, RPC_ENUM_LINK *t);
+void FreeRpcEnumLink(RPC_ENUM_LINK *t);
+void InRpcLinkStatus(RPC_LINK_STATUS *t, PACK *p);
+void OutRpcLinkStatus(PACK *p, RPC_LINK_STATUS *t);
+void FreeRpcLinkStatus(RPC_LINK_STATUS *t);
+void InRpcLink(RPC_LINK *t, PACK *p);
+void OutRpcLink(PACK *p, RPC_LINK *t);
+void InRpcAccessEx(ACCESS *a, PACK *p, UINT index);
+void InRpcAccess(ACCESS *a, PACK *p);
+void OutRpcAccessEx(PACK *p, ACCESS *a, UINT index, UINT total);
+void OutRpcAccess(PACK *p, ACCESS *a);
+void InRpcEnumAccessList(RPC_ENUM_ACCESS_LIST *a, PACK *p);
+void OutRpcEnumAccessList(PACK *p, RPC_ENUM_ACCESS_LIST *a);
+void FreeRpcEnumAccessList(RPC_ENUM_ACCESS_LIST *a);
+void *InRpcAuthData(PACK *p, UINT *authtype);
+void OutRpcAuthData(PACK *p, void *authdata, UINT authtype);
+void FreeRpcAuthData(void *authdata, UINT authtype);
+void InRpcSetUser(RPC_SET_USER *t, PACK *p);
+void OutRpcSetUser(PACK *p, RPC_SET_USER *t);
+void FreeRpcSetUser(RPC_SET_USER *t);
+void InRpcEnumUser(RPC_ENUM_USER *t, PACK *p);
+void OutRpcEnumUser(PACK *p, RPC_ENUM_USER *t);
+void FreeRpcEnumUser(RPC_ENUM_USER *t);
+void InRpcSetGroup(RPC_SET_GROUP *t, PACK *p);
+void OutRpcSetGroup(PACK *p, RPC_SET_GROUP *t);
+void InRpcEnumGroup(RPC_ENUM_GROUP *t, PACK *p);
+void OutRpcEnumGroup(PACK *p, RPC_ENUM_GROUP *t);
+void FreeRpcEnumGroup(RPC_ENUM_GROUP *t);
+void InRpcDeleteUser(RPC_DELETE_USER *t, PACK *p);
+void OutRpcDeleteUser(PACK *p, RPC_DELETE_USER *t);
+void InRpcEnumSession(RPC_ENUM_SESSION *t, PACK *p);
+void OutRpcEnumSession(PACK *p, RPC_ENUM_SESSION *t);
+void FreeRpcEnumSession(RPC_ENUM_SESSION *t);
+void InRpcNodeInfo(NODE_INFO *t, PACK *p);
+void OutRpcNodeInfo(PACK *p, NODE_INFO *t);
+void InRpcSessionStatus(RPC_SESSION_STATUS *t, PACK *p);
+void OutRpcSessionStatus(PACK *p, RPC_SESSION_STATUS *t);
+void FreeRpcSessionStatus(RPC_SESSION_STATUS *t);
+void InRpcDeleteSession(RPC_DELETE_SESSION *t, PACK *p);
+void OutRpcDeleteSession(PACK *p, RPC_DELETE_SESSION *t);
+void InRpcEnumMacTable(RPC_ENUM_MAC_TABLE *t, PACK *p);
+void OutRpcEnumMacTable(PACK *p, RPC_ENUM_MAC_TABLE *t);
+void FreeRpcEnumMacTable(RPC_ENUM_MAC_TABLE *t);
+void InRpcEnumIpTable(RPC_ENUM_IP_TABLE *t, PACK *p);
+void OutRpcEnumIpTable(PACK *p, RPC_ENUM_IP_TABLE *t);
+void FreeRpcEnumIpTable(RPC_ENUM_IP_TABLE *t);
+void InRpcDeleteTable(RPC_DELETE_TABLE *t, PACK *p);
+void OutRpcDeleteTable(PACK *p, RPC_DELETE_TABLE *t);
+void InRpcMemInfo(MEMINFO *t, PACK *p);
+void OutRpcMemInfo(PACK *p, MEMINFO *t);
+void InRpcKeyPair(RPC_KEY_PAIR *t, PACK *p);
+void OutRpcKeyPair(PACK *p, RPC_KEY_PAIR *t);
+void FreeRpcKeyPair(RPC_KEY_PAIR *t);
+void InRpcAddAccess(RPC_ADD_ACCESS *t, PACK *p);
+void OutRpcAddAccess(PACK *p, RPC_ADD_ACCESS *t);
+void InRpcDeleteAccess(RPC_DELETE_ACCESS *t, PACK *p);
+void OutRpcDeleteAccess(PACK *p, RPC_DELETE_ACCESS *t);
+void FreeRpcSetGroup(RPC_SET_GROUP *t);
+void AdjoinRpcEnumSession(RPC_ENUM_SESSION *dest, RPC_ENUM_SESSION *src);
+void AdjoinRpcEnumMacTable(RPC_ENUM_MAC_TABLE *dest, RPC_ENUM_MAC_TABLE *src);
+void AdjoinRpcEnumIpTable(RPC_ENUM_IP_TABLE *dest, RPC_ENUM_IP_TABLE *src);
+void InRpcKeep(RPC_KEEP *t, PACK *p);
+void OutRpcKeep(PACK *p, RPC_KEEP *t);
+void InRpcOsInfo(OS_INFO *t, PACK *p);
+void OutRpcOsInfo(PACK *p, OS_INFO *t);
+void FreeRpcOsInfo(OS_INFO *t);
+void InRpcEnumEth(RPC_ENUM_ETH *t, PACK *p);
+void OutRpcEnumEth(PACK *p, RPC_ENUM_ETH *t);
+void FreeRpcEnumEth(RPC_ENUM_ETH *t);
+void InRpcLocalBridge(RPC_LOCALBRIDGE *t, PACK *p);
+void OutRpcLocalBridge(PACK *p, RPC_LOCALBRIDGE *t);
+void InRpcEnumLocalBridge(RPC_ENUM_LOCALBRIDGE *t, PACK *p);
+void OutRpcEnumLocalBridge(PACK *p, RPC_ENUM_LOCALBRIDGE *t);
+void FreeRpcEnumLocalBridge(RPC_ENUM_LOCALBRIDGE *t);
+void InRpcBridgeSupport(RPC_BRIDGE_SUPPORT *t, PACK *p);
+void OutRpcBridgeSupport(PACK *p, RPC_BRIDGE_SUPPORT *t);
+void InRpcConfig(RPC_CONFIG *t, PACK *p);
+void OutRpcConfig(PACK *p, RPC_CONFIG *t);
+void FreeRpcConfig(RPC_CONFIG *t);
+void InRpcAdminOption(RPC_ADMIN_OPTION *t, PACK *p);
+void OutRpcAdminOption(PACK *p, RPC_ADMIN_OPTION *t);
+void FreeRpcAdminOption(RPC_ADMIN_OPTION *t);
+void InRpcEnumL3Table(RPC_ENUM_L3TABLE *t, PACK *p);
+void OutRpcEnumL3Table(PACK *p, RPC_ENUM_L3TABLE *t);
+void FreeRpcEnumL3Table(RPC_ENUM_L3TABLE *t);
+void InRpcL3Table(RPC_L3TABLE *t, PACK *p);
+void OutRpcL3Table(PACK *p, RPC_L3TABLE *t);
+void InRpcEnumL3If(RPC_ENUM_L3IF *t, PACK *p);
+void OutRpcEnumL3If(PACK *p, RPC_ENUM_L3IF *t);
+void FreeRpcEnumL3If(RPC_ENUM_L3IF *t);
+void InRpcL3If(RPC_L3IF *t, PACK *p);
+void OutRpcL3If(PACK *p, RPC_L3IF *t);
+void InRpcL3Sw(RPC_L3SW *t, PACK *p);
+void OutRpcL3Sw(PACK *p, RPC_L3SW *t);
+void InRpcEnumL3Sw(RPC_ENUM_L3SW *t, PACK *p);
+void OutRpcEnumL3Sw(PACK *p, RPC_ENUM_L3SW *t);
+void FreeRpcEnumL3Sw(RPC_ENUM_L3SW *t);
+void InRpcCrl(RPC_CRL *t, PACK *p);
+void OutRpcCrl(PACK *p, RPC_CRL *t);
+void FreeRpcCrl(RPC_CRL *t);
+void InRpcEnumCrl(RPC_ENUM_CRL *t, PACK *p);
+void OutRpcEnumCrl(PACK *p, RPC_ENUM_CRL *t);
+void FreeRpcEnumCrl(RPC_ENUM_CRL *t);
+void InRpcInt(RPC_INT *t, PACK *p);
+void OutRpcInt(PACK *p, RPC_INT *t);
+void InRpcAcList(RPC_AC_LIST *t, PACK *p);
+void OutRpcAcList(PACK *p, RPC_AC_LIST *t);
+void FreeRpcAcList(RPC_AC_LIST *t);
+void InRpcEnumLogFile(RPC_ENUM_LOG_FILE *t, PACK *p);
+void OutRpcEnumLogFile(PACK *p, RPC_ENUM_LOG_FILE *t);
+void FreeRpcEnumLogFile(RPC_ENUM_LOG_FILE *t);
+void AdjoinRpcEnumLogFile(RPC_ENUM_LOG_FILE *t, RPC_ENUM_LOG_FILE *src);
+void InRpcReadLogFile(RPC_READ_LOG_FILE *t, PACK *p);
+void OutRpcReadLogFile(PACK *p, RPC_READ_LOG_FILE *t);
+void FreeRpcReadLogFile(RPC_READ_LOG_FILE *t);
+void InRpcRenameLink(RPC_RENAME_LINK *t, PACK *p);
+void OutRpcRenameLink(PACK *p, RPC_RENAME_LINK *t);
+void InRpcEnumLicenseKey(RPC_ENUM_LICENSE_KEY *t, PACK *p);
+void OutRpcEnumLicenseKey(PACK *p, RPC_ENUM_LICENSE_KEY *t);
+void FreeRpcEnumLicenseKey(RPC_ENUM_LICENSE_KEY *t);
+void InRpcLicenseStatus(RPC_LICENSE_STATUS *t, PACK *p);
+void OutRpcLicenseStatus(PACK *p, RPC_LICENSE_STATUS *t);
+void InRpcEnumEthVLan(RPC_ENUM_ETH_VLAN *t, PACK *p);
+void OutRpcEnumEthVLan(PACK *p, RPC_ENUM_ETH_VLAN *t);
+void FreeRpcEnumEthVLan(RPC_ENUM_ETH_VLAN *t);
+void InRpcMsg(RPC_MSG *t, PACK *p);
+void OutRpcMsg(PACK *p, RPC_MSG *t);
+void FreeRpcMsg(RPC_MSG *t);
+void InRpcWinVer(RPC_WINVER *t, PACK *p);
+void OutRpcWinVer(PACK *p, RPC_WINVER *t);
+void InIPsecServices(IPSEC_SERVICES *t, PACK *p);
+void OutIPsecServices(PACK *p, IPSEC_SERVICES *t);
+void InRpcEnumEtherIpId(RPC_ENUM_ETHERIP_ID *t, PACK *p);
+void OutRpcEnumEtherIpId(PACK *p, RPC_ENUM_ETHERIP_ID *t);
+void FreeRpcEnumEtherIpId(RPC_ENUM_ETHERIP_ID *t);
+void InEtherIpId(ETHERIP_ID *t, PACK *p);
+void OutEtherIpId(PACK *p, ETHERIP_ID *t);
+void InOpenVpnSstpConfig(OPENVPN_SSTP_CONFIG *t, PACK *p);
+void OutOpenVpnSstpConfig(PACK *p, OPENVPN_SSTP_CONFIG *t);
+void InDDnsClientStatus(DDNS_CLIENT_STATUS *t, PACK *p);
+void OutDDnsClientStatus(PACK *p, DDNS_CLIENT_STATUS *t);
+void InRpcSpecialListener(RPC_SPECIAL_LISTENER *t, PACK *p);
+void OutRpcSpecialListener(PACK *p, RPC_SPECIAL_LISTENER *t);
+void InRpcAzureStatus(RPC_AZURE_STATUS *t, PACK *p);
+void OutRpcAzureStatus(PACK *p, RPC_AZURE_STATUS *t);
+void InRpcInternetSetting(INTERNET_SETTING *t, PACK *p);
+void OutRpcInternetSetting(PACK *p, INTERNET_SETTING *t);
+
+#endif // ADMIN_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/AzureClient.c b/src/Cedar/AzureClient.c
new file mode 100644
index 00000000..7bf2e183
--- /dev/null
+++ b/src/Cedar/AzureClient.c
@@ -0,0 +1,658 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// AzureClient.c
+// VPN Azure Client
+
+#include "CedarPch.h"
+
+// Wait for connection request
+void AcWaitForRequest(AZURE_CLIENT *ac, SOCK *s, AZURE_PARAM *param)
+{
+ // Validate arguments
+ if (ac == NULL || s == NULL || param == NULL)
+ {
+ return;
+ }
+
+ while (ac->Halt == false)
+ {
+ UCHAR uc;
+
+ // Receive 1 byte
+ if (RecvAll(s, &uc, 1, false) == 0)
+ {
+ break;
+ }
+
+ if (uc != 0)
+ {
+ // Receive a Pack
+ PACK *p = RecvPackWithHash(s);
+
+ if (p == NULL)
+ {
+ break;
+ }
+ else
+ {
+ // Verify contents of Pack
+ char opcode[MAX_SIZE];
+ char cipher_name[MAX_SIZE];
+ char hostname[MAX_SIZE];
+
+ PackGetStr(p, "opcode", opcode, sizeof(opcode));
+ PackGetStr(p, "cipher_name", cipher_name, sizeof(cipher_name));
+ PackGetStr(p, "hostname", hostname, sizeof(hostname));
+
+ if (StrCmpi(opcode, "relay") == 0)
+ {
+ IP client_ip, server_ip;
+ UINT client_port;
+ UINT server_port;
+ UCHAR session_id[SHA1_SIZE];
+
+ if (PackGetIp(p, "client_ip", &client_ip) &&
+ PackGetIp(p, "server_ip", &server_ip) &&
+ PackGetData2(p, "session_id", session_id, sizeof(session_id)))
+ {
+ client_port = PackGetInt(p, "client_port");
+ server_port = PackGetInt(p, "server_port");
+
+ if (client_port != 0 && server_port != 0)
+ {
+ SOCK *ns;
+ Debug("Connect Request from %r:%u\n", &client_ip, client_port);
+
+ // Create new socket and connect VPN Azure Server
+ if (ac->DDnsStatusCopy.InternetSetting.ProxyType == PROXY_DIRECT)
+ {
+ ns = ConnectEx2(ac->DDnsStatusCopy.CurrentAzureIp, AZURE_SERVER_PORT,
+ 0, (bool *)&ac->Halt);
+ }
+ else
+ {
+ ns = WpcSockConnect2(ac->DDnsStatusCopy.CurrentAzureIp, AZURE_SERVER_PORT,
+ &ac->DDnsStatusCopy.InternetSetting, NULL, AZURE_VIA_PROXY_TIMEOUT);
+ }
+
+ if (ns == NULL)
+ {
+ Debug("Connect Error.\n");
+ }
+ else
+ {
+ Debug("Connected to the relay server.\n");
+
+ SetTimeout(ns, param->DataTimeout);
+
+ if (StartSSLEx(ns, NULL, NULL, true, 0, NULL))
+ {
+ // Check certification
+ char server_cert_hash_str[MAX_SIZE];
+ UCHAR server_cert_hash[SHA1_SIZE];
+
+ Zero(server_cert_hash, sizeof(server_cert_hash));
+ GetXDigest(ns->RemoteX, server_cert_hash, true);
+
+ BinToStr(server_cert_hash_str, sizeof(server_cert_hash_str),
+ server_cert_hash, SHA1_SIZE);
+
+ if (IsEmptyStr(ac->DDnsStatusCopy.AzureCertHash) || StrCmpi(server_cert_hash_str, ac->DDnsStatusCopy.AzureCertHash) == 0)
+ {
+ if (SendAll(ns, AZURE_PROTOCOL_DATA_SIANGTURE, 24, true))
+ {
+ PACK *p2 = NewPack();
+
+ PackAddStr(p2, "hostname", hostname);
+ PackAddData(p2, "session_id", session_id, sizeof(session_id));
+
+ if (SendPackWithHash(ns, p2))
+ {
+ UCHAR uc;
+
+ if (RecvAll(ns, &uc, 1, true) != false)
+ {
+ if (uc != 0)
+ {
+ SOCK *accept_sock = GetReverseListeningSock(ac->Cedar);
+
+ if (accept_sock != NULL)
+ {
+ AddRef(ns->ref);
+
+ SetTimeout(ns, INFINITE);
+
+ Copy(&ns->Reverse_MyServerGlobalIp, &server_ip, sizeof(IP));
+ ns->Reverse_MyServerPort = server_port;
+
+ InjectNewReverseSocketToAccept(accept_sock, ns,
+ &client_ip, client_port);
+
+ ReleaseSock(accept_sock);
+ }
+ }
+ }
+ }
+
+ FreePack(p2);
+ }
+ }
+ }
+
+ ReleaseSock(ns);
+ }
+ }
+ }
+ }
+
+ FreePack(p);
+ }
+ }
+
+ // Send 1 byte
+ uc = 0;
+ if (SendAll(s, &uc, 1, false) == 0)
+ {
+ break;
+ }
+ }
+}
+
+// VPN Azure client main thread
+void AcMainThread(THREAD *thread, void *param)
+{
+ AZURE_CLIENT *ac = (AZURE_CLIENT *)param;
+ UINT last_ip_revision = INFINITE;
+ UINT64 last_reconnect_tick = 0;
+ UINT64 next_reconnect_interval = AZURE_CONNECT_INITIAL_RETRY_INTERVAL;
+ UINT num_reconnect_retry = 0;
+ UINT64 next_ddns_retry_tick = 0;
+ bool last_connect_ok = false;
+ // Validate arguments
+ if (ac == NULL || thread == NULL)
+ {
+ return;
+ }
+
+ while (ac->Halt == false)
+ {
+ UINT64 now = Tick64();
+ bool connect_was_ok = false;
+ // Wait for enabling VPN Azure function
+ if (ac->IsEnabled)
+ {
+ // VPN Azure is enabled
+ DDNS_CLIENT_STATUS st;
+ bool connect_now = false;
+ bool azure_ip_changed = false;
+
+ Lock(ac->Lock);
+ {
+ Copy(&st, &ac->DDnsStatus, sizeof(DDNS_CLIENT_STATUS));
+
+ if (StrCmpi(st.CurrentAzureIp, ac->DDnsStatusCopy.CurrentAzureIp) != 0)
+ {
+ if (IsEmptyStr(st.CurrentAzureIp) == false)
+ {
+ // Destination IP address is changed
+ connect_now = true;
+ num_reconnect_retry = 0;
+ }
+ }
+
+ if (StrCmpi(st.CurrentHostName, ac->DDnsStatusCopy.CurrentHostName) != 0)
+ {
+ // DDNS host name is changed
+ connect_now = true;
+ num_reconnect_retry = 0;
+ }
+
+ Copy(&ac->DDnsStatusCopy, &st, sizeof(DDNS_CLIENT_STATUS));
+ }
+ Unlock(ac->Lock);
+
+ if (last_ip_revision != ac->IpStatusRevision)
+ {
+ last_ip_revision = ac->IpStatusRevision;
+
+ connect_now = true;
+
+ num_reconnect_retry = 0;
+ }
+
+ if (last_reconnect_tick == 0 || (now >= (last_reconnect_tick + next_reconnect_interval)))
+ {
+ UINT r;
+
+ last_reconnect_tick = now;
+ num_reconnect_retry++;
+ next_reconnect_interval = (UINT64)num_reconnect_retry * AZURE_CONNECT_INITIAL_RETRY_INTERVAL;
+ next_reconnect_interval = MIN(next_reconnect_interval, AZURE_CONNECT_MAX_RETRY_INTERVAL);
+
+ r = (UINT)next_reconnect_interval;
+
+ r = GenRandInterval(r / 2, r);
+
+ next_reconnect_interval = r;
+
+ connect_now = true;
+ }
+
+ if (IsEmptyStr(st.CurrentAzureIp) == false && IsEmptyStr(st.CurrentHostName) == false)
+ {
+ if (connect_now)
+ {
+ SOCK *s;
+ char *host = NULL;
+ UINT port = AZURE_SERVER_PORT;
+
+ Debug("VPN Azure: Connecting to %s...\n", st.CurrentAzureIp);
+
+ if (ParseHostPort(st.CurrentAzureIp, &host, &port, AZURE_SERVER_PORT))
+ {
+ if (st.InternetSetting.ProxyType == PROXY_DIRECT)
+ {
+ s = ConnectEx2(host, port, 0, (bool *)&ac->Halt);
+ }
+ else
+ {
+ s = WpcSockConnect2(host, port, &st.InternetSetting, NULL, AZURE_VIA_PROXY_TIMEOUT);
+ }
+
+ if (s != NULL)
+ {
+ PACK *p;
+ UINT64 established_tick = 0;
+
+ Debug("VPN Azure: Connected.\n");
+
+ SetTimeout(s, AZURE_PROTOCOL_CONTROL_TIMEOUT_DEFAULT);
+
+ Lock(ac->Lock);
+ {
+ ac->CurrentSock = s;
+ ac->IsConnected = true;
+ StrCpy(ac->ConnectingAzureIp, sizeof(ac->ConnectingAzureIp), st.CurrentAzureIp);
+ }
+ Unlock(ac->Lock);
+
+ SendAll(s, AZURE_PROTOCOL_CONTROL_SIGNATURE, StrLen(AZURE_PROTOCOL_CONTROL_SIGNATURE), false);
+
+ // Receive parameter
+ p = RecvPackWithHash(s);
+ if (p != NULL)
+ {
+ UCHAR c;
+ AZURE_PARAM param;
+ bool hostname_changed = false;
+
+ Zero(&param, sizeof(param));
+
+ param.ControlKeepAlive = PackGetInt(p, "ControlKeepAlive");
+ param.ControlTimeout = PackGetInt(p, "ControlTimeout");
+ param.DataTimeout = PackGetInt(p, "DataTimeout");
+ param.SslTimeout = PackGetInt(p, "SslTimeout");
+
+ FreePack(p);
+
+ param.ControlKeepAlive = MAKESURE(param.ControlKeepAlive, 1000, AZURE_SERVER_MAX_KEEPALIVE);
+ param.ControlTimeout = MAKESURE(param.ControlTimeout, 1000, AZURE_SERVER_MAX_TIMEOUT);
+ param.DataTimeout = MAKESURE(param.DataTimeout, 1000, AZURE_SERVER_MAX_TIMEOUT);
+ param.SslTimeout = MAKESURE(param.SslTimeout, 1000, AZURE_SERVER_MAX_TIMEOUT);
+
+ Lock(ac->Lock);
+ {
+ Copy(&ac->AzureParam, &param, sizeof(AZURE_PARAM));
+ }
+ Unlock(ac->Lock);
+
+ SetTimeout(s, param.ControlTimeout);
+
+ // Send parameter
+ p = NewPack();
+ PackAddStr(p, "CurrentHostName", st.CurrentHostName);
+ PackAddStr(p, "CurrentAzureIp", st.CurrentAzureIp);
+ PackAddInt64(p, "CurrentAzureTimestamp", st.CurrentAzureTimestamp);
+ PackAddStr(p, "CurrentAzureSignature", st.CurrentAzureSignature);
+
+ Lock(ac->Lock);
+ {
+ if (StrCmpi(st.CurrentHostName, ac->DDnsStatus.CurrentHostName) != 0)
+ {
+ hostname_changed = true;
+ }
+ }
+ Unlock(ac->Lock);
+
+ if (hostname_changed == false)
+ {
+ if (SendPackWithHash(s, p))
+ {
+ // Receive result
+ if (RecvAll(s, &c, 1, false))
+ {
+ if (c && ac->Halt == false)
+ {
+ connect_was_ok = true;
+
+ established_tick = Tick64();
+
+ AcWaitForRequest(ac, s, &param);
+ }
+ }
+ }
+ }
+
+ FreePack(p);
+ }
+ else
+ {
+ WHERE;
+ }
+
+ Debug("VPN Azure: Disconnected.\n");
+
+ Lock(ac->Lock);
+ {
+ ac->IsConnected = false;
+ ac->CurrentSock = NULL;
+ ClearStr(ac->ConnectingAzureIp, sizeof(ac->ConnectingAzureIp));
+ }
+ Unlock(ac->Lock);
+
+ if (established_tick != 0)
+ {
+ if ((established_tick + (UINT64)AZURE_CONNECT_MAX_RETRY_INTERVAL) <= Tick64())
+ {
+ // If the connected time exceeds the AZURE_CONNECT_MAX_RETRY_INTERVAL, reset the retry counter.
+ last_reconnect_tick = 0;
+ num_reconnect_retry = 0;
+ next_reconnect_interval = AZURE_CONNECT_INITIAL_RETRY_INTERVAL;
+ }
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+ }
+ else
+ {
+ Debug("VPN Azure: Error: Connect Failed.\n");
+ }
+
+ Free(host);
+ }
+ }
+ }
+ }
+ else
+ {
+ last_reconnect_tick = 0;
+ num_reconnect_retry = 0;
+ next_reconnect_interval = AZURE_CONNECT_INITIAL_RETRY_INTERVAL;
+ }
+
+ if (ac->Halt)
+ {
+ break;
+ }
+
+ if (connect_was_ok)
+ {
+ // If connection goes out after connected, increment connection success count to urge DDNS client query
+ next_ddns_retry_tick = Tick64() + MIN((UINT64)DDNS_VPN_AZURE_CONNECT_ERROR_DDNS_RETRY_TIME_DIFF * (UINT64)(num_reconnect_retry + 1), (UINT64)DDNS_VPN_AZURE_CONNECT_ERROR_DDNS_RETRY_TIME_DIFF_MAX);
+ }
+
+ if ((next_ddns_retry_tick != 0) && (Tick64() >= next_ddns_retry_tick))
+ {
+ next_ddns_retry_tick = 0;
+
+ ac->DDnsTriggerInt++;
+ }
+
+ Wait(ac->Event, rand() % 1000);
+ }
+}
+
+// Get enabled or disabled VPN Azure client
+bool AcGetEnable(AZURE_CLIENT *ac)
+{
+ // Validate arguments
+ if (ac == NULL)
+ {
+ return false;
+ }
+
+ return ac->IsEnabled;
+}
+
+// Enable or disable VPN Azure client
+void AcSetEnable(AZURE_CLIENT *ac, bool enabled)
+{
+ bool old_status;
+ // Validate arguments
+ if (ac == NULL)
+ {
+ return;
+ }
+
+ old_status = ac->IsEnabled;
+
+ ac->IsEnabled = enabled;
+
+ if (ac->IsEnabled && (ac->IsEnabled != old_status))
+ {
+ ac->DDnsTriggerInt++;
+ }
+
+ AcApplyCurrentConfig(ac, NULL);
+}
+
+// Set current configuration to VPN Azure client
+void AcApplyCurrentConfig(AZURE_CLIENT *ac, DDNS_CLIENT_STATUS *ddns_status)
+{
+ bool disconnect_now = false;
+ SOCK *disconnect_sock = NULL;
+ // Validate arguments
+ if (ac == NULL)
+ {
+ return;
+ }
+
+ // Get current DDNS configuration
+ Lock(ac->Lock);
+ {
+ if (ddns_status != NULL)
+ {
+ if (StrCmpi(ac->DDnsStatus.CurrentHostName, ddns_status->CurrentHostName) != 0)
+ {
+ // If host name is changed, disconnect current data connection
+ disconnect_now = true;
+ }
+
+ if (Cmp(&ac->DDnsStatus.InternetSetting, &ddns_status->InternetSetting, sizeof(INTERNET_SETTING)) != 0)
+ {
+ // If proxy setting is changed, disconnect current data connection
+ disconnect_now = true;
+ }
+
+ Copy(&ac->DDnsStatus, ddns_status, sizeof(DDNS_CLIENT_STATUS));
+ }
+
+ if (ac->IsEnabled == false)
+ {
+ // If VPN Azure client is disabled, disconnect current data connection
+ disconnect_now = true;
+ }
+
+ if (disconnect_now)
+ {
+ if (ac->CurrentSock != NULL)
+ {
+ disconnect_sock = ac->CurrentSock;
+ AddRef(disconnect_sock->ref);
+ }
+ }
+ }
+ Unlock(ac->Lock);
+
+ if (disconnect_sock != NULL)
+ {
+ Disconnect(disconnect_sock);
+ ReleaseSock(disconnect_sock);
+ }
+
+ Set(ac->Event);
+}
+
+// Free VPN Azure client
+void FreeAzureClient(AZURE_CLIENT *ac)
+{
+ SOCK *disconnect_sock = NULL;
+ // Validate arguments
+ if (ac == NULL)
+ {
+ return;
+ }
+
+ ac->Halt = true;
+
+ Lock(ac->Lock);
+ {
+ if (ac->CurrentSock != NULL)
+ {
+ disconnect_sock = ac->CurrentSock;
+
+ AddRef(disconnect_sock->ref);
+ }
+ }
+ Unlock(ac->Lock);
+
+ if (disconnect_sock != NULL)
+ {
+ Disconnect(disconnect_sock);
+ ReleaseSock(disconnect_sock);
+ }
+
+ Set(ac->Event);
+
+ // Stop main thread
+ WaitThread(ac->MainThread, INFINITE);
+ ReleaseThread(ac->MainThread);
+
+ ReleaseEvent(ac->Event);
+
+ DeleteLock(ac->Lock);
+
+ Free(ac);
+}
+
+// Create new VPN Azure client
+AZURE_CLIENT *NewAzureClient(CEDAR *cedar, SERVER *server)
+{
+ AZURE_CLIENT *ac;
+ // Validate arguments
+ if (cedar == NULL || server == NULL)
+ {
+ return NULL;
+ }
+
+ ac = ZeroMalloc(sizeof(AZURE_CLIENT));
+
+ ac->Cedar = cedar;
+
+ ac->Server = server;
+
+ ac->Lock = NewLock();
+
+ ac->IsEnabled = false;
+
+ ac->Event = NewEvent();
+
+ // Start main thread
+ ac->MainThread = NewThread(AcMainThread, ac);
+
+ return ac;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/AzureClient.h b/src/Cedar/AzureClient.h
new file mode 100644
index 00000000..1a55a9ca
--- /dev/null
+++ b/src/Cedar/AzureClient.h
@@ -0,0 +1,149 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// AzureClient.h
+// Header of AzureClient.c
+
+#ifndef AZURE_CLIENT_H
+#define AZURE_CLIENT_H
+
+// Constants
+#define AZURE_SERVER_PORT 443
+#define AZURE_PROTOCOL_CONTROL_SIGNATURE "ACTL"
+#define AZURE_PROTOCOL_DATA_SIANGTURE "AZURE_CONNECT_SIGNATURE!"
+#define AZURE_PROTOCOL_CONTROL_TIMEOUT_DEFAULT (5 * 1000) // Default timeout
+#define AZURE_CONNECT_INITIAL_RETRY_INTERVAL (1 * 1000) // Initial re-connection interval (15 * 1000)
+#define AZURE_CONNECT_MAX_RETRY_INTERVAL (60 * 60 * 1000) // Maximum re-connection interval
+
+#define AZURE_DOMAIN_SUFFIX ".vpnazure.net"
+
+#define AZURE_SERVER_MAX_KEEPALIVE (5 * 60 * 1000)
+#define AZURE_SERVER_MAX_TIMEOUT (10 * 60 * 1000)
+
+#define AZURE_VIA_PROXY_TIMEOUT 5000
+
+
+// Communications parameter
+struct AZURE_PARAM
+{
+ UINT ControlKeepAlive;
+ UINT ControlTimeout;
+ UINT DataTimeout;
+ UINT SslTimeout;
+};
+
+// VPN Azure Client
+struct AZURE_CLIENT
+{
+ CEDAR *Cedar;
+ SERVER *Server;
+ LOCK *Lock;
+ DDNS_CLIENT_STATUS DDnsStatus;
+ volatile bool IsEnabled;
+ EVENT *Event;
+ volatile bool Halt;
+ THREAD *MainThread;
+ volatile UINT IpStatusRevision;
+ DDNS_CLIENT_STATUS DDnsStatusCopy;
+ SOCK *CurrentSock;
+ char ConnectingAzureIp[MAX_SIZE];
+ AZURE_PARAM AzureParam;
+ volatile UINT DDnsTriggerInt;
+ volatile bool IsConnected;
+};
+
+
+// Function prototype
+AZURE_CLIENT *NewAzureClient(CEDAR *cedar, SERVER *server);
+void FreeAzureClient(AZURE_CLIENT *ac);
+void AcApplyCurrentConfig(AZURE_CLIENT *ac, DDNS_CLIENT_STATUS *ddns_status);
+void AcMainThread(THREAD *thread, void *param);
+void AcSetEnable(AZURE_CLIENT *ac, bool enabled);
+bool AcGetEnable(AZURE_CLIENT *ac);
+void AcWaitForRequest(AZURE_CLIENT *ac, SOCK *s, AZURE_PARAM *param);
+
+
+#endif // AZURE_CLIENT_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/AzureServer.c b/src/Cedar/AzureServer.c
new file mode 100644
index 00000000..caea4c30
--- /dev/null
+++ b/src/Cedar/AzureServer.c
@@ -0,0 +1,90 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// AzureServer.c
+// VPN Azure Server
+
+#include "CedarPch.h"
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/AzureServer.h b/src/Cedar/AzureServer.h
new file mode 100644
index 00000000..c6389c35
--- /dev/null
+++ b/src/Cedar/AzureServer.h
@@ -0,0 +1,94 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// AzureServer.h
+// Header of AzureServer.c
+
+#ifndef AZURE_SERVER_H
+#define AZURE_SERVER_H
+
+
+#endif // AZURE_SERVER_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Bridge.c b/src/Cedar/Bridge.c
new file mode 100644
index 00000000..a2434995
--- /dev/null
+++ b/src/Cedar/Bridge.c
@@ -0,0 +1,532 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Bridge.c
+// Ethernet Bridge Program (Local Bridge)
+
+#include <GlobalConst.h>
+
+#define BRIDGE_C
+
+#ifdef WIN32
+#define OS_WIN32
+#endif
+
+#ifdef OS_WIN32
+
+// Win32
+#include "BridgeWin32.c"
+
+#else
+
+// Unix
+#include "BridgeUnix.c"
+
+#endif // OS_WIN32
+
+// Hash the list of current Ethernet devices
+UINT GetEthDeviceHash()
+{
+#ifdef OS_UNIX
+ // UNIX
+ UINT num;
+ UINT i;
+ char tmp[4096];
+ UCHAR hash[SHA1_SIZE];
+ TOKEN_LIST *t = GetEthList();
+
+ num = t->NumTokens;
+ tmp[0] = 0;
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ StrCat(tmp, sizeof(tmp), t->Token[i]);
+ }
+ FreeToken(t);
+
+ Hash(hash, tmp, StrLen(tmp), true);
+
+ Copy(&num, hash, sizeof(UINT));
+
+ return num;
+#else // OS_UNIX
+ // Win32
+ UINT ret = 0;
+ MS_ADAPTER_LIST *a = MsCreateAdapterListEx(true);
+ UINT num;
+ UINT i;
+ char tmp[4096];
+ UCHAR hash[SHA1_SIZE];
+
+ tmp[0] = 0;
+ if (a != NULL)
+ {
+ for (i = 0;i < a->Num;i++)
+ {
+ StrCat(tmp, sizeof(tmp), a->Adapters[i]->Title);
+ }
+ }
+ MsFreeAdapterList(a);
+
+ Hash(hash, tmp, StrLen(tmp), true);
+
+ Copy(&num, hash, sizeof(UINT));
+
+ return num;
+#endif // OS_UNIX
+}
+
+// Get whether WinPcap is needed
+bool IsNeedWinPcap()
+{
+ if (IsBridgeSupported() == false)
+ {
+ // Not in Windows
+ return false;
+ }
+ else
+ {
+ // Windows
+ if (IsEthSupported())
+ {
+ // Already success to access the Ethernet device
+ return false;
+ }
+ else
+ {
+ // Failed to access the Ethernet device
+ return true;
+ }
+ }
+}
+
+// Get whether the local-bridging is supported by current OS
+bool IsBridgeSupported()
+{
+ UINT type = GetOsInfo()->OsType;
+
+ if (OS_IS_WINDOWS(type))
+ {
+ if (IsEthSupported())
+ {
+ return true;
+ }
+ else
+ {
+ bool ret = false;
+
+#ifdef OS_WIN32
+ ret = MsIsAdmin();
+#endif // OS_WIN32
+
+ return ret;
+ }
+ }
+ else
+ {
+ return IsEthSupported();
+ }
+}
+
+// Delete a local-bridge
+bool DeleteLocalBridge(CEDAR *c, char *hubname, char *devicename)
+{
+ bool ret = false;
+ // Validate arguments
+ if (c == NULL || hubname == NULL || devicename == NULL)
+ {
+ return false;
+ }
+
+ LockList(c->HubList);
+ {
+ LockList(c->LocalBridgeList);
+ {
+ UINT i;
+
+ for (i = 0;i < LIST_NUM(c->LocalBridgeList);i++)
+ {
+ LOCALBRIDGE *br = LIST_DATA(c->LocalBridgeList, i);
+
+ if (StrCmpi(br->HubName, hubname) == 0)
+ {
+ if (StrCmpi(br->DeviceName, devicename) == 0)
+ {
+ if (br->Bridge != NULL)
+ {
+ BrFreeBridge(br->Bridge);
+ br->Bridge = NULL;
+ }
+
+ Delete(c->LocalBridgeList, br);
+ Free(br);
+
+ ret = true;
+ break;
+ }
+ }
+ }
+ }
+ UnlockList(c->LocalBridgeList);
+ }
+ UnlockList(c->HubList);
+
+ return ret;
+}
+
+// Add a local-bridge
+void AddLocalBridge(CEDAR *c, char *hubname, char *devicename, bool local, bool monitor, bool tapmode, char *tapaddr, bool limit_broadcast)
+{
+ UINT i;
+ HUB *h = NULL;
+ LOCALBRIDGE *br = NULL;
+ // Validate arguments
+ if (c == NULL || hubname == NULL || devicename == NULL)
+ {
+ return;
+ }
+
+ if (OS_IS_UNIX(GetOsInfo()->OsType) == false)
+ {
+ tapmode = false;
+ }
+
+ LockList(c->HubList);
+ {
+ LockList(c->LocalBridgeList);
+ {
+ bool exists = false;
+
+ // Ensure that the same configuration local-bridge doesn't exist already
+ for (i = 0;i < LIST_NUM(c->LocalBridgeList);i++)
+ {
+ LOCALBRIDGE *br = LIST_DATA(c->LocalBridgeList, i);
+ if (StrCmpi(br->DeviceName, devicename) == 0)
+ {
+ if (StrCmpi(br->HubName, hubname) == 0)
+ {
+ if (br->TapMode == tapmode)
+ {
+ exists = true;
+ }
+ }
+ }
+ }
+
+ if (exists == false)
+ {
+ // Add configuration
+ br = ZeroMalloc(sizeof(LOCALBRIDGE));
+ StrCpy(br->HubName, sizeof(br->HubName), hubname);
+ StrCpy(br->DeviceName, sizeof(br->DeviceName), devicename);
+ br->Bridge = NULL;
+ br->Local = local;
+ br->TapMode = tapmode;
+ br->LimitBroadcast = limit_broadcast;
+ br->Monitor = monitor;
+ if (br->TapMode)
+ {
+ if (tapaddr != NULL && IsZero(tapaddr, 6) == false)
+ {
+ Copy(br->TapMacAddress, tapaddr, 6);
+ }
+ else
+ {
+ GenMacAddress(br->TapMacAddress);
+ }
+ }
+
+ Add(c->LocalBridgeList, br);
+
+ // Find the hub
+ for (i = 0;i < LIST_NUM(c->HubList);i++)
+ {
+ HUB *hub = LIST_DATA(c->HubList, i);
+ if (StrCmpi(hub->Name, br->HubName) == 0)
+ {
+ h = hub;
+ AddRef(h->ref);
+ break;
+ }
+ }
+ }
+ }
+ UnlockList(c->LocalBridgeList);
+ }
+ UnlockList(c->HubList);
+
+ // Start the local-bridge immediately
+ if (h != NULL && br != NULL && h->Type != HUB_TYPE_FARM_DYNAMIC)
+ {
+ Lock(h->lock_online);
+ {
+ if (h->Offline == false)
+ {
+ LockList(c->LocalBridgeList);
+ {
+ if (IsInList(c->LocalBridgeList, br))
+ {
+ if (br->Bridge == NULL)
+ {
+ br->Bridge = BrNewBridge(h, br->DeviceName, NULL, br->Local, br->Monitor, br->TapMode, br->TapMacAddress, br->LimitBroadcast, br);
+ }
+ }
+ }
+ UnlockList(c->LocalBridgeList);
+ }
+ }
+ Unlock(h->lock_online);
+ }
+
+ ReleaseHub(h);
+}
+
+// Initialize the local-bridge list
+void InitLocalBridgeList(CEDAR *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->LocalBridgeList = NewList(NULL);
+}
+
+// Free the local-bridge list
+void FreeLocalBridgeList(CEDAR *c)
+{
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(c->LocalBridgeList);i++)
+ {
+ LOCALBRIDGE *br = LIST_DATA(c->LocalBridgeList, i);
+ Free(br);
+ }
+
+ ReleaseList(c->LocalBridgeList);
+ c->LocalBridgeList = NULL;
+}
+
+// Bridging thread
+void BrBridgeThread(THREAD *thread, void *param)
+{
+ BRIDGE *b;
+ CONNECTION *c;
+ SESSION *s;
+ HUB *h;
+ char name[MAX_SIZE];
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ b = (BRIDGE *)param;
+
+ // Create a connection object
+ c = NewServerConnection(b->Cedar, NULL, thread);
+ c->Protocol = CONNECTION_HUB_BRIDGE;
+
+ // Create a session object
+ s = NewServerSession(b->Cedar, c, b->Hub, BRIDGE_USER_NAME, b->Policy);
+ HLog(b->Hub, "LH_START_BRIDGE", b->Name, s->Name);
+ StrCpy(name, sizeof(name), b->Name);
+ h = b->Hub;
+ AddRef(h->ref);
+ s->BridgeMode = true;
+ s->Bridge = b;
+ c->Session = s;
+ ReleaseConnection(c);
+
+ // Dummy user name for local-bridge
+ s->Username = CopyStr(BRIDGE_USER_NAME_PRINT);
+
+ b->Session = s;
+ AddRef(s->ref);
+
+ // Notify completion
+ NoticeThreadInit(thread);
+
+ // Main procedure of the session
+ Debug("Bridge %s Start.\n", b->Name);
+ SessionMain(s);
+ Debug("Bridge %s Stop.\n", b->Name);
+
+ HLog(h, "LH_STOP_BRIDGE", name);
+
+ ReleaseHub(h);
+
+ ReleaseSession(s);
+}
+
+// Free the local-bridge object
+void BrFreeBridge(BRIDGE *b)
+{
+ // Validate arguments
+ if (b == NULL)
+ {
+ return;
+ }
+
+ if (b->ParentLocalBridge != NULL)
+ {
+ b->ParentLocalBridge = NULL;
+ }
+
+ // Stop session thread
+ StopSession(b->Session);
+ ReleaseSession(b->Session);
+
+ Free(b);
+}
+
+// Create new local-bridge
+BRIDGE *BrNewBridge(HUB *h, char *name, POLICY *p, bool local, bool monitor, bool tapmode, char *tapaddr, bool limit_broadcast, LOCALBRIDGE *parent_local_bridge)
+{
+ BRIDGE *b;
+ POLICY *policy;
+ THREAD *t;
+ // Validate arguments
+ if (h == NULL || name == NULL || parent_local_bridge == NULL)
+ {
+ return NULL;
+ }
+
+ if (p == NULL)
+ {
+ policy = ClonePolicy(GetDefaultPolicy());
+ }
+ else
+ {
+ policy = ClonePolicy(p);
+ }
+
+ b = ZeroMalloc(sizeof(BRIDGE));
+ b->Cedar = h->Cedar;
+ b->Hub = h;
+ StrCpy(b->Name, sizeof(b->Name), name);
+ b->Policy = policy;
+ b->Local = local;
+ b->Monitor = monitor;
+ b->TapMode = tapmode;
+ b->LimitBroadcast = limit_broadcast;
+ b->ParentLocalBridge = parent_local_bridge;
+
+ if (b->TapMode)
+ {
+ if (tapaddr != NULL && IsZero(tapaddr, 6) == false)
+ {
+ Copy(b->TapMacAddress, tapaddr, 6);
+ }
+ else
+ {
+ GenMacAddress(b->TapMacAddress);
+ }
+ }
+
+ if (monitor)
+ {
+ // Enabling monitoring mode
+ policy->MonitorPort = true;
+ }
+
+ if (b->LimitBroadcast == false)
+ {
+ // Disable broadcast limiter
+ policy->NoBroadcastLimiter = true;
+ }
+
+ // Start thread
+ t = NewThread(BrBridgeThread, b);
+ WaitThreadInit(t);
+ ReleaseThread(t);
+
+ return b;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Bridge.h b/src/Cedar/Bridge.h
new file mode 100644
index 00000000..771ef4ef
--- /dev/null
+++ b/src/Cedar/Bridge.h
@@ -0,0 +1,152 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Bridge.h
+// Header of Bridge.c
+
+#ifndef BRIDGE_H
+#define BRIDGE_H
+
+#ifdef OS_WIN32
+
+// For Win32
+#include <Cedar/BridgeWin32.h>
+
+#else
+
+// For Unix
+#include <Cedar/BridgeUnix.h>
+
+#endif // OS_WIN32
+
+// Bridge
+struct BRIDGE
+{
+ bool Active; // Status
+ CEDAR *Cedar; // Cedar
+ HUB *Hub; // HUB
+ SESSION *Session; // Session
+ POLICY *Policy; // Policy
+ ETH *Eth; // Ethernet
+ char Name[MAX_SIZE]; // Device name
+ UINT64 LastBridgeTry; // Time to try to bridge at last
+ bool Local; // Local mode
+ bool Monitor; // Monitor mode
+ bool TapMode; // Tap mode
+ bool LimitBroadcast; // Broadcasts limiting mode
+ UCHAR TapMacAddress[6]; // MAC address of the tap
+ UINT LastNumDevice; // Number of device (Number of last checked)
+ UINT64 LastNumDeviceCheck; // Time at which to check the number of devices at last
+ UINT64 LastChangeMtuError; // Time that recorded the error to change the MTU at last
+ LOCALBRIDGE *ParentLocalBridge; // Parent Local Bridge
+};
+
+// Local bridge
+struct LOCALBRIDGE
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // Virtual HUB name
+ char DeviceName[MAX_SIZE]; // Device name
+ bool Local; // Local mode
+ bool Monitor; // Monitor mode
+ bool TapMode; // Tap mode
+ bool LimitBroadcast; // Broadcast packets limiting mode
+ UCHAR TapMacAddress[6]; // MAC address of the tap
+ BRIDGE *Bridge; // Bridge
+};
+
+BRIDGE *BrNewBridge(HUB *h, char *name, POLICY *p, bool local, bool monitor, bool tapmode, char *tapaddr, bool limit_broadcast, LOCALBRIDGE *parent_local_bridge);
+void BrBridgeThread(THREAD *thread, void *param);
+void BrFreeBridge(BRIDGE *b);
+void InitLocalBridgeList(CEDAR *c);
+void FreeLocalBridgeList(CEDAR *c);
+void AddLocalBridge(CEDAR *c, char *hubname, char *devicename, bool local, bool monitor, bool tapmode, char *tapaddr, bool limit_broadcast);
+bool DeleteLocalBridge(CEDAR *c, char *hubname, char *devicename);
+bool IsBridgeSupported();
+bool IsNeedWinPcap();
+UINT GetEthDeviceHash();
+
+#endif // BRIDGE_H
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/BridgeUnix.c b/src/Cedar/BridgeUnix.c
new file mode 100644
index 00000000..ee8c93a2
--- /dev/null
+++ b/src/Cedar/BridgeUnix.c
@@ -0,0 +1,1813 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// BridgeUnix.c
+// Ethernet Bridge Program (for UNIX)
+//#define BRIDGE_C
+//#define UNIX_LINUX
+
+#include <GlobalConst.h>
+
+#ifdef BRIDGE_C
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+
+#ifdef UNIX_SOLARIS
+#include <sys/sockio.h>
+#endif
+
+#ifdef BRIDGE_PCAP
+#include <pcap.h>
+#endif // BRIDGE_PCAP
+
+#ifdef BRIDGE_BPF
+#include <sys/ioctl.h>
+#include <net/bpf.h>
+#include <net/if_types.h>
+#include <net/if_dl.h>
+#include <ifaddrs.h>
+#endif // BRIDGE_BPF
+
+// Initialize
+void InitEth()
+{
+}
+
+// Free
+void FreeEth()
+{
+}
+
+// Check whether interface description string of Ethernet device can be retrieved in this system
+bool EthIsInterfaceDescriptionSupportedUnix()
+{
+ bool ret = false;
+ DIRLIST *d = EnumDir("/etc/sysconfig/networking/devices/");
+
+ if (d == NULL)
+ {
+ return false;
+ }
+
+ if (d->NumFiles >= 1)
+ {
+ ret = true;
+ }
+
+ FreeDir(d);
+
+ return ret;
+}
+
+// Get interface description string
+bool EthGetInterfaceDescriptionUnix(char *name, char *str, UINT size)
+{
+ char tmp[MAX_SIZE];
+ bool ret = false;
+ BUF *b;
+ // Validate arguments
+ if (name == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ StrCpy(str, size, name);
+
+ Format(tmp, sizeof(tmp), "/etc/sysconfig/networking/devices/ifcfg-%s", name);
+
+ b = ReadDump(tmp);
+ if (b != NULL)
+ {
+ char *line = CfgReadNextLine(b);
+
+ if (IsEmptyStr(line) == false)
+ {
+ if (StartWith(line, "#"))
+ {
+ char tmp[MAX_SIZE];
+
+ StrCpy(tmp, sizeof(tmp), line + 1);
+
+ Trim(tmp);
+ tmp[60] = 0;
+
+ StrCpy(str, size, tmp);
+
+ ret = true;
+ }
+ }
+
+ Free(line);
+
+ FreeBuf(b);
+ }
+
+ return ret;
+}
+
+// Open raw socket
+int UnixEthOpenRawSocket()
+{
+#ifdef UNIX_LINUX
+ int s;
+
+ s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (s < 0)
+ {
+ return INVALID_SOCKET;
+ }
+ else
+ {
+ return s;
+ }
+#else // UNIX_LINUX
+ return -1;
+#endif // UNIX_LINUX
+}
+
+// Is Ethernet device control supported?
+bool IsEthSupported()
+{
+ bool ret = false;
+
+#if defined(UNIX_LINUX)
+ ret = IsEthSupportedLinux();
+#elif defined(UNIX_SOLARIS)
+ ret = IsEthSupportedSolaris();
+#elif defined(BRIDGE_PCAP)
+ ret = true;
+#elif defined(BRIDGE_BPF)
+ ret = true;
+#endif
+ return ret;
+}
+
+#ifdef UNIX_LINUX
+bool IsEthSupportedLinux()
+{
+ int s;
+
+ // Try to open a raw socket
+ s = UnixEthOpenRawSocket();
+ if (s == INVALID_SOCKET)
+ {
+ // fail
+ return false;
+ }
+
+ // success
+ closesocket(s);
+
+ return true;
+}
+#endif // UNIX_LINUX
+
+#ifdef UNIX_SOLARIS
+bool IsEthSupportedSolaris()
+{
+ return true;
+}
+#endif // UNIX_SOLARIS
+
+#ifdef UNIX_SOLARIS
+// Get Ethernet device list on Solaris
+TOKEN_LIST *GetEthListSolaris()
+{
+ TOKEN_LIST *t;
+ int i, s;
+ LIST *o;
+
+
+ o = NewListFast(CompareStr);
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s != INVALID_SOCKET)
+ {
+ struct lifnum lifn;
+ lifn.lifn_family = AF_INET;
+ lifn.lifn_flags = 0;
+ if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) >= 0)
+ {
+ struct lifconf lifc;
+ struct lifreq *buf;
+ UINT numifs;
+ UINT bufsize;
+
+ numifs = lifn.lifn_count;
+ Debug("NumIFs:%d\n",numifs);
+ bufsize = numifs * sizeof(struct lifreq);
+ buf = Malloc(bufsize);
+
+ lifc.lifc_family = AF_INET;
+ lifc.lifc_flags = 0;
+ lifc.lifc_len = bufsize;
+ lifc.lifc_buf = (char*) buf;
+ if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) >= 0)
+ {
+ for (i = 0; i<numifs; i++)
+ {
+ if(StartWith(buf[i].lifr_name, "lo") == false){
+ Add(o, CopyStr(buf[i].lifr_name));
+ }
+ }
+ }
+ Free(buf);
+ }
+ closesocket(s);
+ }
+
+ Sort(o);
+
+ t = ZeroMalloc(sizeof(TOKEN_LIST));
+ t->NumTokens = LIST_NUM(o);
+ t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ char *name = LIST_DATA(o, i);
+ t->Token[i] = name;
+ }
+
+ ReleaseList(o);
+
+ return t;
+}
+#endif // UNIX_SOLARIS
+
+#ifdef UNIX_LINUX
+// Get Ethernet device list on Linux
+TOKEN_LIST *GetEthListLinux()
+{
+ struct ifreq ifr;
+ TOKEN_LIST *t;
+ UINT i, n;
+ int s;
+ LIST *o;
+ char name[MAX_SIZE];
+
+ o = NewListFast(CompareStr);
+
+ s = UnixEthOpenRawSocket();
+ if (s != INVALID_SOCKET)
+ {
+ n = 0;
+ for (i = 0;;i++)
+ {
+ Zero(&ifr, sizeof(ifr));
+ ifr.ifr_ifindex = i;
+
+ if (ioctl(s, SIOCGIFNAME, &ifr) >= 0)
+ {
+ n = 0;
+ StrCpy(name, sizeof(name), ifr.ifr_name);
+
+ Zero(&ifr, sizeof(ifr));
+ StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);
+ if (ioctl(s, SIOCGIFHWADDR, &ifr) >= 0)
+ {
+ UINT type = ifr.ifr_hwaddr.sa_family;
+ if (type == 1 || type == 2 || type == 6 || type == 800 || type == 801)
+ {
+ if (IsInListStr(o, name) == false)
+ {
+ if (StartWith(name, "tap_") == false)
+ {
+ Add(o, CopyStr(name));
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ n++;
+ if (n >= 64)
+ {
+ break;
+ }
+ }
+ }
+ closesocket(s);
+ }
+
+ Sort(o);
+
+ t = ZeroMalloc(sizeof(TOKEN_LIST));
+ t->NumTokens = LIST_NUM(o);
+ t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ char *name = LIST_DATA(o, i);
+ t->Token[i] = name;
+ }
+
+ ReleaseList(o);
+
+ return t;
+}
+#endif // UNIX_LINUX
+
+#ifdef BRIDGE_PCAP
+// Ethernet device list by Pcap API
+TOKEN_LIST *GetEthListPcap()
+{
+ pcap_if_t *alldevs;
+ char errbuf[PCAP_ERRBUF_SIZE];
+ LIST *o;
+ TOKEN_LIST *t;
+ int i;
+
+ o = NewListFast(CompareStr);
+
+ if( pcap_findalldevs(&alldevs,errbuf) != -1)
+ {
+ pcap_if_t *dev = alldevs;
+ while(dev != NULL)
+ {
+ pcap_t *p;
+ // Device type will be unknown until open the device?
+ p = pcap_open_live(dev->name, 0, false, 0, errbuf);
+ if(p != NULL)
+ {
+ int datalink = pcap_datalink(p);
+ // Debug("type:%s\n",pcap_datalink_val_to_name(datalink));
+ pcap_close(p);
+ if(datalink == DLT_EN10MB){
+ // Enumerate only Ethernet type device
+ Add(o, CopyStr(dev->name));
+ }
+ }
+ dev = dev->next;
+ }
+ pcap_freealldevs(alldevs);
+ }
+
+ Sort(o);
+ t = ZeroMalloc(sizeof(TOKEN_LIST));
+ t->NumTokens = LIST_NUM(o);
+ t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ t->Token[i] = LIST_DATA(o, i);
+ }
+ ReleaseList(o);
+ return t;
+}
+#endif // BRIDGE_PCAP
+
+#ifdef BRIDGE_BPF
+// Ethernet device list by BPF API
+TOKEN_LIST *GetEthListBpf()
+{
+ struct ifaddrs *ifadrs;
+ struct sockaddr_dl *sockadr;
+ LIST *o;
+ TOKEN_LIST *t;
+ int i;
+
+ o = NewListFast(CompareStr);
+
+ // Enumerate network devices
+ if(getifaddrs( &ifadrs ) == 0)
+ {
+ struct ifaddrs *ifadr = ifadrs;
+ while(ifadr)
+ {
+ sockadr = (struct sockaddr_dl*)ifadr->ifa_addr;
+ if(sockadr->sdl_family == AF_LINK && sockadr->sdl_type == IFT_ETHER)
+ {
+ // Is this Ethernet device?
+ if(!IsInListStr(o,ifadr->ifa_name))
+ {
+ // Ignore the foregoing device (for device which have multiple MAC address)
+ Add(o, CopyStr(ifadr->ifa_name));
+ }
+ }
+ ifadr = ifadr -> ifa_next;
+ }
+ freeifaddrs(ifadrs);
+ }
+
+ Sort(o);
+ t = ZeroMalloc(sizeof(TOKEN_LIST));
+ t->NumTokens = LIST_NUM(o);
+ t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ t->Token[i] = LIST_DATA(o, i);
+ }
+ ReleaseList(o);
+ return t;
+}
+#endif // BRIDGE_BPF
+
+// Enumerate Ethernet devices
+TOKEN_LIST *GetEthList()
+{
+ TOKEN_LIST *t = NULL;
+
+#if defined(UNIX_LINUX)
+ t = GetEthListLinux();
+#elif defined(UNIX_SOLARIS)
+ t = GetEthListSolaris();
+#elif defined(BRIDGE_PCAP)
+ t = GetEthListPcap();
+#elif defined(BRIDGE_BPF)
+ t = GetEthListBpf();
+#endif
+
+ return t;
+}
+
+#ifdef UNIX_LINUX
+// Open Ethernet device (Linux)
+ETH *OpenEthLinux(char *name, bool local, bool tapmode, char *tapaddr)
+{
+ ETH *e;
+ struct ifreq ifr;
+ struct sockaddr_ll addr;
+ int s;
+ int index;
+ CANCEL *c;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return NULL;
+ }
+
+ if (tapmode)
+ {
+#ifndef NO_VLAN
+ // In tap mode
+ VLAN *v = NewTap(name, tapaddr);
+ if (v == NULL)
+ {
+ return NULL;
+ }
+
+ e = ZeroMalloc(sizeof(ETH));
+ e->Name = CopyStr(name);
+ e->Title = CopyStr(name);
+ e->Cancel = VLanGetCancel(v);
+ e->IfIndex = 0;
+ e->Socket = INVALID_SOCKET;
+ e->Tap = v;
+
+ return e;
+#else // NO_VLAN
+ return NULL;
+#endif // NO_VLAN
+ }
+
+ s = UnixEthOpenRawSocket();
+ if (s == INVALID_SOCKET)
+ {
+ return NULL;
+ }
+
+ Zero(&ifr, sizeof(ifr));
+ StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);
+
+ if (ioctl(s, SIOCGIFINDEX, &ifr) < 0)
+ {
+ closesocket(s);
+ return NULL;
+ }
+
+ index = ifr.ifr_ifindex;
+
+ Zero(&addr, sizeof(addr));
+ addr.sll_family = PF_PACKET;
+ addr.sll_protocol = htons(ETH_P_ALL);
+ addr.sll_ifindex = index;
+
+ if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+ {
+ closesocket(s);
+ return NULL;
+ }
+
+ if (local == false)
+ {
+ // Enable promiscious mode
+ Zero(&ifr, sizeof(ifr));
+ StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), name);
+ if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0)
+ {
+ // Failed
+ closesocket(s);
+ return NULL;
+ }
+
+ ifr.ifr_flags |= IFF_PROMISC;
+
+ if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0)
+ {
+ // Failed
+ closesocket(s);
+ return NULL;
+ }
+ }
+
+ e = ZeroMalloc(sizeof(ETH));
+ e->Name = CopyStr(name);
+ e->Title = CopyStr(name);
+ e->IfIndex = index;
+ e->Socket = s;
+
+ c = NewCancel();
+ UnixDeletePipe(c->pipe_read, c->pipe_write);
+ c->pipe_read = c->pipe_write = -1;
+
+ UnixSetSocketNonBlockingMode(s, true);
+
+ c->SpecialFlag = true;
+ c->pipe_read = s;
+
+ e->Cancel = c;
+
+ // Get MTU
+ e->InitialMtu = EthGetMtu(e);
+
+ if (tapmode == false)
+ {
+ // Disable hardware offloading
+ UnixDisableInterfaceOffload(name);
+ }
+
+ return e;
+}
+#endif // UNIX_LINUX
+
+// Get the MTU value
+UINT EthGetMtu(ETH *e)
+{
+#if defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ UINT ret = 0;
+#ifdef UNIX_SOLARIS
+ struct lifreq ifr;
+#else // UNIX_SOLARIS
+ struct ifreq ifr;
+#endif // UNIX_SOLARIS
+ int s;
+ // Validate arguments
+ if (e == NULL || e->Tap != NULL)
+ {
+ return 0;
+ }
+
+ if (e->CurrentMtu != 0)
+ {
+ return e->CurrentMtu;
+ }
+
+#if defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ s = e->SocketBsdIf;
+#else // defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ s = e->Socket;
+#endif // defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+
+ Zero(&ifr, sizeof(ifr));
+
+#ifdef UNIX_SOLARIS
+ StrCpy(ifr.lifr_name, sizeof(ifr.lifr_name), e->Name);
+#else // UNIX_SOLARIS
+ StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), e->Name);
+#endif // UNIX_SOLARIS
+
+#ifdef UNIX_SOLARIS
+ if (ioctl(s, SIOCGLIFMTU, &ifr) < 0)
+ {
+ // failed
+ return 0;
+ }
+#else // UNIX_SOLARIS
+ if (ioctl(s, SIOCGIFMTU, &ifr) < 0)
+ {
+ // failed
+ return 0;
+ }
+#endif // UNIX_SOLARIS
+
+#ifdef UNIX_SOLARIS
+ ret = ifr.lifr_mtu + 14;
+#else // UNIX_SOLARIS
+ ret = ifr.ifr_mtu + 14;
+#endif // UNIX_SOLARIS
+
+ e->CurrentMtu = ret;
+
+ Debug("%s: GetMtu: %u\n", e->Name, ret);
+
+ return ret;
+#else // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ return 0;
+#endif // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+}
+
+// Set the MTU value
+bool EthSetMtu(ETH *e, UINT mtu)
+{
+#if defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ UINT ret = 0;
+#ifdef UNIX_SOLARIS
+ struct lifreq ifr;
+#else // UNIX_SOLARIS
+ struct ifreq ifr;
+#endif // UNIX_SOLARIS
+ int s;
+ // Validate arguments
+ if (e == NULL || e->Tap != NULL || (mtu > 1 && mtu < 1514))
+ {
+ return false;
+ }
+ if (mtu == 0 && e->InitialMtu == 0)
+ {
+ return false;
+ }
+
+ if (mtu == 0)
+ {
+ // Restore initial MTU value when parameter mtu == 0
+ mtu = e->InitialMtu;
+ }
+
+#if defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ s = e->SocketBsdIf;
+#else // defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ s = e->Socket;
+#endif // defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+
+ if (e->CurrentMtu == mtu)
+ {
+ // No need to change
+ return true;
+ }
+
+ Zero(&ifr, sizeof(ifr));
+
+#ifdef UNIX_SOLARIS
+ StrCpy(ifr.lifr_name, sizeof(ifr.lifr_name), e->Name);
+ ifr.lifr_mtu = mtu - 14;
+#else // UNIX_SOLARIS
+ StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), e->Name);
+ ifr.ifr_mtu = mtu - 14;
+#endif // UNIX_SOLARIS
+
+#ifdef UNIX_SOLARIS
+ if (ioctl(s, SIOCSLIFMTU, &ifr) < 0)
+ {
+ // Failed
+ return false;
+ }
+#else // UNIX_SOLARIS
+ if (ioctl(s, SIOCSIFMTU, &ifr) < 0)
+ {
+ // Failed
+ return false;
+ }
+#endif // UNIX_SOLARIS
+
+ e->CurrentMtu = mtu;
+
+ Debug("%s: SetMtu: %u\n", e->Name, mtu);
+
+ return true;
+#else // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ return false;
+#endif // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+}
+
+// Is changing MTU supported?
+bool EthIsChangeMtuSupported(ETH *e)
+{
+#if defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ // Validate arguments
+ if (e == NULL || e->Tap != NULL)
+ {
+ return false;
+ }
+
+ return true;
+#else // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+ return false;
+#endif // defined(UNIX_LINUX) || defined(UNIX_BSD) || defined(UNIX_SOLARIS)
+}
+
+#ifdef UNIX_SOLARIS
+// Open Ethernet adapter (Solaris)
+ETH *OpenEthSolaris(char *name, bool local, bool tapmode, char *tapaddr)
+{
+ char devname[MAX_SIZE];
+ UINT devid;
+ int fd;
+ ETH *e;
+ CANCEL *c;
+ struct strioctl sioc;
+
+ // Validate arguments
+ if (name == NULL || tapmode != false)
+ {
+ return NULL;
+ }
+
+ // Parse device name
+ if (ParseUnixEthDeviceName(devname, sizeof(devname), &devid, name) == false)
+ {
+ return NULL;
+ }
+
+ // Open the device
+ fd = open(devname, O_RDWR);
+ if (fd == -1)
+ {
+ // Failed
+ return NULL;
+ }
+
+ // Attach to the device
+ if (DlipAttatchRequest(fd, devid) == false)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ // Verify ACK message
+ if (DlipReceiveAck(fd) == false)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ // Bind to SAP
+ if (DlipBindRequest(fd) == false)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ // Verify ACK message
+ if (DlipReceiveAck(fd) == false)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ // Set to ignore SAP and promiscuous mode
+ if (DlipPromiscuous(fd, DL_PROMISC_SAP) == false)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ // Verify ACK message
+ if (DlipReceiveAck(fd) == false)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ // Set to the mode to receive self sending packet
+ if (DlipPromiscuous(fd, DL_PROMISC_PHYS) == false)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ // Verify ACK message
+ if (DlipReceiveAck(fd) == false)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ // Set to raw mode
+ sioc.ic_cmd = DLIOCRAW;
+ sioc.ic_timout = -1;
+ sioc.ic_len = 0;
+ sioc.ic_dp = NULL;
+ if (ioctl(fd, I_STR, &sioc) < 0)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ if (ioctl(fd, I_FLUSH, FLUSHR) < 0)
+ {
+ // Failed
+ close(fd);
+ return NULL;
+ }
+
+ e = ZeroMalloc(sizeof(ETH));
+ e->Name = CopyStr(name);
+ e->Title = CopyStr(name);
+
+ c = NewCancel();
+ UnixDeletePipe(c->pipe_read, c->pipe_write);
+ c->pipe_read = c->pipe_write = -1;
+
+ c->SpecialFlag = true;
+ c->pipe_read = fd;
+
+ e->Cancel = c;
+
+ e->IfIndex = -1;
+ e->Socket = fd;
+
+ UnixSetSocketNonBlockingMode(fd, true);
+
+ // Get control interface
+ e->SocketBsdIf = socket(AF_INET, SOCK_DGRAM, 0);
+
+ // Get MTU value
+ e->InitialMtu = EthGetMtu(e);
+
+ return e;
+}
+
+// Set to promiscuous mode
+bool DlipPromiscuous(int fd, UINT level)
+{
+ dl_promiscon_req_t req;
+ struct strbuf ctl;
+ int flags;
+ // Validate arguments
+ if (fd == -1)
+ {
+ return false;
+ }
+
+ Zero(&req, sizeof(req));
+ req.dl_primitive = DL_PROMISCON_REQ;
+ req.dl_level = level;
+
+ Zero(&ctl, sizeof(ctl));
+ ctl.maxlen = 0;
+ ctl.len = sizeof(req);
+ ctl.buf = (char *)&req;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, NULL, flags) < 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Bind to a SAP
+bool DlipBindRequest(int fd)
+{
+ dl_bind_req_t req;
+ struct strbuf ctl;
+
+ if (fd == -1)
+ {
+ return false;
+ }
+
+ Zero(&req, sizeof(req));
+ req.dl_primitive = DL_BIND_REQ;
+ req.dl_service_mode = DL_CLDLS;
+ req.dl_sap = 0;
+
+ Zero(&ctl, sizeof(ctl));
+ ctl.maxlen = 0;
+ ctl.len = sizeof(req);
+ ctl.buf = (char *)&req;
+
+ if (putmsg(fd, &ctl, NULL, 0) < 0)
+ {
+ return false;
+ }
+ return true;
+}
+
+// Attach to the device
+bool DlipAttatchRequest(int fd, UINT devid)
+{
+ dl_attach_req_t req;
+ struct strbuf ctl;
+ int flags;
+ // Validate arguments
+ if (fd == -1)
+ {
+ return false;
+ }
+
+ Zero(&req, sizeof(req));
+ req.dl_primitive = DL_ATTACH_REQ;
+ req.dl_ppa = devid;
+
+ Zero(&ctl, sizeof(ctl));
+ ctl.maxlen = 0;
+ ctl.len = sizeof(req);
+ ctl.buf = (char *)&req;
+
+ flags = 0;
+
+ if (putmsg(fd, &ctl, NULL, flags) < 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Verify the ACK message
+bool DlipReceiveAck(int fd)
+{
+ union DL_primitives *dlp;
+ struct strbuf ctl;
+ int flags = 0;
+ char *buf;
+ // Validate arguments
+ if (fd == -1)
+ {
+ return false;
+ }
+
+ buf = MallocFast(SOLARIS_MAXDLBUF);
+
+ Zero(&ctl, sizeof(ctl));
+ ctl.maxlen = SOLARIS_MAXDLBUF;
+ ctl.len = 0;
+ ctl.buf = buf;
+
+ if (getmsg(fd, &ctl, NULL, &flags) < 0)
+ {
+ return false;
+ }
+
+ dlp = (union DL_primitives *)ctl.buf;
+ if (dlp->dl_primitive != (UINT)DL_OK_ACK && dlp->dl_primitive != (UINT)DL_BIND_ACK)
+ {
+ Free(buf);
+ return false;
+ }
+
+ Free(buf);
+
+ return true;
+}
+
+#endif // UNIX_SOLARIS
+
+// Separate UNIX device name string into device name and id number
+bool ParseUnixEthDeviceName(char *dst_devname, UINT dst_devname_size, UINT *dst_devid, char *src_name)
+{
+ UINT len, i, j;
+
+ // Validate arguments
+ if (dst_devname == NULL || dst_devid == NULL || src_name == NULL)
+ {
+ return false;
+ }
+
+ len = strlen(src_name);
+ // Check string length
+ if(len == 0)
+ {
+ return false;
+ }
+
+ for (i = len-1; i+1 != 0; i--)
+ {
+ // Find last non-numeric character
+ if (src_name[i] < '0' || '9' < src_name[i])
+ {
+ // last character must be a number
+ if(src_name[i+1]==0)
+ {
+ return false;
+ }
+ *dst_devid = ToInt(src_name + i + 1);
+ StrCpy(dst_devname, dst_devname_size, "/dev/");
+ for (j = 0; j<i+1 && j<dst_devname_size-6; j++)
+ {
+ dst_devname[j+5] = src_name[j];
+ }
+ dst_devname[j+5]=0;
+ return true;
+ }
+ }
+ // All characters in the string was numeric: error
+ return false;
+}
+
+#if defined(BRIDGE_BPF) || defined(BRIDGE_PCAP)
+// Initialize captured packet data structure
+struct CAPTUREBLOCK *NewCaptureBlock(UCHAR *data, UINT size){
+ struct CAPTUREBLOCK *block = Malloc(sizeof(struct CAPTUREBLOCK));
+ block->Buf = data;
+ block->Size = size;
+ return block;
+}
+
+// Free captured packet data structure
+void FreeCaptureBlock(struct CAPTUREBLOCK *block){
+ Free(block);
+}
+#endif // BRIDGE_BPF || BRIDGE_PCAP
+
+#ifdef BRIDGE_PCAP
+// Callback function to receive arriving packet (Pcap)
+void PcapHandler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
+{
+ ETH *e = (ETH*) user;
+ struct CAPTUREBLOCK *block;
+ UCHAR *data;
+
+ data = Malloc(h->caplen);
+ Copy(data, bytes, h->caplen);
+ block = NewCaptureBlock(data, h->caplen);
+ LockQueue(e->Queue);
+ // Discard arriving packet when queue filled
+ if(e->QueueSize < BRIDGE_MAX_QUEUE_SIZE){
+ InsertQueue(e->Queue, block);
+ e->QueueSize += h->caplen;
+ }
+ UnlockQueue(e->Queue);
+ Cancel(e->Cancel);
+ return;
+}
+
+// Relay thread for captured packet (Pcap)
+void PcapThread(THREAD *thread, void *param)
+{
+ ETH *e = (ETH*)param;
+ pcap_t *p = e->Pcap;
+ int ret;
+
+ // Notify initialize completed
+ NoticeThreadInit(thread);
+
+ // Return -1:Error -2:Terminated externally
+ ret = pcap_loop(p, -1, PcapHandler, (u_char*) e);
+ if(ret == -1){
+ e->Socket = INVALID_SOCKET;
+ pcap_perror(p, "capture");
+ }
+ return;
+}
+
+
+// Open Ethernet adapter (Pcap)
+ETH *OpenEthPcap(char *name, bool local, bool tapmode, char *tapaddr)
+{
+ char errbuf[PCAP_ERRBUF_SIZE];
+ ETH *e;
+ pcap_t *p;
+ CANCEL *c;
+
+ // Validate arguments
+ if (name == NULL || tapmode != false)
+ {
+ return NULL;
+ }
+
+ // Initialize error message buffer
+ errbuf[0] = 0;
+
+ // Open capturing device
+ p = pcap_open_live(name, 65535, (local == false), 1, errbuf);
+ if(p==NULL)
+ {
+ return NULL;
+ }
+
+ // Set to non-block mode
+ // (In old BSD OSs, 'select(2)' don't block normally for BPF device. To prevent busy loop)
+ /*
+ if(pcap_setnonblock(p, true, errbuf) == -1)
+ {
+ Debug("pcap_setnonblock:%s\n",errbuf);
+ pcap_close(p);
+ return NULL;
+ }
+ */
+
+ e = ZeroMalloc(sizeof(ETH));
+ e->Name = CopyStr(name);
+ e->Title = CopyStr(name);
+ e->Queue = NewQueue();
+ e->QueueSize = 0;
+ e->Cancel = NewCancel();
+ e->IfIndex = -1;
+ e->Socket = pcap_get_selectable_fd(p);
+ e->Pcap = p;
+
+ e->CaptureThread = NewThread(PcapThread, e);
+ WaitThreadInit(e->CaptureThread);
+
+ return e;
+}
+#endif // BRIDGE_PCAP
+
+#ifdef BRIDGE_BPF
+#ifdef BRIDGE_BPF_THREAD
+// Relay thread for captured packet (BPF)
+void BpfThread(THREAD *thread, void *param)
+{
+ ETH *e = (ETH*)param;
+ int fd = e->Socket;
+ int len;
+ int rest; // Rest size in buffer
+ UCHAR *next; // Head of next packet in buffer
+ struct CAPTUREBLOCK *block; // Data to enqueue
+ UCHAR *data;
+ struct bpf_hdr *hdr;
+
+ // Allocate the buffer
+ UCHAR *buf = Malloc(e->BufSize);
+
+ // Notify initialize completed
+ NoticeThreadInit(thread);
+
+ while(1){
+ // Determining to exit loop
+ if(e->Socket == INVALID_SOCKET){
+ break;
+ }
+
+ rest = read(fd, buf, e->BufSize);
+ if(rest < 0 && errno != EAGAIN){
+ // Error
+ close(fd);
+ e->Socket = INVALID_SOCKET;
+ Free(buf);
+ Cancel(e->Cancel);
+ return;
+ }
+ next = buf;
+ LockQueue(e->Queue);
+ while(rest>0){
+ // Cut out a packet
+ hdr = (struct bpf_hdr*)next;
+
+ // Discard arriving packet when queue filled
+ if(e->QueueSize < BRIDGE_MAX_QUEUE_SIZE){
+ data = Malloc(hdr->bh_caplen);
+ Copy(data, next+(hdr->bh_hdrlen), hdr->bh_caplen);
+ block = NewCaptureBlock(data, hdr->bh_caplen);
+ InsertQueue(e->Queue, block);
+ e->QueueSize += hdr->bh_caplen;
+ }
+
+ // Find the head of next packet
+ rest -= BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
+ next += BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
+ }
+ UnlockQueue(e->Queue);
+ Cancel(e->Cancel);
+ }
+ Free(buf);
+ Cancel(e->Cancel);
+ return;
+}
+#endif // BRIDGE_BPF_THREAD
+
+// Open Ethernet adapter (BPF)
+ETH *OpenEthBpf(char *name, bool local, bool tapmode, char *tapaddr)
+{
+ ETH *e;
+ CANCEL *c;
+ char devname[MAX_SIZE];
+ int n = 0;
+ int fd;
+ int ret;
+ UINT bufsize;
+ struct ifreq ifr;
+ struct timeval to;
+
+ // Find unused bpf device and open it
+ do{
+ Format(devname, sizeof(devname), "/dev/bpf%d", n++);
+ fd = open (devname, O_RDWR);
+ if(fd<0){
+ perror("open");
+ }
+ }while(fd < 0 && errno == EBUSY);
+
+ // No free bpf device was found
+ if(fd < 0){
+ Debug("BPF: No minor number are free.\n");
+ return NULL;
+ }
+
+ // Enlarge buffer size
+ n = 524288; // Somehow(In libpcap, this size is 32768)
+ while(true){
+ // Specify buffer size
+ ioctl(fd, BIOCSBLEN, &n);
+
+ // Bind to the network device
+ StrCpy(ifr.ifr_name, IFNAMSIZ, name);
+ ret = ioctl(fd, BIOCSETIF, &ifr);
+ if(ret < 0){
+ if(ret == ENOBUFS && n>1500){
+ // Inappropriate buffer size
+ // Retry with half buffer size
+ // If buffer size is under 1500 bytes, something goes wrong
+ n /= 2;
+ continue;
+ }
+ Debug("bpf: binding network failed.\n");
+ close(fd);
+ return NULL;
+ }else{
+ break;
+ }
+ }
+ bufsize = n;
+
+ // Set to promiscuous mode
+ if(local == false){
+ if (ioctl(fd, BIOCPROMISC, NULL) < 0){
+ printf("bpf: promisc mode failed.\n");
+ close(fd);
+ return NULL;
+ }
+ }
+
+
+ // Set to immediate mode (Return immediately when packet arrives)
+ n = 1;
+ if (ioctl(fd, BIOCIMMEDIATE, &n) < 0){
+ Debug("BPF: non-block mode failed.\n");
+ close(fd);
+ return NULL;
+ }
+
+ // Set receiving self sending packet
+ n = 1;
+ if (ioctl(fd, BIOCGSEESENT, &n) < 0){
+ Debug("BPF: see sent mode failed.\n");
+ close(fd);
+ return NULL;
+ }
+
+ // Header complete mode (Generate whole header of sending packet)
+ n = 1;
+ if (ioctl(fd, BIOCSHDRCMPLT, &n) < 0){
+ Debug("BPF: Header complete mode failed.\n");
+ close(fd);
+ return NULL;
+ }
+
+ // Set timeout delay to 1 second
+ to.tv_sec = 1;
+ to.tv_usec = 0;
+ if (ioctl(fd, BIOCSRTIMEOUT, &to) < 0){
+ Debug("BPF: Read timeout setting failed.\n");
+ close(fd);
+ return NULL;
+ }
+
+ e = ZeroMalloc(sizeof(ETH));
+ e->Name = CopyStr(name);
+ e->Title = CopyStr(name);
+ e->IfIndex = -1;
+ e->Socket = fd;
+ e->BufSize = bufsize;
+
+#ifdef BRIDGE_BPF_THREAD
+ e->Queue = NewQueue();
+ e->QueueSize = 0;
+ e->Cancel = NewCancel();
+
+ // Start capture thread
+ e->CaptureThread = NewThread(BpfThread, e);
+ WaitThreadInit(e->CaptureThread);
+
+#else // BRIDGE_BPF_THREAD
+ c = NewCancel();
+ UnixDeletePipe(c->pipe_read, c->pipe_write);
+ c->pipe_read = c->pipe_write = -1;
+ c->SpecialFlag = true;
+ c->pipe_read = fd;
+ e->Cancel = c;
+ e->Buffer = Malloc(bufsize);
+ e->Next = e->Buffer;
+ e->Rest = 0;
+
+ // Set to non-blocking mode
+ UnixSetSocketNonBlockingMode(fd, true);
+#endif // BRIDGE_BPF_THREAD
+
+ // Open interface control socket for FreeBSD
+ e->SocketBsdIf = socket(AF_LOCAL, SOCK_DGRAM, 0);
+
+ // Get MTU value
+ e->InitialMtu = EthGetMtu(e);
+
+ return e;
+}
+#endif // BRIDGE_BPF
+
+// Open Ethernet adapter
+ETH *OpenEth(char *name, bool local, bool tapmode, char *tapaddr)
+{
+ ETH *ret = NULL;
+
+#if defined(UNIX_LINUX)
+ ret = OpenEthLinux(name, local, tapmode, tapaddr);
+#elif defined(UNIX_SOLARIS)
+ ret = OpenEthSolaris(name, local, tapmode, tapaddr);
+#elif defined(BRIDGE_PCAP)
+ ret = OpenEthPcap(name, local, tapmode, tapaddr);
+#elif defined(BRIDGE_BPF)
+ ret = OpenEthBpf(name, local, tapmode, tapaddr);
+#endif
+
+ return ret;
+}
+
+typedef struct UNIXTHREAD
+{
+ pthread_t thread;
+ bool finished;
+} UNIXTHREAD;
+
+// Close Ethernet adapter
+void CloseEth(ETH *e)
+{
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ if (e->Tap != NULL)
+ {
+#ifndef NO_VLAN
+ FreeTap(e->Tap);
+#endif // NO_VLAN
+ }
+
+#ifdef BRIDGE_PCAP
+ {
+ struct CAPTUREBLOCK *block;
+ pcap_breakloop(e->Pcap);
+ WaitThread(e->CaptureThread, INFINITE);
+ ReleaseThread(e->CaptureThread);
+ pcap_close(e->Pcap);
+ while (block = GetNext(e->Queue)){
+ Free(block->Buf);
+ FreeCaptureBlock(block);
+ }
+ ReleaseQueue(e->Queue);
+ }
+#endif // BRIDGE_PCAP
+
+#ifdef BRIDGE_BPF
+#ifdef BRIDGE_BPF_THREAD
+ {
+ struct CAPTUREBLOCK *block;
+ int fd = e->Socket;
+ e->Socket = INVALID_SOCKET;
+ WaitThread(e->CaptureThread, INFINITE);
+ ReleaseThread(e->CaptureThread);
+ e->Socket = fd; // restore to close after
+ while (block = GetNext(e->Queue)){
+ Free(block->Buf);
+ FreeCaptureBlock(block);
+ }
+ ReleaseQueue(e->Queue);
+ }
+#else // BRIDGE_BPF_THREAD
+ Free(e->Buffer);
+#endif // BRIDGE_BPF_THREAD
+#endif // BRIDGE_BPF
+
+ ReleaseCancel(e->Cancel);
+ Free(e->Name);
+ Free(e->Title);
+
+ // Restore MTU value
+ EthSetMtu(e, 0);
+
+ if (e->Socket != INVALID_SOCKET)
+ {
+#if defined(BRIDGE_BPF) || defined(BRIDGE_PCAP) || defined(UNIX_SOLARIS)
+ close(e->Socket);
+#else // BRIDGE_PCAP
+ closesocket(e->Socket);
+#endif // BRIDGE_PCAP
+#if defined(BRIDGE_BPF) || defined(UNIX_SOLARIS)
+ if (e->SocketBsdIf != INVALID_SOCKET)
+ {
+ close(e->SocketBsdIf);
+ }
+#endif // BRIDGE_BPF || UNIX_SOLARIS
+ }
+
+ Free(e);
+}
+
+// Get cancel object
+CANCEL *EthGetCancel(ETH *e)
+{
+ CANCEL *c;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return NULL;
+ }
+
+ c = e->Cancel;
+ AddRef(c->ref);
+
+ return c;
+}
+
+// Read a packet
+UINT EthGetPacket(ETH *e, void **data)
+{
+ UINT ret = 0;
+
+#if defined(UNIX_LINUX)
+ ret = EthGetPacketLinux(e, data);
+#elif defined(UNIX_SOLARIS)
+ ret = EthGetPacketSolaris(e, data);
+#elif defined(BRIDGE_PCAP)
+ ret = EthGetPacketPcap(e, data);
+#elif defined(BRIDGE_BPF)
+ ret = EthGetPacketBpf(e, data);
+#endif
+
+ return ret;
+}
+
+#ifdef UNIX_LINUX
+UINT EthGetPacketLinux(ETH *e, void **data)
+{
+ int s, ret;
+ UCHAR tmp[UNIX_ETH_TMP_BUFFER_SIZE];
+ // Validate arguments
+ if (e == NULL || data == NULL)
+ {
+ return INFINITE;
+ }
+
+ if (e->Tap != NULL)
+ {
+#ifndef NO_VLAN
+ // tap mode
+ void *buf;
+ UINT size;
+
+ if (VLanGetNextPacket(e->Tap, &buf, &size) == false)
+ {
+ return INFINITE;
+ }
+
+ *data = buf;
+ return size;
+#else // NO_VLAN
+ return INFINITE;
+#endif
+ }
+
+ s = e->Socket;
+
+ if (s == INVALID_SOCKET)
+ {
+ return INFINITE;
+ }
+
+ // Read
+ ret = read(s, tmp, sizeof(tmp));
+ if (ret == 0 || (ret == -1 && errno == EAGAIN))
+ {
+ // No packet
+ *data = NULL;
+ return 0;
+ }
+ else if (ret == -1 || ret > sizeof(tmp))
+ {
+ // Error
+ *data = NULL;
+ e->Socket = INVALID_SOCKET;
+ return INFINITE;
+ }
+ else
+ {
+ // Success to read a packet
+ *data = MallocFast(ret);
+ Copy(*data, tmp, ret);
+ return ret;
+ }
+
+ return 0;
+}
+#endif // UNIX_LINUX
+
+#ifdef UNIX_SOLARIS
+UINT EthGetPacketSolaris(ETH *e, void **data)
+{
+ UCHAR tmp[UNIX_ETH_TMP_BUFFER_SIZE];
+ struct strbuf buf;
+ int s;
+ int flags = 0;
+ int ret;
+ // Validate arguments
+ if (e == NULL || data == NULL)
+ {
+ return INFINITE;
+ }
+
+ s = e->Socket;
+ if (s == INVALID_SOCKET)
+ {
+ return INFINITE;
+ }
+
+ Zero(&buf, sizeof(buf));
+ buf.buf = tmp;
+ buf.maxlen = sizeof(tmp);
+
+ ret = getmsg(s, NULL, &buf, &flags);
+
+ if (ret < 0 || ret > sizeof(tmp))
+ {
+ if (errno == EAGAIN)
+ {
+ // No packet
+ *data = NULL;
+ return 0;
+ }
+ // Error
+ *data = NULL;
+ return INFINITE;
+ }
+
+ ret = buf.len;
+
+ *data = MallocFast(ret);
+ Copy(*data, tmp, ret);
+ return ret;
+}
+#endif // UNIX_SOLARIS
+
+#ifdef BRIDGE_PCAP
+UINT EthGetPacketPcap(ETH *e, void **data)
+{
+ struct CAPTUREBLOCK *block;
+ UINT size;
+
+ LockQueue(e->Queue);
+ block = GetNext(e->Queue);
+ if(block != NULL){
+ e->QueueSize -= block->Size;
+ }
+ UnlockQueue(e->Queue);
+
+ if(block == NULL){
+ *data = NULL;
+ if(e->Socket == INVALID_SOCKET){
+ return INFINITE;
+ }
+ return 0;
+ }
+
+ *data = block->Buf;
+ size = block->Size;
+ FreeCaptureBlock(block);
+
+ return size;
+}
+#endif // BRIDGE_PCAP
+
+#ifdef BRIDGE_BPF
+#ifdef BRIDGE_BPF_THREAD
+UINT EthGetPacketBpf(ETH *e, void **data)
+{
+ struct CAPTUREBLOCK *block;
+ UINT size;
+
+ LockQueue(e->Queue);
+ block = GetNext(e->Queue);
+ if(block != NULL){
+ e->QueueSize -= block->Size;
+ }
+ UnlockQueue(e->Queue);
+
+ if(block == NULL){
+ *data = NULL;
+ if(e->Socket == INVALID_SOCKET){
+ return INFINITE;
+ }
+ return 0;
+ }
+
+ *data = block->Buf;
+ size = block->Size;
+ FreeCaptureBlock(block);
+
+ return size;
+}
+#else // BRIDGE_BPF_THREAD
+UINT EthGetPacketBpf(ETH *e, void **data)
+{
+ struct bpf_hdr *hdr;
+
+ if(e->Rest<=0){
+ e->Rest = read(e->Socket, e->Buffer, e->BufSize);
+ if(e->Rest < 0){
+ *data = NULL;
+ if(errno != EAGAIN){
+ // Error
+ return INFINITE;
+ }
+ // No packet
+ return 0;
+ }
+ e->Next = e->Buffer;
+ }
+ // Cut out a packet
+ hdr = (struct bpf_hdr*)e->Next;
+ *data = Malloc(hdr->bh_caplen);
+ Copy(*data, e->Next+(hdr->bh_hdrlen), hdr->bh_caplen);
+
+ // Find the head of next packet
+ e->Rest -= BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
+ e->Next += BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_caplen);
+
+ return hdr->bh_caplen;
+}
+#endif // BRIDGE_BPF_THREAD
+#endif // BRIDGE_BPF
+
+
+// Send multiple packets
+void EthPutPackets(ETH *e, UINT num, void **datas, UINT *sizes)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL || num == 0 || datas == NULL || sizes == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < num;i++)
+ {
+ EthPutPacket(e, datas[i], sizes[i]);
+ }
+}
+
+// Send a packet
+void EthPutPacket(ETH *e, void *data, UINT size)
+{
+ int s, ret;
+ // Validate arguments
+ if (e == NULL || data == NULL)
+ {
+ return;
+ }
+ if (size < 14 || size > MAX_PACKET_SIZE)
+ {
+ Free(data);
+ return;
+ }
+
+ if (e->Tap != NULL)
+ {
+#ifndef NO_VLAN
+ // tap mode
+ VLanPutPacket(e->Tap, data, size);
+#endif // NO_VLAN
+ return;
+ }
+
+ s = e->Socket;
+
+ if (s == INVALID_SOCKET)
+ {
+ Free(data);
+ return;
+ }
+
+ // Send to device
+#ifdef BRIDGE_PCAP
+ ret = pcap_inject(e->Pcap, data, size);
+ if( ret == -1 ){
+#ifdef _DEBUG
+ pcap_perror(e->Pcap, "inject");
+#endif // _DEBUG
+ Debug("EthPutPacket: ret:%d size:%d\n", ret, size);
+ }
+#else // BRIDGE_PCAP
+ ret = write(s, data, size);
+ if (ret<0)
+ {
+ Debug("EthPutPacket: ret:%d errno:%d size:%d\n", ret, errno, size);
+ }
+#endif //BRIDGE_PCAP
+
+ Free(data);
+}
+
+#endif // BRIDGE_C
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/BridgeUnix.h b/src/Cedar/BridgeUnix.h
new file mode 100644
index 00000000..275ce097
--- /dev/null
+++ b/src/Cedar/BridgeUnix.h
@@ -0,0 +1,191 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// BridgeUnix.h
+// Header of BridgeUnix.c
+
+#ifndef BRIDGEUNIX_H
+#define BRIDGEUNIX_H
+
+// Macro
+#ifndef SOL_PACKET
+#define SOL_PACKET 263
+#endif
+#ifndef ifr_newname
+#define ifr_newname ifr_ifru.ifru_slave
+#endif
+
+// Constants
+#define UNIX_ETH_TMP_BUFFER_SIZE (2000)
+#define SOLARIS_MAXDLBUF (32768)
+#define BRIDGE_MAX_QUEUE_SIZE (4096*1500)
+
+// ETH structure
+struct ETH
+{
+ char *Name; // Adapter name
+ char *Title; // Adapter title
+ CANCEL *Cancel; // Cancel object
+ int IfIndex; // Index
+ int Socket; // Socket
+ UINT InitialMtu; // Initial MTU value
+ UINT CurrentMtu; // Current MTU value
+ int SocketBsdIf; // BSD interface operation socket
+ UCHAR MacAddress[6]; // MAC address
+
+#ifdef BRIDGE_PCAP
+ void *Pcap; // Pcap descriptor
+ QUEUE *Queue; // Queue of the relay thread
+ UINT QueueSize; // Number of bytes in Queue
+ THREAD *CaptureThread; // Pcap relay thread
+#endif // BRIDGE_PCAP
+
+#ifdef BRIDGE_BPF
+ UINT BufSize; // Buffer size to read the BPF (error for other)
+#ifdef BRIDGE_BPF_THREAD
+ QUEUE *Queue; // Queue of the relay thread
+ UINT QueueSize; // Number of bytes in Queue
+ THREAD *CaptureThread; // BPF relay thread
+#else // BRIDGE_BPF_THREAD
+ UCHAR *Buffer; // Buffer to read the BPF
+ UCHAR *Next;
+ int Rest;
+#endif // BRIDGE_BPF_THREAD
+#endif // BRIDGE_BPF
+
+ VLAN *Tap; // tap
+};
+
+#if defined( BRIDGE_BPF ) || defined( BRIDGE_PCAP )
+struct CAPTUREBLOCK{
+ UINT Size;
+ UCHAR *Buf;
+};
+#endif // BRIDGE_BPF
+
+
+// Function prototype
+void InitEth();
+void FreeEth();
+bool IsEthSupported();
+bool IsEthSupportedLinux();
+bool IsEthSupportedSolaris();
+bool IsEthSupportedPcap();
+TOKEN_LIST *GetEthList();
+TOKEN_LIST *GetEthListLinux();
+TOKEN_LIST *GetEthListSolaris();
+TOKEN_LIST *GetEthListPcap();
+ETH *OpenEth(char *name, bool local, bool tapmode, char *tapaddr);
+ETH *OpenEthLinux(char *name, bool local, bool tapmode, char *tapaddr);
+ETH *OpenEthSolaris(char *name, bool local, bool tapmode, char *tapaddr);
+ETH *OpenEthPcap(char *name, bool local, bool tapmode, char *tapaddr);
+bool ParseUnixEthDeviceName(char *dst_devname, UINT dst_devname_size, UINT *dst_devid, char *src_name);
+void CloseEth(ETH *e);
+CANCEL *EthGetCancel(ETH *e);
+UINT EthGetPacket(ETH *e, void **data);
+UINT EthGetPacketLinux(ETH *e, void **data);
+UINT EthGetPacketSolaris(ETH *e, void **data);
+UINT EthGetPacketPcap(ETH *e, void **data);
+UINT EthGetPacketBpf(ETH *e, void **data);
+void EthPutPacket(ETH *e, void *data, UINT size);
+void EthPutPackets(ETH *e, UINT num, void **datas, UINT *sizes);
+UINT EthGetMtu(ETH *e);
+bool EthSetMtu(ETH *e, UINT mtu);
+bool EthIsChangeMtuSupported(ETH *e);
+bool EthGetInterfaceDescriptionUnix(char *name, char *str, UINT size);
+bool EthIsInterfaceDescriptionSupportedUnix();
+
+#ifdef UNIX_SOLARIS
+// Function prototype for Solaris
+bool DlipAttatchRequest(int fd, UINT devid);
+bool DlipReceiveAck(int fd);
+bool DlipPromiscuous(int fd, UINT level);
+bool DlipBindRequest(int fd);
+#endif // OS_SOLARIS
+
+int UnixEthOpenRawSocket();
+
+#endif // BRIDGEUNIX_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/BridgeWin32.c b/src/Cedar/BridgeWin32.c
new file mode 100644
index 00000000..985a5111
--- /dev/null
+++ b/src/Cedar/BridgeWin32.c
@@ -0,0 +1,2217 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// BridgeWin32.c
+// Ethernet Bridge Program (Win32)
+
+#include <GlobalConst.h>
+
+#ifdef BRIDGE_C
+
+#include <winsock2.h>
+#include <Ws2tcpip.h>
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Packet32.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+
+
+static WP *wp = NULL;
+static LIST *eth_list = NULL;
+
+static LOCK *eth_list_lock = NULL;
+static bool is_see_mode = false;
+static bool is_using_selow = false;
+static bool enable_selow = true;
+
+static bool g_bridge_win32_show_all_if = false;
+
+#define LOAD_DLL_ADDR(name) \
+ { \
+ void *addr = GetProcAddress(h, #name); \
+ Copy(&wp->name, &addr, sizeof(void *)); \
+ }
+
+// Set the flag which indicates whether using SeLow
+void Win32SetEnableSeLow(bool b)
+{
+ enable_selow = b;
+}
+
+// Get the flag which indicates whether using SeLow
+bool Win32GetEnableSeLow()
+{
+ return enable_selow;
+}
+
+// Set the flag which indicates whether enumerating all interfaces
+void Win32EthSetShowAllIf(bool b)
+{
+ g_bridge_win32_show_all_if = b;
+}
+
+// Get the flag which indicates whether enumerating all interfaces
+bool Win32EthGetShowAllIf()
+{
+ return g_bridge_win32_show_all_if;
+}
+
+// Compare Ethernet device list
+int CmpRpcEnumEthVLan(void *p1, void *p2)
+{
+ RPC_ENUM_ETH_VLAN_ITEM *v1, *v2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ v1 = *((RPC_ENUM_ETH_VLAN_ITEM **)p1);
+ v2 = *((RPC_ENUM_ETH_VLAN_ITEM **)p2);
+ if (v1 == NULL || v2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(v1->DeviceName, v2->DeviceName);
+}
+
+// Get the value of MTU (Not supported in Windows)
+UINT EthGetMtu(ETH *e)
+{
+ return 0;
+}
+
+// Set the value of MTU (Not supported in Windows)
+bool EthSetMtu(ETH *e, UINT mtu)
+{
+ return false;
+}
+
+// Check whether setting MEU value (Not supported in Windows)
+bool EthIsChangeMtuSupported(ETH *e)
+{
+ return false;
+}
+
+// Set the state of VLAN tag pass-through
+bool SetVLanEnableStatus(char *title, bool enable)
+{
+ RPC_ENUM_ETH_VLAN t;
+ RPC_ENUM_ETH_VLAN_ITEM *e;
+ bool ret = false;
+ char key[MAX_SIZE];
+ char tcpkey[MAX_SIZE];
+ char short_key[MAX_SIZE];
+ // Validate arguments
+ if (title == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+ if (EnumEthVLanWin32(&t) == false)
+ {
+ return false;
+ }
+
+ e = FindEthVLanItem(&t, title);
+
+ if (e != NULL)
+ {
+ if (GetClassRegKeyWin32(key, sizeof(key), short_key, sizeof(short_key), e->Guid))
+ {
+ if (StrCmpi(e->DriverType, "Intel") == 0)
+ {
+ if (enable)
+ {
+ MsRegWriteStr(REG_LOCAL_MACHINE, key, "VlanFiltering", "0");
+ MsRegWriteStr(REG_LOCAL_MACHINE, key, "TaggingMode", "0");
+ MsRegWriteInt(REG_LOCAL_MACHINE, key, "MonitorMode", 1);
+ MsRegWriteInt(REG_LOCAL_MACHINE, key, "MonitorModeEnabled", 1);
+ }
+ else
+ {
+ if (MsRegReadInt(REG_LOCAL_MACHINE, key, "TaggingMode") == 0)
+ {
+ MsRegDeleteValue(REG_LOCAL_MACHINE, key, "TaggingMode");
+ }
+
+ if (MsRegReadInt(REG_LOCAL_MACHINE, key, "MonitorMode") == 1)
+ {
+ MsRegDeleteValue(REG_LOCAL_MACHINE, key, "MonitorMode");
+ }
+
+ if (MsRegReadInt(REG_LOCAL_MACHINE, key, "MonitorModeEnabled") == 1)
+ {
+ MsRegDeleteValue(REG_LOCAL_MACHINE, key, "MonitorModeEnabled");
+ }
+ }
+
+ ret = true;
+ }
+ else if (StrCmpi(e->DriverType, "Broadcom") == 0)
+ {
+ if (enable)
+ {
+ MsRegWriteStr(REG_LOCAL_MACHINE, key, "PreserveVlanInfoInRxPacket", "1");
+ }
+ else
+ {
+ MsRegDeleteValue(REG_LOCAL_MACHINE, key, "PreserveVlanInfoInRxPacket");
+ }
+
+ ret = true;
+ }
+ else if (StrCmpi(e->DriverType, "Marvell") == 0)
+ {
+ if (enable)
+ {
+ MsRegWriteInt(REG_LOCAL_MACHINE, key, "SkDisableVlanStrip", 1);
+ }
+ else
+ {
+ MsRegDeleteValue(REG_LOCAL_MACHINE, key, "SkDisableVlanStrip");
+ }
+
+ ret = true;
+ }
+
+ Format(tcpkey, sizeof(tcpkey),
+ "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%s",
+ e->Guid);
+
+ if (enable)
+ {
+ if (MsRegIsValue(REG_LOCAL_MACHINE, tcpkey, "MTU") == false)
+ {
+ MsRegWriteInt(REG_LOCAL_MACHINE, tcpkey, "MTU", 1500);
+ }
+ }
+ else
+ {
+ UINT mtu = MsRegReadInt(REG_LOCAL_MACHINE, tcpkey, "MTU");
+ if (mtu == 1500)
+ {
+ MsRegDeleteValue(REG_LOCAL_MACHINE, tcpkey, "MTU");
+ }
+ }
+ }
+ }
+
+ FreeRpcEnumEthVLan(&t);
+
+ return ret;
+}
+
+// Find Ethernet device
+RPC_ENUM_ETH_VLAN_ITEM *FindEthVLanItem(RPC_ENUM_ETH_VLAN *t, char *name)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || name == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ if (StrCmpi(t->Items[i].DeviceName, name) == 0)
+ {
+ return &t->Items[i];
+ }
+ }
+
+ return NULL;
+}
+
+// Get the state of VLAN tag pass-through
+void GetVLanEnableStatus(RPC_ENUM_ETH_VLAN_ITEM *e)
+{
+ char key[MAX_SIZE];
+ char short_key[MAX_SIZE];
+ char tcpkey[MAX_SIZE];
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ e->Enabled = false;
+
+ if (e->Support == false)
+ {
+ return;
+ }
+
+ if (GetClassRegKeyWin32(key, sizeof(key), short_key, sizeof(short_key), e->Guid) == false)
+ {
+ return;
+ }
+
+ Format(tcpkey, sizeof(tcpkey),
+ "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\%s",
+ e->Guid);
+
+ if (StrCmpi(e->DriverType, "Intel") == 0)
+ {
+ char *VlanFiltering = MsRegReadStr(REG_LOCAL_MACHINE, key, "VlanFiltering");
+ UINT MonitorMode = MsRegReadInt(REG_LOCAL_MACHINE, key, "MonitorMode");
+ UINT MonitorModeEnabled = MsRegReadInt(REG_LOCAL_MACHINE, key, "MonitorModeEnabled");
+ char *TaggingMode = MsRegReadStr(REG_LOCAL_MACHINE, key, "TaggingMode");
+
+ if (StrCmpi(VlanFiltering, "0") == 0 &&
+ MonitorMode == 1 &&
+ MonitorModeEnabled == 1 &&
+ StrCmpi(TaggingMode, "0") == 0)
+ {
+ e->Enabled = true;
+ }
+
+ Free(VlanFiltering);
+ Free(TaggingMode);
+ }
+ else if (StrCmpi(e->DriverType, "Broadcom") == 0)
+ {
+ char *PreserveVlanInfoInRxPacket = MsRegReadStr(REG_LOCAL_MACHINE,
+ key, "PreserveVlanInfoInRxPacket");
+
+ if (StrCmpi(PreserveVlanInfoInRxPacket, "1") == 0)
+ {
+ e->Enabled = true;
+ }
+
+ Free(PreserveVlanInfoInRxPacket);
+ }
+ else if (StrCmpi(e->DriverType, "Marvell") == 0)
+ {
+ DWORD SkDisableVlanStrip = MsRegReadInt(REG_LOCAL_MACHINE,
+ key, "SkDisableVlanStrip");
+
+ if (SkDisableVlanStrip == 1)
+ {
+ e->Enabled = true;
+ }
+ }
+
+ if (MsRegIsValue(REG_LOCAL_MACHINE, tcpkey, "MTU") == false)
+ {
+ e->Enabled = false;
+ }
+}
+
+// Get VLAN tag pass-through availability of the device
+void GetVLanSupportStatus(RPC_ENUM_ETH_VLAN_ITEM *e)
+{
+ BUF *b;
+ char filename[MAX_SIZE];
+ void *wow;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ wow = MsDisableWow64FileSystemRedirection();
+
+ // Read the device driver file
+ CombinePath(filename, sizeof(filename), MsGetSystem32Dir(), "drivers");
+ CombinePath(filename, sizeof(filename), filename, e->DriverName);
+
+ b = ReadDump(filename);
+
+ if (b != NULL)
+ {
+ char intel1[] = "VlanFiltering";
+ char intel2[] = "V\0l\0a\0n\0F\0i\0l\0t\0e\0r\0i\0n\0g";
+ char intel3[] = "MonitorMode";
+ char intel4[] = "M\0o\0n\0i\0t\0o\0r\0M\0o\0d\0e";
+ char intel5[] = "TaggingMode";
+ char intel6[] = "T\0a\0g\0g\0i\0n\0g\0M\0o\0d\0e";
+ char broadcom1[] = "PreserveVlanInfoInRxPacket";
+ char broadcom2[] = "P\0r\0e\0s\0e\0r\0v\0e\0V\0l\0a\0n\0I\0n\0f\0o\0I\0n\0R\0x\0P\0a\0c\0k\0e\0t";
+ char marvell1[] = "SkDisableVlanStrip";
+ char marvell2[] = "S\0k\0D\0i\0s\0a\0b\0l\0e\0V\0l\0a\0n\0S\0t\0r\0i\0p";
+ char *driver_type = "";
+
+ if (SearchBin(b->Buf, 0, b->Size, intel1, sizeof(intel1)) != INFINITE
+ || SearchBin(b->Buf, 0, b->Size, intel2, sizeof(intel2)) != INFINITE
+ || SearchBin(b->Buf, 0, b->Size, intel3, sizeof(intel3)) != INFINITE
+ || SearchBin(b->Buf, 0, b->Size, intel4, sizeof(intel4)) != INFINITE
+ || SearchBin(b->Buf, 0, b->Size, intel5, sizeof(intel5)) != INFINITE
+ || SearchBin(b->Buf, 0, b->Size, intel6, sizeof(intel6)) != INFINITE)
+ {
+ driver_type = "Intel";
+ }
+ else if (SearchBin(b->Buf, 0, b->Size, broadcom1, sizeof(broadcom1)) != INFINITE
+ || SearchBin(b->Buf, 0, b->Size, broadcom2, sizeof(broadcom2)) != INFINITE)
+ {
+ driver_type = "Broadcom";
+ }
+ else if (SearchBin(b->Buf, 0, b->Size, marvell1, sizeof(marvell1)) != INFINITE
+ || SearchBin(b->Buf, 0, b->Size, marvell2, sizeof(marvell2)) != INFINITE)
+ {
+ driver_type = "Marvell";
+ }
+
+ if (IsEmptyStr(driver_type) == false)
+ {
+ StrCpy(e->DriverType, sizeof(e->DriverType), driver_type);
+ e->Support = true;
+ }
+
+ FreeBuf(b);
+ }
+
+ MsRestoreWow64FileSystemRedirection(wow);
+}
+
+// Get the device instance id from short_key
+char *SearchDeviceInstanceIdFromShortKey(char *short_key)
+{
+ char *ret = NULL;
+ TOKEN_LIST *t1;
+ // Validate arguments
+ if (short_key == NULL)
+ {
+ return NULL;
+ }
+
+ t1 = MsRegEnumKey(REG_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Enum");
+
+ if (t1 != NULL)
+ {
+ TOKEN_LIST *t2;
+ char tmp[MAX_SIZE];
+ UINT i;
+
+ for (i = 0;i < t1->NumTokens;i++)
+ {
+ Format(tmp, sizeof(tmp), "SYSTEM\\CurrentControlSet\\Enum\\%s", t1->Token[i]);
+
+ t2 = MsRegEnumKey(REG_LOCAL_MACHINE, tmp);
+
+ if (t2 != NULL)
+ {
+ TOKEN_LIST *t3;
+ UINT i;
+
+ for (i = 0;i < t2->NumTokens;i++)
+ {
+ char tmp2[MAX_SIZE];
+
+ Format(tmp2, sizeof(tmp2), "%s\\%s", tmp, t2->Token[i]);
+
+ t3 = MsRegEnumKey(REG_LOCAL_MACHINE, tmp2);
+
+ if (t3 != NULL)
+ {
+ UINT i;
+
+ for (i = 0;i < t3->NumTokens;i++)
+ {
+ char tmp3[MAX_SIZE];
+ char *s;
+
+ Format(tmp3, sizeof(tmp3), "%s\\%s", tmp2, t3->Token[i]);
+
+ s = MsRegReadStr(REG_LOCAL_MACHINE, tmp3, "Driver");
+
+ if (s != NULL)
+ {
+ if (StrCmpi(s, short_key) == 0)
+ {
+ if (ret != NULL)
+ {
+ Free(ret);
+ }
+
+ ret = CopyStr(tmp3 + StrLen("SYSTEM\\CurrentControlSet\\Enum\\"));
+ }
+
+ Free(s);
+ }
+ }
+
+ FreeToken(t3);
+ }
+ }
+
+ FreeToken(t2);
+ }
+ }
+
+ FreeToken(t1);
+ }
+
+ return ret;
+}
+
+// Get VLAN tag pass-through availability of all devices
+bool EnumEthVLanWin32(RPC_ENUM_ETH_VLAN *t)
+{
+ UINT i;
+ LIST *o;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return false;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_ETH_VLAN));
+
+ if (MsIsWin2000OrGreater() == false)
+ {
+ return false;
+ }
+
+ if (IsEthSupported() == false)
+ {
+ return false;
+ }
+
+ // Get device list
+ Lock(eth_list_lock);
+
+ InitEthAdaptersList();
+
+ o = NewListFast(CmpRpcEnumEthVLan);
+
+ for (i = 0;i < LIST_NUM(eth_list);i++)
+ {
+ WP_ADAPTER *a = LIST_DATA(eth_list, i);
+
+ if (IsEmptyStr(a->Guid) == false)
+ {
+ char class_key[MAX_SIZE];
+ char short_key[MAX_SIZE];
+
+ if (GetClassRegKeyWin32(class_key, sizeof(class_key),
+ short_key, sizeof(short_key), a->Guid))
+ {
+ char *device_instance_id = MsRegReadStr(REG_LOCAL_MACHINE, class_key, "DeviceInstanceID");
+
+ if (IsEmptyStr(device_instance_id))
+ {
+ Free(device_instance_id);
+ device_instance_id = SearchDeviceInstanceIdFromShortKey(short_key);
+ }
+
+ if (IsEmptyStr(device_instance_id) == false)
+ {
+ char device_key[MAX_SIZE];
+ char *service_name;
+
+ Format(device_key, sizeof(device_key), "SYSTEM\\CurrentControlSet\\Enum\\%s",
+ device_instance_id);
+
+ service_name = MsRegReadStr(REG_LOCAL_MACHINE, device_key, "Service");
+ if (IsEmptyStr(service_name) == false)
+ {
+ char service_key[MAX_SIZE];
+ char *sys;
+
+ Format(service_key, sizeof(service_key),
+ "SYSTEM\\CurrentControlSet\\services\\%s",
+ service_name);
+
+ sys = MsRegReadStr(REG_LOCAL_MACHINE, service_key, "ImagePath");
+
+ if (IsEmptyStr(sys) == false)
+ {
+ char sysname[MAX_PATH];
+
+ GetFileNameFromFilePath(sysname, sizeof(sysname), sys);
+
+ Trim(sysname);
+
+ if (EndWith(sysname, ".sys"))
+ {
+ // device found
+ RPC_ENUM_ETH_VLAN_ITEM *e = ZeroMalloc(sizeof(RPC_ENUM_ETH_VLAN_ITEM));
+
+ StrCpy(e->DeviceName, sizeof(e->DeviceName), a->Title);
+ StrCpy(e->Guid, sizeof(e->Guid), a->Guid);
+ StrCpy(e->DeviceInstanceId, sizeof(e->DeviceInstanceId), device_instance_id);
+ StrCpy(e->DriverName, sizeof(e->DriverName), sysname);
+
+ // Get VLAN tag pass-through availability of the device
+ GetVLanSupportStatus(e);
+
+ // Get current pass-through setting of the device
+ GetVLanEnableStatus(e);
+
+ Insert(o, e);
+ }
+ }
+
+ Free(sys);
+ }
+
+ Free(service_name);
+ }
+
+ Free(device_instance_id);
+ }
+ }
+ }
+
+ t->NumItem = LIST_NUM(o);
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_ETH_VLAN_ITEM) * i);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ RPC_ENUM_ETH_VLAN_ITEM *e = LIST_DATA(o, i);
+
+ Copy(&t->Items[i], e, sizeof(RPC_ENUM_ETH_VLAN_ITEM));
+
+ Free(e);
+ }
+
+ ReleaseList(o);
+
+ Unlock(eth_list_lock);
+
+ return true;
+}
+
+// Get registry key of the network class data by GUID
+bool GetClassRegKeyWin32(char *key, UINT key_size, char *short_key, UINT short_key_size, char *guid)
+{
+ TOKEN_LIST *t;
+ bool ret = false;
+ UINT i;
+ // Validate arguments
+ if (key == NULL || short_key == NULL || guid == NULL)
+ {
+ return false;
+ }
+
+ t = MsRegEnumKey(REG_LOCAL_MACHINE,
+ "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}");
+ if (t == NULL)
+ {
+ return false;
+ }
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ char keyname[MAX_SIZE];
+ char *value;
+
+ Format(keyname, sizeof(keyname),
+ "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s",
+ t->Token[i]);
+
+ value = MsRegReadStr(REG_LOCAL_MACHINE, keyname, "NetCfgInstanceId");
+
+ if (StrCmpi(value, guid) == 0)
+ {
+ ret = true;
+
+ StrCpy(key, key_size, keyname);
+
+ Format(short_key, short_key_size, "{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s",
+ t->Token[i]);
+ }
+
+ Free(value);
+ }
+
+ FreeToken(t);
+
+ return ret;
+}
+
+// Send multiple packets
+void EthPutPackets(ETH *e, UINT num, void **datas, UINT *sizes)
+{
+ UINT i, total_size;
+ UCHAR *buf;
+ UINT write_pointer;
+ UINT err = 0;
+ // Validate arguments
+ if (e == NULL || num == 0 || datas == NULL || sizes == NULL)
+ {
+ return;
+ }
+ if (e->HasFatalError)
+ {
+ return;
+ }
+
+ if (e->SuAdapter != NULL)
+ {
+ bool ok = true;
+
+ // Send packets with SeLow
+ for (i = 0;i < num;i++)
+ {
+ UCHAR *data = datas[i];
+ UINT size = sizes[i];
+
+ if (ok)
+ {
+ // Actually, only enqueuing
+ ok = SuPutPacket(e->SuAdapter, data, size);
+ }
+
+ if (ok == false)
+ {
+ // Free memory on write error
+ Free(data);
+ }
+ }
+
+ if (ok)
+ {
+ // Send all data in queue at once
+ ok = SuPutPacket(e->SuAdapter, NULL, 0);
+ }
+
+ if (ok == false)
+ {
+ // Error occurred
+ e->HasFatalError = true;
+ }
+
+ return;
+ }
+
+ if (IsWin32BridgeWithSee() == false)
+ {
+ if (e->LastSetSingleCpu == 0 || (e->LastSetSingleCpu + 10000) <= Tick64())
+ {
+ e->LastSetSingleCpu = Tick64();
+ MsSetThreadSingleCpu();
+ }
+ }
+
+ // Calculate buffer size
+ total_size = 0;
+ for (i = 0;i < num;i++)
+ {
+ void *data = datas[i];
+ UINT size = sizes[i];
+ if (data != NULL && size >= 14 && size <= MAX_PACKET_SIZE)
+ {
+ total_size += size + sizeof(struct dump_bpf_hdr);
+ }
+ }
+
+ buf = MallocFast(total_size * 100 / 75 + 1600);
+
+ write_pointer = 0;
+ // Enqueue
+ for (i = 0;i < num;i++)
+ {
+ void *data = datas[i];
+ UINT size = sizes[i];
+ if (data != NULL && size >= 14 && size <= MAX_PACKET_SIZE)
+ {
+ struct dump_bpf_hdr *h;
+
+ h = (struct dump_bpf_hdr *)(buf + write_pointer);
+ Zero(h, sizeof(struct dump_bpf_hdr));
+ h->caplen = h->len = size;
+ write_pointer += sizeof(struct dump_bpf_hdr);
+ Copy(buf + write_pointer, data, size);
+ write_pointer += size;
+
+ PROBE_DATA2("EthPutPackets", data, size);
+ }
+ // Free original buffer
+ Free(data);
+ }
+
+ // Send
+ if (total_size != 0)
+ {
+ err = wp->PacketSendPackets(e->Adapter, buf, total_size, true);
+ }
+
+ Free(buf);
+
+ if (err == 0x7FFFFFFF)
+ {
+ // Critical error (infinite loop) occurred on sending
+ e->HasFatalError = true;
+ }
+}
+
+// Send a packet
+void EthPutPacket(ETH *e, void *data, UINT size)
+{
+ // Validate arguments
+ if (e == NULL || data == NULL || size == 0)
+ {
+ return;
+ }
+
+ EthPutPackets(e, 1, &data, &size);
+}
+
+// Read next packet
+UINT EthGetPacket(ETH *e, void **data)
+{
+ BLOCK *b;
+ bool flag = false;
+ // Validate arguments
+ if (e == NULL || data == NULL)
+ {
+ return INFINITE;
+ }
+ if (e->HasFatalError)
+ {
+ return INFINITE;
+ }
+
+ if (e->SuAdapter != NULL)
+ {
+ // Read packet with SeLow
+ UINT size;
+ if (SuGetNextPacket(e->SuAdapter, data, &size) == false)
+ {
+ // Error occurred
+ e->HasFatalError = true;
+ return INFINITE;
+ }
+
+ return size;
+ }
+
+RETRY:
+ // Check the presence of the packet in queue
+ b = GetNext(e->PacketQueue);
+ if (b != NULL)
+ {
+ UINT size;
+ size = b->Size;
+ *data = b->Buf;
+ Free(b);
+
+ if (e->PacketQueue->num_item == 0)
+ {
+ e->Empty = true;
+ }
+
+ return size;
+ }
+
+ if (e->Empty)
+ {
+ e->Empty = false;
+ return 0;
+ }
+
+ if (flag == false)
+ {
+ // Try to get next packet
+ PROBE_STR("EthGetPacket: PacketInitPacket");
+ wp->PacketInitPacket(e->Packet, e->Buffer, e->BufferSize);
+ PROBE_STR("EthGetPacket: PacketReceivePacket");
+ if (wp->PacketReceivePacket(e->Adapter, e->Packet, false) == false)
+ {
+ // Failed
+ return INFINITE;
+ }
+ else
+ {
+ UCHAR *buf;
+ UINT total;
+ UINT offset;
+
+ buf = (UCHAR *)e->Packet->Buffer;
+ total = e->Packet->ulBytesReceived;
+ offset = 0;
+
+ while (offset < total)
+ {
+ struct bpf_hdr *header;
+ UINT packet_size;
+ UCHAR *packet_data;
+
+ header = (struct bpf_hdr *)(buf + offset);
+ packet_size = header->bh_caplen;
+ offset += header->bh_hdrlen;
+ packet_data = buf + offset;
+ offset = Packet_WORDALIGN(offset + packet_size);
+
+ if (packet_size >= 14)
+ {
+ UCHAR *tmp;
+ BLOCK *b;
+
+ PROBE_DATA2("EthGetPacket: NewBlock", packet_data, packet_size);
+
+ tmp = MallocFast(packet_size);
+
+ Copy(tmp, packet_data, packet_size);
+ b = NewBlock(tmp, packet_size, 0);
+ InsertQueue(e->PacketQueue, b);
+ }
+ }
+
+ flag = true;
+ goto RETRY;
+ }
+ }
+
+ // No more packet
+ return 0;
+}
+
+// Get cancel object
+CANCEL *EthGetCancel(ETH *e)
+{
+ // Validate arguments
+ if (e == NULL)
+ {
+ return NULL;
+ }
+
+ AddRef(e->Cancel->ref);
+
+ return e->Cancel;
+}
+
+// Close adapter
+void CloseEth(ETH *e)
+{
+ BLOCK *b;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ ReleaseCancel(e->Cancel);
+
+ if (e->SuAdapter != NULL)
+ {
+ // Close SeLow adapter
+ SuCloseAdapter(e->SuAdapter);
+ SuFree(e->Su);
+ }
+ else
+ {
+ // Close SEE adapter
+ wp->PacketCloseAdapter(e->Adapter);
+ wp->PacketFreePacket(e->Packet);
+ wp->PacketFreePacket(e->PutPacket);
+ }
+
+ while (b = GetNext(e->PacketQueue))
+ {
+ FreeBlock(b);
+ }
+ ReleaseQueue(e->PacketQueue);
+
+ Free(e->Name);
+ Free(e->Title);
+ Free(e->Buffer);
+
+ Free(e);
+}
+
+// Search adapter with the name
+struct WP_ADAPTER *Win32EthSearch(char *name)
+{
+ UINT i;
+ UINT id;
+ char simple_name[MAX_SIZE];
+ WP_ADAPTER *ret = NULL;
+
+ id = Win32EthGetNameAndIdFromCombinedName(simple_name, sizeof(simple_name), name);
+
+ if (id != 0)
+ {
+ UINT num_match = 0;
+ // Search with ID when ID is specified
+ for (i = 0;i < LIST_NUM(eth_list);i++)
+ {
+ WP_ADAPTER *a = LIST_DATA(eth_list, i);
+
+ if (a->Id != 0 && a->Id == id)
+ {
+ ret = a;
+ num_match++;
+ }
+ }
+
+ if (num_match >= 2)
+ {
+ // If the ID matches to 2 or more devices, search with the name
+ for (i = 0;i < LIST_NUM(eth_list);i++)
+ {
+ WP_ADAPTER *a = LIST_DATA(eth_list, i);
+
+ if (a->Id != 0 && a->Id == id)
+ {
+ if (StrCmpi(a->Title, name) == 0)
+ {
+ ret = a;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Search with name when ID is not specified
+ for (i = 0;i < LIST_NUM(eth_list);i++)
+ {
+ WP_ADAPTER *a = LIST_DATA(eth_list, i);
+
+ if (StrCmpi(a->Title, name) == 0)
+ {
+ ret = a;
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+// Open adapter
+ETH *OpenEth(char *name, bool local, bool tapmode, char *tapaddr)
+{
+ ETH *ret;
+ void *p;
+
+ p = MsDisableWow64FileSystemRedirection();
+
+ ret = OpenEthInternal(name, local, tapmode, tapaddr);
+
+ MsRestoreWow64FileSystemRedirection(p);
+
+ return ret;
+}
+ETH *OpenEthInternal(char *name, bool local, bool tapmode, char *tapaddr)
+{
+ WP_ADAPTER *t;
+ ETH *e;
+ ADAPTER *a = NULL;
+ HANDLE h;
+ CANCEL *c;
+ MS_ADAPTER *ms;
+ char name_with_id[MAX_SIZE];
+ SU *su = NULL;
+ SU_ADAPTER *su_adapter = NULL;
+ // Validate arguments
+ if (name == NULL || IsEthSupported() == false)
+ {
+ return NULL;
+ }
+
+ if (tapmode)
+ {
+ // Tap is not supported in Windows
+ return NULL;
+ }
+
+ Lock(eth_list_lock);
+
+ InitEthAdaptersList();
+
+ t = Win32EthSearch(name);
+
+ if (t == NULL)
+ {
+ Unlock(eth_list_lock);
+ return NULL;
+ }
+
+ Debug("OpenEthInternal: %s\n", t->Name);
+
+ if (StartWith(t->Name, SL_ADAPTER_ID_PREFIX))
+ {
+ // Open with SU
+ su = SuInit();
+ if (su == NULL)
+ {
+ // Fail to initialize SU
+ Unlock(eth_list_lock);
+ return NULL;
+ }
+
+ su_adapter = SuOpenAdapter(su, t->Name);
+
+ if (su_adapter == NULL)
+ {
+ // Fail to get adapter
+ SuFree(su);
+ Unlock(eth_list_lock);
+ return NULL;
+ }
+
+ is_using_selow = true;
+ }
+ else
+ {
+ // Open with SEE
+ a = wp->PacketOpenAdapter(t->Name);
+ if (a == NULL)
+ {
+ Unlock(eth_list_lock);
+ return NULL;
+ }
+
+ if (IsWin32BridgeWithSee() == false)
+ {
+ MsSetThreadSingleCpu();
+ }
+
+ is_using_selow = false;
+ }
+
+ e = ZeroMalloc(sizeof(ETH));
+ e->Name = CopyStr(t->Name);
+
+ Win32EthMakeCombinedName(name_with_id, sizeof(name_with_id), t->Title, t->Guid);
+ e->Title = CopyStr(name_with_id);
+
+ if (su_adapter != NULL)
+ {
+ // SU
+ e->SuAdapter = su_adapter;
+ e->Su = su;
+
+ // Get event object
+ h = e->SuAdapter->hEvent;
+
+ c = NewCancelSpecial(h);
+ e->Cancel = c;
+ }
+ else
+ {
+ // SEE
+ e->Adapter = a;
+
+ wp->PacketSetBuff(e->Adapter, BRIDGE_WIN32_ETH_BUFFER);
+ wp->PacketSetHwFilter(e->Adapter, local ? 0x0080 : 0x0020);
+ wp->PacketSetMode(e->Adapter, PACKET_MODE_CAPT);
+ wp->PacketSetReadTimeout(e->Adapter, -1);
+ wp->PacketSetNumWrites(e->Adapter, 1);
+
+ if (wp->PacketSetLoopbackBehavior != NULL)
+ {
+ // Filter loopback packet in kernel
+ if (GET_KETA(GetOsType(), 100) >= 3)
+ {
+ if (MsIsWindows8() == false)
+ {
+ // Enable for Windows XP, Server 2003 or later
+ // But disable for Windows 8 or later
+ bool ret = wp->PacketSetLoopbackBehavior(e->Adapter, 1);
+ Debug("*** PacketSetLoopbackBehavior: %u\n", ret);
+
+ e->LoopbackBlock = ret;
+ }
+ }
+ }
+
+ // Get event object
+ h = wp->PacketGetReadEvent(e->Adapter);
+
+ c = NewCancelSpecial(h);
+ e->Cancel = c;
+
+ e->Packet = wp->PacketAllocatePacket();
+
+ e->PutPacket = wp->PacketAllocatePacket();
+ }
+
+ e->Buffer = Malloc(BRIDGE_WIN32_ETH_BUFFER);
+ e->BufferSize = BRIDGE_WIN32_ETH_BUFFER;
+
+ e->PacketQueue = NewQueue();
+
+ // Get MAC address by GUID
+ ms = MsGetAdapterByGuid(t->Guid);
+ if (ms != NULL)
+ {
+ if (ms->AddressSize == 6)
+ {
+ Copy(e->MacAddress, ms->Address, 6);
+ }
+
+ MsFreeAdapter(ms);
+ }
+
+ Unlock(eth_list_lock);
+
+ return e;
+}
+
+// Generate a combined name from NIC name and GUID
+void Win32EthMakeCombinedName(char *dst, UINT dst_size, char *nicname, char *guid)
+{
+ // Validate arguments
+ if (dst == NULL || nicname == NULL || guid == NULL)
+ {
+ return;
+ }
+
+ if (IsEmptyStr(guid) == false)
+ {
+ Format(dst, dst_size, "%s (ID=%010u)", nicname, Win32EthGenIdFromGuid(guid));
+ }
+ else
+ {
+ StrCpy(dst, dst_size, nicname);
+ }
+}
+
+// Decompose combined name
+UINT Win32EthGetNameAndIdFromCombinedName(char *name, UINT name_size, char *str)
+{
+ UINT ret = 0;
+ char id_str[MAX_SIZE];
+ UINT len;
+ // Validate arguments
+ ClearStr(name, name_size);
+ StrCpy(name, name_size, str);
+ if (name == NULL || str == NULL)
+ {
+ return 0;
+ }
+
+ len = StrLen(str);
+
+ if (len >= 16)
+ {
+ StrCpy(id_str, sizeof(id_str), str + len - 16);
+
+ if (StartWith(id_str, " (ID="))
+ {
+ if (EndWith(id_str, ")"))
+ {
+ char num[MAX_SIZE];
+
+ Zero(num, sizeof(num));
+ StrCpy(num, sizeof(num), id_str + 5);
+
+ num[StrLen(num) - 1] = 0;
+
+ ret = ToInt(num);
+
+ if (ret != 0)
+ {
+ name[len - 16] = 0;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+// Generate an ID from GUID
+UINT Win32EthGenIdFromGuid(char *guid)
+{
+ char tmp[MAX_SIZE];
+ UCHAR hash[SHA1_SIZE];
+ UINT i;
+ // Validate arguments
+ if (guid == NULL)
+ {
+ return 0;
+ }
+
+ StrCpy(tmp, sizeof(tmp), guid);
+ Trim(tmp);
+ StrUpper(tmp);
+
+ HashSha1(hash, tmp, StrLen(tmp));
+
+ Copy(&i, hash, sizeof(UINT));
+
+ i = Endian32(i);
+
+ if (i == 0)
+ {
+ i = 1;
+ }
+
+ return i;
+}
+
+// Get Ethernet adapter list
+TOKEN_LIST *GetEthList()
+{
+ UINT v;
+
+ return GetEthListEx(&v);
+}
+TOKEN_LIST *GetEthListEx(UINT *total_num_including_hidden)
+{
+ TOKEN_LIST *ret;
+ UINT i;
+ UINT j;
+ UINT dummy_int;
+ MS_ADAPTER_LIST *adapter_list;
+
+ if (IsEthSupported() == false)
+ {
+ return NULL;
+ }
+
+ if (total_num_including_hidden == NULL)
+ {
+ total_num_including_hidden = &dummy_int;
+ }
+
+ *total_num_including_hidden = 0;
+
+ Lock(eth_list_lock);
+
+ InitEthAdaptersList();
+
+ adapter_list = MsCreateAdapterList();
+
+ ret = ZeroMalloc(sizeof(TOKEN_LIST));
+ ret->NumTokens = LIST_NUM(eth_list);
+ ret->Token = ZeroMalloc(sizeof(char *) * ret->NumTokens);
+ j = 0;
+ for (i = 0;i < ret->NumTokens;i++)
+ {
+ char tmp[MAX_SIZE];
+ WP_ADAPTER *a = LIST_DATA(eth_list, i);
+ MS_ADAPTER *msa = NULL;
+ bool show = true;
+
+ if (Win32EthGetShowAllIf() == false)
+ {
+ msa = MsGetAdapterByGuidFromList(adapter_list, a->Guid);
+
+ if (InStr(a->Title, "vpn client adapter"))
+ {
+ // Hide virtual NIC for VPN client
+ show = false;
+ }
+
+ if (InStr(a->Title, "tunnel adapter"))
+ {
+ // Hide tunnel adapter
+ show = false;
+ }
+
+ if (InStr(a->Title, "teredo tunnel"))
+ {
+ // Hide tunnel adapter
+ show = false;
+ }
+
+ if (InStr(a->Title, "MS Tunnel Interface"))
+ {
+ // Hide tunnel adapter
+ show = false;
+ }
+
+ if (InStr(a->Title, "pseudo-interface"))
+ {
+ // Hide tunnel adapter
+ show = false;
+ }
+ }
+
+ if (msa != NULL)
+ {
+ // Hide except physical Ethernet NIC
+ if (msa->IsNotEthernetLan)
+ {
+ show = false;
+ }
+
+ MsFreeAdapter(msa);
+ }
+
+ Win32EthMakeCombinedName(tmp, sizeof(tmp), a->Title, a->Guid);
+
+ if (show)
+ {
+ ret->Token[j++] = CopyStr(tmp);
+
+ Debug("%s - %s\n", a->Guid, a->Title);
+ }
+ }
+
+ *total_num_including_hidden = ret->NumTokens;
+
+ ret->NumTokens = j;
+
+ Unlock(eth_list_lock);
+
+ MsFreeAdapterList(adapter_list);
+
+ return ret;
+}
+
+// Compare the name of WP_ADAPTER
+int CompareWpAdapter(void *p1, void *p2)
+{
+ int i;
+ WP_ADAPTER *a1, *a2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ a1 = *(WP_ADAPTER **)p1;
+ a2 = *(WP_ADAPTER **)p2;
+ if (a1 == NULL || a2 == NULL)
+ {
+ return 0;
+ }
+ i = StrCmpi(a1->Title, a2->Title);
+ return i;
+}
+
+// Get whether the SeLow is used
+bool Win32IsUsingSeLow()
+{
+ return is_using_selow;
+}
+
+// Get Ethernet adapter list
+LIST *GetEthAdapterList()
+{
+ void *p;
+ LIST *o;
+
+ p = MsDisableWow64FileSystemRedirection();
+
+ o = GetEthAdapterListInternal();
+
+ MsRestoreWow64FileSystemRedirection(p);
+
+ return o;
+}
+LIST *GetEthAdapterListInternal()
+{
+ LIST *o;
+ LIST *ret;
+ UINT size;
+ char *buf;
+ UINT i, j;
+ char *qos_tag = " (Microsoft's Packet Scheduler)";
+ SU *su = NULL;
+ LIST *su_adapter_list = NULL;
+
+ // Try to use SeLow
+ if (enable_selow)
+ {
+ su = SuInit();
+ }
+
+ o = NewListFast(CompareWpAdapter);
+
+ size = 200000;
+ buf = ZeroMalloc(size);
+
+ // Try to enumerate with SeLow
+ if (su != NULL)
+ {
+ su_adapter_list = SuGetAdapterList(su);
+
+ if (su_adapter_list == NULL)
+ {
+ // Fail to enumerate
+ SuFree(su);
+ su = NULL;
+ //WHERE;
+ is_using_selow = false;
+ }
+ else
+ {
+ //WHERE;
+ is_using_selow = true;
+ }
+ }
+ else
+ {
+ is_using_selow = false;
+ }
+
+ if (su_adapter_list != NULL)
+ {
+ // If 1 or more adapters are enumerated by SeLow, create adapter list object
+ UINT i;
+
+ for (i = 0;i < LIST_NUM(su_adapter_list);i++)
+ {
+ SU_ADAPTER_LIST *t = LIST_DATA(su_adapter_list, i);
+ WP_ADAPTER *a = ZeroMalloc(sizeof(WP_ADAPTER));
+
+ StrCpy(a->Name, sizeof(a->Name), t->Name);
+ StrCpy(a->Guid, sizeof(a->Guid), t->Guid);
+ StrCpy(a->Title, sizeof(a->Title), t->Info.FriendlyName);
+
+ TrimCrlf(a->Title);
+ Trim(a->Title);
+ TrimCrlf(a->Title);
+ Trim(a->Title);
+
+ if (EndWith(a->Title, qos_tag))
+ {
+ a->Title[StrLen(a->Title) - StrLen(qos_tag)] = 0;
+ TrimCrlf(a->Title);
+ Trim(a->Title);
+ TrimCrlf(a->Title);
+ Trim(a->Title);
+ }
+
+ Add(o, a);
+ }
+ }
+ else
+ {
+ // When SeLow is not used, create adapter list with SEE or WinPcap
+ if (wp->PacketGetAdapterNames(buf, &size) == false)
+ {
+ Free(buf);
+ return o;
+ }
+
+ i = 0;
+
+ if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType))
+ {
+ // Windows NT
+ if (size >= 2 && buf[0] != 0 && buf[1] != 0)
+ {
+ goto ANSI_STR;
+ }
+
+ while (true)
+ {
+ wchar_t tmp[MAX_SIZE];
+ WP_ADAPTER *a;
+ UniStrCpy(tmp, sizeof(tmp), L"");
+
+ if (*((wchar_t *)(&buf[i])) == 0)
+ {
+ i += sizeof(wchar_t);
+ break;
+ }
+
+ for (;*((wchar_t *)(&buf[i])) != 0;i += sizeof(wchar_t))
+ {
+ wchar_t str[2];
+ str[0] = *((wchar_t *)(&buf[i]));
+ str[1] = 0;
+ UniStrCat(tmp, sizeof(tmp), str);
+ }
+
+ i += sizeof(wchar_t);
+
+ a = ZeroMalloc(sizeof(WP_ADAPTER));
+ UniToStr(a->Name, sizeof(a->Name), tmp);
+
+ Add(o, a);
+ }
+ }
+ else
+ {
+ // Windows 9x
+ANSI_STR:
+ while (true)
+ {
+ char tmp[MAX_SIZE];
+ WP_ADAPTER *a;
+ StrCpy(tmp, sizeof(tmp), "");
+
+ if (*((char *)(&buf[i])) == 0)
+ {
+ i += sizeof(char);
+ break;
+ }
+
+ for (;*((char *)(&buf[i])) != 0;i += sizeof(char))
+ {
+ char str[2];
+ str[0] = *((char *)(&buf[i]));
+ str[1] = 0;
+ StrCat(tmp, sizeof(tmp), str);
+ }
+
+ i += sizeof(char);
+
+ a = ZeroMalloc(sizeof(WP_ADAPTER));
+ StrCpy(a->Name, sizeof(a->Name), tmp);
+
+ Add(o, a);
+ }
+ }
+
+ for (j = 0;j < LIST_NUM(o);j++)
+ {
+ WP_ADAPTER *a = LIST_DATA(o, j);
+
+ StrCpy(a->Title, sizeof(a->Title), &buf[i]);
+ i += StrSize(a->Title);
+
+ // If device description is "Unknown" in Win9x, skip 1 byte
+ if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType))
+ {
+ if (StrCmp(a->Title, "Unknown") == 0)
+ {
+ if (buf[i] == 0)
+ {
+ i+=sizeof(char);
+ }
+ }
+ }
+
+ TrimCrlf(a->Title);
+ Trim(a->Title);
+ TrimCrlf(a->Title);
+ Trim(a->Title);
+
+ if (EndWith(a->Title, qos_tag))
+ {
+ a->Title[StrLen(a->Title) - StrLen(qos_tag)] = 0;
+ TrimCrlf(a->Title);
+ Trim(a->Title);
+ TrimCrlf(a->Title);
+ Trim(a->Title);
+ }
+ }
+ }
+
+ for (j = 0;j < LIST_NUM(o);j++)
+ {
+ // Extract GUID
+ WP_ADAPTER *a = LIST_DATA(o, j);
+
+ if (IsEmptyStr(a->Guid))
+ {
+ StrCpy(a->Guid, sizeof(a->Guid), a->Name);
+ ReplaceStr(a->Guid, sizeof(a->Guid), a->Guid, "\\Device\\SEE_", "");
+ ReplaceStr(a->Guid, sizeof(a->Guid), a->Guid, "\\Device\\NPF_", "");
+ ReplaceStr(a->Guid, sizeof(a->Guid), a->Guid, "\\Device\\PCD_", "");
+ }
+ }
+
+ // Sort
+ if (su_adapter_list != NULL)
+ {
+ // Since adapter list made by SeLow is already sorted, don't sort here
+ Sort(o);
+ }
+
+ ret = NewListFast(CompareWpAdapter);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ WP_ADAPTER *a = LIST_DATA(o, i);
+ ADAPTER *ad;
+ bool is_ethernet = false;
+ bool ok = false;
+
+ if (SearchStrEx(a->Title, "ppp", 0, false) != INFINITE ||
+ SearchStrEx(a->Title, "wan", 0, false) != INFINITE ||
+ SearchStrEx(a->Title, "dialup", 0, false) != INFINITE ||
+ SearchStrEx(a->Title, "pptp", 0, false) != INFINITE ||
+ SearchStrEx(a->Title, "telepho", 0, false) != INFINITE ||
+ SearchStrEx(a->Title, "modem", 0, false) != INFINITE ||
+ SearchStrEx(a->Title, "ras", 0, false) != INFINITE)
+ {
+ Free(a);
+ continue;
+ }
+
+ // Determine whether the adapter type is Ethernet
+ if (su == NULL)
+ {
+ // Determine with See
+ ad = wp->PacketOpenAdapter(a->Name);
+ if (ad != NULL)
+ {
+ NetType type;
+ if (wp->PacketGetNetType(ad, &type))
+ {
+ if (type.LinkType == 0)
+ {
+ is_ethernet = true;
+ }
+ }
+
+ wp->PacketCloseAdapter(ad);
+ }
+ }
+ else
+ {
+ // In using SeLow, all devices should be Ethernet device
+ is_ethernet = true;
+ }
+
+ if (is_ethernet)
+ {
+ // Add only Ethernet device
+ char tmp[MAX_SIZE];
+ UINT k;
+
+ StrCpy(tmp, sizeof(tmp), a->Title);
+
+ for (k = 0;;k++)
+ {
+ if (k == 0)
+ {
+ StrCpy(tmp, sizeof(tmp), a->Title);
+ }
+ else
+ {
+ Format(tmp, sizeof(tmp), "%s (%u)", a->Title, k + 1);
+ }
+
+ ok = true;
+ for (j = 0;j < LIST_NUM(ret);j++)
+ {
+ WP_ADAPTER *aa = LIST_DATA(ret, j);
+ if (StrCmpi(aa->Title, tmp) == 0)
+ {
+ ok = false;
+ }
+ }
+
+ if (ok)
+ {
+ break;
+ }
+ }
+
+ StrCpy(a->Title, sizeof(a->Title), tmp);
+ a->Id = Win32EthGenIdFromGuid(a->Guid);
+ Add(ret, a);
+ }
+
+ if (ok == false)
+ {
+ Free(a);
+ }
+ }
+
+ Free(buf);
+
+ Sort(ret);
+
+ ReleaseList(o);
+
+ if (su != NULL)
+ {
+ SuFreeAdapterList(su_adapter_list);
+
+ SuFree(su);
+ }
+
+ return ret;
+}
+
+// Initialize Ethernet adapter list
+void InitEthAdaptersList()
+{
+ if (eth_list != NULL)
+ {
+ FreeEthAdaptersList();
+ eth_list = NULL;
+ }
+ eth_list = GetEthAdapterList();
+}
+
+// Free Ethernet adapter list
+void FreeEthAdaptersList()
+{
+ UINT i;
+ if (eth_list == NULL)
+ {
+ return;
+ }
+ for (i = 0;i < LIST_NUM(eth_list);i++)
+ {
+ WP_ADAPTER *a = LIST_DATA(eth_list, i);
+ Free(a);
+ }
+ ReleaseList(eth_list);
+ eth_list = NULL;
+}
+
+// Is the SU supported
+bool Win32EthIsSuSupported()
+{
+ bool ret = false;
+ SU *su = SuInit();
+
+ if (su != NULL)
+ {
+ ret = true;
+ }
+
+ SuFree(su);
+
+ return ret;
+}
+
+// Is the Ethernet supported
+bool IsEthSupported()
+{
+ bool ret = IsEthSupportedInner();
+
+ if (ret == false)
+ {
+ ret = Win32EthIsSuSupported();
+ }
+
+ return ret;
+}
+bool IsEthSupportedInner()
+{
+ if (wp == NULL)
+ {
+ return false;
+ }
+
+ return wp->Inited;
+}
+
+// Is the PCD driver supported in current OS
+bool IsPcdSupported()
+{
+ UINT type;
+ OS_INFO *info = GetOsInfo();
+
+ type = info->OsType;
+
+ if (OS_IS_WINDOWS_NT(type) == false)
+ {
+ // Only on Windows NT series
+ return false;
+ }
+
+ if (GET_KETA(type, 100) >= 2)
+ {
+ // Good for Windows 2000 or later
+ return true;
+ }
+
+ // Not good for Windows NT 4.0 or Longhorn
+ return false;
+}
+
+// Save build number of PCD driver
+void SavePcdDriverBuild(UINT build)
+{
+ MsRegWriteInt(REG_LOCAL_MACHINE, BRIDGE_WIN32_PCD_REGKEY, BRIDGE_WIN32_PCD_BUILDVALUE,
+ build);
+}
+
+// Load build number of PCD driver
+UINT LoadPcdDriverBuild()
+{
+ return MsRegReadInt(REG_LOCAL_MACHINE, BRIDGE_WIN32_PCD_REGKEY, BRIDGE_WIN32_PCD_BUILDVALUE);
+}
+
+// Try to install PCD driver
+HINSTANCE InstallPcdDriver()
+{
+ HINSTANCE ret;
+ void *p = MsDisableWow64FileSystemRedirection();
+
+ ret = InstallPcdDriverInternal();
+
+ MsRestoreWow64FileSystemRedirection(p);
+
+ return ret;
+}
+HINSTANCE InstallPcdDriverInternal()
+{
+ char tmp[MAX_PATH];
+ bool install_driver = true;
+ HINSTANCE h;
+ char *dll_filename;
+
+ // Confirm whether the see.sys is installed in system32\drivers folder
+ Format(tmp, sizeof(tmp), "%s\\drivers\\see.sys", MsGetSystem32Dir());
+
+ if (IsFileExists(tmp))
+ {
+ // If driver file is exist, try to get build number from registry
+ if (LoadPcdDriverBuild() >= CEDAR_BUILD)
+ {
+ // Already latest driver is installed
+ install_driver = false;
+ }
+ }
+
+ if (install_driver)
+ {
+ char *src_filename = BRIDGE_WIN32_PCD_SYS;
+ // If need to install the driver, confirm user is administrator
+ if (MsIsAdmin() == false)
+ {
+ // Non administrator can't install driver
+ return NULL;
+ }
+
+ if (MsIsX64())
+ {
+ src_filename = BRIDGE_WIN32_PCD_SYS_X64;
+ }
+
+ if (MsIsIA64())
+ {
+ src_filename = BRIDGE_WIN32_PCD_SYS_IA64;
+ }
+
+ // Copy see.sys
+ if (FileCopy(src_filename, tmp) == false)
+ {
+ return NULL;
+ }
+
+ // Save build number
+ SavePcdDriverBuild(CEDAR_BUILD);
+ }
+
+ dll_filename = BRIDGE_WIN32_PCD_DLL;
+
+ if (Is64())
+ {
+ if (MsIsX64())
+ {
+ dll_filename = BRIDGE_WIN32_PCD_DLL_X64;
+ }
+ else if (MsIsIA64())
+ {
+ dll_filename = BRIDGE_WIN32_PCD_DLL_IA64;
+ }
+ }
+
+ // Try to load see.dll and initialize
+ h = MsLoadLibrary(dll_filename);
+ if (h == NULL)
+ {
+ return NULL;
+ }
+
+ return h;
+}
+
+// Initialize Ethernet
+void InitEth()
+{
+ HINSTANCE h;
+ if (wp != NULL)
+ {
+ // Already initialized
+ return;
+ }
+
+ eth_list_lock = NewLock();
+
+ wp = ZeroMalloc(sizeof(WP));
+
+ is_see_mode = false;
+
+ if (IsPcdSupported())
+ {
+ // PCD is supported in this OS
+ h = InstallPcdDriver();
+ if (h != NULL)
+ {
+ // Try to initialize with PCD
+ if (InitWpWithLoadLibrary(wp, h) == false)
+ {
+ Debug("InitEth: SEE Failed.\n");
+ FreeLibrary(h);
+ }
+ else
+ {
+ Debug("InitEth: SEE Loaded.\n");
+ is_see_mode = true;
+ }
+ }
+ }
+
+ if (wp->Inited == false)
+ {
+ // Try to initialize with Packet.dll of WinPcap
+ h = LoadLibrary(BRIDGE_WIN32_PACKET_DLL);
+ if (h != NULL)
+ {
+ if (InitWpWithLoadLibrary(wp, h) == false)
+ {
+ Debug("InitEth: Packet.dll Failed.\n");
+ FreeLibrary(h);
+ }
+ else
+ {
+ Debug("InitEth: Packet.dll Loaded.\n");
+ }
+ }
+ }
+}
+
+// Get whether local-bridge uses see.sys
+bool IsWin32BridgeWithSee()
+{
+ return is_see_mode;
+}
+
+// Initialize WP structure with DLL
+bool InitWpWithLoadLibrary(WP *wp, HINSTANCE h)
+{
+ TOKEN_LIST *o;
+ UINT total_num = 0;
+ // Validate arguments
+ if (wp == NULL || h == NULL)
+ {
+ return false;
+ }
+ wp->Inited = true;
+ wp->hPacketDll = h;
+
+ LOAD_DLL_ADDR(PacketGetVersion);
+ LOAD_DLL_ADDR(PacketGetDriverVersion);
+ LOAD_DLL_ADDR(PacketSetMinToCopy);
+ LOAD_DLL_ADDR(PacketSetNumWrites);
+ LOAD_DLL_ADDR(PacketSetMode);
+ LOAD_DLL_ADDR(PacketSetReadTimeout);
+ LOAD_DLL_ADDR(PacketSetBpf);
+ LOAD_DLL_ADDR(PacketSetSnapLen);
+ LOAD_DLL_ADDR(PacketGetStats);
+ LOAD_DLL_ADDR(PacketGetStatsEx);
+ LOAD_DLL_ADDR(PacketSetBuff);
+ LOAD_DLL_ADDR(PacketGetNetType);
+ LOAD_DLL_ADDR(PacketOpenAdapter);
+ LOAD_DLL_ADDR(PacketSendPacket);
+ LOAD_DLL_ADDR(PacketSendPackets);
+ LOAD_DLL_ADDR(PacketAllocatePacket);
+ LOAD_DLL_ADDR(PacketInitPacket);
+ LOAD_DLL_ADDR(PacketFreePacket);
+ LOAD_DLL_ADDR(PacketReceivePacket);
+ LOAD_DLL_ADDR(PacketSetHwFilter);
+ LOAD_DLL_ADDR(PacketGetAdapterNames);
+ LOAD_DLL_ADDR(PacketGetNetInfoEx);
+ LOAD_DLL_ADDR(PacketRequest);
+ LOAD_DLL_ADDR(PacketGetReadEvent);
+ LOAD_DLL_ADDR(PacketSetDumpName);
+ LOAD_DLL_ADDR(PacketSetDumpLimits);
+ LOAD_DLL_ADDR(PacketSetDumpLimits);
+ LOAD_DLL_ADDR(PacketIsDumpEnded);
+ LOAD_DLL_ADDR(PacketStopDriver);
+ LOAD_DLL_ADDR(PacketCloseAdapter);
+ LOAD_DLL_ADDR(PacketSetLoopbackBehavior);
+
+ if (wp->PacketSetMinToCopy == NULL ||
+ wp->PacketSetNumWrites == NULL ||
+ wp->PacketSetMode == NULL ||
+ wp->PacketSetReadTimeout == NULL ||
+ wp->PacketSetBuff == NULL ||
+ wp->PacketGetNetType == NULL ||
+ wp->PacketOpenAdapter == NULL ||
+ wp->PacketSendPacket == NULL ||
+ wp->PacketSendPackets == NULL ||
+ wp->PacketAllocatePacket == NULL ||
+ wp->PacketInitPacket == NULL ||
+ wp->PacketFreePacket == NULL ||
+ wp->PacketReceivePacket == NULL ||
+ wp->PacketSetHwFilter == NULL ||
+ wp->PacketGetAdapterNames == NULL ||
+ wp->PacketGetNetInfoEx == NULL ||
+ wp->PacketCloseAdapter == NULL)
+ {
+RELEASE:
+ wp->Inited = false;
+ wp->hPacketDll = NULL;
+
+ return false;
+ }
+
+ o = GetEthListEx(&total_num);
+ if (o == NULL || total_num == 0)
+ {
+ FreeToken(o);
+ goto RELEASE;
+ }
+
+ FreeToken(o);
+
+ return true;
+}
+
+// Free Ethernet
+void FreeEth()
+{
+ if (wp == NULL)
+ {
+ // Not initialized
+ return;
+ }
+
+ // Free adapter list
+ FreeEthAdaptersList();
+
+ if (wp->Inited)
+ {
+ // Free DLL
+ FreeLibrary(wp->hPacketDll);
+ }
+
+ Free(wp);
+ wp = NULL;
+
+ DeleteLock(eth_list_lock);
+ eth_list_lock = NULL;
+}
+
+// Get network connection name from Ethernet device name
+void GetEthNetworkConnectionName(wchar_t *dst, UINT size, char *device_name)
+{
+ WP_ADAPTER *t;
+ char *tmp = NULL, guid[MAX_SIZE];
+ wchar_t *ncname = NULL;
+
+ UniStrCpy(dst, size, L"");
+
+ // Validate arguments
+ if (device_name == NULL || IsEthSupported() == false ||
+ IsNt() == false || MsIsWin2000OrGreater() == false)
+ {
+ return;
+ }
+
+ Lock(eth_list_lock);
+
+ InitEthAdaptersList();
+
+ t = Win32EthSearch(device_name);
+
+ if (t == NULL)
+ {
+ Unlock(eth_list_lock);
+ return;
+ }
+
+ tmp = CopyStr(t->Name);
+ Unlock(eth_list_lock);
+
+ if (IsEmptyStr(t->Guid) == false)
+ {
+ StrCpy(guid, sizeof(guid), t->Guid);
+
+ Free(tmp);
+ }
+ else
+ {
+ ReplaceStr(guid, sizeof(guid), tmp, "\\Device\\SEE_", "");
+ Free(tmp);
+
+ ReplaceStr(guid, sizeof(guid), guid, "\\Device\\NPF_", "");
+ ReplaceStr(guid, sizeof(guid), guid, "\\Device\\PCD_", "");
+ }
+
+ if(guid == NULL)
+ {
+ return;
+ }
+
+ ncname = MsGetNetworkConnectionName(guid);
+ if(ncname != NULL)
+ {
+ UniStrCpy(dst, size, ncname);
+ }
+ Free(ncname);
+}
+
+#endif // BRIDGE_C
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/BridgeWin32.h b/src/Cedar/BridgeWin32.h
new file mode 100644
index 00000000..2cc4615c
--- /dev/null
+++ b/src/Cedar/BridgeWin32.h
@@ -0,0 +1,238 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// BridgeWin32.h
+// Header of BridgeWin32.c
+
+#ifndef BRIDGEWIN32_H
+#define BRIDGEWIN32_H
+
+#define BRIDGE_WIN32_PACKET_DLL "Packet.dll"
+#define BRIDGE_WIN32_PCD_DLL "|see.dll"
+#define BRIDGE_WIN32_PCD_SYS "|see.sys"
+#define BRIDGE_WIN32_PCD_DLL_X64 "|see_x64.dll"
+#define BRIDGE_WIN32_PCD_SYS_X64 "|see_x64.sys"
+#define BRIDGE_WIN32_PCD_DLL_IA64 "|see_ia64.dll"
+#define BRIDGE_WIN32_PCD_SYS_IA64 "|see_ia64.sys"
+#define BRIDGE_WIN32_PCD_REGKEY "SYSTEM\\CurrentControlSet\\services\\SEE"
+#define BRIDGE_WIN32_PCD_BUILDVALUE "CurrentInstalledBuild"
+
+#define BRIDGE_WIN32_ETH_BUFFER (1048576)
+
+
+typedef void *HANDLE;
+
+#ifdef BRIDGE_C
+
+// Header for Internal function (for BridgeWin32.c)
+typedef struct WP
+{
+ bool Inited;
+ HINSTANCE hPacketDll;
+ PCHAR (*PacketGetVersion)();
+ PCHAR (*PacketGetDriverVersion)();
+ BOOLEAN (*PacketSetMinToCopy)(LPADAPTER AdapterObject,int nbytes);
+ BOOLEAN (*PacketSetNumWrites)(LPADAPTER AdapterObject,int nwrites);
+ BOOLEAN (*PacketSetMode)(LPADAPTER AdapterObject,int mode);
+ BOOLEAN (*PacketSetReadTimeout)(LPADAPTER AdapterObject,int timeout);
+ BOOLEAN (*PacketSetBpf)(LPADAPTER AdapterObject,struct bpf_program *fp);
+ INT (*PacketSetSnapLen)(LPADAPTER AdapterObject,int snaplen);
+ BOOLEAN (*PacketGetStats)(LPADAPTER AdapterObject,struct bpf_stat *s);
+ BOOLEAN (*PacketGetStatsEx)(LPADAPTER AdapterObject,struct bpf_stat *s);
+ BOOLEAN (*PacketSetBuff)(LPADAPTER AdapterObject,int dim);
+ BOOLEAN (*PacketGetNetType)(LPADAPTER AdapterObject,NetType *type);
+ LPADAPTER (*PacketOpenAdapter)(PCHAR AdapterName);
+ BOOLEAN (*PacketSendPacket)(LPADAPTER AdapterObject,LPPACKET pPacket,BOOLEAN Sync);
+ INT (*PacketSendPackets)(LPADAPTER AdapterObject,PVOID PacketBuff,ULONG Size, BOOLEAN Sync);
+ LPPACKET (*PacketAllocatePacket)(void);
+ VOID (*PacketInitPacket)(LPPACKET lpPacket,PVOID Buffer,UINT Length);
+ VOID (*PacketFreePacket)(LPPACKET lpPacket);
+ BOOLEAN (*PacketReceivePacket)(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync);
+ BOOLEAN (*PacketSetHwFilter)(LPADAPTER AdapterObject,ULONG Filter);
+ BOOLEAN (*PacketGetAdapterNames)(PTSTR pStr,PULONG BufferSize);
+ BOOLEAN (*PacketGetNetInfoEx)(PCHAR AdapterName, npf_if_addr* buffer, PLONG NEntries);
+ BOOLEAN (*PacketRequest)(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData);
+ HANDLE (*PacketGetReadEvent)(LPADAPTER AdapterObject);
+ BOOLEAN (*PacketSetDumpName)(LPADAPTER AdapterObject, void *name, int len);
+ BOOLEAN (*PacketSetDumpLimits)(LPADAPTER AdapterObject, UINT maxfilesize, UINT maxnpacks);
+ BOOLEAN (*PacketIsDumpEnded)(LPADAPTER AdapterObject, BOOLEAN sync);
+ BOOL (*PacketStopDriver)();
+ VOID (*PacketCloseAdapter)(LPADAPTER lpAdapter);
+ BOOLEAN (*PacketSetLoopbackBehavior)(LPADAPTER AdapterObject, UINT LoopbackBehavior);
+} WP;
+
+// Adapter list
+typedef struct WP_ADAPTER
+{
+ char Name[MAX_SIZE];
+ char Title[MAX_SIZE];
+ char Guid[MAX_SIZE];
+ UINT Id;
+} WP_ADAPTER;
+
+// Internal function prototype
+void InitEthAdaptersList();
+void FreeEthAdaptersList();
+int CompareWpAdapter(void *p1, void *p2);
+LIST *GetEthAdapterList();
+LIST *GetEthAdapterListInternal();
+bool InitWpWithLoadLibrary(WP *wp, HINSTANCE h);
+bool IsPcdSupported();
+HINSTANCE InstallPcdDriver();
+HINSTANCE InstallPcdDriverInternal();
+UINT LoadPcdDriverBuild();
+void SavePcdDriverBuild(UINT build);
+
+#endif // BRIDGE_C
+
+typedef struct _ADAPTER ADAPTER;
+typedef struct _PACKET PACKET;
+
+// ETH structure
+struct ETH
+{
+ char *Name; // Adapter name
+ char *Title; // Adapter title
+ ADAPTER *Adapter; // Adapter
+ CANCEL *Cancel; // Cancel object
+ UCHAR *Buffer; // Buffer
+ UINT BufferSize; // Buffer size
+ PACKET *Packet; // Packet
+ PACKET *PutPacket; // Write packet
+ QUEUE *PacketQueue; // Packet queue
+ UINT64 LastSetSingleCpu; // Date and time set to a single CPU to last
+ bool LoopbackBlock; // Whether to block the loop back packet
+ bool Empty; // It is empty
+ UCHAR MacAddress[6]; // MAC address
+ bool HasFatalError; // A fatal error occurred on the transmission side
+
+ SU *Su; // SeLow handle
+ SU_ADAPTER *SuAdapter; // SeLow adapter handle
+};
+
+// Function prototype
+void InitEth();
+void FreeEth();
+bool IsEthSupported();
+bool IsEthSupportedInner();
+TOKEN_LIST *GetEthList();
+TOKEN_LIST *GetEthListEx(UINT *total_num_including_hidden);
+ETH *OpenEth(char *name, bool local, bool tapmode, char *tapaddr);
+ETH *OpenEthInternal(char *name, bool local, bool tapmode, char *tapaddr);
+void CloseEth(ETH *e);
+CANCEL *EthGetCancel(ETH *e);
+UINT EthGetPacket(ETH *e, void **data);
+void EthPutPacket(ETH *e, void *data, UINT size);
+void EthPutPackets(ETH *e, UINT num, void **datas, UINT *sizes);
+void GetEthNetworkConnectionName(wchar_t *dst, UINT size, char *device_name);
+bool IsWin32BridgeWithSee();
+UINT EthGetMtu(ETH *e);
+bool EthSetMtu(ETH *e, UINT mtu);
+bool EthIsChangeMtuSupported(ETH *e);
+
+bool Win32EthIsSuSupported();
+
+void Win32EthSetShowAllIf(bool b);
+bool Win32EthGetShowAllIf();
+
+bool EnumEthVLanWin32(RPC_ENUM_ETH_VLAN *t);
+bool GetClassRegKeyWin32(char *key, UINT key_size, char *short_key, UINT short_key_size, char *guid);
+int CmpRpcEnumEthVLan(void *p1, void *p2);
+void GetVLanSupportStatus(RPC_ENUM_ETH_VLAN_ITEM *e);
+void GetVLanEnableStatus(RPC_ENUM_ETH_VLAN_ITEM *e);
+bool SetVLanEnableStatus(char *title, bool enable);
+RPC_ENUM_ETH_VLAN_ITEM *FindEthVLanItem(RPC_ENUM_ETH_VLAN *t, char *name);
+char *SearchDeviceInstanceIdFromShortKey(char *short_key);
+void Win32EthMakeCombinedName(char *dst, UINT dst_size, char *nicname, char *guid);
+UINT Win32EthGenIdFromGuid(char *guid);
+UINT Win32EthGetNameAndIdFromCombinedName(char *name, UINT name_size, char *str);
+
+struct WP_ADAPTER *Win32EthSearch(char *name);
+bool Win32IsUsingSeLow();
+void Win32SetEnableSeLow(bool b);
+bool Win32GetEnableSeLow();
+
+#endif // BRIDGEWIN32_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/CM.c b/src/Cedar/CM.c
new file mode 100644
index 00000000..379ee9cd
--- /dev/null
+++ b/src/Cedar/CM.c
@@ -0,0 +1,12394 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// CM.c
+// VPN Client Connection Manager for Win32
+
+#include <GlobalConst.h>
+
+#ifdef WIN32
+
+#define CM_C
+#define SM_C
+#define MICROSOFT_C
+
+#define _WIN32_WINNT 0x0502
+#define WINVER 0x0502
+#include <winsock2.h>
+#include <windows.h>
+#include <Iphlpapi.h>
+#include <tlhelp32.h>
+#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#include <setupapi.h>
+#include <regstr.h>
+#include <process.h>
+#include <psapi.h>
+#include <wtsapi32.h>
+#include <Ntsecapi.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+#include "CMInner.h"
+#include "SMInner.h"
+#include "NMInner.h"
+#include "EMInner.h"
+#include "../PenCore/resource.h"
+
+
+// Get the proxy server settings from the registry string of IE
+bool CmGetProxyServerNameAndPortFromIeProxyRegStr(char *name, UINT name_size, UINT *port, char *str, char *server_type)
+{
+ TOKEN_LIST *t;
+ UINT i;
+ bool ret = false;
+ // Validate arguments
+ if (name == NULL || port == NULL || str == NULL || server_type == NULL)
+ {
+ return false;
+ }
+
+ t = ParseToken(str, ";");
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ char *s = t->Token[i];
+ UINT i;
+
+ Trim(s);
+
+ i = SearchStrEx(s, "=", 0, false);
+ if (i != INFINITE)
+ {
+ char tmp[MAX_PATH];
+
+ StrCpy(name, name_size, s);
+ name[i] = 0;
+
+ if (StrCmpi(name, server_type) == 0)
+ {
+ char *host;
+ StrCpy(tmp, sizeof(tmp), s + i + 1);
+
+ if (ParseHostPort(tmp, &host, port, 0))
+ {
+ StrCpy(name, name_size, host);
+ Free(host);
+
+ if (*port != 0)
+ {
+ ret = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ FreeToken(t);
+
+ return ret;
+}
+
+
+// Reflect the contents of the proxy settings to the connection settings
+void CmProxyDlgSet(HWND hWnd, CLIENT_OPTION *o, CM_INTERNET_SETTING *setting)
+{
+ // Validate arguments
+ if(hWnd == NULL || setting == NULL)
+ {
+ return;
+ }
+
+ // Make check in check-box
+ Check(hWnd, R_DIRECT_TCP, setting->ProxyType == PROXY_DIRECT);
+ Check(hWnd, R_HTTPS, setting->ProxyType == PROXY_HTTP);
+ Check(hWnd, R_SOCKS, setting->ProxyType == PROXY_SOCKS);
+
+ // Proxy Settings
+ if(setting->ProxyType != PROXY_DIRECT)
+ {
+ StrCpy(o->ProxyName, sizeof(setting->ProxyHostName), setting->ProxyHostName);
+ o->ProxyPort = setting->ProxyPort;
+ }
+}
+
+// Get the proxy settings of IE
+void CmGetSystemInternetSetting(CM_INTERNET_SETTING *setting)
+{
+ bool use_proxy;
+ // Validate arguments
+ if (setting == NULL)
+ {
+ return;
+ }
+
+ Zero(setting, sizeof(CM_INTERNET_SETTING));
+
+ use_proxy = MsRegReadInt(REG_CURRENT_USER,
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
+ "ProxyEnable");
+
+ if (use_proxy)
+ {
+ char *str = MsRegReadStr(REG_CURRENT_USER,
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
+ "ProxyServer");
+ if (str != NULL)
+ {
+ char name[MAX_HOST_NAME_LEN + 1];
+ UINT port;
+
+ if (CmGetProxyServerNameAndPortFromIeProxyRegStr(name, sizeof(name),
+ &port, str, "https"))
+ {
+ setting->ProxyType = PROXY_HTTP;
+ StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), name);
+ setting->ProxyPort = port;
+ }
+ else if (CmGetProxyServerNameAndPortFromIeProxyRegStr(name, sizeof(name),
+ &port, str, "http"))
+ {
+ setting->ProxyType = PROXY_HTTP;
+ StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), name);
+ setting->ProxyPort = port;
+ }
+ else if (CmGetProxyServerNameAndPortFromIeProxyRegStr(name, sizeof(name),
+ &port, str, "socks"))
+ {
+ setting->ProxyType = PROXY_SOCKS;
+ StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), name);
+ setting->ProxyPort = port;
+ }
+ else
+ {
+ if (SearchStrEx(str, "=", 0, false) == INFINITE)
+ {
+ char *host;
+ UINT port;
+ if (ParseHostPort(str, &host, &port, 0))
+ {
+ if (port != 0)
+ {
+ setting->ProxyType = PROXY_HTTP;
+ StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), host);
+ setting->ProxyPort = port;
+ }
+ Free(host);
+ }
+ }
+ }
+
+ Free(str);
+ }
+ }
+}
+
+// For the proxy settings to go through, use the IE settings
+void CmProxyDlgUseForIE(HWND hWnd, CLIENT_OPTION *o)
+{
+ CM_INTERNET_SETTING s;
+
+ // Validate arguments
+ if(hWnd == NULL)
+ {
+ return;
+ }
+
+ Zero(&s, sizeof(s));
+ CmGetSystemInternetSetting(&s);
+
+ CmProxyDlgSet(hWnd, o, &s);
+}
+
+// Determine the bitmap ID of the smart card authentication screen
+UINT CmGetSecureBitmapId(char *dest_hostname)
+{
+ // Validate arguments
+ if (dest_hostname == NULL)
+ {
+ return 0;
+ }
+
+ if (EndWith(dest_hostname, ".cc.tsukuba.ac.jp"))
+ {
+ return BMP_TSUKUBA;
+ }
+
+ return 0;
+}
+
+// Activate the window of UAC
+void CmSetUacWindowActive()
+{
+ HWND hWnd;
+
+ if (MsIsVista() == false)
+ {
+ return;
+ }
+
+ hWnd = FindWindowA("$$$Secure UAP Dummy Window Class For Interim Dialog", NULL);
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SwitchToThisWindow(hWnd, true);
+}
+
+// UAC helper thread
+void CmUacHelperThread(THREAD *thread, void *param)
+{
+ CM_UAC_HELPER *c = (CM_UAC_HELPER *)param;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ while (c->Halt == false)
+ {
+ CmSetUacWindowActive();
+
+ Wait(c->HaltEvent, 200);
+ }
+}
+
+// Start the UAC helper
+void *CmStartUacHelper()
+{
+ CM_UAC_HELPER *c = ZeroMalloc(sizeof(CM_UAC_HELPER));
+
+ c->HaltEvent = NewEvent();
+ c->Thread = NewThread(CmUacHelperThread, c);
+
+ return (void *)c;
+}
+
+// Stop the UAC helper
+void CmStopUacHelper(void *p)
+{
+ CM_UAC_HELPER *c = (CM_UAC_HELPER *)p;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->Halt = true;
+ Set(c->HaltEvent);
+ WaitThread(c->Thread, INFINITE);
+ ReleaseEvent(c->HaltEvent);
+ ReleaseThread(c->Thread);
+
+ Free(c);
+}
+
+// Command invocation of the simple connection manager
+void CmEasyDlgOnCommand(HWND hWnd, CM_EASY_DLG *d, WPARAM wParam, LPARAM lParam)
+{
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ switch (wParam)
+ {
+ case B_MODE:
+ Command(hWnd, CMD_CM_SETTING);
+ return;
+
+ case B_STATUS:
+ Command(hWnd, CMD_STATUS);
+ return;
+
+ case IDCANCEL:
+ Close(hWnd);
+ return;
+
+ }
+
+ if (wParam == CMD_CONNECT)
+ {
+ cm->ConnectStartedFlag = false;
+ }
+
+ CmMainWindowOnCommandEx(hWnd, wParam, lParam, true);
+
+ if (wParam == CMD_CONNECT && cm->ConnectStartedFlag)
+ {
+ // Close the window when the connection started successfully
+ Close(hWnd);
+ }
+}
+
+// Keyboard pressing of the simple connection manager
+void CmEasyDlgOnKey(HWND hWnd, CM_EASY_DLG *d, bool ctrl, bool alt, UINT key)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Single key
+ switch (key)
+ {
+ case VK_RETURN:
+ Command(hWnd, IDOK);
+ break;
+ case VK_DELETE:
+ // Delete
+ if (IsFocus(hWnd, L_ACCOUNT))
+ {
+ // Operation on the account list
+ Command(hWnd, CMD_DELETE);
+ }
+ else
+ {
+ // Operation on the virtual LAN card list
+ Command(hWnd, CMD_DELETE_VLAN);
+ }
+ break;
+ case VK_F2:
+ // Change the name
+ Command(hWnd, CMD_RENAME);
+ break;
+ case VK_F5:
+ // Update the status
+ Command(hWnd, CMD_REFRESH);
+ break;
+ }
+
+ if (alt)
+ {
+ switch (key)
+ {
+ case 'Q':
+ // Close
+ Command(hWnd, CMD_QUIT);
+ break;
+ }
+ }
+
+ if (ctrl)
+ {
+ switch (key)
+ {
+ case 'G':
+ // Smart Card Manager
+ Command(hWnd, CMD_SECURE_MANAGER);
+ break;
+ case 'S':
+ // Show the status
+ Command(hWnd, CMD_STATUS);
+ break;
+ case 'I':
+ // Disconnect all connections
+ Command(hWnd, CMD_DISCONNECT_ALL);
+ break;
+ case 'D':
+ // Disconnect
+ Command(hWnd, CMD_DISCONNECT);
+ break;
+ case 'N':
+ // Create a new connection setting
+ Command(hWnd, CMD_NEW);
+ break;
+ case 'C':
+ // Creating a copy
+ Command(hWnd, CMD_CLONE);
+ break;
+ case 'T':
+ // Set to start-up connection
+ Command(hWnd, CMD_STARTUP);
+ break;
+ case 'A':
+ // Select all
+ Command(hWnd, CMD_SELECT_ALL);
+ break;
+ case 'L':
+ // Create a new virtual LAN card
+ Command(hWnd, CMD_NEW_VLAN);
+ break;
+ case 'P':
+ // Set the password
+ Command(hWnd, CMD_PASSWORD);
+ break;
+ case 'O':
+ // Option settings
+ Command(hWnd, CMD_TRAFFIC);
+ break;
+ case 'R':
+ // Certificate management
+ Command(hWnd, CMD_TRUST);
+ break;
+ case 'Q':
+ // Throughput
+ Command(hWnd, CMD_TRAFFIC);
+ break;
+ }
+ }
+}
+
+// Operation on the list view of the simple connection manager
+void CmEasyDlgOnNotify(HWND hWnd, CM_EASY_DLG *d, NMHDR *n)
+{
+ NMLVDISPINFOW *disp_info;
+ NMLVKEYDOWN *key;
+
+ // Validate arguments
+ if (hWnd == NULL || n == NULL)
+ {
+ return;
+ }
+
+ switch (n->idFrom)
+ {
+ case L_ACCOUNT:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ CmEasyDlgUpdate(hWnd, d);
+ break;
+ case NM_DBLCLK:
+ // Double click
+ Command(hWnd, CMD_EASY_DBLCLICK);
+ break;
+ case NM_RCLICK:
+ // Right click
+ CmAccountListRightClick(hWnd);
+ break;
+ case LVN_ENDLABELEDITW:
+ // Change the name
+ disp_info = (NMLVDISPINFOW *)n;
+ if (disp_info->item.pszText != NULL)
+ {
+ wchar_t *new_name = disp_info->item.pszText;
+ wchar_t *old_name = LvGetStr(hWnd, L_ACCOUNT, disp_info->item.iItem, 0);
+
+ if (old_name != NULL)
+ {
+ if (UniStrCmp(new_name, old_name) != 0 && UniIsEmptyStr(new_name) == false)
+ {
+ RPC_RENAME_ACCOUNT a;
+ Zero(&a, sizeof(a));
+ UniStrCpy(a.OldName, sizeof(a.OldName), old_name);
+ UniStrCpy(a.NewName, sizeof(a.NewName), new_name);
+ if (CALL(hWnd, CcRenameAccount(cm->Client, &a)))
+ {
+ LvSetItem(hWnd, L_ACCOUNT, disp_info->item.iItem, 0, new_name);
+ }
+ }
+
+ Free(old_name);
+ }
+ }
+ break;
+ case LVN_KEYDOWN:
+ // Key-press
+ key = (NMLVKEYDOWN *)n;
+ if (key != NULL)
+ {
+ bool ctrl, alt;
+ UINT code = key->wVKey;
+ ctrl = (GetKeyState(VK_CONTROL) & 0x8000) == 0 ? false : true;
+ alt = (GetKeyState(VK_MENU) & 0x8000) == 0 ? false : true;
+ CmEasyDlgOnKey(hWnd, d, ctrl, alt, code);
+ }
+ break;
+ }
+ break;
+ }
+}
+
+// Send an update notification to the Simple Connection Manager
+void CmRefreshEasy()
+{
+ if (cm->hEasyWnd == NULL)
+ {
+ return;
+ }
+
+ SendMessage(cm->hEasyWnd, WM_CM_EASY_REFRESH, 0, 0);
+}
+
+// Initialze the Simple Connect Manager
+void CmEasyDlgInit(HWND hWnd, CM_EASY_DLG *d)
+{
+ HFONT hFontForList;
+ HFONT hFontButton;
+ HFONT hFontTitle;
+ HFONT hFontInfo;
+ HFONT hFontOther;
+ UINT i, num, num2, j;
+ bool b = false;
+ char *font_name = NULL;
+ bool font_bold = true;
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_VPN);
+
+ // Window handle registration
+ cm->hEasyWnd = hWnd;
+
+ // Show in the center
+ Center(hWnd);
+
+ // Update the account list
+ CmInitAccountListEx(hWnd, true);
+
+ // Font settings of the list
+ if (cm->VistaStyle)
+ {
+ if (_GETLANG() == 0)
+ {
+ font_name = "Meiryo";
+ font_bold = false;
+ }
+ else if (_GETLANG() == 2)
+ {
+ font_name = "Microsoft YaHei";
+ font_bold = false;
+ }
+ }
+
+ hFontForList = GetFont(font_name, 14, font_bold, false, false, false);
+ hFontButton = GetFont(font_name, 13, font_bold, false, false, false);
+ hFontTitle = GetFont(font_name, 14, font_bold, false, false, false);
+ hFontInfo = GetFont(font_name, 11, font_bold, false, false, false);
+ hFontOther = GetDialogDefaultFont();
+
+ if (cm->VistaStyle)
+ {
+ hFontOther = GetMeiryoFont();
+ }
+
+ SetFont(hWnd, L_ACCOUNT, hFontForList);
+ SetFont(hWnd, IDOK, hFontButton);
+ SetFont(hWnd, S_TITLE, hFontTitle);
+ SetFont(hWnd, S_INFO, hFontInfo);
+ SetFont(hWnd, B_MODE, hFontOther);
+ SetFont(hWnd, IDCANCEL, hFontOther);
+ SetFont(hWnd, B_VGC, hFontOther);
+
+ SetShow(hWnd, B_VGC, cm->Client->IsVgcSupported);
+
+ CmEasyDlgRefresh(hWnd, d);
+
+ num = LvNum(hWnd, L_ACCOUNT);
+ num2 = 0;
+ j = 0;
+ for (i = 0;i < num;i++)
+ {
+ wchar_t *str = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+
+ if (str != NULL)
+ {
+ if (UniStrCmpi(str, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(str, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+ {
+ num2++;
+ j = i;
+ }
+ Free(str);
+ }
+ }
+
+ if (num2 == 1)
+ {
+ LvSelect(hWnd, L_ACCOUNT, j);
+ b = true;
+ }
+
+ if (b == false)
+ {
+ if (UniIsEmptyStr(cm->EasyLastSelectedAccountName) == false)
+ {
+ i = LvSearchStr(hWnd, L_ACCOUNT, 0, cm->EasyLastSelectedAccountName);
+ if (i != INFINITE)
+ {
+ LvSelect(hWnd, L_ACCOUNT, i);
+ b = true;
+ }
+ }
+ }
+
+ if (b == false)
+ {
+ if (LvNum(hWnd, L_ACCOUNT) != 0)
+ {
+ LvSelect(hWnd, L_ACCOUNT, 0);
+ }
+ }
+
+ Focus(hWnd, L_ACCOUNT);
+
+ CmEasyDlgUpdate(hWnd, d);
+}
+
+// Update the Simple Connection Manager control
+void CmEasyDlgUpdate(HWND hWnd, CM_EASY_DLG *d)
+{
+ bool ok = true;
+ bool show_status = false;
+ wchar_t *button_str = _UU("CM_EASY_CONNECT_BUTTON_1");
+ wchar_t *info_str = _UU("CM_EASY_INFO_1");
+ wchar_t *title_str = _UU("CM_EASY_TITLE");
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ if (LvIsSingleSelected(hWnd, L_ACCOUNT) == false)
+ {
+ ok = false;
+ }
+
+ if (ok)
+ {
+ UINT i = LvGetSelected(hWnd, L_ACCOUNT);
+ wchar_t *str = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+
+ info_str = _UU("CM_EASY_INFO_2");
+
+ if (str != NULL)
+ {
+ if (UniStrCmpi(str, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(str, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+ {
+ button_str = _UU("CM_EASY_CONNECT_BUTTON_2");
+ show_status = true;
+ info_str = _UU("CM_EASY_INFO_3");
+
+ if (UniStrCmpi(str, _UU("CM_ACCOUNT_ONLINE")) == 0)
+ {
+ title_str = _UU("CM_EASY_CONNECTED");
+ }
+ else
+ {
+ title_str = _UU("CM_EASY_CONNECTING");
+ }
+ }
+ Free(str);
+ }
+ }
+
+ SetShow(hWnd, B_STATUS, show_status);
+
+ SetText(hWnd, IDOK, button_str);
+ SetText(hWnd, S_INFO, info_str);
+ SetText(hWnd, S_TITLE, title_str);
+
+ SetShow(hWnd, IDOK, ok);
+}
+
+// Update the Simple Connect Manager content
+void CmEasyDlgRefresh(HWND hWnd, CM_EASY_DLG *d)
+{
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ // Update the account list
+ CmRefreshAccountListEx(hWnd, true);
+
+ CmEasyDlgUpdate(hWnd, d);
+}
+
+// Dialog procedure of the simple connection manager
+UINT CmEasyDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ CM_EASY_DLG *d = (CM_EASY_DLG *)param;
+ NMHDR *n;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmEasyDlgInit(hWnd, d);
+ SetTimer(hWnd, 1, 10, NULL);
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+ SetForegroundWindow(hWnd);
+ SetActiveWindow(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CM_EASY_REFRESH:
+ CmEasyDlgRefresh(hWnd, d);
+ break;
+
+ case WM_COMMAND:
+ CmEasyDlgOnCommand(hWnd, d, wParam, lParam);
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ CmEasyDlgOnNotify(hWnd, d, n);
+ break;
+
+ case WM_CLOSE:
+ i = LvGetSelected(hWnd, L_ACCOUNT);
+ if (i != INFINITE)
+ {
+ wchar_t *s = LvGetStr(hWnd, L_ACCOUNT, i, 0);
+ if (s != NULL)
+ {
+ UniStrCpy(cm->EasyLastSelectedAccountName, sizeof(cm->EasyLastSelectedAccountName),
+ s);
+ Free(s);
+ }
+ }
+ else
+ {
+ Zero(cm->EasyLastSelectedAccountName, sizeof(cm->EasyLastSelectedAccountName));
+ }
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Show the window of the simple connection manager (This is called by a delaying timer)
+void CmMainWindowOnShowEasy(HWND hWnd)
+{
+ CM_EASY_DLG d;
+
+ Zero(&d, sizeof(d));
+
+ if (cm->CmSetting.EasyMode == false)
+ {
+ // Not in simple mode
+ return;
+ }
+
+ if (cm->hEasyWnd != NULL)
+ {
+ // It is shown already
+ SetForegroundWindow(cm->hEasyWnd);
+ SetActiveWindow(cm->hEasyWnd);
+ return;
+ }
+
+ Dialog(NULL, D_CM_EASY, CmEasyDlg, &d);
+
+ cm->hEasyWnd = NULL;
+}
+
+// Show the window of the simple connection manager
+void CmShowEasy()
+{
+ SetTimer(cm->hMainWnd, 4, 2, NULL);
+}
+
+// Close the window of the simple connection manager
+void CmCloseEasy()
+{
+ if (cm->hEasyWnd == NULL)
+ {
+ return;
+ }
+
+ SendMessage(cm->hEasyWnd, WM_CLOSE, 0, 0);
+}
+
+// Message processing for such as clicking on the tray icon
+void CmMainWindowOnTrayClicked(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+ bool easymode = cm->CmSetting.EasyMode;
+
+ switch (wParam)
+ {
+ case 1:
+ switch (lParam)
+ {
+ case WM_LBUTTONDOWN:
+ case WM_RBUTTONDOWN:
+ // Click
+ if (easymode == false)
+ {
+ if (IsEnable(hWnd, 0))
+ {
+ CmShowTrayMenu(hWnd);
+ }
+ else
+ {
+ CmShowOrHideWindow(hWnd);
+ }
+ }
+ else
+ {
+ if (cm->hEasyWnd == NULL || IsEnable(cm->hEasyWnd, 0))
+ {
+ CmShowTrayMenu(hWnd);
+ }
+ else
+ {
+ //CmShowOrHideWindow(hWnd);
+ }
+ }
+ break;
+ case WM_LBUTTONDBLCLK:
+ case WM_RBUTTONDBLCLK:
+ // Double click
+ if (easymode == false)
+ {
+ if (IsEnable(hWnd, 0))
+ {
+ CmShowOrHideWindow(hWnd);
+ }
+ }
+ else
+ {
+ if (cm->hEasyWnd == NULL)
+ {
+ CmShowEasy();
+ }
+ else
+ {
+ SetForegroundWindow(cm->hEasyWnd);
+ SetActiveWindow(cm->hEasyWnd);
+ }
+ }
+ break;
+ }
+ break;
+ }
+}
+
+// Apply the setting of the operation mode
+void CmApplyCmSetting()
+{
+ CM_SETTING a;
+ bool changed = false;
+
+ if (cm->CmSettingSupported == false)
+ {
+ return;
+ }
+
+ // Get the configuration of the current vpnclient
+ Zero(&a, sizeof(a));
+ CcGetCmSetting(cm->Client, &a);
+
+ // Check whether there is change point as compared to the previous CM_SETTING
+ if (cm->CmSetting.EasyMode != a.EasyMode)
+ {
+ changed = true;
+ }
+ if (cm->CmSetting.LockMode != a.LockMode)
+ {
+ changed = true;
+ }
+
+ Copy(&cm->CmSetting, &a, sizeof(CM_SETTING));
+
+ if (changed == false)
+ {
+ return;
+ }
+
+ if (cm->StartupFinished)
+ {
+ if (IsShow(cm->hMainWnd, 0) && cm->CmSetting.EasyMode)
+ {
+ // Close the main window if it is shown
+ Hide(cm->hMainWnd, 0);
+ }
+ else
+ {
+ WINDOWPLACEMENT current_pos;
+ if (cm->CmSetting.EasyMode == false && IsShow(cm->hMainWnd, 0) == false)
+ {
+ // When restored to normal mode, restore the main window
+ if (IsZero(&cm->FakeWindowPlacement, sizeof(cm->FakeWindowPlacement)) == false)
+ {
+ cm->FakeWindowPlacement.flags = cm->FakeWindowPlacement.flags & ~SW_MINIMIZE;
+ SetWindowPlacement(cm->hMainWnd, &cm->FakeWindowPlacement);
+ Zero(&cm->FakeWindowPlacement, sizeof(cm->FakeWindowPlacement));
+ Hide(cm->hMainWnd, 0);
+ }
+ CmShowOrHideWindow(cm->hMainWnd);
+ }
+
+ if (cm->CmSetting.EasyMode == false)
+ {
+ if (GetWindowPlacement(cm->hMainWnd, &current_pos))
+ {
+ if (current_pos.rcNormalPosition.right < 0 ||
+ current_pos.rcNormalPosition.bottom < 0)
+ {
+ // If the window is off the screen for some reason,
+ // return it in a visible place
+ SetWindowPos(cm->hMainWnd, NULL, 0, 0, CM_DEFAULT_WIDTH, CM_DEFAULT_HEIGHT, SWP_NOREDRAW | SWP_SHOWWINDOW);
+ Center(cm->hMainWnd);
+ }
+ }
+ }
+ }
+
+ Command(cm->hMainWnd, CMD_REFRESH);
+ }
+
+ if (cm->CmSetting.EasyMode)
+ {
+ if (cm->StartupFinished == false && cm->StartupMode)
+ {
+ // Don't show in the case of /startup
+ }
+ else
+ {
+ CmShowEasy();
+ }
+ }
+ else
+ {
+ CmCloseEasy();
+ }
+}
+
+// Initialize the operation mode changing dialog
+void CmSettingDlgInit(HWND hWnd, CM_SETTING_DLG *d)
+{
+ CM_SETTING a;
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ // Get the configuration of the current vpnclient
+ Zero(&a, sizeof(a));
+ CcGetCmSetting(cm->Client, &a);
+
+ Check(hWnd, R_EASY, a.EasyMode);
+ Check(hWnd, R_NORMAL, a.EasyMode == false);
+
+ if (a.EasyMode == false)
+ {
+ Focus(hWnd, R_NORMAL);
+ }
+ else
+ {
+ Focus(hWnd, R_EASY);
+ }
+
+ Check(hWnd, R_LOCK, a.LockMode);
+
+ SetEnable(hWnd, R_EASY, cm->CmEasyModeSupported);
+
+ if (a.LockMode)
+ {
+ if (IsZero(a.HashedPassword, sizeof(a.HashedPassword)) == false)
+ {
+ // Password is set
+ SetText(hWnd, S_PASSWORD1, _UU("CM_SETTING_PASSWORD"));
+ Hide(hWnd, S_PASSWORD3);
+ Hide(hWnd, E_PASSWORD2);
+
+ d->CheckPassword = true;
+ Copy(d->HashedPassword, a.HashedPassword, sizeof(d->HashedPassword));
+ }
+ }
+
+ SetShow(hWnd, S_VGS1, cm->Client->IsVgcSupported);
+ SetShow(hWnd, S_VGS2, cm->Client->IsVgcSupported);
+ SetShow(hWnd, S_VGS3, cm->Client->IsVgcSupported);
+ SetShow(hWnd, B_VGS, cm->Client->IsVgcSupported);
+
+ CmSettingDlgUpdate(hWnd, d);
+}
+
+// Update the operation mode changing dialog
+void CmSettingDlgUpdate(HWND hWnd, CM_SETTING_DLG *d)
+{
+ bool ok = true;
+ char tmp1[MAX_SIZE], tmp2[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ GetTxtA(hWnd, E_PASSWORD1, tmp1, sizeof(tmp1));
+ GetTxtA(hWnd, E_PASSWORD2, tmp2, sizeof(tmp2));
+
+ if (d->CheckPassword == false)
+ {
+ if (IsChecked(hWnd, R_LOCK))
+ {
+ if (StrCmp(tmp1, tmp2) != 0)
+ {
+ ok = false;
+ }
+ }
+ }
+ else
+ {
+ bool password_ok = false;
+ UCHAR hash[SHA1_SIZE];
+
+ Hash(hash, tmp1, StrLen(tmp1), true);
+ if (Cmp(hash, d->HashedPassword, sizeof(hash)) == 0)
+ {
+ password_ok = true;
+ }
+
+ if (password_ok == false)
+ {
+ Check(hWnd, R_LOCK, true);
+ Disable(hWnd, R_LOCK);
+ }
+ else
+ {
+ Enable(hWnd, R_LOCK);
+ }
+ }
+
+ SetEnable(hWnd, S_PASSWORD1, IsChecked(hWnd, R_LOCK));
+ SetEnable(hWnd, S_PASSWORD2, IsChecked(hWnd, R_LOCK));
+ SetEnable(hWnd, S_PASSWORD3, IsChecked(hWnd, R_LOCK));
+ SetEnable(hWnd, E_PASSWORD1, IsChecked(hWnd, R_LOCK));
+ SetEnable(hWnd, E_PASSWORD2, IsChecked(hWnd, R_LOCK));
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Operation mode changing dialog OK
+void CmSettingDlgOnOk(HWND hWnd, CM_SETTING_DLG *d)
+{
+ CM_SETTING a;
+ char tmp1[MAX_SIZE], tmp2[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ GetTxtA(hWnd, E_PASSWORD1, tmp1, sizeof(tmp1));
+ GetTxtA(hWnd, E_PASSWORD2, tmp2, sizeof(tmp2));
+
+ Zero(&a, sizeof(a));
+
+ a.EasyMode = IsChecked(hWnd, R_EASY);
+ a.LockMode = IsChecked(hWnd, R_LOCK);
+
+ if (a.LockMode)
+ {
+ if (d->CheckPassword && IsEnable(hWnd, R_LOCK) == false)
+ {
+ Copy(a.HashedPassword, d->HashedPassword, sizeof(a.HashedPassword));
+ }
+ else
+ {
+ if (StrLen(tmp1) >= 1)
+ {
+ Hash(a.HashedPassword, tmp1, StrLen(tmp1), true);
+ }
+ }
+ }
+
+ CcSetCmSetting(cm->Client, &a);
+
+ EndDialog(hWnd, true);
+}
+
+// Operation mode changing dialog
+UINT CmSettingDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ CM_SETTING_DLG *d = (CM_SETTING_DLG *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmSettingDlgInit(hWnd, d);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case R_EASY:
+ case R_NORMAL:
+ case R_LOCK:
+ case E_PASSWORD1:
+ case E_PASSWORD2:
+ case IDOK:
+ case IDCANCEL:
+ CmSettingDlgUpdate(hWnd, d);
+ break;
+ }
+ switch (wParam)
+ {
+ case IDOK:
+ CmSettingDlgOnOk(hWnd, d);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case R_LOCK:
+ if (IsChecked(hWnd, R_LOCK))
+ {
+ if (IsEmpty(hWnd, E_PASSWORD1))
+ {
+ Focus(hWnd, E_PASSWORD1);
+ }
+ }
+ break;
+
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+
+// Change operation mode
+bool CmSetting(HWND hWnd)
+{
+ CM_SETTING_DLG d;
+
+ Zero(&d, sizeof(d));
+
+ return Dialog(hWnd, D_CM_SETTING, CmSettingDlg, &d);
+}
+
+
+// Attempting thread for starting the UI Helper
+void CmTryToExecUiHelperThread(THREAD *thread, void *param)
+{
+ bool first_flag = true;
+
+ while (cm->TryExecUiHelperHalt == false && cm->WindowsShutdowning == false)
+ {
+ if (first_flag == false)
+ {
+ // Wait a little for other than the first time
+ Wait(cm->TryExecUiHelperHaltEvent, CM_TRY_EXEC_UI_HELPER_INTERVAL * 2);
+
+ if (cm->TryExecUiHelperHalt || cm->WindowsShutdowning)
+ {
+ break;
+ }
+ }
+ first_flag = false;
+
+ if (cm->TryExecUiHelperHalt == false && cm->WindowsShutdowning == false)
+ {
+ if (cm->TryExecUiHelperProcessHandle == NULL)
+ {
+ CmTryToExecUiHelper();
+ }
+ }
+
+ if (cm->TryExecUiHelperHalt || cm->WindowsShutdowning)
+ {
+ break;
+ }
+
+ if (cm->TryExecUiHelperProcessHandle == NULL)
+ {
+ Wait(cm->TryExecUiHelperHaltEvent, CM_TRY_EXEC_UI_HELPER_INTERVAL);
+ }
+ else
+ {
+ HANDLE handles[2];
+ handles[0] = cm->TryExecUiHelperProcessHandle;
+ handles[1] = (HANDLE)cm->TryExecUiHelperHaltEvent->pData;
+ WaitForMultipleObjects(2, handles, false, CM_TRY_EXEC_UI_HELPER_INTERVAL);
+
+ if (WaitForSingleObject(cm->TryExecUiHelperProcessHandle, 0) != WAIT_TIMEOUT)
+ {
+ CloseHandle(cm->TryExecUiHelperProcessHandle);
+ cm->TryExecUiHelperProcessHandle = NULL;
+ if (cm->TryExecUiHelperHalt || cm->WindowsShutdowning)
+ {
+ break;
+ }
+ Wait(cm->TryExecUiHelperHaltEvent, CM_TRY_EXEC_UI_HELPER_INTERVAL * 2);
+ }
+ }
+ }
+}
+
+// Stop the UI Helper
+void CmFreeTryToExecUiHelper()
+{
+ cm->TryExecUiHelperHalt = true;
+ Set(cm->TryExecUiHelperHaltEvent);
+
+ WaitThread(cm->TryExecUiHelperThread, INFINITE);
+
+ ReleaseThread(cm->TryExecUiHelperThread);
+ cm->TryExecUiHelperThread = NULL;
+
+ ReleaseEvent(cm->TryExecUiHelperHaltEvent);
+ cm->TryExecUiHelperHaltEvent = NULL;
+
+ cm->TryExecUiHelperHalt = false;
+ cm->TryExecUiHelperProcessHandle = NULL;
+}
+
+// Initialize the UI Helper starting
+void CmInitTryToExecUiHelper()
+{
+ cm->TryExecUiHelperProcessHandle = NULL;
+ cm->TryExecUiHelperHalt = false;
+ cm->TryExecUiHelperHaltEvent = NewEvent();
+ cm->TryExecUiHelperThread = NewThread(CmTryToExecUiHelperThread, NULL);
+}
+
+// Start the UI Helper
+void *CmExecUiHelperMain()
+{
+ HANDLE h;
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), L"%s\\%S", MsGetExeDirNameW(), CiGetVpnClientExeFileName());
+
+ // Start
+ h = Win32RunExW(tmp, SVC_ARG_UIHELP_W, false);
+
+ return (void *)h;
+}
+
+// Attempt to start the UI Helper
+void CmTryToExecUiHelper()
+{
+ HANDLE h;
+ // Check that it isn't already running
+ if (CnCheckAlreadyExists(false))
+ {
+ // It have already started
+ return;
+ }
+
+ h = (HANDLE)CmExecUiHelperMain();
+
+ if (h != NULL)
+ {
+ cm->TryExecUiHelperProcessHandle = h;
+ }
+}
+
+// Initialize the dialog
+void CmTrafficResultDlgInit(HWND hWnd, TT_RESULT *res)
+{
+ LVB *ct;
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ char str[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || res == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_SWITCH);
+
+ SetFont(hWnd, L_STATUS, GetFont(_SS("DEFAULT_FONT_2"), 10, false, false, false, false));
+
+ LvInit(hWnd, L_STATUS);
+ LvSetStyle(hWnd, L_STATUS, LVS_EX_GRIDLINES);
+ LvInsertColumn(hWnd, L_STATUS, 0, _UU("TTC_RES_COLUMN_1"), 100);
+ LvInsertColumn(hWnd, L_STATUS, 1, _UU("TTC_RES_COLUMN_2"), 100);
+ LvInsertColumn(hWnd, L_STATUS, 2, _UU("TTC_RES_COLUMN_3"), 100);
+
+ ct = LvInsertStart();
+
+ // Time that was used to measure
+ GetSpanStrMilli(str, sizeof(str), res->Span);
+ StrToUni(tmp, sizeof(tmp), str);
+ LvInsertAdd(ct, ICO_DATETIME, NULL, 3, _UU("TTC_RES_SPAN"), tmp, L"");
+
+ // Correct the data for Ethernet frame
+ LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_ETHER"), res->Raw ? _UU("SEC_NO") : _UU("SEC_YES"), L"");
+
+ // Amount of communication data of download direction
+ ToStr3(str, sizeof(str), res->NumBytesDownload);
+ UniFormat(tmp1, sizeof(tmp1), L"%S Bytes", str);
+ ToStrByte1000(str, sizeof(str), res->NumBytesDownload);
+ StrToUni(tmp2, sizeof(tmp2), str);
+ LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_BYTES_DOWNLOAD"), tmp1, tmp2);
+
+ // Amount of communication data of upload direction
+ ToStr3(str, sizeof(str), res->NumBytesUpload);
+ UniFormat(tmp1, sizeof(tmp1), L"%S Bytes", str);
+ ToStrByte1000(str, sizeof(str), res->NumBytesUpload);
+ StrToUni(tmp2, sizeof(tmp2), str);
+ LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_BYTES_UPLOAD"), tmp1, tmp2);
+
+ // Total amount of communication data
+ ToStr3(str, sizeof(str), res->NumBytesTotal);
+ UniFormat(tmp1, sizeof(tmp1), L"%S Bytes", str);
+ ToStrByte1000(str, sizeof(str), res->NumBytesTotal);
+ StrToUni(tmp2, sizeof(tmp2), str);
+ LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_BYTES_TOTAL"), tmp1, tmp2);
+
+ // Calculate the total throughput of input and output of the relay equipment
+ LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_DOUBLE"), (res->Double == false) ? _UU("SEC_NO") : _UU("SEC_YES"), L"");
+
+ // Average throughput of download direction
+ ToStr3(str, sizeof(str), res->BpsDownload);
+ UniFormat(tmp1, sizeof(tmp1), L"%S bps", str);
+ ToStrByte1000(str, sizeof(str), res->BpsDownload);
+ ReplaceStr(str, sizeof(str), str, "Bytes", "bps");
+ StrToUni(tmp2, sizeof(tmp2), str);
+ LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_BPS_DOWNLOAD"), tmp1, tmp2);
+
+ // Average throughput of upload direction
+ ToStr3(str, sizeof(str), res->BpsUpload);
+ UniFormat(tmp1, sizeof(tmp1), L"%S bps", str);
+ ToStrByte1000(str, sizeof(str), res->BpsUpload);
+ ReplaceStr(str, sizeof(str), str, "Bytes", "bps");
+ StrToUni(tmp2, sizeof(tmp2), str);
+ LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_BPS_UPLOAD"), tmp1, tmp2);
+
+ // Total average throughput
+ ToStr3(str, sizeof(str), res->BpsTotal);
+ UniFormat(tmp1, sizeof(tmp1), L"%S bps", str);
+ ToStrByte1000(str, sizeof(str), res->BpsTotal);
+ ReplaceStr(str, sizeof(str), str, "Bytes", "bps");
+ StrToUni(tmp2, sizeof(tmp2), str);
+ LvInsertAdd(ct, ICO_INFORMATION, NULL, 3, _UU("TTC_RES_BPS_TOTAL"), tmp1, tmp2);
+
+ LvInsertEnd(ct, hWnd, L_STATUS);
+
+ LvAutoSize(hWnd, L_STATUS);
+}
+
+// Dialog procedure to display results of traffic measurements
+UINT CmTrafficResultDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ TT_RESULT *r = (TT_RESULT *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmTrafficResultDlgInit(hWnd, r);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Display results of traffic measurement
+void CmTrafficResult(HWND hWnd, TT_RESULT *r)
+{
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_CM_TRAFFIC_RESULT, CmTrafficResultDlg, r);
+}
+
+// Thread to wait for the termination of the client
+void CmTrafficRunDlgClientWaitThread(THREAD *t, void *param)
+{
+ CM_TRAFFIC_DLG *d = (CM_TRAFFIC_DLG *)param;
+ TT_RESULT result;
+ UINT ret;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ Zero(&result, sizeof(result));
+ ret = FreeTtc(d->Ttc, &result);
+ d->Ttc = NULL;
+
+ d->RetCode = ret;
+ Copy(&d->Result, &result, sizeof(TT_RESULT));
+
+ PostMessage(d->hWnd, WM_APP + 66, 0, 0);
+}
+
+// Append the string
+void CmTrafficRunDlgAddStr(HWND hWnd, wchar_t *str)
+{
+ wchar_t *tmp;
+ UINT tmp_size;
+
+ tmp_size = UniStrSize(str) + 32;
+ tmp = Malloc(tmp_size);
+ UniStrCpy(tmp, tmp_size, str);
+ if (UniEndWith(str, L"\n") == false)
+ {
+ UniStrCat(tmp, tmp_size, L"\n");
+ }
+
+ UniReplaceStrEx(tmp, tmp_size, tmp, L"\r\n", L"\n", false);
+ UniReplaceStrEx(tmp, tmp_size, tmp, L"\n", L"\r\n", false);
+
+ if (MsIsNt())
+ {
+ SendMsg(hWnd, E_EDIT, EM_SETSEL, 0x7fffffff, 0x7fffffff);
+ SendMsg(hWnd, E_EDIT, EM_REPLACESEL, false, (LPARAM)tmp);
+ }
+ else
+ {
+ char *s = CopyUniToStr(tmp);
+ UINT len;
+
+ len = GetWindowTextLength(DlgItem(hWnd, E_EDIT));
+ SendMsg(hWnd, E_EDIT, EM_SETSEL, 0x7fffffff, 0x7fffffff);
+ SendMsg(hWnd, E_EDIT, EM_SETSEL, len, len);
+ SendMsg(hWnd, E_EDIT, EM_REPLACESEL, false, (LPARAM)s);
+ Free(s);
+ }
+
+ Free(tmp);
+}
+
+// Show the string
+void CmTrafficRunDlgPrintProc(void *param, wchar_t *str)
+{
+ CM_TRAFFIC_DLG *d = (CM_TRAFFIC_DLG *)param;
+ HWND hWnd;
+ // Validate arguments
+ if (param == NULL || str == NULL)
+ {
+ return;
+ }
+
+ hWnd = d->hWnd;
+
+ PostMessage(hWnd, WM_APP + 64, 0, (LPARAM)UniCopyStr(str));
+}
+
+// Thread for stop the measurement program
+void CmTrafficRunDlgHaltThread(THREAD *t, void *param)
+{
+ CM_TRAFFIC_DLG *d = (CM_TRAFFIC_DLG *)param;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ if (d->Setting->ServerMode)
+ {
+ // Stop the server
+ d->RetCode = FreeTts(d->Tts);
+
+ PostMessage(d->hWnd, WM_APP + 65, 0, 0);
+ }
+}
+
+// Stop the measurement program
+void CmTrafficRunDlgHalt(HWND hWnd, CM_TRAFFIC_DLG *d)
+{
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ if (d->Started == false)
+ {
+ return;
+ }
+
+ if (d->Setting->ServerMode)
+ {
+ if (d->HaltThread == NULL)
+ {
+ Disable(hWnd, IDCANCEL);
+ d->HaltThread = NewThread(CmTrafficRunDlgHaltThread, d);
+ }
+ }
+ else
+ {
+ if (d->ClientEndWaitThread != NULL)
+ {
+ StopTtc(d->Ttc);
+ }
+ else
+ {
+ EndDialog(hWnd, 0);
+ }
+ }
+}
+
+// Start the operation of traffic measurement
+void CmTrafficRunDlgStart(HWND hWnd, CM_TRAFFIC_DLG *d)
+{
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ if (d->Setting->ServerMode)
+ {
+ // Start the measurement server
+ d->Tts = NewTts(d->Setting->Port, d, CmTrafficRunDlgPrintProc);
+ }
+ else
+ {
+ // Start the measurement client
+ d->Ttc = NewTtc(d->Setting->Host, d->Setting->Port,
+ d->Setting->NumTcp, d->Setting->Type, d->Setting->Span * 1000ULL,
+ d->Setting->Double, d->Setting->Raw, CmTrafficRunDlgPrintProc, d);
+
+ d->ClientEndWaitThread = NewThread(CmTrafficRunDlgClientWaitThread, d);
+ }
+
+ d->Started = true;
+}
+
+// Traffic measurement operation dialog initialization
+void CmTrafficRunDlgInit(HWND hWnd, CM_TRAFFIC_DLG *d)
+{
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ d->hWnd = hWnd;
+
+ SetIcon(hWnd, 0, ICO_SWITCH);
+ DlgFont(hWnd, S_INFO, 11, false);
+ SetFont(hWnd, E_EDIT, GetFont(_SS("DEFAULT_FONT_2"), 0, false, false,
+ false, false));
+
+ Focus(hWnd, IDCANCEL);
+}
+
+// Traffic measurement operation dialog procedure
+UINT CmTrafficRunDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ CM_TRAFFIC_DLG *d = (CM_TRAFFIC_DLG *)param;
+ wchar_t *s;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmTrafficRunDlgInit(hWnd, d);
+
+ SetTimer(hWnd, 1, 10, NULL);
+ break;
+
+ case WM_APP + 64:
+ // Add a string
+ s = (wchar_t *)lParam;
+ if (s != NULL)
+ {
+ CmTrafficRunDlgAddStr(hWnd, s);
+ Free(s);
+ }
+ break;
+
+ case WM_APP + 65:
+ // Stopping complete
+ if (d->HaltThread != NULL)
+ {
+ WaitThread(d->HaltThread, INFINITE);
+ ReleaseThread(d->HaltThread);
+ d->HaltThread = NULL;
+ EndDialog(hWnd, 0);
+ }
+ break;
+
+ case WM_APP + 66:
+ // Show results
+ if (d->RetCode == ERR_NO_ERROR)
+ {
+ CmTrafficResult(hWnd, &d->Result);
+ }
+
+ if (d->ClientEndWaitThread != NULL)
+ {
+ WaitThread(d->ClientEndWaitThread, INFINITE);
+ ReleaseThread(d->ClientEndWaitThread);
+ d->ClientEndWaitThread = NULL;
+ }
+
+ if (d->CloseDialogAfter)
+ {
+ EndDialog(hWnd, 0);
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+
+ CmTrafficRunDlgStart(hWnd, d);
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ d->CloseDialogAfter = true;
+ CmTrafficRunDlgHalt(hWnd, d);
+ return 1;
+ }
+
+ return 0;
+}
+
+// Execute a traffic measurement
+void CmExecTraffic(HWND hWnd, CM_TRAFFIC *t)
+{
+ CM_TRAFFIC_DLG d;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Zero(&d, sizeof(d));
+ d.Setting = t;
+ d.ResultShowEvent = NewEvent();
+
+ MsSetThreadPriorityHigh();
+ Dialog(hWnd, D_CM_TRAFFIC_RUN, CmTrafficRunDlg, &d);
+ MsRestoreThreadPriority();
+
+ ReleaseEvent(d.ResultShowEvent);
+}
+
+// Write the settings to the registry
+void CmTrafficSaveToReg(CM_TRAFFIC *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "ServerMode", t->ServerMode ? 1 : 0);
+ MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Double", t->Double ? 1 : 0);
+ MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Raw", t->Raw ? 1 : 0);
+ MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Port", t->Port);
+ MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "NumTcp", t->NumTcp);
+ MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Type", t->Type);
+ MsRegWriteInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Span", t->Span);
+ MsRegWriteStr(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Host", t->Host);
+}
+
+// Read the settings from the registry
+bool CmTrafficLoadFromReg(CM_TRAFFIC *t)
+{
+ char *s;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return false;
+ }
+
+ Zero(t, sizeof(CM_TRAFFIC));
+
+ if (MsRegIsKey(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY) == false)
+ {
+ return false;
+ }
+
+ t->Double = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Double") == 0 ? false : true;
+ t->Raw = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Raw") == 0 ? false : true;
+ t->Port = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Port");
+ if (t->Port == 0)
+ {
+ t->Port = TRAFFIC_DEFAULT_PORT;
+ }
+
+ s = MsRegReadStr(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Host");
+
+ if (IsEmptyStr(s) == false)
+ {
+ Trim(s);
+ StrCpy(t->Host, sizeof(t->Host), s);
+ }
+
+ Free(s);
+
+ t->NumTcp = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "NumTcp");
+ t->NumTcp = MAKESURE(t->NumTcp, 1, TRAFFIC_NUMTCP_MAX);
+ t->Type = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Type");
+
+ if (t->Type != TRAFFIC_TYPE_DOWNLOAD && t->Type != TRAFFIC_TYPE_UPLOAD &&
+ t->Type != TRAFFIC_TYPE_FULL)
+ {
+ t->Type = TRAFFIC_TYPE_FULL;
+ }
+
+ t->Span = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "Span");
+ if (t->Span == 0)
+ {
+ t->Span = TRAFFIC_SPAN_DEFAULT;
+ }
+
+ t->ServerMode = MsRegReadInt(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "ServerMode") == 0 ? false : true;
+
+ return true;
+}
+
+// Get the default settings
+void CmTrafficGetDefaultSetting(CM_TRAFFIC *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(CM_TRAFFIC));
+
+ t->Double = false;
+ t->Raw = false;
+ t->Port = TRAFFIC_DEFAULT_PORT;
+ t->NumTcp = TRAFFIC_NUMTCP_DEFAULT;
+ t->Type = TRAFFIC_TYPE_FULL;
+ t->Span = TRAFFIC_SPAN_DEFAULT;
+ t->ServerMode = false;
+}
+
+// Communication throughput measurement tool dialog initialization
+void CmTrafficDlgInit(HWND hWnd)
+{
+ CM_TRAFFIC t;
+ LIST *c1, *c2;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ DlgFont(hWnd, S_8, 9, true);
+ DlgFont(hWnd, S_3, 9, true);
+
+ Zero(&t, sizeof(t));
+ if (CmTrafficLoadFromReg(&t) == false)
+ {
+ CmTrafficGetDefaultSetting(&t);
+ }
+
+ // Write the settings to the dialog
+ Check(hWnd, R_SERVER, t.ServerMode);
+ Check(hWnd, R_CLIENT, t.ServerMode == false);
+
+ c1 = ReadCandidateFromReg(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "HostCandidate");
+ if (c1 != NULL)
+ {
+ UINT i;
+
+ CbReset(hWnd, C_HOST);
+
+ for (i = 0;i < LIST_NUM(c1);i++)
+ {
+ CANDIDATE *c = LIST_DATA(c1, i);
+
+ CbAddStr(hWnd, C_HOST, c->Str, 0);
+ }
+
+ FreeCandidateList(c1);
+ }
+
+ if (CbNum(hWnd, C_HOST) == 0)
+ {
+ CbAddStr(hWnd, C_HOST, L"speed.softether.com", 0);
+ }
+
+ if (IsEmptyStr(t.Host) == false)
+ {
+ SetTextA(hWnd, C_HOST, t.Host);
+ }
+
+ c2 = ReadCandidateFromReg(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "PortCandidate");
+ if (c2 != NULL)
+ {
+ UINT i;
+
+ if (t.Port != 0)
+ {
+ wchar_t tmp[32];
+
+ UniToStru(tmp, t.Port);
+
+ AddCandidate(c2, tmp, 0);
+ }
+
+ CbReset(hWnd, C_PORT);
+
+ for (i = 0;i < LIST_NUM(c2);i++)
+ {
+ CANDIDATE *c = LIST_DATA(c2, i);
+
+ CbAddStr(hWnd, C_PORT, c->Str, 0);
+ }
+
+ FreeCandidateList(c2);
+ }
+
+ CbReset(hWnd, C_NUM);
+
+ for (i = 1;i <= TRAFFIC_NUMTCP_MAX;i++)
+ {
+ wchar_t tmp[32];
+
+ UniToStru(tmp, i);
+
+ CbAddStr(hWnd, C_NUM, tmp, i);
+ }
+
+ CbSelect(hWnd, C_NUM, t.NumTcp);
+
+ Check(hWnd, R_DOWNLOAD, t.Type == TRAFFIC_TYPE_DOWNLOAD);
+ Check(hWnd, R_UPLOAD, t.Type == TRAFFIC_TYPE_UPLOAD);
+ Check(hWnd, R_FULL, t.Type == TRAFFIC_TYPE_FULL);
+
+ Check(hWnd, R_ETHERNET, t.Raw ? false : true);
+ Check(hWnd, R_DOUBLE, t.Double);
+
+ SetIntEx(hWnd, E_SPAN, t.Span);
+
+ CmTrafficDlgUpdate(hWnd);
+}
+
+// Put the contents of the dialog to structure
+void CmTrafficDlgToStruct(HWND hWnd, CM_TRAFFIC *t)
+{
+ // Validate arguments
+ if (hWnd == NULL || t == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(CM_TRAFFIC));
+ t->ServerMode = IsChecked(hWnd, R_SERVER);
+ GetTxtA(hWnd, C_HOST, t->Host, sizeof(t->Host));
+ Trim(t->Host);
+
+ t->Port = GetInt(hWnd, C_PORT);
+ t->NumTcp = CbGetSelect(hWnd, C_NUM);
+ t->Span = GetInt(hWnd, E_SPAN);
+ t->Raw = IsChecked(hWnd, R_ETHERNET) ? false : true;
+ t->Double = IsChecked(hWnd, R_DOUBLE);
+
+ if (IsChecked(hWnd, R_DOWNLOAD))
+ {
+ t->Type = TRAFFIC_TYPE_DOWNLOAD;
+ }
+ else if (IsChecked(hWnd, R_UPLOAD))
+ {
+ t->Type = TRAFFIC_TYPE_UPLOAD;
+ }
+ else
+ {
+ t->Type = TRAFFIC_TYPE_FULL;
+ }
+}
+
+// Communication throughput measurement tool dialog update
+bool CmTrafficDlgUpdate(HWND hWnd)
+{
+ CM_TRAFFIC t;
+ bool ok = true;
+ bool client_only;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return false;
+ }
+
+ CmTrafficDlgToStruct(hWnd, &t);
+
+ client_only = t.ServerMode ? false : true;
+
+ SetEnable(hWnd, C_HOST, client_only);
+ SetEnable(hWnd, S_5, client_only);
+ SetEnable(hWnd, S_8, client_only);
+ SetEnable(hWnd, S_9, client_only);
+ SetEnable(hWnd, R_DOWNLOAD, client_only);
+ SetEnable(hWnd, R_UPLOAD, client_only);
+ SetEnable(hWnd, R_FULL, client_only);
+ SetEnable(hWnd, S_10, client_only);
+ SetEnable(hWnd, S_11, client_only);
+ SetEnable(hWnd, C_NUM, client_only);
+ SetEnable(hWnd, S_14, client_only);
+ SetEnable(hWnd, S_12, client_only);
+ SetEnable(hWnd, E_SPAN, client_only);
+ SetEnable(hWnd, S_13, client_only);
+ SetEnable(hWnd, R_ETHERNET, client_only);
+ SetEnable(hWnd, R_DOUBLE, client_only);
+
+ if (t.Port == 0 || t.Port >= 65536)
+ {
+ ok = false;
+ }
+
+ if (t.ServerMode == false)
+ {
+ if (IsEmptyStr(t.Host))
+ {
+ ok = false;
+ }
+
+ if (t.NumTcp == 0 || t.NumTcp >= 33)
+ {
+ ok = false;
+ }
+
+ if (t.Span == 0)
+ {
+ ok = false;
+ }
+
+ if (t.Type == TRAFFIC_TYPE_FULL && ((t.NumTcp % 2) != 0))
+ {
+ ok = false;
+ }
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+
+ return ok;
+}
+
+// Communication throughput measurement tool dialog OK button
+void CmTrafficDlgOnOk(HWND hWnd)
+{
+ CM_TRAFFIC t;
+ LIST *c;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Get the basic data
+ CmTrafficDlgToStruct(hWnd, &t);
+
+ // Save to registry
+ CmTrafficSaveToReg(&t);
+
+ // Retrieve and save the server name candidate
+ if (IsEmptyStr(t.Host) == false)
+ {
+ c = ReadCandidateFromReg(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "HostCandidate");
+ if (c != NULL)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ StrToUni(tmp, sizeof(tmp), t.Host);
+ AddCandidate(c, tmp, 0);
+
+ WriteCandidateToReg(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, c, "HostCandidate");
+
+ FreeCandidateList(c);
+ }
+ }
+
+ if (t.Port != 0 && t.Port <= 65536)
+ {
+ // Retrieve and store the port number candidate
+ c = ReadCandidateFromReg(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, "PortCandidate");
+ if (c != NULL)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniToStru(tmp, t.Port);
+ AddCandidate(c, tmp, 0);
+
+ WriteCandidateToReg(REG_CURRENT_USER, CM_TRAFFIC_REG_KEY, c, "PortCandidate");
+
+ FreeCandidateList(c);
+ }
+ }
+
+ // Execute
+ CmExecTraffic(hWnd, &t);
+
+ // Update the dialog
+ CmTrafficDlgInit(hWnd);
+}
+
+// Communication throughput measurement tool dialog procedure
+UINT CmTrafficDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetIcon(hWnd, 0, ICO_SWITCH);
+ CmTrafficDlgInit(hWnd);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case R_SERVER:
+ case R_CLIENT:
+ case C_HOST:
+ case C_PORT:
+ case R_DOWNLOAD:
+ case R_UPLOAD:
+ case R_FULL:
+ case C_NUM:
+ case E_SPAN:
+ case R_ETHERNET:
+ case R_DOUBLE:
+ CmTrafficDlgUpdate(hWnd);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ CmTrafficDlgOnOk(hWnd);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Communication throughput measurement tool
+void CmTraffic(HWND hWnd)
+{
+ Dialog(hWnd, D_CM_TRAFFIC, CmTrafficDlgProc, NULL);
+}
+
+// Delete old startup file
+void CmDeleteOldStartupTrayFile()
+{
+ char tmp[MAX_SIZE];
+ char *tag = _SS("CM_JAPANESE_ONLY_OLD_STARTUP");
+ if (IsEmptyStr(tag))
+ {
+ return;
+ }
+
+ Format(tmp, sizeof(tmp), tag, MsGetCommonStartupDir());
+
+ FileDelete(tmp);
+}
+
+// PKCS license confirmation dialog
+UINT CmPkcsEulaDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ UINT id;
+ SECURE_DEVICE *dev;
+ char *name;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ id = (UINT)param;
+ dev = GetSecureDevice(id);
+ if (dev == NULL)
+ {
+ EndDialog(hWnd, 0);
+ return 0;
+ }
+
+ name = dev->ModuleName;
+
+ FormatText(hWnd, S_INFO_1, name);
+ FormatText(hWnd, S_INFO_2, name, name);
+ FormatText(hWnd, S_INFO_3, name);
+
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ EndDialog(hWnd, 1);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Confirmation screen of whether the user accepts the EULA of the PKCS DLL
+bool CmCheckPkcsEula(HWND hWnd, UINT id)
+{
+ return (Dialog(hWnd, D_CM_PKCSEULA, CmPkcsEulaDlg, (void *)id) == 0) ? false : true;
+}
+
+// Update controls
+void CmSecurePinDlgUpdate(HWND hWnd)
+{
+ char *tmp1, *tmp2, *tmp3;
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ tmp1 = GetTextA(hWnd, E_PIN1);
+ tmp2 = GetTextA(hWnd, E_PIN2);
+ tmp3 = GetTextA(hWnd, E_PIN3);
+ if (IsEmptyStr(tmp1))
+ {
+ ok = false;
+ }
+ if (IsEmptyStr(tmp2))
+ {
+ ok = false;
+ }
+ if (IsEmptyStr(tmp3))
+ {
+ ok = false;
+ }
+ if (StrCmp(tmp2, tmp3) != 0)
+ {
+ ok = false;
+ }
+ Free(tmp1);
+ Free(tmp2);
+ Free(tmp3);
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// PIN code changing dialog
+UINT CmSecurePinDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ UINT id = (UINT)param;
+ char *src, *dst;
+ SECURE *s;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmSecurePinDlgUpdate(hWnd);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_PIN1:
+ case E_PIN2:
+ case E_PIN3:
+ CmSecurePinDlgUpdate(hWnd);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ src = GetTextA(hWnd, E_PIN1);
+ dst = GetTextA(hWnd, E_PIN3);
+
+ Disable(hWnd, IDOK);
+ Disable(hWnd, IDCANCEL);
+
+ s = OpenSec(id);
+ if (s == NULL)
+ {
+ if (GetSecureDevice(id) != NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SEC_PIN_DEVICE_OPEN_ERR"),
+ GetSecureDevice(id)->DeviceName);
+ }
+ else
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SEC_PIN_DEVICE_OPEN_ERR"),
+ "Unknown");
+ }
+ }
+ else
+ {
+ if (OpenSecSession(s, 0) == false)
+ {
+ if (GetSecureDevice(id) != NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SEC_PIN_DEVICE_OPEN_ERR"),
+ GetSecureDevice(id)->DeviceName);
+ }
+ else
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SEC_PIN_DEVICE_OPEN_ERR"),
+ "Unknown");
+ }
+ }
+ else
+ {
+ if (LoginSec(s, src) == false)
+ {
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SEC_PIN_CURRENT_BAD"));
+ FocusEx(hWnd, E_PIN1);
+ }
+ else
+ {
+ if (ChangePin(s, src, dst) == false)
+ {
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SEC_PIN_CHANGE_FAILED"));
+ FocusEx(hWnd, E_PIN1);
+ }
+ else
+ {
+ // Clear the cache for PIN code
+ cached_pin_code_expires = 0;
+ cached_pin_code[0] = 0;
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SEC_PIN_OK"));
+ EndDialog(hWnd, true);
+ }
+
+ LogoutSec(s);
+ }
+
+ CloseSecSession(s);
+ }
+ CloseSec(s);
+ }
+
+ Enable(hWnd, IDOK);
+ Enable(hWnd, IDCANCEL);
+
+ Free(src);
+ Free(dst);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Change the PIN code
+void CmSecurePin(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL || id == 0 || CheckSecureDeviceId(id) == false)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_CM_SECURE_PIN, CmSecurePinDlg, (void *)id);
+}
+
+// Object type selection dialog
+UINT CmSecureTypeDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ UINT type;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ type = MsRegReadInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "DefaultImportType");
+ Check(hWnd, R_DATA, type == SEC_DATA);
+ Check(hWnd, R_CERT, type == SEC_X);
+ Check(hWnd, R_KEY, type == SEC_K);
+ goto UPDATE_CONTROL;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ type = SEC_DATA;
+ if (IsChecked(hWnd, R_CERT))
+ {
+ type = SEC_X;
+ }
+ else if (IsChecked(hWnd, R_KEY))
+ {
+ type = SEC_K;
+ }
+
+ MsRegWriteInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "DefaultImportType", type);
+
+ EndDialog(hWnd, type);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ case R_CERT:
+ case R_KEY:
+ case R_DATA:
+UPDATE_CONTROL:
+ SetEnable(hWnd, IDOK, IsChecked(hWnd, R_CERT) ||
+ IsChecked(hWnd, R_KEY) ||
+ IsChecked(hWnd, R_DATA));
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, INFINITE);
+ break;
+ }
+
+ return 0;
+}
+
+// Object type selection
+UINT CmSecureType(HWND hWnd)
+{
+ return Dialog(hWnd, D_CM_SECURE_TYPE, CmSecureTypeDlg, NULL);
+}
+
+// Initialize the dialog
+void CmSecureManagerDlgInit(HWND hWnd, UINT id)
+{
+ SECURE_DEVICE *dev;
+ // Validate arguments
+ if (hWnd == NULL || id == 0)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_SECURE);
+
+ dev = GetSecureDevice(id);
+ if (dev != NULL)
+ {
+ FormatText(hWnd, S_INFO, dev->DeviceName);
+ }
+
+ SetFont(hWnd, B_BOLD, Font(0, true));
+
+ LvInit(hWnd, L_LIST);
+ LvInsertColumn(hWnd, L_LIST, 0, _UU("SEC_MGR_COLUMN1"), 200);
+ LvInsertColumn(hWnd, L_LIST, 1, _UU("SEC_MGR_COLUMN2"), 110);
+
+ CmSecureManagerDlgUpdate(hWnd, id);
+}
+
+// Update controls
+void CmSecureManagerDlgUpdate(HWND hWnd, UINT id)
+{
+ bool b = true;
+ bool read_only = IsJPKI(id);
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (LvIsSingleSelected(hWnd, L_LIST) == false)
+ {
+ b = false;
+ }
+
+ SetEnable(hWnd, B_EXPORT, b && ((UINT)LvGetParam(hWnd, L_LIST, LvGetSelected(hWnd, L_LIST)) != SEC_K));
+ SetEnable(hWnd, B_DELETE, b && (read_only == false));
+ SetEnable(hWnd, B_PIN, (read_only == false));
+ SetEnable(hWnd, B_IMPORT, (read_only == false));
+ SetEnable(hWnd, B_NEW_CERT, (read_only == false));
+}
+
+// Content update
+void CmSecureManagerDlgRefresh(HWND hWnd, UINT id)
+{
+ bool ret;
+ LIST *o;
+ WINUI_SECURE_BATCH batch[] =
+ {
+ {WINUI_SECURE_ENUM_OBJECTS, NULL, false, NULL, NULL, NULL, NULL, NULL, NULL},
+ };
+ // Validate arguments
+ if (hWnd == NULL || id == 0)
+ {
+ return;
+ }
+
+ ret = SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0);
+
+ if (ret == false)
+ {
+ return;
+ }
+
+ o = batch[0].EnumList;
+ if (o != NULL)
+ {
+ CmSecureManagerDlgPrintList(hWnd, o);
+
+ FreeEnumSecObject(o);
+ }
+
+ // update controls
+ CmSecureManagerDlgUpdate(hWnd, id);
+}
+
+// Show the list of secure objects
+void CmSecureManagerDlgPrintList(HWND hWnd, LIST *o)
+{
+ CmSecureManagerDlgPrintListEx(hWnd, L_LIST, o, INFINITE);
+}
+void CmSecureManagerDlgPrintListEx(HWND hWnd, UINT id, LIST *o, UINT type)
+{
+ UINT i;
+ LVB *v;
+ // Validate arguments
+ if (hWnd == NULL || o == NULL)
+ {
+ return;
+ }
+
+ LvReset(hWnd, id);
+
+ v = LvInsertStart();
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ UINT icon = ICO_LOG2;
+ wchar_t tmp1[MAX_SIZE], *tmp2, *tmp3;
+ SEC_OBJ *obj = LIST_DATA(o, i);
+
+ if (type == INFINITE || obj->Type == type)
+ {
+ StrToUni(tmp1, sizeof(tmp1), obj->Name);
+ tmp2 = CmSecureObjTypeToStr(obj->Type);
+ tmp3 = obj->Private ? _UU("SEC_YES") : _UU("SEC_NO");
+
+ if (obj->Type == SEC_X)
+ {
+ icon = ICO_CERT;
+ }
+ else if (obj->Type == SEC_K || obj->Type == SEC_P)
+ {
+ icon = ICO_KEY;
+ }
+
+ LvInsertAdd(v, icon, (void *)obj->Type, 2, tmp1, tmp2);
+ }
+ }
+
+ LvInsertEnd(v, hWnd, id);
+}
+
+// Convert the type of secure object to a string
+wchar_t *CmSecureObjTypeToStr(UINT type)
+{
+ wchar_t *ret = _UU("SEC_TYPE_DATA");
+
+ if (type == SEC_X)
+ {
+ ret = _UU("SEC_TYPE_CERT");
+ }
+ else if (type == SEC_K)
+ {
+ ret = _UU("SEC_TYPE_KEY");
+ }
+ else if (type == SEC_P)
+ {
+ ret = _UU("SEC_TYPE_PUB");
+ }
+
+ return ret;
+}
+
+// Write by creating a new certificate
+void CmSecureManagerDlgNewCert(HWND hWnd, UINT id)
+{
+ X *x;
+ K *k;
+ char default_name[MAX_SIZE];
+ char *object_name;
+ bool ok = false;
+ WINUI_SECURE_BATCH batch[] =
+ {
+ {WINUI_SECURE_WRITE_CERT, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL},
+ {WINUI_SECURE_WRITE_KEY, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL},
+ {WINUI_SECURE_ENUM_OBJECTS, NULL, false, NULL, NULL, NULL, NULL, NULL, NULL},
+ };
+ // Validate arguments
+ if (hWnd == NULL || id == 0)
+ {
+ return;
+ }
+
+ // Dialog for creating certificate
+ if (SmCreateCert(hWnd, &x, &k, true, NULL, false) == false)
+ {
+ return;
+ }
+ // Generate the default name
+ GetPrintNameFromXA(default_name, sizeof(default_name), x);
+ ConvertSafeFileName(default_name, sizeof(default_name), default_name);
+
+ object_name = StringDlgA(hWnd, _UU("SEC_OBJECT_NAME_TITLE"),
+ _UU("SEC_OBJECT_NAME_INFO"), default_name, ICO_CERT, false, false);
+
+ if (object_name != NULL)
+ {
+ // Enumerate and write
+ batch[0].InputX = x;
+ batch[0].Name = object_name;
+ batch[1].InputK = k;
+ batch[1].Name = object_name;
+
+ if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0) == false)
+ {
+ // Failure
+ }
+ else
+ {
+ ok = true;
+ }
+
+ Free(object_name);
+ }
+
+ if (ok)
+ {
+ LIST *o = batch[2].EnumList;
+
+ CmSecureManagerDlgPrintList(hWnd, o);
+
+ FreeEnumSecObject(o);
+
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SEC_NEW_CERT_IMPORT_OK"));
+ }
+
+ FreeX(x);
+ FreeK(k);
+}
+
+// Import
+void CmSecureManagerDlgImport(HWND hWnd, UINT id)
+{
+ UINT type;
+ char name[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t *tmp;
+ wchar_t *filename;
+ BUF *b;
+ K *k;
+ bool ok = false;
+ X *x;
+ WINUI_SECURE_BATCH batch[] =
+ {
+ {WINUI_SECURE_WRITE_DATA, name, true, NULL, NULL, NULL, NULL, NULL, NULL},
+ {WINUI_SECURE_ENUM_OBJECTS, NULL, false, NULL, NULL, NULL, NULL, NULL, NULL},
+ };
+ // Validate arguments
+ if (hWnd == NULL || id == 0)
+ {
+ return;
+ }
+
+ // Select the type of secure object
+ type = CmSecureType(hWnd);
+
+ switch (type)
+ {
+ case SEC_DATA:
+ // Data
+ tmp = OpenDlg(hWnd, _UU("DLG_ALL_FILES"), _UU("SEC_IMPORT_DATA"));
+ if (tmp == NULL)
+ {
+ return;
+ }
+
+ filename = CopyUniStr(tmp);
+ Free(tmp);
+
+ // Read the file
+ b = ReadDumpW(filename);
+ if (b == NULL)
+ {
+ // Read failure
+ MsgBox(hWnd, MB_ICONSTOP, _UU("SEC_READ_FAILED"));
+ }
+ else
+ {
+ if (b->Size > MAX_SEC_DATA_SIZE)
+ {
+ // File size is too large
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SEC_DATA_TOO_BIG"), MAX_SEC_DATA_SIZE);
+ }
+ else
+ {
+ // Generate the default name
+ char default_name[MAX_SIZE];
+ wchar_t default_name_w[MAX_SIZE];
+ char *object_name;
+ GetFileNameFromFilePathW(default_name_w, sizeof(default_name_w), filename);
+ UniToStr(default_name, sizeof(default_name), default_name_w);
+ ConvertSafeFileName(default_name, sizeof(default_name), default_name);
+
+ object_name = StringDlgA(hWnd, _UU("SEC_OBJECT_NAME_TITLE"),
+ _UU("SEC_OBJECT_NAME_INFO"), default_name, ICO_LOG2, false, false);
+
+ if (object_name != NULL)
+ {
+ // Enumerate and write
+ batch[0].InputData = b;
+ batch[0].Name = object_name;
+
+ if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0) == false)
+ {
+ // Failure
+ }
+ else
+ {
+ ok = true;
+ }
+
+ Free(object_name);
+ }
+ }
+
+ FreeBuf(b);
+ }
+
+ Free(filename);
+ break;
+
+ case SEC_X:
+ // Read a certificate
+ if (CmLoadXExW(hWnd, &x, tmp2, sizeof(tmp2)))
+ {
+ // Generate the default name
+ char default_name[MAX_SIZE];
+ wchar_t default_name_w[MAX_PATH];
+ char *object_name;
+ GetFileNameFromFilePathW(default_name_w, sizeof(default_name_w), tmp2);
+ UniToStr(default_name, sizeof(default_name), default_name_w);
+ ConvertSafeFileName(default_name, sizeof(default_name), default_name);
+
+ object_name = StringDlgA(hWnd, _UU("SEC_OBJECT_NAME_TITLE"),
+ _UU("SEC_OBJECT_NAME_INFO"), default_name, ICO_CERT, false, false);
+
+ if (object_name != NULL)
+ {
+ // Enumerate and write
+ batch[0].Type = WINUI_SECURE_WRITE_CERT;
+ batch[0].InputX = x;
+ batch[0].Name = object_name;
+
+ if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0) == false)
+ {
+ // Failure
+ }
+ else
+ {
+ ok = true;
+ }
+
+ Free(object_name);
+ }
+
+ FreeX(x);
+ }
+
+ break;
+
+ case SEC_K:
+ // Secret key
+ if (CmLoadKExW(hWnd, &k, tmp2, sizeof(tmp2)))
+ {
+ // Generate the default name
+ char default_name[MAX_SIZE];
+ wchar_t default_name_w[MAX_PATH];
+ char *object_name;
+ GetFileNameFromFilePathW(default_name_w, sizeof(default_name_w), tmp2);
+ UniToStr(default_name, sizeof(default_name), default_name_w);
+ ConvertSafeFileName(default_name, sizeof(default_name), default_name);
+
+ object_name = StringDlgA(hWnd, _UU("SEC_OBJECT_NAME_TITLE"),
+ _UU("SEC_OBJECT_NAME_INFO"), default_name, ICO_KEY, false, false);
+
+ if (object_name != NULL)
+ {
+ // Enumerate and write
+ batch[0].Type = WINUI_SECURE_WRITE_KEY;
+ batch[0].InputK = k;
+ batch[0].Name = object_name;
+
+ if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0) == false)
+ {
+ // Failure
+ }
+ else
+ {
+ ok = true;
+ }
+
+ Free(object_name);
+ }
+
+ FreeK(k);
+ }
+ break;
+
+ default:
+ // Invalid
+ return;
+ }
+
+ if (ok)
+ {
+ LIST *o = batch[1].EnumList;
+
+ CmSecureManagerDlgPrintList(hWnd, o);
+
+ FreeEnumSecObject(o);
+
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SEC_OBJECT_IMPORT_OK"));
+ }
+}
+
+// Export the object
+void CmSecureManagerDlgExport(HWND hWnd, UINT id)
+{
+ char name[MAX_SIZE];
+ UINT method = WINUI_SECURE_READ_DATA;
+ char *tmp;
+ UINT type;
+ wchar_t filename[MAX_PATH];
+ wchar_t *uni_tmp;
+ X *x;
+ BUF *b;
+ wchar_t default_name[128];
+ WINUI_SECURE_BATCH batch[] =
+ {
+ {WINUI_SECURE_READ_DATA, name, true, NULL, NULL, NULL, NULL, NULL, NULL},
+ };
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || id == 0)
+ {
+ return;
+ }
+
+ i = LvGetSelected(hWnd, L_LIST);
+ if (i == INFINITE)
+ {
+ return;
+ }
+
+ tmp = LvGetStrA(hWnd, L_LIST, i, 0);
+ StrCpy(name, sizeof(name), tmp);
+ Free(tmp);
+
+ type = (UINT)LvGetParam(hWnd, L_LIST, i);
+
+ switch (type)
+ {
+ case SEC_X:
+ method = WINUI_SECURE_READ_CERT;
+ break;
+
+ default:
+ method = WINUI_SECURE_READ_DATA;
+ break;
+ }
+
+ batch[0].Type = method;
+
+ // Operate the smart card
+ if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0) == false)
+ {
+ return;
+ }
+
+ switch (type)
+ {
+ case SEC_X:
+ // Certificate
+ x = batch[0].OutputX;
+
+ CertDlg(hWnd, x, NULL, true);
+
+ FreeX(x);
+ break;
+
+ default:
+ // File
+ b = batch[0].OutputData;
+ StrToUni(default_name, sizeof(default_name), name);
+ uni_tmp = SaveDlg(hWnd, _UU("DLG_ALL_FILES"), _UU("DLG_SAVE_FILE"), default_name, NULL);
+
+ if (uni_tmp != NULL)
+ {
+ UniStrCpy(filename, sizeof(filename), uni_tmp);
+
+ DumpBufW(b, filename);
+
+ Free(uni_tmp);
+
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SEC_OBJECT_EXPORT_OK"));
+ }
+
+
+ FreeBuf(b);
+ break;
+ }
+}
+
+// Delete the object
+void CmSecureManagerDlgDelete(HWND hWnd, UINT id)
+{
+ char name[MAX_SIZE];
+ UINT method = WINUI_SECURE_DELETE_DATA;
+ char *tmp;
+ UINT type;
+ LIST *o;
+ WINUI_SECURE_BATCH batch[] =
+ {
+ {WINUI_SECURE_DELETE_OBJECT, name, false, NULL, NULL, NULL, NULL, NULL, NULL},
+ {WINUI_SECURE_ENUM_OBJECTS, NULL, false, NULL, NULL, NULL, NULL, NULL, NULL},
+ };
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || id == 0)
+ {
+ return;
+ }
+
+ i = LvGetSelected(hWnd, L_LIST);
+ if (i == INFINITE)
+ {
+ return;
+ }
+
+ tmp = LvGetStrA(hWnd, L_LIST, i, 0);
+ StrCpy(name, sizeof(name), tmp);
+ Free(tmp);
+
+ type = (UINT)LvGetParam(hWnd, L_LIST, i);
+
+ switch (type)
+ {
+ case SEC_X:
+ method = WINUI_SECURE_DELETE_CERT;
+ break;
+
+ case SEC_K:
+ method = WINUI_SECURE_DELETE_KEY;
+ break;
+
+ default:
+ method = WINUI_SECURE_DELETE_DATA;
+ break;
+ }
+
+ batch[0].Type = method;
+
+ if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), id, 0) == false)
+ {
+ return;
+ }
+
+ o = batch[1].EnumList;
+
+ CmSecureManagerDlgPrintList(hWnd, o);
+
+ FreeEnumSecObject(o);
+}
+
+static bool cm_secure_manager_no_new_cert = false;
+
+// Smart Card Manager dialog
+UINT CmSecureManagerDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ NMHDR *n;
+ UINT id = (UINT)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmSecureManagerDlgInit(hWnd, id);
+
+ if (cm_secure_manager_no_new_cert)
+ {
+ Hide(hWnd, B_NEW_CERT);
+ }
+
+ SetTimer(hWnd, 1, 1, NULL);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_REFRESH:
+ CmSecureManagerDlgRefresh(hWnd, id);
+ break;
+
+ case B_IMPORT:
+ CmSecureManagerDlgImport(hWnd, id);
+ break;
+
+ case B_EXPORT:
+ CmSecureManagerDlgExport(hWnd, id);
+ break;
+
+ case B_DELETE:
+ if (MsgBox(hWnd, MB_YESNO | MB_ICONEXCLAMATION | MB_DEFBUTTON2,
+ _UU("SEC_DELETE_MSG")) == IDYES)
+ {
+ CmSecureManagerDlgDelete(hWnd, id);
+ }
+ break;
+
+ case B_NEW_CERT:
+ CmSecureManagerDlgNewCert(hWnd, id);
+ break;
+
+ case B_PIN:
+ CmSecurePin(hWnd, id);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+
+ CmSecureManagerDlgRefresh(hWnd, id);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ CmSecureManagerDlgUpdate(hWnd, id);
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Smart Card Manager
+void CmSecureManager(HWND hWnd, UINT id)
+{
+ CmSecureManagerEx(hWnd, id, false);
+}
+void CmSecureManagerEx(HWND hWnd, UINT id, bool no_new_cert)
+{
+ // Validate arguments
+ if (hWnd == NULL || id == 0)
+ {
+ return;
+ }
+
+ // ID check
+ if (CheckSecureDeviceId(id) == false)
+ {
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SEC_INVALID_ID"));
+ return;
+ }
+
+ if (no_new_cert)
+ {
+ cm_secure_manager_no_new_cert = true;
+ }
+ else
+ {
+ cm_secure_manager_no_new_cert = false;
+ }
+
+ Dialog(hWnd, D_CM_SECURE_MANAGER, CmSecureManagerDlg, (void *)id);
+}
+
+// Smart Card Manager for Client
+void CmClientSecureManager(HWND hWnd)
+{
+ RPC_USE_SECURE t;
+ UINT id;
+
+ Zero(&t, sizeof(t));
+ CcGetUseSecure(cm->Client, &t);
+
+ id = t.DeviceId;
+
+ if (id == 0 || CheckSecureDeviceId(id) == false)
+ {
+ id = CmClientSelectSecure(hWnd);
+ }
+
+ if (id == 0)
+ {
+ return;
+ }
+
+ CmSecureManager(hWnd, id);
+}
+
+// Initialize the dialog
+void CmSelectSecureDlgInit(HWND hWnd, UINT default_id)
+{
+ UINT i;
+ LIST *o;
+ LVB *v;
+
+ SetIcon(hWnd, 0, ICO_SECURE);
+
+ o = GetSecureDeviceList();
+
+ LvInit(hWnd, L_LIST);
+ LvInsertColumn(hWnd, L_LIST, 0, _UU("SEC_COLUMN1"), 150);
+ LvInsertColumn(hWnd, L_LIST, 1, _UU("SEC_COLUMN2"), 100);
+ LvInsertColumn(hWnd, L_LIST, 2, _UU("SEC_COLUMN3"), 130);
+ LvInsertColumn(hWnd, L_LIST, 3, _UU("SEC_COLUMN4"), 100);
+
+ v = LvInsertStart();
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t *tmp2;
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ SECURE_DEVICE *dev = LIST_DATA(o, i);
+
+ StrToUni(tmp1, sizeof(tmp1), dev->DeviceName);
+ tmp2 = (dev->Type == SECURE_IC_CARD) ? _UU("SEC_SMART_CARD") : _UU("SEC_USB_TOKEN");
+ StrToUni(tmp3, sizeof(tmp3), dev->Manufacturer);
+ StrToUni(tmp4, sizeof(tmp4), dev->ModuleName);
+
+ LvInsertAdd(v, ICO_SECURE, (void *)dev->Id, 4, tmp1, tmp2, tmp3, tmp4);
+ }
+
+ LvInsertEnd(v, hWnd, L_LIST);
+
+ if (default_id != 0)
+ {
+ LvSelect(hWnd, L_LIST, LvSearchParam(hWnd, L_LIST, (void *)default_id));
+ }
+
+ ReleaseList(o);
+
+ // Control update
+ CmSelectSecureDlgUpdate(hWnd);
+}
+
+// Update controls of the dialog
+void CmSelectSecureDlgUpdate(HWND hWnd)
+{
+ SetEnable(hWnd, IDOK, LvIsSingleSelected(hWnd, L_LIST));
+}
+
+// Smart card selection dialog
+UINT CmSelectSecureDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ UINT default_id = (UINT)param;
+ NMHDR *n = NULL;
+ static UINT old_id;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ old_id = default_id;
+ CmSelectSecureDlgInit(hWnd, default_id);
+
+ if (LvNum(hWnd, L_LIST) == 0)
+ {
+ // There is no smart card
+ SetTimer(hWnd, 1, 100, NULL);
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+
+ Disable(hWnd, L_LIST);
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SEC_NO_SECURE_DEVICE"));
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ if (IsEnable(hWnd, IDOK))
+ {
+ UINT i = LvGetSelected(hWnd, L_LIST);
+ if (i != INFINITE)
+ {
+ UINT id = (UINT)LvGetParam(hWnd, L_LIST, i);
+
+ if (old_id != id)
+ {
+ if (CmCheckPkcsEula(hWnd, id) == false)
+ {
+ break;
+ }
+ }
+ EndDialog(hWnd, id);
+ }
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ CmSelectSecureDlgUpdate(hWnd);
+ break;
+ case NM_DBLCLK:
+ Command(hWnd, IDOK);
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Select the smart card device to be used
+UINT CmSelectSecure(HWND hWnd, UINT current_id)
+{
+ return Dialog(hWnd, D_CM_SELECT_SECURE, CmSelectSecureDlg, (void *)current_id);
+}
+
+// Select the smart card device to be used (client)
+UINT CmClientSelectSecure(HWND hWnd)
+{
+ UINT id;
+ RPC_USE_SECURE t;
+
+ if (cm->server_name != NULL)
+ {
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("CM_SECURE_MUST_LOCAL"));
+ return 0;
+ }
+
+ Zero(&t, sizeof(t));
+ CcGetUseSecure(cm->Client, &t);
+
+ id = t.DeviceId;
+
+ id = CmSelectSecure(hWnd, id);
+ if (id != 0)
+ {
+ Zero(&t, sizeof(t));
+ t.DeviceId = id;
+
+ CALL(hWnd, CcUseSecure(cm->Client, &t));
+
+ SmWriteSelectSecureIdReg(id);
+ }
+
+ return id;
+}
+
+// Shortcut connection
+void CmConnectShortcut(UCHAR *key)
+{
+ UINT ret;
+ // Validate arguments
+ if (key == NULL)
+ {
+ return;
+ }
+
+ // Attempt to connect
+ ret = CcShortcut(key);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ if (ret == ERR_ACCOUNT_ACTIVE)
+ {
+ // Because it is currently connected, to query whether or not to disconnect
+ if (MsgBox(NULL, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_SHORTCUT_DISCONNECT")) == IDYES)
+ {
+ // Try to disconnect
+ ret = CcShortcutDisconnect(key);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error
+ MsgBox(NULL, MB_ICONEXCLAMATION, GetUniErrorStr(ret));
+ }
+ }
+ }
+ else
+ {
+ // Other errors
+ MsgBox(NULL, MB_ICONEXCLAMATION, GetUniErrorStr(ret));
+ }
+ }
+}
+
+// Play the audio guide
+void CmVoice(char *name)
+{
+ UINT i;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return;
+ }
+
+ // Voice guidance features disappeared!!
+ return;
+
+ if (cm->DisableVoice)
+ {
+ return;
+ }
+
+ for (i = 0;i < sizeof(cm_voice) / sizeof(CM_VOICE);i++)
+ {
+ if (cm_voice[i].voice_id == cm->VoiceId)
+ {
+ char tmp[MAX_SIZE];
+ Format(tmp, sizeof(tmp), "%s_%s.wav", cm_voice[i].perfix, name);
+ MsPlaySound(tmp);
+ return;
+ }
+ }
+}
+
+// Update the password changing dialog
+void CmChangePasswordUpdate(HWND hWnd, CM_CHANGE_PASSWORD *p)
+{
+ bool ok = true;
+ char *s1, *s2;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (IsEmpty(hWnd, E_USERNAME))
+ {
+ ok = false;
+ }
+
+ s1 = GetTextA(hWnd, E_NEW_PASSWORD1);
+ s2 = GetTextA(hWnd, E_NEW_PASSWORD2);
+
+ if (StrCmp(s1, s2) != 0)
+ {
+ ok = false;
+ }
+
+ Free(s1);
+ Free(s2);
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Password changing dialog procedure
+UINT CmChangePasswordProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ CM_CHANGE_PASSWORD *p = (CM_CHANGE_PASSWORD *)param;
+ char username[MAX_USERNAME_LEN + 1];
+ char old_pass[MAX_PASSWORD_LEN + 1];
+ char new_pass[MAX_PASSWORD_LEN + 1];
+ UINT ret;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetTextA(hWnd, E_HUBNAME, p->HubName);
+ SetTextA(hWnd, E_USERNAME, p->Username);
+ FormatText(hWnd, S_TITLE, p->ClientOption->Hostname);
+
+ if (IsEmpty(hWnd, E_USERNAME))
+ {
+ FocusEx(hWnd, E_USERNAME);
+ }
+ else
+ {
+ FocusEx(hWnd, E_OLD_PASSWORD);
+ }
+
+ CmChangePasswordUpdate(hWnd, p);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_USERNAME:
+ case E_OLD_PASSWORD:
+ case E_NEW_PASSWORD1:
+ case E_NEW_PASSWORD2:
+ CmChangePasswordUpdate(hWnd, p);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ GetTxtA(hWnd, E_USERNAME, username, sizeof(username));
+ GetTxtA(hWnd, E_OLD_PASSWORD, old_pass, sizeof(old_pass));
+ GetTxtA(hWnd, E_NEW_PASSWORD1, new_pass, sizeof(new_pass));
+
+ Disable(hWnd, E_USERNAME);
+ Disable(hWnd, E_OLD_PASSWORD);
+ Disable(hWnd, E_NEW_PASSWORD1);
+ Disable(hWnd, E_NEW_PASSWORD2);
+ Disable(hWnd, IDOK);
+ Disable(hWnd, IDCANCEL);
+
+ ret = ChangePassword(cm->Cedar, p->ClientOption, p->HubName, username, old_pass, new_pass);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_PASSWORD_CHANGED"));
+ EndDialog(hWnd, true);
+ }
+ else
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _E(ret));
+ Enable(hWnd, E_USERNAME);
+ Enable(hWnd, E_OLD_PASSWORD);
+ Enable(hWnd, E_NEW_PASSWORD1);
+ Enable(hWnd, E_NEW_PASSWORD2);
+ Enable(hWnd, IDOK);
+ Enable(hWnd, IDCANCEL);
+
+ SetTextA(hWnd, E_OLD_PASSWORD, "");
+ SetTextA(hWnd, E_NEW_PASSWORD1, "");
+ SetTextA(hWnd, E_NEW_PASSWORD2, "");
+
+ Focus(hWnd, E_OLD_PASSWORD);
+ }
+
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ }
+
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Show the password changing dialog
+void CmChangePassword(HWND hWnd, CLIENT_OPTION *o, char *hubname, char *username)
+{
+ CM_CHANGE_PASSWORD p;
+ // Validate arguments
+ if (hWnd == NULL || o == NULL || hubname == NULL || username == NULL)
+ {
+ return;
+ }
+
+ Zero(&p, sizeof(p));
+ StrCpy(p.Username, sizeof(p.Username), username);
+ StrCpy(p.HubName, sizeof(p.HubName), hubname);
+ p.ClientOption = o;
+
+ CmVoice("password");
+
+ Dialog(hWnd, D_CM_CHANGE_PASSWORD, CmChangePasswordProc, &p);
+}
+
+// Prohibit the installation of the virtual LAN card
+bool CmStopInstallVLan(HWND hWnd)
+{
+ if (cm->Client->Unix)
+ {
+ // There is no need to be prohibited if the client is an UNIX
+ return true;
+ }
+ if (cm->Client->Win9x)
+ {
+ // There is no need to prohibit if the client is a Win9x
+ return true;
+ }
+
+ return true;
+
+ if (MsIsTerminalServiceInstalled() || MsIsUserSwitchingInstalled())
+ {
+ if (MsGetCurrentTerminalSessionId() == 0)
+ {
+ // There is no need to prohibit
+ return true;
+ }
+ else
+ {
+ // Prohibit to install the device drivers since
+ // the user logged in other than the console session
+ wchar_t *user = MsGetSessionUserName(0);
+
+ if (user == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("CM_STOP_INST_VLAN_2"),
+ MsIsTerminalServiceInstalled() ? _UU("CM_DESKTOP_MSG_LOCAL_TS") : _UU("CM_DESKTOP_MSG_LOCAL_SW"),
+ MsGetCurrentTerminalSessionId());
+ }
+ else
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("CM_STOP_INST_VLAN_1"),
+ MsIsTerminalServiceInstalled() ? _UU("CM_DESKTOP_MSG_LOCAL_TS") : _UU("CM_DESKTOP_MSG_LOCAL_SW"),
+ MsGetCurrentTerminalSessionId(), 0, user);
+ }
+
+ if (user != NULL)
+ {
+ Free(user);
+ }
+ return false;
+ }
+ }
+ else
+ {
+ // There is no need to prohibit
+ return true;
+ }
+}
+
+// Desktop difference warning message dialog initialization
+void CmDesktopDlgInit(HWND hWnd, wchar_t *account_name)
+{
+ wchar_t tmp[2048];
+ bool remote = false;
+ bool user_switching = false;
+ bool console_active = false;
+ wchar_t *console_user = NULL;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ FormatText(hWnd, 0, account_name);
+ FormatText(hWnd, S_TITLE, account_name);
+ DlgFont(hWnd, S_TITLE, 11, true);
+ DlgFont(hWnd, S_INFO, 11, true);
+ if (cm->server_name == NULL)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_DESKTOP_LOCAL_PC"));
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_REMOTE_PC"), cm->server_name);
+ }
+ FormatText(hWnd, S_WARNING, tmp);
+
+ if (cm->server_name != NULL)
+ {
+ remote = true;
+ }
+ else
+ {
+ if (MsIsTerminalServiceInstalled())
+ {
+ user_switching = false;
+ }
+ else
+ {
+ user_switching = true;
+ }
+
+ console_user = MsGetSessionUserName(0);
+
+ if (console_user == NULL)
+ {
+ console_active = false;
+ }
+ else
+ {
+ console_active = true;
+ }
+ }
+
+ // MSG1
+ if (remote == false)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_LOCAL_1"),
+ user_switching ? _UU("CM_DESKTOP_MSG_LOCAL_SW") : _UU("CM_DESKTOP_MSG_LOCAL_TS"));
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_REMOTE_1"),
+ cm->server_name);
+ }
+ SetText(hWnd, S_MSG_1, tmp);
+
+ // MSG2
+ if (remote == false)
+ {
+ if (console_active)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_LOCAL_21"),
+ console_user, MsGetCurrentTerminalSessionId());
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_LOCAL_22"),
+ MsGetCurrentTerminalSessionId());
+ }
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_REMOTE_2"), cm->server_name);
+ }
+ SetText(hWnd, S_MSG_2, tmp);
+
+ // MSG3
+ if (remote == false)
+ {
+ if (console_active)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_LOCAL_31"),
+ console_user, account_name);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_LOCAL_32"),
+ account_name);
+ }
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_DESKTOP_MSG_REMOTE_3"), cm->server_name,
+ account_name);
+ }
+ SetText(hWnd, S_MSG_3, tmp);
+
+ if (console_user != NULL)
+ {
+ Free(console_user);
+ }
+}
+
+// Desktop difference warning message dialog
+UINT CmDesktopDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ wchar_t *account_name = (wchar_t *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmDesktopDlgInit(hWnd, account_name);
+ break;
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ EndDialog(hWnd, true);
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Show a warning message that the desktop is different, if necessary
+bool CmWarningDesktop(HWND hWnd, wchar_t *account_name)
+{
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return false;
+ }
+
+ if (cm->Client->Unix)
+ {
+ //There is no need for warning if the client is an UNIX
+ return true;
+ }
+
+ if (/*MsIsTerminalServiceInstalled() || MsIsUserSwitchingInstalled() ||*/ (cm->server_name != NULL))
+ {
+ if (cm->server_name == NULL)
+ {
+ //if (MsGetCurrentTerminalSessionId() == 0)
+ {
+ // No need for warning
+ return true;
+ }
+ }
+ // There is a need for warning
+ return Dialog(hWnd, D_CM_DESKTOP, CmDesktopDlgProc, account_name);
+ }
+ else
+ {
+ // No need for warning
+ return true;
+ }
+}
+
+// Update the password setting dialog
+void CmPasswordRefresh(HWND hWnd)
+{
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SetEnable(hWnd, E_PASSWORD, IsChecked(hWnd, R_USE_PASSWORD));
+ SetEnable(hWnd, E_PASSWORD2, IsChecked(hWnd, R_USE_PASSWORD));
+ SetEnable(hWnd, IDC_STATIC1, IsChecked(hWnd, R_USE_PASSWORD));
+ SetEnable(hWnd, IDC_STATIC2, IsChecked(hWnd, R_USE_PASSWORD));
+ SetEnable(hWnd, R_REMOTE_ONLY, IsChecked(hWnd, R_USE_PASSWORD));
+
+ if (IsChecked(hWnd, R_USE_PASSWORD))
+ {
+ char tmp1[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ if (IsEmpty(hWnd, E_PASSWORD))
+ {
+ ok = false;
+ }
+ GetTxtA(hWnd, E_PASSWORD, tmp1, sizeof(tmp1));
+ GetTxtA(hWnd, E_PASSWORD2, tmp2, sizeof(tmp2));
+ if (StrCmp(tmp1, tmp2) != 0)
+ {
+ ok = false;
+ }
+ if (StrCmp(tmp1, HIDDEN_PASSWORD) == 0)
+ {
+ ok = false;
+ }
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Password setting procedure
+UINT CmPasswordProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ RPC_CLIENT_PASSWORD_SETTING c;
+ RPC_CLIENT_PASSWORD p;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Get the password setting
+ if (CALL(hWnd, CcGetPasswordSetting(cm->Client, &c)))
+ {
+ Check(hWnd, R_USE_PASSWORD, c.IsPasswordPresented);
+ if (c.IsPasswordPresented)
+ {
+ SetTextA(hWnd, E_PASSWORD, HIDDEN_PASSWORD);
+ SetTextA(hWnd, E_PASSWORD2, HIDDEN_PASSWORD);
+ FocusEx(hWnd, E_PASSWORD);
+ Check(hWnd, R_REMOTE_ONLY, c.PasswordRemoteOnly);
+ }
+ else
+ {
+ Focus(hWnd, R_USE_PASSWORD);
+ }
+ }
+ CmPasswordRefresh(hWnd);
+ break;
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case R_USE_PASSWORD:
+ if (IsChecked(hWnd, R_USE_PASSWORD))
+ {
+ FocusEx(hWnd, E_PASSWORD);
+ }
+ break;
+ case IDOK:
+ GetTxtA(hWnd, E_PASSWORD, tmp, sizeof(tmp));
+ Zero(&p, sizeof(p));
+ if (IsChecked(hWnd, R_USE_PASSWORD))
+ {
+ StrCpy(p.Password, sizeof(p.Password), tmp);
+ p.PasswordRemoteOnly = IsChecked(hWnd, R_REMOTE_ONLY);
+ }
+
+ if (CALL(hWnd, CcSetPassword(cm->Client, &p)))
+ {
+ if (StrLen(p.Password) > 0)
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_PASSWORD_SET"));
+ }
+ else
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_PASSWORD_REMOVE"));
+ }
+ EndDialog(hWnd, true);
+ }
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ switch (LOWORD(wParam))
+ {
+ case R_USE_PASSWORD:
+ case R_REMOTE_ONLY:
+ case E_PASSWORD:
+ case E_PASSWORD2:
+ CmPasswordRefresh(hWnd);
+ break;
+ }
+ switch (wParam)
+ {
+ case R_REMOTE_ONLY:
+ case R_USE_PASSWORD:
+ if (IsChecked(hWnd, R_USE_PASSWORD))
+ {
+ FocusEx(hWnd, E_PASSWORD);
+ }
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Set the password
+void CmPassword(HWND hWnd)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_CM_PASSWORD, CmPasswordProc, NULL);
+}
+
+// CA dialog update
+void CmTrustDlgUpdate(HWND hWnd)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SetEnable(hWnd, B_EXPORT, LvIsSelected(hWnd, L_CERT));
+ SetEnable(hWnd, B_DELETE, LvIsSelected(hWnd, L_CERT) && cm->CmSetting.LockMode == false);
+ SetEnable(hWnd, IDOK, LvIsSelected(hWnd, L_CERT));
+ SetEnable(hWnd, B_IMPORT, cm->CmSetting.LockMode == false);
+}
+
+// Update the list of certificates
+void CmTrustDlgRefresh(HWND hWnd)
+{
+ RPC_CLIENT_ENUM_CA c;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (CALL(hWnd, CcEnumCa(cm->Client, &c)))
+ {
+ UINT i;
+ LVB *b = LvInsertStart();
+ for (i = 0;i < c.NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_CA_ITEM *cert = c.Items[i];
+ wchar_t tmp[MAX_SIZE];
+
+ GetDateStrEx64(tmp, sizeof(tmp), SystemToLocal64(cert->Expires), NULL);
+ LvInsertAdd(b, ICO_CERT, (void *)cert->Key, 3,
+ cert->SubjectName, cert->IssuerName, tmp);
+ }
+ LvInsertEnd(b, hWnd, L_CERT);
+ CiFreeClientEnumCa(&c);
+ }
+
+ CmTrustDlgUpdate(hWnd);
+}
+
+// Import
+void CmTrustImport(HWND hWnd)
+{
+ X *x;
+ RPC_CERT c;
+ if (CmLoadXFromFileOrSecureCard(hWnd, &x) == false)
+ {
+ return;
+ }
+
+ Zero(&c, sizeof(c));
+ c.x = x;
+
+ CALL(hWnd, CcAddCa(cm->Client, &c));
+ CmVoice("new_cert");
+
+ FreeX(c.x);
+ CmTrustDlgRefresh(hWnd);
+}
+
+// Export
+void CmTrustExport(HWND hWnd)
+{
+ UINT key;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ key = (UINT)LvGetParam(hWnd, L_CERT, LvGetSelected(hWnd, L_CERT));
+ if (key != INFINITE)
+ {
+ RPC_GET_CA a;
+ Zero(&a, sizeof(a));
+ a.Key = key;
+
+ if (CALL(hWnd, CcGetCa(cm->Client, &a)))
+ {
+ wchar_t *name;
+ X *x = CloneX(a.x);
+ CiFreeGetCa(&a);
+
+ // Save
+ name = SaveDlg(hWnd, _UU("DLG_CERT_FILES"), _UU("DLG_SAVE_CERT"), NULL, L".cer");
+ if (name != NULL)
+ {
+ wchar_t str[MAX_SIZE];
+ UniStrCpy(str, sizeof(str), name);
+ if (XToFileW(x, str, true))
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("DLG_CERT_SAVE_OK"));
+ }
+ else
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("DLG_CERT_SAVE_ERROR"));
+ }
+ Free(name);
+ }
+ FreeX(x);
+ }
+ }
+}
+
+// Display
+void CmTrustView(HWND hWnd)
+{
+ UINT key;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ key = (UINT)LvGetParam(hWnd, L_CERT, LvGetSelected(hWnd, L_CERT));
+ if (key != INFINITE)
+ {
+ RPC_GET_CA a;
+ Zero(&a, sizeof(a));
+ a.Key = key;
+
+ if (CALL(hWnd, CcGetCa(cm->Client, &a)))
+ {
+ X *x = CloneX(a.x);
+ X *x_issuer;
+ CiFreeGetCa(&a);
+
+ x_issuer = CmGetIssuer(x);
+ CertDlg(hWnd, x, x_issuer, true);
+ FreeX(x);
+ FreeX(x_issuer);
+ }
+ }
+}
+
+// CA dialog procedure
+UINT CmTrustDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ NMHDR *n;
+ UINT index;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ LvInit(hWnd, L_CERT);
+ LvInsertColumn(hWnd, L_CERT, 0, _UU("CM_CERT_COLUMN_1"), 190);
+ LvInsertColumn(hWnd, L_CERT, 1, _UU("CM_CERT_COLUMN_2"), 190);
+ LvInsertColumn(hWnd, L_CERT, 2, _UU("CM_CERT_COLUMN_3"), 160);
+ CmTrustDlgRefresh(hWnd);
+ break;
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_IMPORT:
+ CmTrustImport(hWnd);
+ break;
+ case B_EXPORT:
+ CmTrustExport(hWnd);
+ break;
+ case B_DELETE:
+ index = LvGetSelected(hWnd, L_CERT);
+ if (index != INFINITE)
+ {
+ UINT key = (UINT)LvGetParam(hWnd, L_CERT, index);
+ if (key != INFINITE)
+ {
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_CERT_DELETE_MSG")) == IDYES)
+ {
+ RPC_CLIENT_DELETE_CA c;
+ Zero(&c, sizeof(c));
+ c.Key = key;
+ if (CALL(hWnd, CcDeleteCa(cm->Client, &c)))
+ {
+ CmTrustDlgRefresh(hWnd);
+ }
+ }
+ }
+ }
+ break;
+ case IDOK:
+ if (IsEnable(hWnd, IDOK))
+ {
+ CmTrustView(hWnd);
+ }
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_CERT:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ CmTrustDlgUpdate(hWnd);
+ break;
+ case NM_DBLCLK:
+ Command(hWnd, IDOK);
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ LvSortHander(hWnd, msg, wParam, lParam, L_CERT);
+
+ return 0;
+}
+
+// Show the CA dialog
+void CmTrustDlg(HWND hWnd)
+{
+ Dialog(hWnd, D_CM_TRUST, CmTrustDlgProc, NULL);
+}
+
+// Main window procedure
+UINT CmMainWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ NMHDR *n;
+ static UINT taskbar_msg = 0;
+ COPYDATASTRUCT *cpy;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ if (taskbar_msg != 0 && msg == taskbar_msg)
+ {
+ // The task-bar is regenerated
+ if (cm->TrayInited)
+ {
+ MsRestoreIconOnTray();
+ }
+ }
+
+ // CmSetForegroundProcessToCnService();
+
+ switch (msg)
+ {
+ case WM_CM_SETTING_CHANGED_MESSAGE:
+ // CM_SETTING has changed
+ CmApplyCmSetting();
+ break;
+ case WM_INITDIALOG:
+ CmMainWindowOnInit(hWnd);
+ taskbar_msg = RegisterWindowMessage("TaskbarCreated");
+ CmEndStartupMutex();
+ break;
+ case WM_CM_SHOW:
+ // Received a display request from another process
+ if (cm->CmSetting.EasyMode == false)
+ {
+ ShowWindow(hWnd, SW_SHOWNORMAL);
+ }
+ else
+ {
+ if (cm->hEasyWnd == NULL)
+ {
+ CmShowEasy();
+ }
+ else
+ {
+ SetForegroundWindow(cm->hEasyWnd);
+ SetActiveWindow(cm->hEasyWnd);
+ }
+ }
+ break;
+ case WM_COMMAND:
+ CmMainWindowOnCommand(hWnd, wParam, lParam);
+ break;
+ case WM_SIZE:
+ CmMainWindowOnSize(hWnd);
+ break;
+ case WM_CLOSE:
+ if (cm->CmSetting.EasyMode == false)
+ {
+ CmShowOrHideWindow(hWnd);
+ }
+ else
+ {
+ if (cm->hEasyWnd == NULL)
+ {
+ CmShowEasy();
+ }
+ else
+ {
+ SetForegroundWindow(cm->hEasyWnd);
+ SetActiveWindow(cm->hEasyWnd);
+ }
+ }
+ return 1;
+ case WM_INITMENUPOPUP:
+ if (HIWORD(lParam) == false)
+ {
+ CmMainWindowOnPopupMenu(hWnd, (HMENU)wParam, LOWORD(lParam));
+ }
+ break;
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ if (n->idFrom == L_ACCOUNT && (n->code == LVN_BEGINLABELEDITW || n->code == LVN_BEGINLABELEDITA))
+ {
+ wchar_t *tmp = LvGetSelectedStr(hWnd, L_ACCOUNT, 0);
+ if (tmp != NULL)
+ {
+ if (UniStrCmpi(tmp, _UU("CM_NEW_ICON")) == 0 || UniStrCmpi(tmp, _UU("CM_VGC_ICON")) == 0 || UniStrCmpi(tmp, _UU("CM_VGC_LINK")) == 0
+ )
+ {
+ SendMsg(hWnd, L_ACCOUNT, LVM_CANCELEDITLABEL, 0, 0);
+ Free(tmp);
+ return true;
+ }
+ Free(tmp);
+ }
+ }
+ CmMainWindowOnNotify(hWnd, (NMHDR *)lParam);
+ break;
+ case WM_CM_NOTIFY:
+ CmRefreshVLanList(hWnd);
+ CmRefreshAccountList(hWnd);
+ CmRefreshStatusBar(hWnd);
+ break;
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ CmSetForegroundProcessToCnService();
+ break;
+ case 2:
+ CmPollingTray(hWnd);
+ break;
+ case 3:
+ KillTimer(hWnd, 3);
+ Hide(hWnd, 0);
+ break;
+ case 4:
+ KillTimer(hWnd, 4);
+ CmMainWindowOnShowEasy(hWnd);
+ break;
+ case 6:
+ if (cm->Update == NULL)
+ {
+ if (cm->server_name == NULL)
+ {
+ if (CmGetNumConnected(hWnd) == 0)
+ {
+ cm->Update = InitUpdateUi(_UU("PRODUCT_NAME_VPN_CMGR"), NAME_OF_VPN_CLIENT_MANAGER, NULL,
+ GetCurrentBuildDate(), CEDAR_BUILD, CEDAR_VER, ((cm->Client == NULL) ? NULL : cm->Client->ClientId));
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case WM_CM_TRAY_MESSAGE:
+ // Message from the icon in the task tray
+ CmMainWindowOnTrayClicked(hWnd, wParam, lParam);
+ break;
+ case WM_COPYDATA:
+ cpy = (COPYDATASTRUCT *)lParam;
+ if (cpy != NULL)
+ {
+ if (cpy->dwData == CM_IMPORT_FILENAME_MSG || cpy->dwData == CM_IMPORT_FILENAME_MSG_OVERWRITE)
+ {
+ char *filename = (char *)cpy->lpData;
+
+ if (cm->CmSetting.LockMode == false || cpy->dwData == CM_IMPORT_FILENAME_MSG_OVERWRITE)
+ {
+ wchar_t fullpath[MAX_PATH];
+
+ if (StrLen(filename) >= 2 && IsFileExists(filename))
+ {
+ StrToUni(fullpath, sizeof(fullpath), filename);
+ }
+ else
+ {
+ UniStrCpy(fullpath, sizeof(fullpath), (wchar_t *)filename);
+ }
+
+ CmImportAccountMainEx(cm->hEasyWnd ? cm->hEasyWnd : hWnd, fullpath, cpy->dwData == CM_IMPORT_FILENAME_MSG_OVERWRITE);
+ }
+ else
+ {
+ MsgBox(cm->hEasyWnd ? cm->hEasyWnd : hWnd, MB_ICONEXCLAMATION | MB_SETFOREGROUND | MB_TOPMOST, _UU("CM_VPN_FILE_IMPORT_NG"));
+ }
+ }
+ }
+ break;
+ case WM_QUERYENDSESSION:
+ // Windows is about to terminate
+ cm->WindowsShutdowning = true;
+ CmSaveMainWindowPos(hWnd);
+ SleepThread(256);
+ break;
+ case WM_ENDSESSION:
+ // Windows has terminated
+ _exit(0);
+ break;
+ }
+
+ LvSortHander(hWnd, msg, wParam, lParam, L_ACCOUNT);
+ LvSortHander(hWnd, msg, wParam, lParam, L_VLAN);
+
+ return 0;
+}
+
+// Specify the notification service to the foreground process
+void CmSetForegroundProcessToCnService()
+{
+ if (cm->MenuPopuping)
+ {
+ return;
+ }
+ if (cm->server_name == NULL)
+ {
+ if (CnCheckAlreadyExists(false))
+ {
+ AllowFGWindow(MsRegReadInt(REG_CURRENT_USER,
+ CM_REG_KEY, "NotifyServerProcessId"));
+ }
+ }
+}
+
+// Show the [recent destination] sub-menu
+HMENU CmCreateRecentSubMenu(HWND hWnd, UINT start_id)
+{
+ HMENU h = NULL;
+ UINT i;
+ RPC_CLIENT_ENUM_ACCOUNT a;
+ LIST *o;
+ bool easy;
+
+ easy = cm->CmSetting.EasyMode;
+
+ Zero(&a, sizeof(a));
+
+ if (CcEnumAccount(cm->Client, &a) == ERR_NO_ERROR)
+ {
+ o = NewListFast(CiCompareClientAccountEnumItemByLastConnectDateTime);
+
+ for (i = 0;i < a.NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = a.Items[i];
+
+ item->tmp1 = i;
+
+ if (item->LastConnectDateTime != 0)
+ {
+ Add(o, item);
+ }
+ }
+
+ Sort(o);
+
+ for (i = 0;i < MIN(LIST_NUM(o), CM_NUM_RECENT);i++)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = (RPC_CLIENT_ENUM_ACCOUNT_ITEM *)LIST_DATA(o, i);
+ wchar_t tmp[MAX_PATH];
+ wchar_t *account_name;
+ char *server_name;
+ char *hub_name;
+ UINT pos;
+
+ if (h == NULL)
+ {
+ h = CreatePopupMenu();
+ }
+
+ account_name = item->AccountName;
+ server_name = item->ServerName;
+ hub_name = item->HubName;
+
+ UniStrCpy(tmp, sizeof(tmp), account_name);
+
+ pos = LvSearchStr(hWnd, L_ACCOUNT, 0, account_name);
+ if (pos != INFINITE)
+ {
+ MsAppendMenu(h, MF_STRING, start_id + pos, tmp);
+ }
+ }
+
+ ReleaseList(o);
+
+ CiFreeClientEnumAccount(&a);
+ }
+
+ return h;
+}
+
+// Show the sub-menu of the right-click menu in the task tray
+HMENU CmCreateTraySubMenu(HWND hWnd, bool flag, UINT start_id)
+{
+ HMENU h = NULL;
+ UINT i, num;
+ bool easy;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return NULL;
+ }
+
+ easy = cm->CmSetting.EasyMode;
+
+ num = LvNum(hWnd, L_ACCOUNT);
+
+ for (i = 0;i < num;i++)
+ {
+ wchar_t *status_str = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+
+ if (status_str != NULL)
+ {
+ bool b = false;
+ bool is_account = false;
+
+ if (UniStrCmpi(status_str, _UU("CM_ACCOUNT_OFFLINE")) == 0)
+ {
+ if (flag == false)
+ {
+ b = true;
+ }
+
+ is_account = true;
+ }
+
+ if (UniStrCmpi(status_str, _UU("CM_ACCOUNT_ONLINE")) == 0 ||
+ UniStrCmpi(status_str, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+ {
+ if (flag == true)
+ {
+ b = true;
+ }
+
+ is_account = true;
+ }
+
+ if (b)
+ {
+ wchar_t tmp[MAX_PATH];
+ wchar_t *account_name, *server_name;
+ wchar_t *hub_name;
+ if (h == NULL)
+ {
+ h = CreatePopupMenu();
+ }
+
+ account_name = LvGetStr(hWnd, L_ACCOUNT, i, 0);
+ server_name = LvGetStr(hWnd, L_ACCOUNT, i, 2);
+ hub_name = LvGetStr(hWnd, L_ACCOUNT, i, 3);
+
+ if (easy == false)
+ {
+ UniFormat(tmp, sizeof(tmp), L"%s\t- %s [%s]", account_name, server_name, hub_name);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), account_name);
+ }
+
+ MsAppendMenu(h, MF_STRING, start_id + i, tmp);
+
+ Free(account_name);
+ Free(server_name);
+ Free(hub_name);
+ }
+
+ Free(status_str);
+ }
+ }
+
+ return h;
+}
+
+// Display the right-click menu of the task tray
+void CmShowTrayMenu(HWND hWnd)
+{
+ HMENU h;
+ POINT p;
+ HMENU sub1, sub2, sub3, sub4;
+ bool locked;
+ bool easy;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ cm->MenuPopuping = true;
+
+ locked = cm->CmSetting.LockMode;
+ easy = cm->CmSetting.EasyMode;
+
+ // Create a menu
+ h = CreatePopupMenu();
+
+ // Cancel
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, 100007, _UU("CM_TRAY_MENU_CANCEL"));
+
+ // Separator
+ MsAppendMenu(h, MF_SEPARATOR, 10006, NULL);
+
+ if (locked == false && easy == false)
+ {
+ // Creating a new connection settings
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_NEW, _UU("CM_TRAY_MENU_NEW"));
+
+ // Separator
+ MsAppendMenu(h, MF_SEPARATOR, 10005, NULL);
+ }
+
+ // Connection menu
+ sub1 = CmCreateTraySubMenu(hWnd, false, CM_TRAY_MENU_CONNECT_ID_START);
+ if (sub1 != NULL)
+ {
+ MsAppendMenu(h, MF_BYPOSITION | MF_ENABLED | MF_POPUP | MF_STRING,
+ (UINT_PTR)sub1, _UU("CM_TRAY_MENU_CONNECT"));
+ }
+
+ // Disconnection menu
+ sub2 = CmCreateTraySubMenu(hWnd, true, CM_TRAY_MENU_DISCONNECT_ID_START);
+ if (sub2 != NULL)
+ {
+ MsAppendMenu(h, MF_BYPOSITION | MF_ENABLED | MF_POPUP | MF_STRING,
+ (UINT_PTR)sub2, _UU("CM_TRAY_MENU_DISCONNECT"));
+ }
+
+ // Status Display menu
+ sub3 = CmCreateTraySubMenu(hWnd, true, CM_TRAY_MENU_STATUS_ID_START);
+ if (sub3 != NULL)
+ {
+ MsAppendMenu(h, MF_BYPOSITION | MF_ENABLED | MF_POPUP | MF_STRING,
+ (UINT_PTR)sub3, _UU("CM_TRAY_MENU_STATUS"));
+ }
+
+ if (sub3 != NULL)
+ {
+ // Disconnect all connections
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_DISCONNECT_ALL, _UU("CM_TRAY_MENU_DISCONNECT_ALL"));
+ }
+
+ if (sub1 != NULL || sub2 != NULL || sub3 != NULL)
+ {
+ // Separator
+ MsAppendMenu(h, MF_SEPARATOR, 10003, NULL);
+ }
+
+ // Connect to the recently connected VPN server
+ sub4 = CmCreateRecentSubMenu(hWnd, CM_TRAY_MENU_RECENT_ID_START);
+ if (sub4 != NULL)
+ {
+ MsAppendMenu(h, MF_BYPOSITION | MF_ENABLED | MF_POPUP | MF_STRING,
+ (UINT_PTR)sub4, _UU("CM_TRAY_MENU_RECENT"));
+ MsAppendMenu(h, MF_SEPARATOR, 10008, NULL);
+ }
+
+ if (locked == false && easy == false)
+ {
+ // Communication throughput measurement
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_TRAFFIC, _UU("CM_TRAY_MENU_TRAFFIC"));
+ }
+
+ if (easy == false)
+ {
+ // Network device status
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_NETIF, _UU("CM_TRAY_MENU_NETIF"));
+ }
+
+ // Version information
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_ABOUT, _UU("CM_TRAY_MENU_ABOUT"));
+
+ // Separator
+ MsAppendMenu(h, MF_SEPARATOR, 10001, NULL);
+
+ // Change the operating mode
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_CM_SETTING, _UU("CM_TRAY_MENU_SETTING"));
+
+ // Separator
+ MsAppendMenu(h, MF_SEPARATOR, 10001, NULL);
+
+ // Hide the icon
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_TRAYICON, _UU("CM_MENU@CMD_TRAYICON"));
+
+ // Separator
+ MsAppendMenu(h, MF_SEPARATOR, 10001, NULL);
+
+ // Show or hide
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_EXIT,
+ IsHide(hWnd, 0) ? _UU("CM_TRAY_MENU_1_SHOW") : _UU("CM_TRAY_MENU_1_HIDE"));
+
+ // Quit
+ MsAppendMenu(h, MF_ENABLED | MF_STRING, CMD_QUIT, _UU("CM_TRAY_MENU_2_QUIT"));
+
+ // Show the menu
+ GetCursorPos(&p);
+
+ SetForegroundWindow(hWnd);
+ TrackPopupMenu(h, TPM_LEFTALIGN, p.x, p.y, 0, hWnd, NULL);
+ PostMessage(hWnd, WM_NULL, 0, 0);
+
+ if (sub1 != NULL)
+ {
+ DestroyMenu(sub1);
+ }
+
+ if (sub2 != NULL)
+ {
+ DestroyMenu(sub2);
+ }
+
+ if (sub3 != NULL)
+ {
+ DestroyMenu(sub3);
+ }
+
+ DestroyMenu(h);
+
+ cm->MenuPopuping = false;
+}
+
+// Hide or show the main window
+void CmShowOrHideWindow(HWND hWnd)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (IsHide(hWnd, 0))
+ {
+ Show(hWnd, 0);
+ if (IsIconic(hWnd))
+ {
+ ShowWindow(hWnd, SW_SHOWNORMAL);
+ }
+ SetForegroundWindow(hWnd);
+ SetActiveWindow(hWnd);
+ }
+ else
+ {
+ CmSaveMainWindowPos(hWnd);
+ Hide(hWnd, 0);
+
+ if (cm->TrayInited == false)
+ {
+ Command(hWnd, CMD_QUIT);
+ return;
+ }
+ }
+}
+
+// Right-clicked on the account list
+void CmAccountListRightClick(HWND hWnd)
+{
+ HMENU h;
+ HMENU parent;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Load the menu
+ h = LoadSubMenu(M_MAIN, 0, &parent);
+ if (h == NULL)
+ {
+ return;
+ }
+
+ InitMenuInternational(h, "CM_MENU");
+
+ // Remove the shortcut key
+ RemoveShortcutKeyStrFromMenu(h);
+
+ // Delete the exit menu
+ i = GetMenuItemPos(h, CMD_QUIT);
+ if (i != INFINITE)
+ {
+ DeleteMenuItem(h, i);
+ DeleteMenuItem(h, i - 1);
+ DeleteMenuItem(h, i - 2);
+ DeleteMenuItem(h, i - 3);
+ }
+
+ // Set enable / disable
+ CmMainWindowOnPopupMenu(hWnd, h, INFINITE);
+
+ if (h != NULL)
+ {
+ // Determine whether the selected account is under connecting
+ UINT i = LvGetSelected(hWnd, L_ACCOUNT);
+ wchar_t *str;
+ bool is_connected = false;
+ if (i != INFINITE)
+ {
+ str = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+ if (str != NULL)
+ {
+ if (UniStrCmpi(str, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(str, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+ {
+ // Connecting
+ is_connected = true;
+ }
+ Free(str);
+ }
+ }
+
+ if (i == INFINITE)
+ {
+ // Bold the New menu
+ SetMenuItemBold(h, GetMenuItemPos(h, CMD_NEW), true);
+ }
+ else
+ {
+ if (is_connected == false)
+ {
+ // Bold the connection menu
+ SetMenuItemBold(h, GetMenuItemPos(h, CMD_CONNECT), true);
+ }
+ else
+ {
+ // Bold the status menu
+ SetMenuItemBold(h, GetMenuItemPos(h, CMD_STATUS), true);
+ }
+ }
+ }
+
+ // Show the menu
+ PrintMenu(hWnd, h);
+
+ DestroyMenu(parent);
+}
+
+// Right-clicked on the virtual LAN card list
+void CmVLanListRightClick(HWND hWnd)
+{
+ HMENU h;
+ HMENU parent;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Load the menu
+ h = LoadSubMenu(M_MAIN, 3, &parent);
+ if (h == NULL)
+ {
+ return;
+ }
+
+ InitMenuInternational(h, "CM_MENU");
+
+ // Remove the shortcut key
+ RemoveShortcutKeyStrFromMenu(h);
+
+ // Set enable / disable
+ CmMainWindowOnPopupMenu(hWnd, h, INFINITE);
+
+ if (h != NULL)
+ {
+ // Examine whether the selected device is enabled
+ UINT i = LvGetSelected(hWnd, L_VLAN);
+ wchar_t *str;
+ bool is_active = false;
+ if (i != INFINITE)
+ {
+ str = LvGetStr(hWnd, L_VLAN, i, 1);
+ if (str != NULL)
+ {
+ if (UniStrCmpi(str, _UU("CM_VLAN_ENABLED")) == 0)
+ {
+ // Enabled
+ is_active = true;
+ }
+ Free(str);
+ }
+ }
+
+ if (i == INFINITE)
+ {
+ // Bold the New menu
+ SetMenuItemBold(h, GetMenuItemPos(h, CMD_NEW_VLAN), true);
+ }
+ else
+ {
+ if (is_active == false)
+ {
+ // Bold the enable menu
+ SetMenuItemBold(h, GetMenuItemPos(h, CMD_ENABLE_VLAN), true);
+ }
+ else
+ {
+ // Bold the Windows Network Setup menu
+ SetMenuItemBold(h, GetMenuItemPos(h, CMD_WINNET), true);
+ }
+ }
+ }
+
+ // Show the menu
+ PrintMenu(hWnd, h);
+
+ DestroyMenu(parent);
+}
+
+// Notify to the main window
+void CmMainWindowOnNotify(HWND hWnd, NMHDR *n)
+{
+ bool item_vlan;
+ NMLVDISPINFOW *disp_info;
+ NMLVKEYDOWN *key;
+
+ // Validate arguments
+ if (hWnd == NULL || n == NULL)
+ {
+ return;
+ }
+
+ switch (n->idFrom)
+ {
+ case L_ACCOUNT:
+ case L_VLAN:
+ if (n->idFrom == L_ACCOUNT)
+ {
+ item_vlan = false;
+ }
+ else
+ {
+ item_vlan = true;
+ }
+
+ switch (n->code)
+ {
+ case NM_DBLCLK:
+ // Double click
+ CmOnKey(hWnd, false, false, VK_RETURN);
+ break;
+ case NM_RCLICK:
+ // Right click
+ if (item_vlan == false)
+ {
+ CmAccountListRightClick(hWnd);
+ }
+ else
+ {
+ CmVLanListRightClick(hWnd);
+ }
+ break;
+ case LVN_ENDLABELEDITW:
+ // Change the name
+ disp_info = (NMLVDISPINFOW *)n;
+ if (disp_info->item.pszText != NULL)
+ {
+ wchar_t *new_name = disp_info->item.pszText;
+ wchar_t *old_name = LvGetStr(hWnd, L_ACCOUNT, disp_info->item.iItem, 0);
+
+ if (old_name != NULL)
+ {
+ if (UniStrCmp(new_name, old_name) != 0 && UniIsEmptyStr(new_name) == false)
+ {
+ RPC_RENAME_ACCOUNT a;
+ Zero(&a, sizeof(a));
+ UniStrCpy(a.OldName, sizeof(a.OldName), old_name);
+ UniStrCpy(a.NewName, sizeof(a.NewName), new_name);
+ if (CALL(hWnd, CcRenameAccount(cm->Client, &a)))
+ {
+ LvSetItem(hWnd, L_ACCOUNT, disp_info->item.iItem, 0, new_name);
+ }
+ }
+
+ Free(old_name);
+ }
+ }
+ break;
+ case LVN_KEYDOWN:
+ // Key pressed
+ key = (NMLVKEYDOWN *)n;
+ if (key != NULL)
+ {
+ bool ctrl, alt;
+ UINT code = key->wVKey;
+ ctrl = (GetKeyState(VK_CONTROL) & 0x8000) == 0 ? false : true;
+ alt = (GetKeyState(VK_MENU) & 0x8000) == 0 ? false : true;
+ CmOnKey(hWnd, ctrl, alt, code);
+ }
+ break;
+ }
+ break;
+ }
+}
+
+// Keyboard pressed
+void CmOnKey(HWND hWnd, bool ctrl, bool alt, UINT key)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Single key
+ switch (key)
+ {
+ case VK_RETURN:
+ Command(hWnd, IDOK);
+ break;
+ case VK_DELETE:
+ // Delete
+ if (IsFocus(hWnd, L_ACCOUNT))
+ {
+ // Operation on the account list
+ Command(hWnd, CMD_DELETE);
+ }
+ else
+ {
+ // Operation on the virtual LAN card list
+ Command(hWnd, CMD_DELETE_VLAN);
+ }
+ break;
+ case VK_F2:
+ // Change the name
+ Command(hWnd, CMD_RENAME);
+ break;
+ case VK_F5:
+ // Update the status
+ Command(hWnd, CMD_REFRESH);
+ break;
+ }
+
+ if (alt)
+ {
+ switch (key)
+ {
+ case 'Q':
+ // Close
+ Command(hWnd, CMD_QUIT);
+ break;
+ }
+ }
+
+ if (ctrl)
+ {
+ switch (key)
+ {
+ case 'G':
+ // Smart Card Manager
+ Command(hWnd, CMD_SECURE_MANAGER);
+ break;
+ case 'S':
+ // Show the state
+ Command(hWnd, CMD_STATUS);
+ break;
+ case 'I':
+ // Disconnect all connections
+ Command(hWnd, CMD_DISCONNECT_ALL);
+ break;
+ case 'D':
+ // Disconnect
+ Command(hWnd, CMD_DISCONNECT);
+ break;
+ case 'N':
+ // Create a new connection settings
+ Command(hWnd, CMD_NEW);
+ break;
+ case 'C':
+ // Creating a copy
+ Command(hWnd, CMD_CLONE);
+ break;
+ case 'T':
+ // Set to start-up connection
+ Command(hWnd, CMD_STARTUP);
+ break;
+ case 'A':
+ // Select all
+ Command(hWnd, CMD_SELECT_ALL);
+ break;
+ case 'L':
+ // Create a new virtual LAN card
+ Command(hWnd, CMD_NEW_VLAN);
+ break;
+ case 'E':
+ // Enable the virtual LAN card
+ Command(hWnd, CMD_ENABLE_VLAN);
+ break;
+ case 'B':
+ // Disable the virtual LAN card
+ Command(hWnd, CMD_DISABLE_VLAN);
+ break;
+ case 'U':
+ // Reinstall the driver
+ Command(hWnd, CMD_REINSTALL);
+ break;
+ case 'W':
+ // Configure Windows network connection
+ Command(hWnd, CMD_WINNET);
+ break;
+ case 'P':
+ // Set the password
+ Command(hWnd, CMD_PASSWORD);
+ break;
+ case 'O':
+ // Option settings
+ Command(hWnd, CMD_TRAFFIC);
+ break;
+ case 'R':
+ // Certificate management
+ Command(hWnd, CMD_TRUST);
+ break;
+ case 'Q':
+ // Throughput
+ Command(hWnd, CMD_TRAFFIC);
+ break;
+ }
+ }
+}
+
+// Command of the main window
+void CmMainWindowOnCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+ CmMainWindowOnCommandEx(hWnd, wParam, lParam, false);
+}
+void CmMainWindowOnCommandEx(HWND hWnd, WPARAM wParam, LPARAM lParam, bool easy)
+{
+ wchar_t *tmp;
+ char *name;
+ UINT index;
+ UINT id;
+ bool ctrl, alt;
+ UINT flag = 0;
+ // Validate arguments
+ wchar_t *selected_name = NULL;
+ UINT starter_id = 0;
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ ctrl = (GetKeyState(VK_CONTROL) & 0x8000) == 0 ? false : true;
+ alt = (GetKeyState(VK_MENU) & 0x8000) == 0 ? false : true;
+
+ if (wParam == IDOK)
+ {
+ tmp = LvGetSelectedStr(hWnd, L_ACCOUNT, 0);
+ if (tmp != NULL)
+ {
+ if (UniStrCmpi(tmp, _UU("CM_NEW_ICON")) == 0)
+ {
+ Free(tmp);
+ Command(hWnd, CMD_NEW);
+ return;
+ }
+ if (UniStrCmpi(tmp, _UU("CM_VGC_ICON")) == 0 || UniStrCmpi(tmp, _UU("CM_VGC_LINK")) == 0)
+ {
+ Free(tmp);
+ Command(hWnd, CMD_VGC_CONNECT);
+ return;
+ }
+ Free(tmp);
+ }
+ }
+
+ if (CmIsEnabled(hWnd, (UINT)wParam) == false)
+ {
+ return;
+ }
+
+ if (CM_TRAY_IS_CONNECT_ID(wParam))
+ {
+ // Connection request
+ starter_id = CM_TRAY_MENU_CONNECT_ID_START;
+ flag = 1;
+ }
+
+ if (CM_TRAY_IS_STATUS_ID(wParam))
+ {
+ // Information display request
+ starter_id = CM_TRAY_MENU_STATUS_ID_START;
+ flag = 2;
+ }
+
+ if (CM_TRAY_IS_DISCONNECT_ID(wParam))
+ {
+ // Disconnect request
+ starter_id = CM_TRAY_MENU_DISCONNECT_ID_START;
+ flag = 3;
+ }
+
+ if (CM_TRAY_IS_RECENT_ID(wParam))
+ {
+ // Recent destinations
+ starter_id = CM_TRAY_MENU_RECENT_ID_START;
+ flag = 1;
+ }
+
+ if (starter_id != 0)
+ {
+ UINT num;
+
+ id = (UINT)wParam - starter_id;
+
+ num = LvNum(hWnd, L_ACCOUNT);
+
+ if (id < num)
+ {
+ selected_name = LvGetStr(hWnd, L_ACCOUNT, id, 0);
+
+ if (selected_name != NULL)
+ {
+ if (UniStrCmpi(selected_name, _UU("CM_NEW_ICON")) != 0 &&
+ UniStrCmpi(selected_name, _UU("CM_VGC_ICON")) != 0 &&
+ UniStrCmpi(selected_name, _UU("CM_VGC_LINK")) != 0)
+ {
+ switch (flag)
+ {
+ case 1:
+ CmConnect(hWnd, selected_name);
+ break;
+
+ case 2:
+ CmStatus(hWnd, selected_name);
+ break;
+
+ case 3:
+ CmDisconnect(hWnd, selected_name);
+ break;
+ }
+ }
+ }
+
+ Free(selected_name);
+ }
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ case CMD_EASY_DBLCLICK:
+ // Property or connection
+ if (IsFocus(hWnd, L_ACCOUNT) || (hWnd == cm->hEasyWnd))
+ {
+ // Operation about the account list
+ if (alt == false)
+ {
+ UINT index = LvGetSelected(hWnd, L_ACCOUNT);
+ bool b = false;
+ if (index != INFINITE)
+ {
+ wchar_t *s = LvGetStr(hWnd, L_ACCOUNT, index, 1);
+ if (s != NULL)
+ {
+ if (UniStrCmpi(s, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(s, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+ {
+ b = true;
+ }
+ Free(s);
+ }
+ }
+
+ if (b == false)
+ {
+ // Connection
+ Command(hWnd, CMD_CONNECT);
+ }
+ else
+ {
+ if (hWnd != cm->hEasyWnd || wParam == CMD_EASY_DBLCLICK)
+ {
+ // Display status
+ Command(hWnd, CMD_STATUS);
+ }
+ else
+ {
+ // Disconnect
+ Command(hWnd, CMD_DISCONNECT);
+ }
+ }
+ }
+ else
+ {
+ // Property
+ Command(hWnd, CMD_PROPERTY);
+ }
+ }
+ else
+ {
+ // Configure Windows network connection
+ Command(hWnd, CMD_WINNET);
+ }
+ break;
+ case CMD_CONNECT:
+ // Connection
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ CmConnect(hWnd, tmp);
+ Free(tmp);
+ }
+ break;
+ case CMD_STATUS:
+ // Show the status
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ CmStatus(hWnd, tmp);
+ Free(tmp);
+ }
+ break;
+ case CMD_DISCONNECT_ALL:
+ // Disconnect all connections
+ CmDisconnectAll(hWnd);
+ break;
+ case CMD_DISCONNECT:
+ // Disconnect
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ CmDisconnect(hWnd, tmp);
+ Free(tmp);
+ }
+ break;
+ case CMD_NEW:
+ // Create new
+ CmNewAccount(hWnd);
+ break;
+
+
+ case CMD_CLONE:
+ // Copy
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ CmCopyAccount(hWnd, tmp);
+ Free(tmp);
+ }
+ break;
+ case CMD_SHORTCUT:
+ // Create a shortcut
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ CmSortcut(hWnd, tmp);
+ Free(tmp);
+ }
+ break;
+ case CMD_EXPORT_ACCOUNT:
+ // Export settings
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ CmExportAccount(hWnd, tmp);
+ Free(tmp);
+ }
+ break;
+ case CMD_IMPORT_ACCOUNT:
+ // Import settings
+ CmImportAccount(hWnd);
+ break;
+ case CMD_STARTUP:
+ // Set to start-up connection
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ RPC_CLIENT_DELETE_ACCOUNT c;
+ Zero(&c, sizeof(c));
+ UniStrCpy(c.AccountName, sizeof(c.AccountName), tmp);
+ CALL(hWnd, CcSetStartupAccount(cm->Client, &c));
+ CmVoice("set_startup");
+ MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("CM_SET_STARTUP"), tmp);
+ Free(tmp);
+ }
+ break;
+ case CMD_NOSTARTUP:
+ // Unset the start-up connection
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
+ _UU("CM_REMOVE_STARTUP"), tmp) == IDYES)
+ {
+ RPC_CLIENT_DELETE_ACCOUNT c;
+ Zero(&c, sizeof(c));
+ UniStrCpy(c.AccountName, sizeof(c.AccountName), tmp);
+ CALL(hWnd, CcRemoveStartupAccount(cm->Client, &c));
+ CmVoice("remove_startup");
+ }
+ Free(tmp);
+ }
+ break;
+ case CMD_DELETE:
+ // Delete
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ CmDeleteAccount(hWnd, tmp);
+ Free(tmp);
+ }
+ break;
+ case CMD_RENAME:
+ // Change the name
+ Focus(hWnd, L_ACCOUNT);
+ LvRename(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT));
+ break;
+ case CMD_PROPERTY:
+ // Property
+ tmp = LvGetStr(hWnd, L_ACCOUNT, LvGetSelected(hWnd, L_ACCOUNT), 0);
+ if (tmp != NULL)
+ {
+ CmEditAccount(hWnd, tmp);
+ Free(tmp);
+ }
+ break;
+ case IDCANCEL:
+ case CMD_EXIT:
+ // Close
+ Close(hWnd);
+ break;
+ case CMD_QUIT:
+ // Exit
+ CmMainWindowOnQuit(hWnd);
+ break;
+ case CMD_SELECT_ALL:
+ // Select all
+ LvSelectAll(hWnd, L_ACCOUNT);
+ LvSelectAll(hWnd, L_VLAN);
+ break;
+ case CMD_SWITCH_SELECT:
+ // Invert selection
+ LvSwitchSelect(hWnd, L_ACCOUNT);
+ LvSwitchSelect(hWnd, L_VLAN);
+ break;
+ case CMD_GRID:
+ // Show grid
+ cm->ShowGrid = !cm->ShowGrid;
+ CmRefreshVLanListEx(hWnd, true);
+ CmRefreshAccountListEx2(hWnd, false, true);
+ break;
+ case CMD_STATUSBAR:
+ // Show the status bar
+ if (cm->HideStatusBar == false)
+ {
+ cm->HideStatusBar = true;
+ Hide(hWnd, S_STATUSBAR);
+ CmMainWindowOnSize(hWnd);
+ }
+ else
+ {
+ cm->HideStatusBar = false;
+ Show(hWnd, S_STATUSBAR);
+ CmMainWindowOnSize(hWnd);
+ }
+ CmSaveMainWindowPos(hWnd);
+ break;
+ case CMD_VISTASTYLE:
+ cm->VistaStyle = !cm->VistaStyle;
+ CmRefreshEx(hWnd, true);
+ CmSaveMainWindowPos(hWnd);
+ break;
+ case CMD_TRAYICON:
+ // Tray icon display
+ if (cm->HideTrayIcon == false)
+ {
+ cm->HideTrayIcon = true;
+ CmFreeTray(hWnd);
+
+ if (IsHide(hWnd, 0))
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_TRAY_ICON_RESTORE"));
+ }
+ }
+ else
+ {
+ cm->HideTrayIcon = false;
+ if (cm->server_name == NULL)
+ {
+ CmInitTray(hWnd);
+ }
+ }
+ break;
+ case CMD_SHOWPORT:
+ // Show the port number
+ cm->ShowPort = !cm->ShowPort;
+ CmRefresh(hWnd);
+ break;
+ case CMD_ICON:
+ // Show the icon
+ if (cm->IconView == false)
+ {
+ cm->IconView = true;
+ CmRefresh(hWnd);
+ }
+ break;
+ case CMD_DETAIL:
+ // Show details
+ if (cm->IconView)
+ {
+ cm->IconView = false;
+ CmRefresh(hWnd);
+ }
+ break;
+ case CMD_REFRESH:
+ if (easy == false)
+ {
+ // Display update
+ LvReset(hWnd, L_ACCOUNT);
+ LvReset(hWnd, L_VLAN);
+ CmRefresh(hWnd);
+ }
+ break;
+ case CMD_NEW_VLAN:
+ // Create a Virtual LAN card
+ if (CmStopInstallVLan(hWnd) == false)
+ {
+ // Installation is prohibited
+ break;
+ }
+ name = CmNewVLanDlg(hWnd);
+ if (name != NULL)
+ {
+ wchar_t tmp[MAX_SIZE];
+ void *helper = NULL;
+ RPC_CLIENT_CREATE_VLAN c;
+ Zero(&c, sizeof(c));
+ StrCpy(c.DeviceName, sizeof(c.DeviceName), name);
+ if (MsIsNt() == false)
+ {
+ // Change the title of the window
+ GetTxt(hWnd, 0, tmp, sizeof(tmp));
+ SetText(hWnd, 0, _UU("CM_VLAN_INSTALLING"));
+ }
+ // Minimize
+ if (MsIsVista() == false)
+ {
+ ShowWindow(hWnd, SW_SHOWMINIMIZED);
+ }
+
+ if (MsIsVista())
+ {
+ helper = CmStartUacHelper();
+ }
+
+ if (CALL(hWnd, CcCreateVLan(cm->Client, &c)))
+ {
+ CmVoice("new_vlan");
+ }
+
+ CmStopUacHelper(helper);
+
+ if (MsIsNt() == false)
+ {
+ // Restore the title of the window
+ SetText(hWnd, 0, tmp);
+ }
+ // Restore
+ if (MsIsVista() == false)
+ {
+ ShowWindow(hWnd, SW_SHOWNORMAL);
+ }
+ Free(name);
+ }
+ break;
+ case CMD_DELETE_VLAN:
+ // Delete the Virtual LAN card
+ index = LvGetSelected(hWnd, L_VLAN);
+ if (index != INFINITE)
+ {
+ if (cm->Client->Win9x == false)
+ {
+ // Windows 2000 or later
+ wchar_t *s = LvGetStr(hWnd, L_VLAN, index, 0);
+ if (s != NULL)
+ {
+ RPC_CLIENT_CREATE_VLAN c;
+ char str[MAX_SIZE];
+ CmVoice("delete_vlan_1");
+ if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_DELETE_VLAN"), s) == IDYES)
+ {
+ Zero(&c, sizeof(c));
+ UniToStr(str, sizeof(str), s);
+ if (CmPrintNameToVLanName(c.DeviceName, sizeof(c.DeviceName), str))
+ {
+ if (CALL(hWnd, CcDeleteVLan(cm->Client, &c)))
+ {
+ CmVoice("delete_vlan_2");
+ }
+ }
+ }
+ Free(s);
+ }
+ }
+ else
+ {
+ // Windows 9x
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("CM_9X_VLAN_UNINSTALL")) == IDYES)
+ {
+ Run("rundll32.exe", "shell32.dll,Control_RunDLL NETCPL.CPL",
+ false, false);
+ }
+ }
+ }
+ break;
+ case CMD_ENABLE_VLAN:
+ // Enable the virtual LAN card
+ index = LvGetSelected(hWnd, L_VLAN);
+ if (index != INFINITE)
+ {
+ wchar_t *s = LvGetStr(hWnd, L_VLAN, index, 0);
+ if (s != NULL)
+ {
+ RPC_CLIENT_CREATE_VLAN c;
+ char str[MAX_SIZE];
+ Zero(&c, sizeof(c));
+ UniToStr(str, sizeof(str), s);
+ if (CmPrintNameToVLanName(c.DeviceName, sizeof(c.DeviceName), str))
+ {
+ CALL(hWnd, CcEnableVLan(cm->Client, &c));
+ }
+ Free(s);
+ }
+ }
+ break;
+ case CMD_DISABLE_VLAN:
+ // Disable the virtual LAN card
+ index = LvGetSelected(hWnd, L_VLAN);
+ if (index != INFINITE)
+ {
+ wchar_t *s = LvGetStr(hWnd, L_VLAN, index, 0);
+ if (s != NULL)
+ {
+ RPC_CLIENT_CREATE_VLAN c;
+ char str[MAX_SIZE];
+ Zero(&c, sizeof(c));
+ UniToStr(str, sizeof(str), s);
+ if (CmPrintNameToVLanName(c.DeviceName, sizeof(c.DeviceName), str))
+ {
+ CALL(hWnd, CcDisableVLan(cm->Client, &c));
+ }
+ Free(s);
+ }
+ }
+ break;
+ case CMD_REINSTALL:
+ // Reinstall the virtual LAN card
+ if (CmStopInstallVLan(hWnd) == false)
+ {
+ // Installation is prohibited
+ break;
+ }
+ index = LvGetSelected(hWnd, L_VLAN);
+ if (index != INFINITE)
+ {
+ wchar_t *s = LvGetStr(hWnd, L_VLAN, index, 0);
+ if (s != NULL)
+ {
+ RPC_CLIENT_CREATE_VLAN c;
+ char str[MAX_SIZE];
+ Zero(&c, sizeof(c));
+ UniToStr(str, sizeof(str), s);
+ if (CmPrintNameToVLanName(c.DeviceName, sizeof(c.DeviceName), str))
+ {
+ void *helper = NULL;
+
+ if (MsIsVista() == false)
+ {
+ ShowWindow(hWnd, SW_SHOWMINIMIZED);
+ }
+
+ if (MsIsVista())
+ {
+ helper = CmStartUacHelper();
+ }
+
+ CALL(hWnd, CcUpgradeVLan(cm->Client, &c));
+
+ CmStopUacHelper(helper);
+
+ if (MsIsVista() == false)
+ {
+ ShowWindow(hWnd, SW_SHOWNORMAL);
+ }
+ }
+ Free(s);
+ }
+ }
+ break;
+ case CMD_PASSWORD:
+ // Password setting
+ CmPassword(hWnd);
+ break;
+ case CMD_OPTION:
+ // Option
+ CmConfigDlg(hWnd);
+ break;
+ case CMD_LANGUAGE:
+ // Language settings
+ if (true)
+ {
+ wchar_t path[MAX_SIZE];
+
+ CombinePathW(path, sizeof(path), MsGetExeDirNameW(), L"vpnsetup.exe");
+
+ if (MsExecuteW(path, L"/language:yes") == false)
+ {
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SW_CHILD_PROCESS_ERROR"));
+ }
+ }
+ break;
+ case CMD_TRUST:
+ // Certificate management
+ CmTrustDlg(hWnd);
+ break;
+ case CMD_ABOUT:
+ // Version information
+ if (IsEnable(hWnd, 0))
+ {
+ AboutEx(hWnd, cm->Cedar, _UU("PRODUCT_NAME_VPN_CMGR"), cm->Update);
+ }
+ break;
+ case CMD_VOIDE_NONE:
+ cm->DisableVoice = true;
+ break;
+ case CMD_VOICE_NORMAL:
+ cm->DisableVoice = false;
+ cm->VoiceId = VOICE_SSK;
+ break;
+ case CMD_VOICE_ODD:
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("CM_EXT_VOICE_MSG")) == IDYES)
+ {
+ cm->DisableVoice = false;
+ cm->VoiceId = VOICE_AHO;
+ }
+ break;
+ case CMD_SECURE_MANAGER:
+ // Smart Card Manager
+ CmClientSecureManager(hWnd);
+ break;
+ case CMD_SECURE_SELECT:
+ // Select a smart card
+ CmClientSelectSecure(hWnd);
+ break;
+ case CMD_NETIF:
+ // State of the network device
+ if (IsEnable(hWnd, 0))
+ {
+ UtSpeedMeterEx(hWnd);
+ }
+ break;
+ case CMD_MMCSS:
+ // Optimization utility for Windows Vista
+ if (MsIsVista() == false)
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("VISTA_MMCSS_MSG_4"));
+ }
+ else
+ {
+ if (MsIsAdmin() == false)
+ {
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("VISTA_MMCSS_MSG_4"));
+ }
+ else
+ {
+ if (MsIsMMCSSNetworkThrottlingEnabled())
+ {
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("VISTA_MMCSS_MSG")) == IDYES)
+ {
+ MsSetMMCSSNetworkThrottlingEnable(false);
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("VISTA_MMCSS_MSG_5"));
+ }
+ }
+ else
+ {
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("VISTA_MMCSS_MSG_2")) == IDYES)
+ {
+ MsSetMMCSSNetworkThrottlingEnable(true);
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("VISTA_MMCSS_MSG_6"));
+ }
+ }
+ }
+ }
+ break;
+ case CMD_TRAFFIC:
+ // Communication traffic measurement
+ if (IsEnable(hWnd, 0))
+ {
+ CmTraffic(hWnd);
+ }
+ break;
+ case CMD_CM_SETTING:
+ // Operation mode setting
+ if (IsEnable(hWnd, 0))
+ {
+ if (CmSetting(hWnd))
+ {
+ CmApplyCmSetting();
+ }
+ }
+ break;
+ case CMD_WINNET:
+ // Windows network settings
+ ShowWindowsNetworkConnectionDialog();
+ break;
+ }
+}
+
+// Option dialog
+void CmConfigDlg(HWND hWnd)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_CM_CONFIG, CmConfigDlgProc, NULL);
+}
+
+// Initialize the option dialog
+void CmConfigDlgInit(HWND hWnd)
+{
+ bool use_alpha;
+ UINT alpha_value;
+ UINT os;
+ CLIENT_CONFIG c;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ DlgFont(hWnd, S_WARNING, 10, true);
+ DlgFont(hWnd, S_INFO, 10, false);
+
+ Zero(&c, sizeof(c));
+ if (CALL(hWnd, CcGetClientConfig(cm->Client, &c)) == false)
+ {
+ EndDialog(hWnd, 0);
+ return;
+ }
+
+ Check(hWnd, R_ALLOW_REMOTE_CONFIG, c.AllowRemoteConfig);
+
+ Check(hWnd, R_USE_KEEP_CONNECT, c.UseKeepConnect);
+ SetTextA(hWnd, E_HOSTNAME, c.KeepConnectHost);
+ SetIntEx(hWnd, E_PORT, c.KeepConnectPort);
+ SetIntEx(hWnd, E_INTERVAL, c.KeepConnectInterval);
+
+ Check(hWnd, R_TCP, c.KeepConnectProtocol == CONNECTION_TCP);
+ Check(hWnd, R_UDP, c.KeepConnectProtocol == CONNECTION_UDP);
+
+ use_alpha = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "UseAlpha") == 0 ? false : true;
+ alpha_value = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "AlphaValue");
+ alpha_value = MAKESURE(alpha_value, 0, 100);
+
+ SetInt(hWnd, E_ALPHA_VALUE, alpha_value == 0 ? 50 : alpha_value);
+ Check(hWnd, R_ALPHA, use_alpha);
+
+ os = GetOsInfo()->OsType;
+ if (OS_IS_WINDOWS_NT(os) && GET_KETA(os, 100) >= 2)
+ {
+ Enable(hWnd, R_ALPHA);
+ }
+ else
+ {
+ Disable(hWnd, R_ALPHA);
+ }
+
+ CmConfigDlgRefresh(hWnd);
+}
+
+// Update the option dialog
+void CmConfigDlgRefresh(HWND hWnd)
+{
+ bool ok = true;
+ bool use_keep_connect;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ use_keep_connect = IsChecked(hWnd, R_USE_KEEP_CONNECT);
+ SetEnable(hWnd, S_HOSTNAME, use_keep_connect);
+ SetEnable(hWnd, S_PORT, use_keep_connect);
+ SetEnable(hWnd, S_INTERVAL, use_keep_connect);
+ SetEnable(hWnd, S_INTERVAL2, use_keep_connect);
+ SetEnable(hWnd, S_PROTOCOL, use_keep_connect);
+ SetEnable(hWnd, S_INFO, use_keep_connect);
+ SetEnable(hWnd, S_INFO2, use_keep_connect);
+ SetEnable(hWnd, E_HOSTNAME, use_keep_connect);
+ SetEnable(hWnd, E_PORT, use_keep_connect);
+ SetEnable(hWnd, E_INTERVAL, use_keep_connect);
+ SetEnable(hWnd, R_TCP, use_keep_connect);
+ SetEnable(hWnd, R_UDP, use_keep_connect);
+
+ SetEnable(hWnd, S_WARNING, IsChecked(hWnd, R_ALLOW_REMOTE_CONFIG));
+
+ if (IsChecked(hWnd, R_USE_KEEP_CONNECT))
+ {
+ if (IsEmpty(hWnd, E_HOSTNAME))
+ {
+ ok = false;
+ }
+ if (IsChecked(hWnd, R_TCP) == false && IsChecked(hWnd, R_UDP) == false)
+ {
+ ok = false;
+ }
+ if (GetInt(hWnd, E_PORT) == 0 || GetInt(hWnd, E_PORT) >= 65536)
+ {
+ ok = false;
+ }
+ if (GetInt(hWnd, E_INTERVAL) == 0)
+ {
+ ok = false;
+ }
+ }
+
+ if (IsChecked(hWnd, R_ALPHA))
+ {
+ UINT i = GetInt(hWnd, E_ALPHA_VALUE);
+ if (i < 20 || i >= 100)
+ {
+ ok = false;
+ }
+ Enable(hWnd, E_ALPHA_VALUE);
+ }
+ else
+ {
+ Disable(hWnd, E_ALPHA_VALUE);
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Save the setting of the option dialog
+void CmConfigDlgOnOk(HWND hWnd)
+{
+ CLIENT_CONFIG c;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ Zero(&c, sizeof(c));
+ c.AllowRemoteConfig = IsChecked(hWnd, R_ALLOW_REMOTE_CONFIG);
+ c.UseKeepConnect = IsChecked(hWnd, R_USE_KEEP_CONNECT);
+ GetTxtA(hWnd, E_HOSTNAME, c.KeepConnectHost, sizeof(c.KeepConnectHost));
+ c.KeepConnectPort = GetInt(hWnd, E_PORT);
+ c.KeepConnectInterval = GetInt(hWnd, E_INTERVAL);
+ if (IsChecked(hWnd, R_TCP))
+ {
+ c.KeepConnectProtocol = CONNECTION_TCP;
+ }
+ else if (IsChecked(hWnd, R_UDP))
+ {
+ c.KeepConnectProtocol = CONNECTION_UDP;
+ }
+ else
+ {
+ return;
+ }
+
+ if (c.UseKeepConnect)
+ {
+ if (c.KeepConnectInterval < KEEP_INTERVAL_MIN || c.KeepConnectInterval > KEEP_INTERVAL_MAX)
+ {
+ MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("CM_KEEP_INTERVAL_MSG"),
+ KEEP_INTERVAL_MIN, KEEP_INTERVAL_MAX);
+ FocusEx(hWnd, E_INTERVAL);
+ return;
+ }
+ }
+
+ if (CALL(hWnd, CcSetClientConfig(cm->Client, &c)) == false)
+ {
+ return;
+ }
+
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "AlphaValue", GetInt(hWnd, E_ALPHA_VALUE));
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "UseAlpha", IsChecked(hWnd, R_ALPHA));
+
+ EndDialog(hWnd, true);
+}
+
+// Option setting dialog procedure
+UINT CmConfigDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmConfigDlgInit(hWnd);
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case R_ALLOW_REMOTE_CONFIG:
+ case R_USE_KEEP_CONNECT:
+ case E_HOSTNAME:
+ case E_PORT:
+ case E_INTERVAL:
+ case R_ALPHA:
+ case E_ALPHA_VALUE:
+ CmConfigDlgRefresh(hWnd);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ CmConfigDlgRefresh(hWnd);
+ CmConfigDlgOnOk(hWnd);
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ case R_ALLOW_REMOTE_CONFIG:
+ if (IsChecked(hWnd, R_ALLOW_REMOTE_CONFIG) == false)
+ {
+ if (cm->server_name != NULL)
+ {
+ // If the current user is remotely connected, show a warning
+ // when the user choose to disable the remote management
+ if (MsgBoxEx(hWnd, MB_ICONEXCLAMATION | MB_DEFBUTTON2 | MB_YESNO, _UU("CM_REMOTE_WARNING"),
+ cm->server_name, cm->server_name) == IDNO)
+ {
+ Check(hWnd, R_ALLOW_REMOTE_CONFIG, true);
+ }
+ }
+ }
+ break;
+ case R_USE_KEEP_CONNECT:
+ if (IsChecked(hWnd, R_USE_KEEP_CONNECT))
+ {
+ FocusEx(hWnd, E_HOSTNAME);
+ }
+ break;
+ case R_ALPHA:
+ if (IsChecked(hWnd, R_ALPHA))
+ {
+ FocusEx(hWnd, E_ALPHA_VALUE);
+ }
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Create a shortcut
+void CmSortcut(HWND hWnd, wchar_t *account_name)
+{
+ wchar_t tmp[MAX_SIZE];
+ CM_ACCOUNT *a;
+ wchar_t *filename;
+ UCHAR key[SHA1_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return;
+ }
+
+ // Get the account information
+ a = CmGetExistAccountObject(hWnd, account_name);
+ if (a == NULL)
+ {
+ return;
+ }
+
+ Copy(key, a->ShortcutKey, SHA1_SIZE);
+
+ if (IsZero(key, SHA1_SIZE))
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_SHORTCUT_UNSUPPORTED"));
+ }
+ else
+ {
+ // Determine the file name
+ UniFormat(tmp, sizeof(tmp), L"%s.lnk", account_name);
+ UniSafeFileName(tmp);
+
+ filename = SaveDlg(hWnd, _UU("CM_SHORTCUT_FILE"),
+ _UU("CM_SHORTCUT_SAVE_TITLE"), tmp, L".vpn");
+
+ if (filename != NULL)
+ {
+ char key_str[64];
+ wchar_t target[MAX_PATH];
+ wchar_t workdir[MAX_PATH];
+ wchar_t args[MAX_PATH];
+ wchar_t comment[MAX_SIZE];
+ wchar_t icon[MAX_PATH];
+
+ BinToStr(key_str, sizeof(key_str), key, SHA1_SIZE);
+
+ // Create a shortcut
+ UniStrCpy(target, sizeof(target), MsGetExeFileNameW());
+ UniStrCpy(workdir, sizeof(workdir), MsGetExeDirNameW());
+ StrToUni(args, sizeof(args), key_str);
+ UniFormat(comment, sizeof(comment), _UU("CM_SHORTCUT_COMMENT"), account_name);
+ UniStrCpy(icon, sizeof(icon), MsGetExeFileNameW());
+
+ if (CreateLink(filename, target, workdir, args, comment, icon, 1) == false)
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("CM_SHORTCUT_ERROR"));
+ }
+
+ Free(filename);
+ }
+ }
+
+ CmFreeAccountObject(hWnd, a);
+}
+
+// Export the account
+void CmExportAccount(HWND hWnd, wchar_t *account_name)
+{
+ wchar_t tmp[MAX_SIZE];
+ CM_ACCOUNT *a;
+ wchar_t *filename;
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return;
+ }
+
+ // Get the account information
+ a = CmGetExistAccountObject(hWnd, account_name);
+ if (a == NULL)
+ {
+ return;
+ }
+
+ // Determine the file name
+ UniFormat(tmp, sizeof(tmp), L"%s.vpn", account_name);
+ UniSafeFileName(tmp);
+
+ filename = SaveDlg(hWnd, _UU("CM_ACCOUNT_SETTING_FILE"),
+ _UU("CM_ACCOUNT_SAVE_TITLE"), tmp, L".vpn");
+
+ if (filename != NULL)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT t;
+ BUF *b;
+ BUF *b2;
+ wchar_t tmp[MAX_SIZE];
+ UCHAR *buf;
+ UINT buf_size;
+ UCHAR bom[] = {0xef, 0xbb, 0xbf, };
+
+ Zero(&t, sizeof(t));
+ t.ClientOption = a->ClientOption;
+ t.ClientAuth = a->ClientAuth;
+ t.StartupAccount = a->Startup;
+ t.CheckServerCert = a->CheckServerCert;
+ t.ServerCert = a->ServerCert;
+ t.ClientOption->FromAdminPack = false;
+
+ b = CiAccountToCfg(&t);
+
+ SeekBuf(b, 0, 0);
+
+ // Check whether the password is contained
+ if (CiHasAccountSensitiveInformation(b))
+ {
+ SeekBuf(b, 0, 0);
+
+ // Confirm that the user want to clear the password
+ if (MsgBox(hWnd, MB_YESNO | MB_ICONQUESTION, _UU("CM_ACCOUNT_MSG_SENSITIVE")) == IDYES)
+ {
+ // Erase
+ CiEraseSensitiveInAccount(b);
+ }
+ }
+
+ UniStrCpy(tmp, sizeof(tmp), filename);
+ b2 = NewBuf();
+
+ WriteBuf(b2, bom, sizeof(bom));
+
+ // Add a header part
+ buf_size = CalcUniToUtf8(_UU("CM_ACCOUNT_FILE_BANNER"));
+ buf = ZeroMalloc(buf_size + 32);
+ UniToUtf8(buf, buf_size, _UU("CM_ACCOUNT_FILE_BANNER"));
+
+ WriteBuf(b2, buf, StrLen((char *)buf));
+ WriteBuf(b2, b->Buf, b->Size);
+ SeekBuf(b2, 0, 0);
+
+ FreeBuf(b);
+
+ if (DumpBufW(b2, tmp) == false)
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("CM_FAILED_TO_SAVE_FILE"));
+ }
+
+ Free(filename);
+ FreeBuf(b2);
+ Free(buf);
+ }
+
+ CmFreeAccountObject(hWnd, a);
+}
+
+// Main process of importing account
+void CmImportAccountMain(HWND hWnd, wchar_t *filename)
+{
+ CmImportAccountMainEx(hWnd, filename, false);
+}
+void CmImportAccountMainEx(HWND hWnd, wchar_t *filename, bool overwrite)
+{
+ wchar_t name[MAX_SIZE];
+ wchar_t tmp[MAX_SIZE];
+ BUF *b;
+ RPC_CLIENT_CREATE_ACCOUNT *t;
+ // Validate arguments
+ if (hWnd == NULL || filename == NULL)
+ {
+ return;
+ }
+
+ UniStrCpy(tmp, sizeof(tmp), filename);
+
+ b = ReadDumpW(tmp);
+ if (b == NULL)
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("CM_FAILED_TO_OPEN_FILE"));
+ return;
+ }
+
+ t = CiCfgToAccount(b);
+ if (t == NULL)
+ {
+ FreeBuf(b);
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("CM_ACCOUNT_PARSE_FAILED"));
+ return;
+ }
+
+ if (overwrite)
+ {
+ // If the same name already exists, remove it
+ if (LvSearchStr(hWnd, L_ACCOUNT, 0, t->ClientOption->AccountName) != INFINITE)
+ {
+ RPC_CLIENT_DELETE_ACCOUNT d;
+ RPC_CLIENT_GET_ACCOUNT get;
+ HWND h = cm->hEasyWnd == NULL ? hWnd : cm->hEasyWnd;
+
+ Zero(&d, sizeof(d));
+ UniStrCpy(d.AccountName, sizeof(d.AccountName), t->ClientOption->AccountName);
+
+ Zero(&get, sizeof(get));
+ UniStrCpy(get.AccountName, sizeof(get.AccountName), t->ClientOption->AccountName);
+ if (CcGetAccount(cm->Client, &get) == ERR_NO_ERROR)
+ {
+ // Inherit the information of some of the client option by getting
+ // the account information of the same name that already exists
+ if (get.ClientOption != NULL && get.ClientAuth != NULL)
+ {
+ CLIENT_OPTION *old_option = get.ClientOption;
+ CLIENT_AUTH *old_auth = get.ClientAuth;
+
+ // Inherit the connection parameters
+ t->ClientOption->ProxyType = old_option->ProxyType;
+ StrCpy(t->ClientOption->ProxyName, sizeof(t->ClientOption->ProxyName),
+ old_option->ProxyName);
+ t->ClientOption->ProxyPort = old_option->ProxyPort;
+ StrCpy(t->ClientOption->ProxyUsername, sizeof(t->ClientOption->ProxyUsername),
+ old_option->ProxyUsername);
+ StrCpy(t->ClientOption->ProxyPassword, sizeof(t->ClientOption->ProxyPassword),
+ old_option->ProxyPassword);
+ t->ClientOption->NumRetry = old_option->NumRetry;
+ t->ClientOption->RetryInterval = old_option->RetryInterval;
+ t->ClientOption->MaxConnection = old_option->MaxConnection;
+ t->ClientOption->UseEncrypt = old_option->UseEncrypt;
+ t->ClientOption->UseCompress = old_option->UseCompress;
+ t->ClientOption->HalfConnection = old_option->HalfConnection;
+ t->ClientOption->NoRoutingTracking = old_option->NoRoutingTracking;
+ StrCpy(t->ClientOption->DeviceName, sizeof(t->ClientOption->DeviceName),
+ old_option->DeviceName);
+ t->ClientOption->AdditionalConnectionInterval = old_option->AdditionalConnectionInterval;
+ t->ClientOption->ConnectionDisconnectSpan = old_option->ConnectionDisconnectSpan;
+ t->ClientOption->HideStatusWindow = old_option->HideStatusWindow;
+ t->ClientOption->RequireMonitorMode = old_option->RequireMonitorMode;
+ t->ClientOption->RequireBridgeRoutingMode = old_option->RequireBridgeRoutingMode;
+ t->ClientOption->DisableQoS = old_option->DisableQoS;
+ t->ClientOption->NoTls1 = old_option->NoTls1;
+
+ // Inherit the authentication data
+ CiFreeClientAuth(t->ClientAuth);
+ t->ClientAuth = CopyClientAuth(old_auth);
+
+ // Other Settings
+ t->StartupAccount = get.StartupAccount;
+ t->CheckServerCert = get.CheckServerCert;
+ if (t->ServerCert != NULL)
+ {
+ FreeX(t->ServerCert);
+ }
+ t->ServerCert = NULL;
+ if (get.ServerCert != NULL)
+ {
+ t->ServerCert = CloneX(get.ServerCert);
+ }
+ Copy(t->ShortcutKey, get.ShortcutKey, sizeof(t->ShortcutKey));
+ }
+
+ CiFreeClientGetAccount(&get);
+ }
+
+ if (CALL(h, CcDeleteAccount(cm->Client, &d)) == false)
+ {
+ CiFreeClientCreateAccount(t);
+ Free(t);
+ return;
+ }
+
+ CmRefreshAccountList(hWnd);
+ }
+ }
+
+ CmGenerateImportName(hWnd, name, sizeof(name), t->ClientOption->AccountName);
+ UniStrCpy(t->ClientOption->AccountName, sizeof(t->ClientOption->AccountName), name);
+
+ if (overwrite)
+ {
+ t->ClientOption->FromAdminPack = true;
+ }
+
+ CALL(hWnd, CcCreateAccount(cm->Client, t));
+
+ CiFreeClientCreateAccount(t);
+ Free(t);
+
+ FreeBuf(b);
+
+ if (overwrite)
+ {
+ // Start to connect the VPN
+ CmConnect(hWnd, name);
+ }
+
+ //MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("CM_IMPORT_MESSAGE"), filename, name);
+}
+
+// Import an account
+void CmImportAccount(HWND hWnd)
+{
+ wchar_t *filename;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Open the file
+ filename = OpenDlg(hWnd, _UU("CM_ACCOUNT_SETTING_FILE"), _UU("CM_ACCOUNT_OPEN_TITLE"));
+ if (filename == NULL)
+ {
+ return;
+ }
+
+ UniStrCpy(tmp, sizeof(tmp), filename);
+ Free(filename);
+
+ CmImportAccountMain(hWnd, tmp);
+}
+
+// Create a copy of the account
+void CmCopyAccount(HWND hWnd, wchar_t *account_name)
+{
+ wchar_t tmp[MAX_SIZE];
+ CM_ACCOUNT *a;
+ RPC_CLIENT_CREATE_ACCOUNT c;
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return;
+ }
+
+ CmGenerateCopyName(hWnd, tmp, sizeof(tmp), account_name);
+
+ // Get an account information
+ a = CmGetExistAccountObject(hWnd, account_name);
+ if (a == NULL)
+ {
+ return;
+ }
+
+ // Change the account name
+ UniStrCpy(a->ClientOption->AccountName, sizeof(a->ClientOption->AccountName), tmp);
+
+ // Write
+ Zero(&c, sizeof(c));
+ c.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(c.ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));
+ c.ClientAuth = CopyClientAuth(a->ClientAuth);
+ if (a->ServerCert)
+ {
+ c.ServerCert = CloneX(a->ServerCert);
+ }
+ c.CheckServerCert = a->CheckServerCert;
+ c.StartupAccount = false; // Don't copy the startup attribute
+
+ CALL(hWnd, CcCreateAccount(cm->Client, &c));
+ CiFreeClientCreateAccount(&c);
+
+ CmFreeAccountObject(hWnd, a);
+}
+
+// Update the Virtual LAN Card Name dialog
+void CmNewVLanDlgUpdate(HWND hWnd)
+{
+ bool ok = true;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ GetTxtA(hWnd, E_NAME, tmp, sizeof(tmp));
+ if (IsSafeStr(tmp) == false)
+ {
+ ok = false;
+ }
+ if (SearchStrEx(tmp, " ", 0, false) != INFINITE)
+ {
+ ok = false;
+ }
+
+ Trim(tmp);
+ if (StrLen(tmp) == 0)
+ {
+ ok = false;
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Virtual LAN card name decision dialog procedure
+UINT CmNewVLanDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ char *tmp = (char *)param;
+ char default_name[MAX_SIZE];
+ RPC_CLIENT_VERSION ver;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ LimitText(hWnd, E_NAME, cm->Client->Win9x ? MAX_DEVICE_NAME_LEN_9X : MAX_DEVICE_NAME_LEN);
+ FormatText(hWnd, S_INFO, cm->Client->Win9x ? MAX_DEVICE_NAME_LEN_9X : MAX_DEVICE_NAME_LEN);
+
+ Zero(&ver, sizeof(ver));
+
+ if (CcGetClientVersion(cm->Client, &ver) == ERR_NO_ERROR)
+ {
+ if (ver.IsVLanNameRegulated)
+ {
+ Show(hWnd, S_WIN8);
+ }
+ }
+
+ if (CiGetNextRecommendedVLanName(cm->Client, default_name, sizeof(default_name)))
+ {
+ // Show a default virtual LAN card name candidate
+ SetTextA(hWnd, E_NAME, default_name);
+ }
+
+ CmNewVLanDlgUpdate(hWnd);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ if (cm->Client->Win9x)
+ {
+ // For Windows 9x, show a confirmation message
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_OKCANCEL, _UU("CM_9X_VLAN_INSTALL")) == IDCANCEL)
+ {
+ break;
+ }
+ }
+ GetTxtA(hWnd, E_NAME, tmp, (cm->Client->Win9x ? MAX_DEVICE_NAME_LEN_9X : MAX_DEVICE_NAME_LEN) + 1);
+ Trim(tmp);
+
+ if (CcGetClientVersion(cm->Client, &ver) == ERR_NO_ERROR)
+ {
+ if (ver.IsVLanNameRegulated)
+ {
+ if (CiIsValidVLanRegulatedName(tmp) == false)
+ {
+ // Virtual LAN card name isn't meeting the format
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("D_CM_NEW_VLAN@S_WIN8"));
+
+ FocusEx(hWnd, E_NAME);
+ break;
+ }
+ }
+ }
+
+ EndDialog(hWnd, true);
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ switch (LOWORD(wParam))
+ {
+ case E_NAME:
+ CmNewVLanDlgUpdate(hWnd);
+ break;
+
+ case R_USE_DISCONNECT:
+ if (IsChecked(hWnd, R_USE_DISCONNECT))
+ {
+ FocusEx(hWnd, E_DISCONNECT_SPAN);
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Dialog to determine the new virtual LAN card name
+char *CmNewVLanDlg(HWND hWnd)
+{
+ char tmp[MAX_DEVICE_NAME_LEN + 1];
+
+ if (Dialog(hWnd, D_CM_NEW_VLAN, CmNewVLanDlgProc, tmp) == false)
+ {
+ return NULL;
+ }
+
+ return CopyStr(tmp);
+}
+
+// Update the advanced settings dialog
+void CmDetailDlgUpdate(HWND hWnd, CM_ACCOUNT *a)
+{
+ bool ok = true;
+ bool locked;
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+ locked = a->LockMode;
+
+ if (a->LinkMode || a->NatMode)
+ {
+ Disable(hWnd, R_NO_ROUTING);
+ }
+ else
+ {
+ if (cm->Client->Unix)
+ {
+ Disable(hWnd, R_NO_ROUTING);
+ }
+ }
+
+ SetEnable(hWnd, E_DISCONNECT_SPAN, IsChecked(hWnd, R_USE_DISCONNECT));
+
+ SetEnable(hWnd, IDOK, ok);
+
+ if (locked)
+ {
+ Disable(hWnd, C_NUM_TCP);
+ Disable(hWnd, S_STATIC5);
+ Disable(hWnd, S_STATIC8);
+ Disable(hWnd, E_INTERVAL);
+ Disable(hWnd, S_STATIC9);
+ Disable(hWnd, E_DISCONNECT_SPAN);
+ Disable(hWnd, S_STATIC10);
+ Disable(hWnd, S_STATIC11);
+ Disable(hWnd, R_USE_DISCONNECT);
+ Disable(hWnd, R_USE_HALF_CONNECTION);
+ Disable(hWnd, R_DISABLE_QOS);
+ Disable(hWnd, R_USE_ENCRYPT);
+ Disable(hWnd, R_USE_COMPRESS);
+ Disable(hWnd, R_BRIDGE);
+ Disable(hWnd, R_MONITOR);
+ Disable(hWnd, R_NO_ROUTING);
+ }
+}
+
+// Advanced Settings dialog procedure
+UINT CmDetailDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ CM_ACCOUNT *a = (CM_ACCOUNT *)param;
+ UINT i;
+ UINT num;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Number of TCP connections
+ for (i = 1;i <= MAX_TCP_CONNECTION;i++)
+ {
+ UniFormat(tmp, sizeof(tmp), L"%u", i);
+ CbAddStr(hWnd, C_NUM_TCP, tmp, i);
+ }
+ CbSelect(hWnd, C_NUM_TCP, a->ClientOption->MaxConnection);
+
+ // Connection establishment interval
+ SetInt(hWnd, E_INTERVAL, a->ClientOption->AdditionalConnectionInterval);
+
+ // Lifetime
+ SetIntEx(hWnd, E_DISCONNECT_SPAN, a->ClientOption->ConnectionDisconnectSpan);
+ Check(hWnd, R_USE_DISCONNECT, a->ClientOption->ConnectionDisconnectSpan != 0);
+ Check(hWnd, R_USE_HALF_CONNECTION, a->ClientOption->HalfConnection);
+ Check(hWnd, R_USE_ENCRYPT, a->ClientOption->UseEncrypt);
+ Check(hWnd, R_USE_COMPRESS, a->ClientOption->UseCompress);
+ Check(hWnd, R_NO_ROUTING, a->ClientOption->NoRoutingTracking);
+ Check(hWnd, R_DISABLE_QOS, a->ClientOption->DisableQoS);
+ Check(hWnd, R_DISABLE_UDP, a->ClientOption->NoUdpAcceleration);
+
+ // Select the Connection Mode
+ if (a->LinkMode == false)
+ {
+ Check(hWnd, R_BRIDGE, a->ClientOption->RequireBridgeRoutingMode);
+ Check(hWnd, R_MONITOR, a->ClientOption->RequireMonitorMode);
+ }
+ else
+ {
+ Check(hWnd, R_BRIDGE, true);
+ Check(hWnd, R_MONITOR, false);
+
+ SetText(hWnd, S_MODE, _UU("CM_DETAIL_MODE_LINK_STR"));
+ Disable(hWnd, R_BRIDGE);
+ Disable(hWnd, R_MONITOR);
+ }
+
+ CmDetailDlgUpdate(hWnd, a);
+ Focus(hWnd, IDOK);
+ break;
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ if (IsChecked(hWnd, R_USE_DISCONNECT) && GetInt(hWnd, E_DISCONNECT_SPAN) == 0)
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_NO_DISCONNECT_SPAN"));
+ FocusEx(hWnd, E_DISCONNECT_SPAN);
+ break;
+ }
+ num = GetInt(hWnd, C_NUM_TCP);
+ if (num == 0)
+ {
+ break;
+ }
+ if (num == 1 && IsChecked(hWnd, R_USE_HALF_CONNECTION))
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_HALF_MSG"));
+ Focus(hWnd, C_NUM_TCP);
+ break;
+ }
+ if (GetInt(hWnd, E_INTERVAL) < 1)
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_TOO_SMALL_INTERVAL"));
+ Focus(hWnd, E_INTERVAL);
+ break;
+ }
+
+ a->ClientOption->MaxConnection = num;
+ a->ClientOption->AdditionalConnectionInterval = GetInt(hWnd, E_INTERVAL);
+ if (IsChecked(hWnd, R_USE_DISCONNECT) == false)
+ {
+ a->ClientOption->ConnectionDisconnectSpan = 0;
+ }
+ else
+ {
+ a->ClientOption->ConnectionDisconnectSpan = GetInt(hWnd, E_DISCONNECT_SPAN);
+ }
+ a->ClientOption->HalfConnection = IsChecked(hWnd, R_USE_HALF_CONNECTION);
+ a->ClientOption->UseEncrypt = IsChecked(hWnd, R_USE_ENCRYPT);
+ a->ClientOption->UseCompress = IsChecked(hWnd, R_USE_COMPRESS);
+ a->ClientOption->NoRoutingTracking = IsChecked(hWnd, R_NO_ROUTING);
+ a->ClientOption->DisableQoS = IsChecked(hWnd, R_DISABLE_QOS);
+ a->ClientOption->NoUdpAcceleration = IsChecked(hWnd, R_DISABLE_UDP);
+
+ if (a->LinkMode)
+ {
+ a->ClientOption->RequireBridgeRoutingMode = true;
+ a->ClientOption->RequireMonitorMode = false;
+ }
+ else
+ {
+ a->ClientOption->RequireBridgeRoutingMode = IsChecked(hWnd, R_BRIDGE);
+ a->ClientOption->RequireMonitorMode = IsChecked(hWnd, R_MONITOR);
+ }
+
+ EndDialog(hWnd, true);
+
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ switch (LOWORD(wParam))
+ {
+ case C_NUM_TCP:
+ case E_INTERVAL:
+ case E_DISCONNECT_SPAN:
+ case R_USE_DISCONNECT:
+ case R_USE_HALF_CONNECTION:
+ CmDetailDlgUpdate(hWnd, a);
+ break;
+ }
+ switch (wParam)
+ {
+ case R_USE_DISCONNECT:
+ if (IsChecked(hWnd, R_USE_DISCONNECT))
+ {
+ FocusEx(hWnd, E_DISCONNECT_SPAN);
+ }
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Advanced Settings dialog
+bool CmDetailDlg(HWND hWnd, CM_ACCOUNT *a)
+{
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return false;
+ }
+
+ return Dialog(hWnd, D_CM_DETAIL, CmDetailDlgProc, a);
+}
+
+// Update the account editing dialog procedure
+void CmEditAccountDlgUpdate(HWND hWnd, CM_ACCOUNT *a)
+{
+ bool ok = true;
+ char str[MAX_SIZE];
+ bool locked;
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+ locked = a->LockMode;
+
+ if (a->Inited == false)
+ {
+ return;
+ }
+
+ if (a->EditMode)
+ {
+ Disable(hWnd, E_ACCOUNT_NAME);
+ }
+
+ // The name of connection settings
+ GetTxt(hWnd, E_ACCOUNT_NAME, a->ClientOption->AccountName, sizeof(a->ClientOption->AccountName));
+ UniTrim(a->ClientOption->AccountName);
+
+ // Host name
+ GetTxtA(hWnd, E_HOSTNAME, a->ClientOption->Hostname, sizeof(a->ClientOption->Hostname));
+ Trim(a->ClientOption->Hostname);
+
+ // Port number
+ a->ClientOption->Port = GetInt(hWnd, C_PORT);
+
+ // HUB name
+ GetTxtA(hWnd,C_HUBNAME, a->ClientOption->HubName, sizeof(a->ClientOption->HubName));
+
+ // Type of proxy
+ a->ClientOption->ProxyType = PROXY_DIRECT;
+ if (IsChecked(hWnd, R_HTTPS))
+ {
+ a->ClientOption->ProxyType = PROXY_HTTP;
+ }
+ if (IsChecked(hWnd, R_SOCKS))
+ {
+ a->ClientOption->ProxyType = PROXY_SOCKS;
+ }
+
+ // To validate the server certificate
+ a->CheckServerCert = IsChecked(hWnd, R_CHECK_CERT);
+
+ if (a->NatMode)
+ {
+ Disable(hWnd, R_CHECK_CERT);
+ Disable(hWnd, B_TRUST);
+ }
+
+ if (a->HideTrustCert)
+ {
+ Disable(hWnd, B_TRUST);
+ }
+
+ // Device name
+ StrCpy(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName), "");
+ if (LvIsSelected(hWnd, L_VLAN))
+ {
+ wchar_t *s = LvGetStr(hWnd, L_VLAN, LvGetSelected(hWnd, L_VLAN), 0);
+ if (s != NULL)
+ {
+ char str[MAX_SIZE];
+ UniToStr(str, sizeof(str), s);
+ CmPrintNameToVLanName(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName), str);
+ Free(s);
+ }
+ }
+
+ // User authentication
+ a->ClientAuth->AuthType = CbGetSelect(hWnd, C_TYPE);
+ GetTxtA(hWnd, E_USERNAME, a->ClientAuth->Username, sizeof(a->ClientAuth->Username));
+ Trim(a->ClientAuth->Username);
+ switch (a->ClientAuth->AuthType)
+ {
+ case CLIENT_AUTHTYPE_PASSWORD:
+ // Password authentication
+ GetTxtA(hWnd, E_PASSWORD, str, sizeof(str));
+ if (StrCmp(str, HIDDEN_PASSWORD) != 0)
+ {
+ HashPassword(a->ClientAuth->HashedPassword, a->ClientAuth->Username, str);
+ }
+ break;
+ case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+ // Plaintext password authentication
+ GetTxtA(hWnd, E_PASSWORD, str, sizeof(str));
+ if (StrCmp(str, HIDDEN_PASSWORD) != 0)
+ {
+ StrCpy(a->ClientAuth->PlainPassword, sizeof(a->ClientAuth->PlainPassword), str);
+ }
+ break;
+ }
+
+ // Reconnection option
+ if ((a->LinkMode || a->NatMode) || a->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE)
+ {
+ Disable(hWnd, R_RETRY);
+ }
+ else
+ {
+ Enable(hWnd, R_RETRY);
+ }
+
+ if (IsChecked(hWnd, R_RETRY) == false)
+ {
+ a->ClientOption->NumRetry = 0;
+ }
+ else
+ {
+ if (IsChecked(hWnd, R_INFINITE))
+ {
+ a->ClientOption->NumRetry = INFINITE;
+ }
+ else
+ {
+ a->ClientOption->NumRetry = GetInt(hWnd, E_RETRY_NUM);
+ }
+ }
+ a->ClientOption->RetryInterval = GetInt(hWnd, E_RETRY_SPAN);
+
+ a->ClientOption->NoTls1 = IsChecked(hWnd, R_NOTLS1);
+
+ // Information determining
+ if (UniStrLen(a->ClientOption->AccountName) == 0 && a->NatMode == false)
+ {
+ ok = false;
+ }
+ if (StrLen(a->ClientOption->Hostname) == 0)
+ {
+ ok = false;
+ }
+ if (a->ClientOption->Port == 0 || a->ClientOption->Port >= 65536)
+ {
+ ok = false;
+ }
+ if (StrLen(a->ClientOption->HubName) == 0)
+ {
+ ok = false;
+ }
+ if (StrLen(a->ClientAuth->Username) == 0)
+ {
+ ok = false;
+ }
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)
+ {
+ if (a->ClientAuth->ClientK == NULL || a->ClientAuth->ClientX == NULL)
+ {
+ ok = false;
+ }
+ }
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE)
+ {
+ if (IsEmptyStr(a->ClientAuth->SecurePrivateKeyName) || IsEmptyStr(a->ClientAuth->SecurePublicCertName))
+ {
+ ok = false;
+ }
+ }
+
+ // Display update
+ if (IsChecked(hWnd, R_RETRY) && IsEnable(hWnd, R_RETRY))
+ {
+ if (a->LinkMode == false && a->NatMode == false)
+ {
+ Enable(hWnd, R_INFINITE);
+ Enable(hWnd, E_RETRY_SPAN);
+ Enable(hWnd, S_RETRY_SPAN_1);
+ Enable(hWnd, S_RETRY_SPAN_2);
+ }
+ else
+ {
+ Disable(hWnd, R_INFINITE);
+ Disable(hWnd, E_RETRY_SPAN);
+ Disable(hWnd, S_RETRY_SPAN_1);
+ Disable(hWnd, S_RETRY_SPAN_2);
+ }
+ if (IsChecked(hWnd, R_INFINITE) == false)
+ {
+ Enable(hWnd, E_RETRY_NUM);
+ Enable(hWnd, S_RETRY_NUM_1);
+ Enable(hWnd, S_RETRY_NUM_2);
+ if (GetInt(hWnd, E_RETRY_NUM) == 0)
+ {
+ ok = false;
+ }
+ }
+ else
+ {
+ Disable(hWnd, E_RETRY_NUM);
+ Disable(hWnd, S_RETRY_NUM_1);
+ Disable(hWnd, S_RETRY_NUM_2);
+ }
+ }
+ else
+ {
+ Disable(hWnd, E_RETRY_NUM);
+ Disable(hWnd, E_RETRY_SPAN);
+ Disable(hWnd, R_INFINITE);
+ Disable(hWnd, S_RETRY_NUM_1);
+ Disable(hWnd, S_RETRY_NUM_2);
+ Disable(hWnd, S_RETRY_SPAN_1);
+ Disable(hWnd, S_RETRY_SPAN_2);
+ }
+
+ if (a->NatMode == false)
+ {
+ if (a->ServerCert == NULL)
+ {
+ SetText(hWnd, B_SERVER_CERT, _UU("CM_SERVER_CERT_1"));
+ Disable(hWnd, B_VIEW_SERVER_CERT);
+ }
+ else
+ {
+ SetText(hWnd, B_SERVER_CERT, _UU("CM_SERVER_CERT_2"));
+ Enable(hWnd, B_VIEW_SERVER_CERT);
+ }
+ }
+ else
+ {
+ Disable(hWnd, B_VIEW_SERVER_CERT);
+ Disable(hWnd, B_SERVER_CERT);
+ }
+
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT || a->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE)
+ {
+ wchar_t tmp[MAX_SIZE * 2];
+ wchar_t issuer[MAX_SIZE];
+ wchar_t subject[MAX_SIZE];
+ wchar_t expires[MAX_SIZE];
+
+ SetIcon(hWnd, S_CERT, (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT) ? ICO_CERT : ICO_SECURE);
+
+ Hide(hWnd, S_PASSWORD);
+ Hide(hWnd, E_PASSWORD);
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)
+ {
+ if (a->ClientAuth->ClientX != NULL)
+ {
+ Enable(hWnd, B_VIEW_CLIENT_CERT);
+ SetText(hWnd, B_REGIST_CLIENT_CERT, _UU("CM_CLIENT_CERT_2"));
+ GetPrintNameFromName(issuer, sizeof(issuer), a->ClientAuth->ClientX->issuer_name);
+ GetPrintNameFromName(subject, sizeof(subject), a->ClientAuth->ClientX->subject_name);
+ GetDateStrEx64(expires, sizeof(expires), SystemToLocal64(a->ClientAuth->ClientX->notAfter), NULL);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_CERT_INFO"), subject, issuer, expires);
+ }
+ else
+ {
+ Disable(hWnd, B_VIEW_CLIENT_CERT);
+ SetText(hWnd, B_REGIST_CLIENT_CERT, _UU("CM_CLIENT_CERT_1"));
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_NO_CERT"));
+ }
+ SetText(hWnd, B_VIEW_CLIENT_CERT, _UU("CM_VIEW_CLIENT_CERT"));
+
+ Enable(hWnd, B_REGIST_CLIENT_CERT);
+ }
+ else
+ {
+ if (IsEmptyStr(a->ClientAuth->SecurePrivateKeyName) || IsEmptyStr(a->ClientAuth->SecurePublicCertName))
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_NO_SECURE"));
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_CERT_SECURE_INFO"),
+ a->ClientAuth->SecurePublicCertName, a->ClientAuth->SecurePrivateKeyName);
+ }
+
+ SetText(hWnd, B_VIEW_CLIENT_CERT, _UU("CM_SELECT_SECURE_DEVICE"));
+ SetText(hWnd, B_REGIST_CLIENT_CERT, _UU("CM_SELECT_CERT_INCARD"));
+ Enable(hWnd, B_VIEW_CLIENT_CERT);
+
+ if (SmGetCurrentSecureIdFromReg() == 0)
+ {
+ Disable(hWnd, B_REGIST_CLIENT_CERT);
+ }
+ else
+ {
+ Enable(hWnd, B_REGIST_CLIENT_CERT);
+ }
+ }
+ SetText(hWnd, S_CERT_INFO, tmp);
+ Show(hWnd, S_CERT);
+ Show(hWnd, S_CERT_INFO);
+ Show(hWnd, B_VIEW_CLIENT_CERT);
+ Show(hWnd, B_REGIST_CLIENT_CERT);
+ }
+ else
+ {
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_ANONYMOUS)
+ {
+ Hide(hWnd, S_PASSWORD);
+ Hide(hWnd, E_PASSWORD);
+ }
+ else
+ {
+ Show(hWnd, S_PASSWORD);
+ Show(hWnd, E_PASSWORD);
+ }
+ Hide(hWnd, S_CERT);
+ Hide(hWnd, S_CERT_INFO);
+ Hide(hWnd, B_VIEW_CLIENT_CERT);
+ Hide(hWnd, B_REGIST_CLIENT_CERT);
+ }
+
+ if (a->ClientOption->ProxyType != PROXY_DIRECT)
+ {
+ Enable(hWnd, B_PROXY_CONFIG);
+ if (StrLen(a->ClientOption->ProxyName) == 0)
+ {
+ ok = false;
+ }
+ if (a->ClientOption->ProxyPort == 0)
+ {
+ ok = false;
+ }
+ }
+ else
+ {
+ Disable(hWnd, B_PROXY_CONFIG);
+ }
+
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_PASSWORD)
+ {
+ bool b = true;
+
+ if (ok == false)
+ {
+ b = false;
+ }
+
+ if (a->LinkMode == false && a->NatMode == false)
+ {
+ SetEnable(hWnd, B_CHANGE_PASSWORD, b);
+ SetEnable(hWnd, S_CHANGE_PASSWORD, b);
+ Show(hWnd, B_CHANGE_PASSWORD);
+ Show(hWnd, S_CHANGE_PASSWORD);
+ }
+ else
+ {
+ Hide(hWnd, B_CHANGE_PASSWORD);
+ Hide(hWnd, S_CHANGE_PASSWORD);
+ }
+ }
+ else
+ {
+ Hide(hWnd, B_CHANGE_PASSWORD);
+ Hide(hWnd, S_CHANGE_PASSWORD);
+ }
+
+ if ((StrLen(a->ClientOption->DeviceName) == 0) && (a->LinkMode == false && a->NatMode == false))
+ {
+ ok = false;
+ }
+
+ if (a->LinkMode || a->NatMode)
+ {
+ Disable(hWnd, L_VLAN);
+ }
+
+ if (a->EditMode == false)
+ {
+ char tmp[MAX_SIZE];
+ GetTxtA(hWnd, E_HOSTNAME, tmp, sizeof(tmp));
+ Trim(tmp);
+
+ if (StartWith(tmp, "127.") || (StrCmpi(tmp, "localhost") == 0))
+ {
+ if (a->Flag1 == false)
+ {
+ a->Flag1 = true;
+ a->ClientOption->UseEncrypt = a->ClientOption->UseCompress = false;
+ a->ClientOption->MaxConnection = 1;
+ }
+ }
+ }
+
+ a->ClientOption->HideStatusWindow = IsChecked(hWnd, R_HIDE);
+ a->ClientOption->HideNicInfoWindow = IsChecked(hWnd, R_HIDE2);
+
+ if (locked)
+ {
+ SetEnable(hWnd, E_HOSTNAME, false);
+ SetEnable(hWnd, C_PORT, false);
+ SetEnable(hWnd, C_HUBNAME, false);
+ SetEnable(hWnd, S_STATIC2, false);
+ SetEnable(hWnd, S_STATIC3, false);
+ SetEnable(hWnd, S_STATIC4, false);
+ SetEnable(hWnd, S_STATIC5, false);
+ SetEnable(hWnd, S_STATIC66, false);
+ SetEnable(hWnd, S_STATIC7, false);
+ SetEnable(hWnd, S_STATIC11, false);
+ SetEnable(hWnd, R_CHECK_CERT, false);
+ SetEnable(hWnd, B_TRUST, false);
+ SetEnable(hWnd, B_SERVER_CERT, false);
+ SetEnable(hWnd, B_VIEW_SERVER_CERT, false);
+ SetEnable(hWnd, R_RETRY, false);
+ SetEnable(hWnd, S_RETRY_NUM_1, false);
+ SetEnable(hWnd, E_RETRY_NUM, false);
+ SetEnable(hWnd, S_RETRY_NUM_2, false);
+ SetEnable(hWnd, S_RETRY_SPAN_1, false);
+ SetEnable(hWnd, E_RETRY_SPAN, false);
+ SetEnable(hWnd, S_RETRY_SPAN_2, false);
+ SetEnable(hWnd, R_INFINITE, false);
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Initialize the account editing dialog
+void CmEditAccountDlgInit(HWND hWnd, CM_ACCOUNT *a)
+{
+ RPC_CLIENT_ENUM_VLAN v;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+ if (a->LockMode)
+ {
+ SetText(hWnd, S_STATIC1, _UU("CM_EASY_ACCOUNT_WARNING"));
+ }
+
+ // Connection settings name
+ if (a->EditMode || a->NatMode)
+ {
+ Disable(hWnd, E_ACCOUNT_NAME);
+ }
+
+ if (a->NatMode || a->LinkMode)
+ {
+ Hide(hWnd, R_HIDE);
+ Hide(hWnd, R_HIDE2);
+ }
+
+ Check(hWnd, R_HIDE, a->ClientOption->HideStatusWindow);
+ Check(hWnd, R_HIDE2, a->ClientOption->HideNicInfoWindow);
+
+ if (a->NatMode)
+ {
+ Hide(hWnd, E_ACCOUNT_NAME);
+ Hide(hWnd, S_ACCOUNT_NAME);
+ }
+
+ if ((cm != NULL && cm->server_name != NULL) || a->LinkMode)
+ {
+ Hide(hWnd, B_IE);
+ }
+
+ SetText(hWnd, E_ACCOUNT_NAME, a->ClientOption->AccountName);
+
+ // Host name
+ SetTextA(hWnd, E_HOSTNAME, a->ClientOption->Hostname);
+ StrCpy(a->old_server_name, sizeof(a->old_server_name), a->ClientOption->Hostname);
+
+ // Port number
+ CbSetHeight(hWnd, C_PORT, 18);
+ CbAddStr(hWnd, C_PORT, _UU("CM_PORT_1"), 0);
+ CbAddStr(hWnd, C_PORT, _UU("CM_PORT_2"), 0);
+ CbAddStr(hWnd, C_PORT, _UU("CM_PORT_3"), 0);
+ CbAddStr(hWnd, C_PORT, _UU("CM_PORT_4"), 0);
+ SetInt(hWnd, C_PORT, a->ClientOption->Port);
+
+ // Virtual HUB name
+ CbSetHeight(hWnd, C_HUBNAME, 18);
+ SetTextA(hWnd, C_HUBNAME, a->ClientOption->HubName);
+
+ // Type of proxy
+ Check(hWnd, R_DIRECT_TCP, a->ClientOption->ProxyType == PROXY_DIRECT);
+ Check(hWnd, R_HTTPS, a->ClientOption->ProxyType == PROXY_HTTP);
+ Check(hWnd, R_SOCKS, a->ClientOption->ProxyType == PROXY_SOCKS);
+
+ // Verify the server certificate
+ Check(hWnd, R_CHECK_CERT, a->CheckServerCert);
+
+ // LAN card list
+ if (a->NatMode == false && a->LinkMode == false)
+ {
+ Zero(&v, sizeof(v));
+ CcEnumVLan(cm->Client, &v);
+ LvInit(hWnd, L_VLAN);
+ LvInsertColumn(hWnd, L_VLAN, 0, L"DeviceName", 345);
+ for (i = 0;i < v.NumItem;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+ CmVLanNameToPrintName(str, sizeof(str), v.Items[i]->DeviceName);
+ StrToUni(tmp, sizeof(tmp), str);
+ LvInsert(hWnd, L_VLAN, ICO_NIC_ONLINE, NULL, 1, tmp);
+ }
+// LvAutoSize(hWnd, L_VLAN);
+
+ if (v.NumItem == 1)
+ {
+ // If only one virtual LAN card exists, initially select it
+ LvSelect(hWnd, L_VLAN, 0);
+ }
+
+ CiFreeClientEnumVLan(&v);
+ }
+
+ // Select the LAN card
+ if (StrLen(a->ClientOption->DeviceName) != 0)
+ {
+ char str[MAX_SIZE];
+ wchar_t tmp[MAX_SIZE];
+ UINT index;
+ CmVLanNameToPrintName(str, sizeof(str), a->ClientOption->DeviceName);
+ StrToUni(tmp, sizeof(tmp), str);
+ index = LvSearchStr(hWnd, L_VLAN, 0, tmp);
+ if (index != INFINITE)
+ {
+ LvSelect(hWnd, L_VLAN, index);
+ }
+ }
+
+ // Authentication type
+ CbSetHeight(hWnd, C_TYPE, 18);
+ CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_0"), CLIENT_AUTHTYPE_ANONYMOUS);
+ CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_1"), CLIENT_AUTHTYPE_PASSWORD);
+ CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_2"), CLIENT_AUTHTYPE_PLAIN_PASSWORD);
+
+ if (a->HideClientCertAuth == false)
+ {
+ // Certificate authentication is not available when HideClientCertAuth is true
+ CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_3"), CLIENT_AUTHTYPE_CERT);
+ }
+
+ if (a->HideSecureAuth == false)
+ {
+ // Authentication using a smart card
+ CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_4"), CLIENT_AUTHTYPE_SECURE);
+ }
+
+ // Select an authentication
+ CbSelect(hWnd, C_TYPE, a->ClientAuth->AuthType);
+
+ // User name
+ SetTextA(hWnd, E_USERNAME, a->ClientAuth->Username);
+
+ // Password
+ if (a->EditMode)
+ {
+ SetTextA(hWnd, E_PASSWORD, HIDDEN_PASSWORD);
+ }
+
+ // Reconnection times
+ if (a->ClientOption->NumRetry == 0)
+ {
+ Check(hWnd, R_RETRY, false);
+ }
+ else
+ {
+ Check(hWnd, R_RETRY, true);
+ if (a->ClientOption->NumRetry == INFINITE)
+ {
+ Check(hWnd, R_INFINITE, true);
+ }
+ else
+ {
+ Check(hWnd, R_INFINITE, false);
+ SetInt(hWnd, E_RETRY_NUM, a->ClientOption->NumRetry);
+ }
+ }
+ SetIntEx(hWnd, E_RETRY_SPAN, a->ClientOption->RetryInterval);
+
+ Check(hWnd, R_NOTLS1, a->ClientOption->NoTls1);
+
+ // Title
+ if (a->NatMode == false)
+ {
+ if (a->EditMode == false)
+ {
+ SetText(hWnd, 0, _UU("CM_ACCOUNT_TITLE_1"));
+ FocusEx(hWnd, E_ACCOUNT_NAME);
+ }
+ else
+ {
+ SetText(hWnd, 0, _UU("CM_ACCOUNT_TITLE_2"));
+ FormatText(hWnd, 0, a->ClientOption->AccountName);
+ FocusEx(hWnd, E_HOSTNAME);
+ }
+ }
+ else
+ {
+ SetText(hWnd, 0, _UU("NM_ACCOUNT_TITLE"));
+ FocusEx(hWnd, E_HOSTNAME);
+ }
+
+ if (a->LinkMode || a->NatMode)
+ {
+ Hide(hWnd, L_VLAN);
+
+ if (a->NatMode == false)
+ {
+ SetText(hWnd, S_VLAN_GROUP, _UU("SM_LINK_POLICY_GROUP"));
+ Show(hWnd, S_POLICY_1);
+ Show(hWnd, S_POLICY_2);
+ Show(hWnd, B_POLICY);
+ }
+ else
+ {
+ Hide(hWnd, S_VLAN_GROUP);
+ Show(hWnd, S_ROUTER_LOGO);
+ }
+ }
+
+ // Display update
+ a->Inited = true;
+ CmEditAccountDlgUpdate(hWnd, a);
+}
+
+// Account editing dialog procedure
+UINT CmEditAccountDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ CM_ACCOUNT *a = (CM_ACCOUNT *)param;
+ NMHDR *n;
+ X *x;
+ K *k;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmEditAccountDlgInit(hWnd, a);
+ if (a->EditMode == false && a->LinkMode == false && a->NatMode == false)
+ {
+ SetTimer(hWnd, 1, 100, NULL);
+ }
+ break;
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ {
+ CM_INTERNET_SETTING s;
+
+ KillTimer(hWnd, 1);
+
+ Zero(&s, sizeof(s));
+ CmGetSystemInternetSetting(&s);
+
+ if (s.ProxyType != PROXY_DIRECT)
+ {
+ if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO,
+ _UU("CM_WOULDYOULOAD_IE_PROXY"),
+ s.ProxyHostName) == IDYES)
+ {
+ Command(hWnd, B_IE);
+ }
+ }
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_ACCOUNT_NAME:
+ case E_HOSTNAME:
+ case C_PORT:
+ case C_HUBNAME:
+ case R_DIRECT_TCP:
+ case R_HTTPS:
+ case R_SOCKS:
+ case R_CHECK_CERT:
+ case C_TYPE:
+ case E_USERNAME:
+ case E_PASSWORD:
+ case R_RETRY:
+ case E_RETRY_NUM:
+ case E_RETRY_SPAN:
+ case R_INFINITE:
+ CmEditAccountDlgUpdate(hWnd, a);
+ break;
+ }
+ switch (HIWORD(wParam))
+ {
+ case EN_KILLFOCUS:
+ switch (LOWORD(wParam))
+ {
+ case E_HOSTNAME:
+ CmEditAccountDlgStartEnumHub(hWnd, a);
+ break;
+ }
+ break;
+ case BN_KILLFOCUS:
+ switch (LOWORD(wParam))
+ {
+ case R_DIRECT_TCP:
+ case R_HTTPS:
+ case R_SOCKS:
+ CmEditAccountDlgStartEnumHub(hWnd, a);
+ break;
+ }
+ break;
+ case CBN_KILLFOCUS:
+ switch (LOWORD(wParam))
+ {
+ case C_PORT:
+ CmEditAccountDlgStartEnumHub(hWnd, a);
+ break;
+ }
+ break;
+ }
+ if (HIWORD(wParam) == 0)
+ {
+ CmEditAccountDlgUpdate(hWnd, a);
+ }
+ switch (wParam)
+ {
+ case B_POLICY:
+ // Policy
+ if (a->LinkMode || a->NatMode)
+ {
+ a->Policy.Access = true;
+ a->Policy.MonitorPort = false;
+ SmPolicyDlgEx2(hWnd, &a->Policy, _UU("SM_LINK_POLICY_CAPTION"), true, a->PolicyVer);
+ a->Policy.Access = true;
+ a->Policy.MonitorPort = false;
+ }
+ break;
+ case IDOK:
+ CmEditAccountDlgUpdate(hWnd, a);
+ CmEditAccountDlgOnOk(hWnd, a);
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ case B_PROXY_CONFIG:
+ // Proxy Settings
+ if (CmProxyDlg(hWnd, a->ClientOption))
+ {
+ UINT n = GetInt(hWnd, C_PORT);
+ if (a->ClientOption->ProxyType == PROXY_HTTP &&
+ n != 443)
+ {
+ // Show a warning message if the destination port is
+ // other than 443 and HTTP proxy is used
+ if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("CM_HTTP_PROXY_WARNING"), n) == IDYES)
+ {
+ // Change the port number to 443
+ SetText(hWnd, C_PORT, _UU("CM_PORT_2"));
+ }
+ }
+ CmEditAccountDlgStartEnumHub(hWnd, a);
+ CmEditAccountDlgUpdate(hWnd, a);
+ }
+ break;
+ case B_IE:
+ // Use the IE settings
+ if(cm->server_name == NULL)
+ {
+ CmProxyDlgUseForIE(hWnd, a->ClientOption);
+ CmEditAccountDlgUpdate(hWnd, a);
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_PROXY_FROM_IE"));
+ }
+ break;
+ case B_TRUST:
+ // CA
+ if (a->LinkMode == false)
+ {
+ CmTrustDlg(hWnd);
+ }
+ else
+ {
+ SmCaDlg(hWnd, a->Hub);
+ }
+ break;
+ case B_SERVER_CERT:
+ // Server certificate registration / delete
+ if (a->ServerCert == NULL)
+ {
+ if (CmLoadXFromFileOrSecureCard(hWnd, &x))
+ {
+ a->ServerCert = x;
+ CmEditAccountDlgUpdate(hWnd, a);
+ }
+ }
+ else
+ {
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_DELETE_SERVER_CERT")) == IDYES)
+ {
+ FreeX(a->ServerCert);
+ a->ServerCert = NULL;
+ CmEditAccountDlgUpdate(hWnd, a);
+ }
+ }
+ break;
+ case B_VIEW_SERVER_CERT:
+ // Show the server certificate
+ if (a->ServerCert != NULL)
+ {
+ X *issuer = CmGetIssuer(a->ServerCert);
+ CertDlg(hWnd, a->ServerCert, issuer, true);
+ FreeX(issuer);
+ }
+ break;
+ case B_VIEW_CLIENT_CERT:
+ if (a->ClientAuth->AuthType != CLIENT_AUTHTYPE_SECURE)
+ {
+ // Show the client certificate
+ if (a->ClientAuth->ClientX != NULL)
+ {
+ X *issuer = CmGetIssuer(a->ClientAuth->ClientX);
+ CertDlg(hWnd, a->ClientAuth->ClientX, issuer, true);
+ FreeX(issuer);
+ }
+ }
+ else
+ {
+ UINT id;
+ // Select the type of smart card
+ SmSelectSecureId(hWnd);
+ id = SmGetCurrentSecureIdFromReg();
+ if (id != 0)
+ {
+ if (cm->server_name == NULL)
+ {
+ RPC_USE_SECURE t;
+
+ Zero(&t, sizeof(t));
+ t.DeviceId = id;
+ CcUseSecure(cm->Client, &t);
+ }
+ }
+ CmEditAccountDlgUpdate(hWnd, a);
+ }
+ break;
+ case B_REGIST_CLIENT_CERT:
+ if (a->ClientAuth->AuthType != CLIENT_AUTHTYPE_SECURE)
+ {
+ // Client certificate registration / deletion
+ if (a->ClientAuth->ClientX == NULL)
+ {
+ if (CmLoadXAndK(hWnd, &x, &k))
+ {
+ a->ClientAuth->ClientX = x;
+ a->ClientAuth->ClientK = k;
+ CmEditAccountDlgUpdate(hWnd, a);
+ }
+ }
+ else
+ {
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_DELETE_CLIENT_CERT")) == IDYES)
+ {
+ FreeX(a->ClientAuth->ClientX);
+ FreeK(a->ClientAuth->ClientK);
+ a->ClientAuth->ClientX = NULL;
+ a->ClientAuth->ClientK = NULL;
+ CmEditAccountDlgUpdate(hWnd, a);
+ }
+ }
+ }
+ else
+ {
+ char cert[MAX_SECURE_DEVICE_FILE_LEN + 1], priv[MAX_SECURE_DEVICE_FILE_LEN + 1];
+
+ // Select a certificate in the smart card
+ if (SmSelectKeyPairEx(hWnd, cert, sizeof(cert), priv, sizeof(priv), CmGetSecureBitmapId(a->ClientOption->Hostname)))
+ {
+ StrCpy(a->ClientAuth->SecurePublicCertName, sizeof(a->ClientAuth->SecurePublicCertName), cert);
+ StrCpy(a->ClientAuth->SecurePrivateKeyName, sizeof(a->ClientAuth->SecurePrivateKeyName), priv);
+ CmEditAccountDlgUpdate(hWnd, a);
+ }
+ }
+ break;
+ case B_DETAIL:
+ // Advanced communication settings
+ if (CmDetailDlg(hWnd, a))
+ {
+ CmEditAccountDlgUpdate(hWnd, a);
+ }
+ break;
+ case B_CHANGE_PASSWORD:
+ // Change the password
+ CmChangePassword(hWnd, a->ClientOption, a->ClientOption->HubName,
+ a->ClientAuth->Username);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_VLAN:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ CmEditAccountDlgUpdate(hWnd, a);
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Update the proxy server settings
+void CmProxyDlgUpdate(HWND hWnd, CLIENT_OPTION *a)
+{
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+ if (IsEmpty(hWnd, E_HOSTNAME))
+ {
+ ok = false;
+ }
+ if (GetInt(hWnd, C_PORT) == 0)
+ {
+ ok = false;
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Proxy server settings dialog c
+UINT CmProxyDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ CLIENT_OPTION *a = (CLIENT_OPTION *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetTextA(hWnd, E_HOSTNAME, a->ProxyName);
+ CbSetHeight(hWnd, C_PORT, 18);
+ CbAddStr(hWnd, C_PORT, L"8080", 0);
+ CbAddStr(hWnd, C_PORT, L"1080", 0);
+ CbAddStr(hWnd, C_PORT, L"80", 0);
+ CbAddStr(hWnd, C_PORT, L"3128", 0);
+ CbAddStr(hWnd, C_PORT, L"443", 0);
+ CbAddStr(hWnd, C_PORT, L"9821", 0);
+ CbAddStr(hWnd, C_PORT, L"9801", 0);
+ SetIntEx(hWnd, C_PORT, a->ProxyPort);
+ SetTextA(hWnd, E_USERNAME, a->ProxyUsername);
+ SetTextA(hWnd, E_PASSWORD, a->ProxyPassword);
+ if (a->ProxyPort == 0)
+ {
+ if (a->ProxyType == PROXY_HTTP)
+ {
+ SetInt(hWnd, C_PORT, 8080);
+ }
+ else
+ {
+ SetInt(hWnd, C_PORT, 1080);
+ }
+ }
+ CmProxyDlgUpdate(hWnd, a);
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_HOSTNAME:
+ case C_PORT:
+ case E_USERNAME:
+ case E_PASSWORD:
+ CmProxyDlgUpdate(hWnd, a);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ GetTxtA(hWnd, E_HOSTNAME, a->ProxyName, sizeof(a->ProxyName));
+ GetTxtA(hWnd, E_USERNAME, a->ProxyUsername, sizeof(a->ProxyUsername));
+ GetTxtA(hWnd, E_PASSWORD, a->ProxyPassword, sizeof(a->ProxyPassword));
+ a->ProxyPort = GetInt(hWnd, C_PORT);
+ EndDialog(hWnd, true);
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Proxy server settings
+bool CmProxyDlg(HWND hWnd, CLIENT_OPTION *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return false;
+ }
+
+ return Dialog(hWnd, D_CM_PROXY, CmProxyDlgProc, a);
+}
+
+// Get issuer of the specified certificate if it is known
+X *CmGetIssuer(X *x)
+{
+ RPC_GET_ISSUER a;
+ X *ret;
+ // Validate arguments
+ if (x == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&a, sizeof(a));
+ a.x = CloneX(x);
+ if (CALLEX(cm->hMainWnd, CcGetIssuer(cm->Client, &a)) == 0)
+ {
+ ret = CloneX(a.issuer_x);
+ }
+ else
+ {
+ ret = NULL;
+ }
+
+ CiFreeGetIssuer(&a);
+
+ return ret;
+}
+
+// Initialize the dialog
+void CmLoadXFromFileOrSecureCardDlgInit(HWND hWnd, CM_LOADX *p)
+{
+ UINT current;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ current = MsRegReadInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "CertLoadSource");
+
+ Check(hWnd, R_FROM_FILE, current == 0);
+ Check(hWnd, R_FROM_SECURE, current != 0);
+
+ SetFont(hWnd, S_INFO, Font(0, true));
+
+ CmLoadXFromFileOrSecureCardDlgUpdate(hWnd, p);
+}
+
+// Update the dialog control
+void CmLoadXFromFileOrSecureCardDlgUpdate(HWND hWnd, CM_LOADX *p)
+{
+ SECURE_DEVICE *dev;
+ wchar_t tmp[MAX_SIZE];
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ dev = GetSecureDevice(SmGetCurrentSecureIdFromReg());
+ if (dev == NULL)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SEC_CURRENT_NO_DEVICE"));
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SEC_CURRENT_DEVICE"), dev->DeviceName);
+ }
+
+ SetText(hWnd, S_INFO, tmp);
+
+ if (IsChecked(hWnd, R_FROM_SECURE))
+ {
+ if (dev == NULL)
+ {
+ ok = false;
+ }
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+ SetEnable(hWnd, B_SELECT, IsChecked(hWnd, R_FROM_SECURE));
+ SetEnable(hWnd, S_CERT, IsChecked(hWnd, R_FROM_SECURE));
+ SetEnable(hWnd, S_FILE, IsChecked(hWnd, R_FROM_FILE));
+}
+
+// Certificate reading selection dialog procedure
+UINT CmLoadXFromFileOrSecureCardDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ CM_LOADX *p = (CM_LOADX *)param;
+ X *x;
+ UINT current;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CmLoadXFromFileOrSecureCardDlgInit(hWnd, p);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ current = (IsChecked(hWnd, R_FROM_FILE)) ? 0 : 1;
+ MsRegWriteInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "CertLoadSource", current);
+
+ if (current == 0)
+ {
+ // From file
+ if (CmLoadX(hWnd, &x))
+ {
+ p->x = x;
+ EndDialog(hWnd, true);
+ }
+ }
+ else
+ {
+ // From the smart card
+ char name[MAX_SIZE];
+
+ // Select the certificate name in the card
+ if (SmSelectKeyPair(hWnd, name, sizeof(name), NULL, 0))
+ {
+ // Read
+ WINUI_SECURE_BATCH batch[] =
+ {
+ {WINUI_SECURE_READ_CERT, name, true, NULL, NULL, NULL, NULL, NULL, NULL},
+ };
+
+ // Do reading
+ if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), SmGetCurrentSecureIdFromReg(), 0))
+ {
+ // Success
+ p->x = batch[0].OutputX;
+ EndDialog(hWnd, true);
+ }
+ }
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case R_FROM_FILE:
+ CmLoadXFromFileOrSecureCardDlgUpdate(hWnd, p);
+ break;
+
+ case R_FROM_SECURE:
+ CmLoadXFromFileOrSecureCardDlgUpdate(hWnd, p);
+ break;
+
+ case B_SELECT:
+ SmSelectSecureId(hWnd);
+ CmLoadXFromFileOrSecureCardDlgUpdate(hWnd, p);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Read certificate from a file or a smart card
+bool CmLoadXFromFileOrSecureCard(HWND hWnd, X **x)
+{
+ CM_LOADX p;
+ // Validate arguments
+ if (x == NULL)
+ {
+ return false;
+ }
+
+ Zero(&p, sizeof(p));
+ if (Dialog(hWnd, D_CM_LOAD_X, CmLoadXFromFileOrSecureCardDlgProc, &p) == false)
+ {
+ return false;
+ }
+
+ *x = p.x;
+
+ return true;
+}
+
+// Read the certificate
+bool CmLoadX(HWND hWnd, X **x)
+{
+ return CmLoadXEx(hWnd, x, NULL, 0);
+}
+bool CmLoadXEx(HWND hWnd, X **x, char *filename, UINT size)
+{
+ wchar_t *filename_w = CopyStrToUni(filename);
+ bool ret;
+
+ ret = CmLoadXExW(hWnd, x, filename_w, size);
+
+ Free(filename_w);
+
+ return ret;
+}
+bool CmLoadXExW(HWND hWnd, X **x, wchar_t *filename, UINT size)
+{
+ wchar_t *s;
+ bool is_p12;
+ wchar_t tmp[MAX_SIZE];
+ K *k;
+ // Validate arguments
+ if (x == NULL)
+ {
+ return false;
+ }
+
+ // Read the certificate
+ s = OpenDlg(hWnd, _UU("DLG_CERT_OR_P12_FILTER"), _UU("DLG_OPEN_CERT"));
+ if (s == NULL)
+ {
+ return false;
+ }
+ UniStrCpy(tmp, sizeof(tmp), s);
+ if (filename != NULL)
+ {
+ UniStrCpy(filename, size, tmp);
+ }
+ Free(s);
+ if (UniEndWith(tmp, L".p12") || UniEndWith(tmp, L".pfx"))
+ {
+ is_p12 = true;
+ }
+ else
+ {
+ is_p12 = false;
+ }
+
+ if (is_p12)
+ {
+ // Processing of PKCS#12
+ BUF *b = ReadDumpW(tmp);
+ P12 *p12;
+ if (b == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+ return false;
+ }
+ p12 = BufToP12(b);
+ if (p12 == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+ FreeBuf(b);
+ return false;
+ }
+ if (IsEncryptedP12(p12) == false)
+ {
+ if (ParseP12(p12, x, &k, NULL) == false)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+ FreeP12(p12);
+ FreeBuf(b);
+ return false;
+ }
+ }
+ else
+ {
+ char password[MAX_SIZE];
+ if (PassphraseDlg(hWnd, password, sizeof(password), b, true) == false)
+ {
+ FreeP12(p12);
+ FreeBuf(b);
+ return false;
+ }
+ else
+ {
+ if (ParseP12(p12, x, &k, password) == false)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+ FreeP12(p12);
+ FreeBuf(b);
+ return false;
+ }
+ }
+ }
+ FreeP12(p12);
+ FreeBuf(b);
+ FreeK(k);
+ return true;
+ }
+ else
+ {
+ // Processing of X509
+ BUF *b = ReadDumpW(tmp);
+ X *x509;
+ if (b == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+ return false;
+ }
+
+ x509 = BufToX(b, IsBase64(b));
+ FreeBuf(b);
+ if (x509 == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_X509_W"), tmp);
+ return false;
+ }
+
+ *x = x509;
+ return true;
+ }
+}
+
+// Read the secret key
+bool CmLoadK(HWND hWnd, K **k)
+{
+ return CmLoadKEx(hWnd, k, NULL, 0);
+}
+bool CmLoadKEx(HWND hWnd, K **k, char *filename, UINT size)
+{
+ wchar_t *filename_w = CopyStrToUni(filename);
+ bool ret;
+
+ ret = CmLoadKExW(hWnd, k, filename_w, size);
+
+ Free(filename_w);
+
+ return ret;
+}
+bool CmLoadKExW(HWND hWnd, K **k, wchar_t *filename, UINT size)
+{
+ wchar_t *s;
+ bool is_p12;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (k == NULL)
+ {
+ return false;
+ }
+
+ // Read the certificate
+ s = OpenDlg(hWnd, _UU("DLG_KEY_OR_P12_FILTER"), _UU("DLG_OPEN_KEY"));
+ if (s == NULL)
+ {
+ return false;
+ }
+ UniStrCpy(tmp, sizeof(tmp), s);
+ Free(s);
+ if (filename != NULL)
+ {
+ UniStrCpy(filename, size, tmp);
+ }
+ if (UniEndWith(tmp, L".p12") || UniEndWith(tmp, L".pfx"))
+ {
+ is_p12 = true;
+ }
+ else
+ {
+ is_p12 = false;
+ }
+
+ if (is_p12)
+ {
+ // Processing of PKCS#12
+ BUF *b = ReadDumpW(tmp);
+ P12 *p12;
+ if (b == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+ return false;
+ }
+ p12 = BufToP12(b);
+ if (p12 == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+ FreeBuf(b);
+ return false;
+ }
+ if (IsEncryptedP12(p12) == false)
+ {
+ X *x;
+ if (ParseP12(p12, &x, k, NULL) == false)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+ FreeP12(p12);
+ FreeBuf(b);
+ return false;
+ }
+
+ FreeX(x);
+ }
+ else
+ {
+ char password[MAX_SIZE];
+ if (PassphraseDlg(hWnd, password, sizeof(password), b, true) == false)
+ {
+ FreeP12(p12);
+ FreeBuf(b);
+ return false;
+ }
+ else
+ {
+ X *x;
+ if (ParseP12(p12, &x, k, password) == false)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+ FreeP12(p12);
+ FreeBuf(b);
+ return false;
+ }
+
+ FreeX(x);
+ }
+ }
+ FreeP12(p12);
+ FreeBuf(b);
+ return true;
+ }
+ else
+ {
+ // Processing of private key
+ BUF *b = ReadDumpW(tmp);
+ K *key;
+ if (b == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+ return false;
+ }
+
+ if (IsEncryptedK(b, true) == false)
+ {
+ key = BufToK(b, true, IsBase64(b), NULL);
+ }
+ else
+ {
+ char pass[MAX_SIZE];
+ if (PassphraseDlg(hWnd, pass, sizeof(pass), b, false) == false)
+ {
+ FreeBuf(b);
+ return false;
+ }
+ key = BufToK(b, true, IsBase64(b), pass);
+ }
+
+ if (key == NULL)
+ {
+ FreeBuf(b);
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_KEY_W"), tmp);
+ return false;
+ }
+
+ FreeBuf(b);
+ *k = key;
+ return true;
+ }
+}
+
+// Read a set of certificate and private key
+bool CmLoadXAndK(HWND hWnd, X **x, K **k)
+{
+ wchar_t *s;
+ bool is_p12;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (x == NULL || k == NULL)
+ {
+ return false;
+ }
+START_FIRST:
+
+ // Read the certificate
+ s = OpenDlg(hWnd, _UU("DLG_CERT_OR_P12_FILTER"), _UU("DLG_OPEN_CERT"));
+ if (s == NULL)
+ {
+ return false;
+ }
+ UniStrCpy(tmp, sizeof(tmp), s);
+ Free(s);
+ if (UniEndWith(tmp, L".p12") || UniEndWith(tmp, L".pfx"))
+ {
+ is_p12 = true;
+ }
+ else
+ {
+ is_p12 = false;
+ }
+
+ if (is_p12)
+ {
+ // Processing of PKCS#12
+ BUF *b = ReadDumpW(tmp);
+ P12 *p12;
+ if (b == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+ return false;
+ }
+ p12 = BufToP12(b);
+ if (p12 == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+ FreeBuf(b);
+ return false;
+ }
+ if (IsEncryptedP12(p12) == false)
+ {
+ if (ParseP12(p12, x, k, NULL) == false)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+ FreeP12(p12);
+ FreeBuf(b);
+ return false;
+ }
+ }
+ else
+ {
+ char password[MAX_SIZE];
+ if (PassphraseDlg(hWnd, password, sizeof(password), b, true) == false)
+ {
+ FreeP12(p12);
+ FreeBuf(b);
+ return false;
+ }
+ else
+ {
+ if (ParseP12(p12, x, k, password) == false)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
+ FreeP12(p12);
+ FreeBuf(b);
+ return false;
+ }
+ }
+ }
+ if (CheckXandK(*x, *k) == false)
+ {
+ FreeX(*x);
+ FreeK(*k);
+ FreeP12(p12);
+ FreeBuf(b);
+ if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_RETRYCANCEL, _UU("DLG_BAD_SIGNATURE")) == IDRETRY)
+ {
+ goto START_FIRST;
+ }
+ return false;
+ }
+ FreeP12(p12);
+ FreeBuf(b);
+ return true;
+ }
+ else
+ {
+ // Processing of X509
+ BUF *b = ReadDumpW(tmp);
+ X *x509;
+ K *key;
+ if (b == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+ return false;
+ }
+
+ x509 = BufToX(b, IsBase64(b));
+ FreeBuf(b);
+ if (x509 == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_X509_W"), tmp);
+ return false;
+ }
+
+ // Read the secret key
+ s = OpenDlg(hWnd, _UU("DLG_KEY_FILTER"), _UU("DLG_OPEN_KEY_WITH_CERT"));
+ if (s == NULL)
+ {
+ FreeX(x509);
+ return false;
+ }
+ UniStrCpy(tmp, sizeof(tmp), s);
+ Free(s);
+
+ b = ReadDumpW(tmp);
+ if (b == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
+ FreeX(x509);
+ return false;
+ }
+
+ if (IsEncryptedK(b, true) == false)
+ {
+ key = BufToK(b, true, IsBase64(b), NULL);
+ }
+ else
+ {
+ char pass[MAX_SIZE];
+ if (PassphraseDlg(hWnd, pass, sizeof(pass), b, false) == false)
+ {
+ FreeBuf(b);
+ FreeX(x509);
+ return false;
+ }
+ key = BufToK(b, true, IsBase64(b), pass);
+ }
+
+ if (key == NULL)
+ {
+ FreeBuf(b);
+ FreeX(x509);
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_KEY_W"), tmp);
+ return false;
+ }
+
+ if (CheckXandK(x509, key) == false)
+ {
+ FreeBuf(b);
+ FreeX(x509);
+ FreeK(key);
+ if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_RETRYCANCEL, _UU("DLG_BAD_SIGNATURE")) == IDRETRY)
+ {
+ goto START_FIRST;
+ }
+ return false;
+ }
+
+ FreeBuf(b);
+ *x = x509;
+ *k = key;
+ return true;
+ }
+}
+
+// Virtual HUB enumeration start
+void CmEditAccountDlgStartEnumHub(HWND hWnd, CM_ACCOUNT *a)
+{
+ char server_name[MAX_HOST_NAME_LEN + 1];
+ UINT old_proxy_type;
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+
+ if (StrLen(a->ClientOption->Hostname) == 0)
+ {
+ return;
+ }
+ if (a->ClientOption->Port == 0)
+ {
+ return;
+ }
+ if (a->ClientOption->ProxyType != PROXY_DIRECT &&
+ (StrLen(a->ClientOption->ProxyName) == 0 ||
+ a->ClientOption->ProxyPort == 0))
+ {
+ return;
+ }
+
+ GetTxtA(hWnd, E_HOSTNAME, server_name, sizeof(server_name));
+
+ if (StrCmpi(server_name, a->old_server_name) == 0)
+ {
+ if (CbNum(hWnd, C_HUBNAME) != 0)
+ {
+ return;
+ }
+ }
+ else
+ {
+ StrCpy(a->old_server_name, sizeof(a->old_server_name), server_name);
+ CbReset(hWnd, C_HUBNAME);
+ }
+
+ old_proxy_type = a->ClientOption->ProxyType;
+
+ if (IsChecked(hWnd, R_DIRECT_TCP))
+ {
+ a->ClientOption->ProxyType = PROXY_DIRECT;
+ }
+ if (IsChecked(hWnd, R_HTTPS))
+ {
+ a->ClientOption->ProxyType = PROXY_HTTP;
+ }
+ if (IsChecked(hWnd, R_SOCKS))
+ {
+ a->ClientOption->ProxyType = PROXY_SOCKS;
+ }
+
+ CmEnumHubStart(hWnd, a->ClientOption);
+
+ a->ClientOption->ProxyType = old_proxy_type;
+}
+
+// [OK] button
+void CmEditAccountDlgOnOk(HWND hWnd, CM_ACCOUNT *a)
+{
+ RPC_CLIENT_CREATE_ACCOUNT c;
+ bool b;
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+ if (a->ClientOption->NumRetry != 0 && a->ClientOption->RetryInterval < 5)
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_RETRY_INTERVAL_ERROR"));
+ FocusEx(hWnd, E_RETRY_SPAN);
+ return;
+ }
+
+ CmEditAccountDlgUpdate(hWnd, a);
+
+ if (a->LinkMode == false && a->NatMode == false)
+ {
+ // Save the account
+ Zero(&c, sizeof(c));
+ c.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(c.ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));
+ c.ClientAuth = CopyClientAuth(a->ClientAuth);
+ c.CheckServerCert = a->CheckServerCert;
+ if (a->ServerCert != NULL)
+ {
+ c.ServerCert = CloneX(a->ServerCert);
+ }
+ c.StartupAccount = a->Startup;
+
+ if (a->EditMode == false)
+ {
+ b = CALL(hWnd, CcCreateAccount(cm->Client, &c));
+ }
+ else
+ {
+ b = CALL(hWnd, CcSetAccount(cm->Client, &c));
+ }
+
+ CiFreeClientCreateAccount(&c);
+
+ // Check whether this account is currently running
+ if (b)
+ {
+ RPC_CLIENT_GET_CONNECTION_STATUS st;
+ Zero(&st, sizeof(st));
+ UniStrCpy(st.AccountName, sizeof(st.AccountName), a->ClientOption->AccountName);
+ if (CALL(hWnd, CcGetAccountStatus(cm->Client, &st)))
+ {
+ if (st.Active)
+ {
+ MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("CM_CURRENT_ACTIVE"),
+ st.AccountName);
+ }
+ }
+ }
+
+ if (b)
+ {
+ EndDialog(hWnd, true);
+ }
+ }
+ else
+ {
+ if (a->LinkMode)
+ {
+ // Link mode
+ RPC_CREATE_LINK t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), a->Hub->HubName);
+ t.Online = a->OnlineFlag;
+ Copy(&t.Policy, &a->Policy, sizeof(POLICY));
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(t.ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));
+ t.ClientAuth = CopyClientAuth(a->ClientAuth);
+ t.CheckServerCert = a->CheckServerCert;
+ t.ServerCert = CloneX(a->ServerCert);
+
+ // Save the settings for cascade connection
+ if (a->EditMode)
+ {
+ if (CALL(hWnd, ScSetLink(a->Hub->Rpc, &t)))
+ {
+ if (a->OnlineFlag)
+ {
+ MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("SM_LINK_SAVE_ONLINE"), a->ClientOption->AccountName);
+ }
+ EndDialog(hWnd, true);
+ }
+ }
+ else
+ {
+ if (CALL(hWnd, ScCreateLink(a->Hub->Rpc, &t)))
+ {
+ if (a->Link_ConnectNow)
+ {
+ RPC_LINK tt;
+
+ Zero(&tt, sizeof(tt));
+ UniStrCpy(tt.AccountName, sizeof(tt.AccountName), a->ClientOption->AccountName);
+ StrCpy(tt.HubName, sizeof(tt.HubName), a->Hub->HubName);
+
+ CALL(hWnd, ScSetLinkOnline(a->Hub->Rpc, &tt));
+ }
+ EndDialog(hWnd, true);
+ }
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+ else
+ {
+ // NAT mode
+ RPC_CREATE_LINK t;
+ Zero(&t, sizeof(t));
+
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(t.ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));
+ t.ClientAuth = CopyClientAuth(a->ClientAuth);
+
+ if (CALL(hWnd, NcSetClientConfig(a->Rpc, &t)))
+ {
+ EndDialog(hWnd, true);
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+ }
+}
+
+// Show the account editing dialog
+bool CmEditAccountDlg(HWND hWnd, CM_ACCOUNT *a)
+{
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return false;
+ }
+
+ return Dialog(hWnd, D_CM_ACCOUNT, CmEditAccountDlgProc, a);
+}
+
+// Edit the account
+void CmEditAccount(HWND hWnd, wchar_t *account_name)
+{
+ CM_ACCOUNT *a;
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return;
+ }
+
+ a = CmGetExistAccountObject(hWnd, account_name);
+ if (a == NULL)
+ {
+ return;
+ }
+
+ CmVoice("input_config");
+ if (CmEditAccountDlg(hWnd, a))
+ {
+ CmVoice("set_config");
+ }
+
+ CmFreeAccountObject(hWnd, a);
+}
+
+// Create an account
+void CmNewAccount(HWND hWnd)
+{
+ CM_ACCOUNT *a;
+ RPC_CLIENT_ENUM_VLAN t;
+ UINT num_vlan = 0;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (IsEnable(hWnd, 0) == false)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ if (CcEnumVLan(cm->Client, &t) == ERR_NO_ERROR)
+ {
+ num_vlan = t.NumItem;
+
+ CiFreeClientEnumVLan(&t);
+ }
+
+ if (num_vlan == 0)
+ {
+ if (MsgBox(hWnd, MB_ICONINFORMATION | MB_YESNO, _UU("CM_NO_VLAN")) == IDNO)
+ {
+ return;
+ }
+ else
+ {
+ if (cm->server_name == NULL)
+ {
+ Command(hWnd, CMD_NEW_VLAN);
+ return;
+ }
+ else
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_VLAN_REMOTE_ERROR"));
+ }
+ return;
+ }
+ }
+
+ a = CmCreateNewAccountObject(hWnd);
+ if (a == NULL)
+ {
+ return;
+ }
+
+ CmVoice("input_config");
+ if (CmEditAccountDlg(hWnd, a))
+ {
+ CmVoice("new_config");
+ }
+
+ CmFreeAccountObject(hWnd, a);
+}
+
+// Release the account object
+void CmFreeAccountObject(HWND hWnd, CM_ACCOUNT *a)
+{
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+ Free(a->ClientOption);
+ CiFreeClientAuth(a->ClientAuth);
+ if (a->ServerCert != NULL)
+ {
+ FreeX(a->ServerCert);
+ }
+ Free(a);
+}
+
+// Get an existing account object
+CM_ACCOUNT *CmGetExistAccountObject(HWND hWnd, wchar_t *account_name)
+{
+ RPC_CLIENT_GET_ACCOUNT c;
+ CM_ACCOUNT *a;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&c, sizeof(c));
+ UniStrCpy(c.AccountName, sizeof(c.AccountName), account_name);
+ if (CALL(hWnd, CcGetAccount(cm->Client, &c)) == false)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(CM_ACCOUNT));
+ a->EditMode = true;
+ a->CheckServerCert = c.CheckServerCert;
+ a->Startup = c.StartupAccount;
+ if (c.ServerCert != NULL)
+ {
+ a->ServerCert = CloneX(c.ServerCert);
+ }
+ a->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(a->ClientOption, c.ClientOption, sizeof(CLIENT_OPTION));
+ a->ClientAuth = CopyClientAuth(c.ClientAuth);
+ Copy(a->ShortcutKey, c.ShortcutKey, SHA1_SIZE);
+ CiFreeClientGetAccount(&c);
+
+ a->LockMode = cm->CmSetting.LockMode;
+
+ return a;
+}
+
+// Create a new account object
+CM_ACCOUNT *CmCreateNewAccountObject(HWND hWnd)
+{
+ CM_ACCOUNT *a;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(CM_ACCOUNT));
+ a->EditMode = false;
+ a->CheckServerCert = false;
+ a->Startup = false;
+ a->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+
+ // Initialize the client options
+ CmGenerateNewAccountName(hWnd, a->ClientOption->AccountName, sizeof(a->ClientOption->AccountName));
+ a->ClientOption->Port = 443; // Default port number
+ a->ClientOption->NumRetry = INFINITE;
+ a->ClientOption->RetryInterval = 15;
+ a->ClientOption->MaxConnection = 1;
+ a->ClientOption->HalfConnection = false;
+ a->ClientOption->UseEncrypt = true;
+ a->ClientOption->AdditionalConnectionInterval = 1;
+
+ if (cm->Client->Unix)
+ {
+ a->ClientOption->NoRoutingTracking = true;
+ }
+
+ a->ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+
+ // Password authentication
+ a->ClientAuth->AuthType = CLIENT_AUTHTYPE_PASSWORD;
+
+ return a;
+}
+
+// Create an imported account name
+void CmGenerateImportName(HWND hWnd, wchar_t *name, UINT size, wchar_t *old_name)
+{
+ UINT i;
+ // Validate arguments
+ if (name == NULL || hWnd == NULL)
+ {
+ return;
+ }
+
+ for (i = 1;;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ if (i == 1)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_IMPORT_NAME_1"), old_name);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_IMPORT_NAME_2"), old_name, i);
+ }
+
+ if (LvSearchStr(hWnd, L_ACCOUNT, 0, tmp) == INFINITE)
+ {
+ UniStrCpy(name, size, tmp);
+ return;
+ }
+ }
+}
+
+// Create a copy name
+void CmGenerateCopyName(HWND hWnd, wchar_t *name, UINT size, wchar_t *old_name)
+{
+ UINT i;
+ // Validate arguments
+ if (name == NULL || hWnd == NULL)
+ {
+ return;
+ }
+
+ for (i = 1;;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ if (i == 1)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_COPY_NAME_1"), old_name);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_COPY_NAME_2"), i, old_name);
+ }
+
+ if (LvSearchStr(hWnd, L_ACCOUNT, 0, tmp) == INFINITE)
+ {
+ UniStrCpy(name, size, tmp);
+ return;
+ }
+ }
+}
+
+// Create a new account name
+void CmGenerateNewAccountName(HWND hWnd, wchar_t *name, UINT size)
+{
+ UINT i;
+ // Validate arguments
+ if (name == NULL || hWnd == NULL)
+ {
+ return;
+ }
+
+ for (i = 1;;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ if (i == 1)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_NEW_ACCOUNT_NAME_1"));
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_NEW_ACCOUNT_NAME_2"), i);
+ }
+
+ if (LvSearchStr(hWnd, L_ACCOUNT, 0, tmp) == INFINITE)
+ {
+ UniStrCpy(name, size, tmp);
+ return;
+ }
+ }
+}
+
+// Show the policy list
+void CmPolicyDlgPrint(HWND hWnd, CM_POLICY *p)
+{
+ CmPolicyDlgPrintEx(hWnd, p, false);
+}
+void CmPolicyDlgPrintEx(HWND hWnd, CM_POLICY *p, bool cascade_mode)
+{
+ CmPolicyDlgPrintEx2(hWnd, p, cascade_mode, POLICY_CURRENT_VERSION);
+}
+void CmPolicyDlgPrintEx2(HWND hWnd, CM_POLICY *p, bool cascade_mode, UINT ver)
+{
+ POLICY *pol;
+ UINT i;
+ LVB *b;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ pol = p->Policy;
+
+ b = LvInsertStart();
+
+ for (i = 0;i < NUM_POLICY_ITEM;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ if (cascade_mode)
+ {
+ if (PolicyIsSupportedForCascade(i) == false)
+ {
+ continue;
+ }
+ }
+
+ if (IS_POLICY_FOR_CURRENT_VER(i, ver))
+ {
+ if (policy_item[i].TypeInt == false)
+ {
+ // bool type
+ UniStrCpy(tmp, sizeof(tmp), POLICY_BOOL(pol, i) ? _UU("POL_BOOL_ENABLE") : (p->Extension ? _UU("POL_BOOL_DISABLE_EX") : _UU("POL_BOOL_DISABLE")));
+ }
+ else
+ {
+ // int type
+ if (policy_item[i].AllowZero && POLICY_INT(pol, i) == 0)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("POL_INT_ZERO"));
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU(policy_item[i].FormatStr), POLICY_INT(pol, i));
+ }
+ }
+
+ LvInsertAdd(b, ICO_MACHINE, (void *)i, 2, GetPolicyTitle(i), tmp);
+ }
+ }
+
+ LvInsertEnd(b, hWnd, L_POLICY);
+}
+
+// Policy list dialog box
+UINT CmPolicyDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ CM_POLICY *p = (CM_POLICY *)param;
+ NMHDR *n;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ FormatText(hWnd, 0, p->AccountName);
+ FormatText(hWnd, S_TITLE, p->AccountName);
+ p->hWnd = hWnd;
+ if (p->CmStatus != NULL)
+ {
+ p->CmStatus->hWndPolicy = hWnd;
+ }
+
+ // Initialize the column
+ LvInit(hWnd, L_POLICY);
+ LvInsertColumn(hWnd, L_POLICY, 0, _UU("POL_TITLE_STR"), 375);
+ LvInsertColumn(hWnd, L_POLICY, 1, _UU("POL_VALUE_STR"), 100);
+
+ // Display
+ CmPolicyDlgPrint(hWnd, p);
+
+ // Select the first
+ LvSelect(hWnd, L_POLICY, 0);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_POLICY:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ // Change selection
+ if (LvIsSelected(hWnd, L_POLICY) == false)
+ {
+ SetText(hWnd, S_DESCRIPTION, L"");
+ }
+ else
+ {
+ UINT index = LvGetSelected(hWnd, L_POLICY);
+ UINT id = (UINT)LvGetParam(hWnd, L_POLICY, index);
+ if (id < NUM_POLICY_ITEM)
+ {
+ SetText(hWnd, S_DESCRIPTION, GetPolicyDescription(id));
+ }
+ }
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ LvSortHander(hWnd, msg, wParam, lParam, L_POLICY);
+
+ return 0;
+}
+
+// Show the policy list dialog
+void CmPolicyDlg(HWND hWnd, CM_STATUS *st)
+{
+ RPC_CLIENT_GET_CONNECTION_STATUS s;
+ POLICY *policy;
+ CM_POLICY cp;
+ // Validate arguments
+ if (hWnd == NULL || st == NULL)
+ {
+ return;
+ }
+
+ // Get the policy
+ Zero(&s, sizeof(s));
+ UniStrCpy(s.AccountName, sizeof(s.AccountName), st->AccountName);
+ if (CALL(hWnd, CcGetAccountStatus(cm->Client, &s)) == false)
+ {
+ return;
+ }
+ if (s.Active == false)
+ {
+ return;
+ }
+
+ policy = &s.Policy;
+
+ Zero(&cp, sizeof(cp));
+ UniStrCpy(cp.AccountName, sizeof(cp.AccountName), st->AccountName);
+ cp.Policy = policy;
+ cp.CmStatus = st;
+
+ Dialog(hWnd, D_CM_POLICY, CmPolicyDlgProc, &cp);
+
+ st->hWndPolicy = NULL;
+
+ CiFreeClientGetConnectionStatus(&s);
+}
+
+// Show the certificate
+void CmStatusDlgPrintCert(HWND hWnd, CM_STATUS *st, bool server)
+{
+ RPC_CLIENT_GET_CONNECTION_STATUS s;
+ X *x, *issuer;
+ // Validate arguments
+ if (hWnd == NULL || st == NULL)
+ {
+ return;
+ }
+
+ // Get the latest information
+ Zero(&s, sizeof(s));
+ UniStrCpy(s.AccountName, sizeof(s.AccountName), st->AccountName);
+ if (CALL(hWnd, CcGetAccountStatus(cm->Client, &s)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ if (s.Active == false)
+ {
+ // Disconnect
+ Close(hWnd);
+ return;
+ }
+
+ if (server == false)
+ {
+ // Show the client certificate
+ x = s.ClientX;
+ }
+ else
+ {
+ // Show the server certificate
+ x = s.ServerX;
+ }
+
+ cm->WindowCount++;
+ issuer = CmGetIssuer(x);
+ CertDlg(hWnd, x, issuer, true);
+ FreeX(issuer);
+ cm->WindowCount--;
+
+ CiFreeClientGetConnectionStatus(&s);
+}
+
+// Show the information of the status dialog
+void CmStatusDlgPrint(HWND hWnd, CM_STATUS *cmst)
+{
+ RPC_CLIENT_GET_CONNECTION_STATUS s;
+ LVB *b;
+ // Validate arguments
+ if (hWnd == NULL || cmst == NULL)
+ {
+ return;
+ }
+
+ // Get the latest information
+ Zero(&s, sizeof(s));
+ UniStrCpy(s.AccountName, sizeof(s.AccountName), cmst->AccountName);
+ if (CALL(hWnd, CcGetAccountStatus(cm->Client, &s)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ if (s.Active == false)
+ {
+ // Disconnect
+ Close(hWnd);
+ return;
+ }
+
+ // Show the status in the list box in the status dialog
+ b = LvInsertStart();
+ CmPrintStatusToListView(b, &s);
+ LvInsertEnd(b, hWnd, L_STATUS);
+
+ LvAutoSize(hWnd, L_STATUS);
+
+ SetEnable(hWnd, B_POLICY, s.Connected);
+
+ SetEnable(hWnd, B_SERVER_CERT, s.ServerX != NULL);
+ SetEnable(hWnd, B_CLIENT_CERT, s.ClientX != NULL);
+
+ CiFreeClientGetConnectionStatus(&s);
+}
+
+// Show the status in the list box in the status dialog
+void CmPrintStatusToListView(LVB *b, RPC_CLIENT_GET_CONNECTION_STATUS *s)
+{
+ CmPrintStatusToListViewEx(b, s, false);
+}
+void CmPrintStatusToListViewEx(LVB *b, RPC_CLIENT_GET_CONNECTION_STATUS *s, bool server_mode)
+{
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+ char vv[128];
+ // Validate arguments
+ if (b == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (server_mode == false)
+ {
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_ACCOUNT_NAME"), s->AccountName);
+
+ if (s->Connected == false)
+ {
+ wchar_t *st = _UU("CM_ST_CONNECTED_FALSE");
+ switch (s->SessionStatus)
+ {
+ case CLIENT_STATUS_CONNECTING:
+ st = _UU("CM_ST_CONNECTING");
+ break;
+ case CLIENT_STATUS_NEGOTIATION:
+ st = _UU("CM_ST_NEGOTIATION");
+ break;
+ case CLIENT_STATUS_AUTH:
+ st = _UU("CM_ST_AUTH");
+ break;
+ case CLIENT_STATUS_ESTABLISHED:
+ st = _UU("CM_ST_ESTABLISHED");
+ break;
+ case CLIENT_STATUS_RETRY:
+ st = _UU("CM_ST_RETRY");
+ break;
+ case CLIENT_STATUS_IDLE:
+ st = _UU("CM_ST_IDLE");
+ break;
+ }
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_CONNECTED"), st);
+ }
+ else
+ {
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_CONNECTED"), _UU("CM_ST_CONNECTED_TRUE"));
+ }
+ }
+
+ if (s->Connected)
+ {
+ if (s->VLanId == 0)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_ST_NO_VLAN"));
+ }
+ else
+ {
+ UniToStru(tmp, s->VLanId);
+ }
+
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_VLAN_ID"), tmp);
+
+ if (server_mode == false)
+ {
+ StrToUni(tmp, sizeof(tmp), s->ServerName);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SERVER_NAME"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_PORT_TCP"), s->ServerPort);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SERVER_PORT"), tmp);
+ }
+
+ StrToUni(tmp, sizeof(tmp), s->ServerProductName);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SERVER_P_NAME"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), L"%u.%02u", s->ServerProductVer / 100, s->ServerProductVer % 100);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SERVER_P_VER"), tmp);
+ UniFormat(tmp, sizeof(tmp), L"Build %u", s->ServerProductBuild);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SERVER_P_BUILD"), tmp);
+ }
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->StartTime), NULL);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_START_TIME"), tmp);
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->FirstConnectionEstablisiedTime), NULL);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_FIRST_ESTAB_TIME"), s->FirstConnectionEstablisiedTime == 0 ? _UU("CM_ST_NONE") : tmp);
+
+ if (s->Connected)
+ {
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->CurrentConnectionEstablishTime), NULL);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_CURR_ESTAB_TIME"), tmp);
+ }
+
+ if (server_mode == false)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_STR"), s->NumConnectionsEatablished);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_NUM_ESTABLISHED"), tmp);
+ }
+
+ if (s->Connected)
+ {
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_HALF_CONNECTION"), s->HalfConnection ? _UU("CM_ST_HALF_TRUE") : _UU("CM_ST_HALF_FALSE"));
+
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_QOS"), s->QoS ? _UU("CM_ST_QOS_TRUE") : _UU("CM_ST_QOS_FALSE"));
+
+ UniFormat(tmp, sizeof(tmp), L"%u", s->NumTcpConnections);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_NUM_TCP"), tmp);
+
+ if (s->HalfConnection)
+ {
+ UniFormat(tmp, sizeof(tmp), L"%u", s->NumTcpConnectionsUpload);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_NUM_TCP_UPLOAD"), tmp);
+ UniFormat(tmp, sizeof(tmp), L"%u", s->NumTcpConnectionsDownload);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_NUM_TCP_DOWNLOAD"), tmp);
+ }
+
+ UniFormat(tmp, sizeof(tmp), L"%u", s->MaxTcpConnections);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_MAX_TCP"), tmp);
+
+ if (s->UseEncrypt == false)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_ST_USE_ENCRYPT_FALSE"));
+ }
+ else
+ {
+ if (StrLen(s->CipherName) != 0)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_USE_ENCRYPT_TRUE"), s->CipherName);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_USE_ENCRYPT_TRUE2"));
+ }
+ }
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_USE_ENCRYPT"), tmp);
+
+ if (s->UseCompress)
+ {
+ UINT percent = 0;
+ if ((s->TotalRecvSize + s->TotalSendSize) > 0)
+ {
+ percent = (UINT)((UINT64)100 - (UINT64)(s->TotalRecvSizeReal + s->TotalSendSizeReal) * (UINT64)100 /
+ (s->TotalRecvSize + s->TotalSendSize));
+ percent = MAKESURE(percent, 0, 100);
+ }
+
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_COMPRESS_TRUE"), percent);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_ST_COMPRESS_FALSE"));
+ }
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_USE_COMPRESS"), tmp);
+
+ if (IsEmptyStr(s->UnderlayProtocol) == false)
+ {
+ StrToUni(tmp, sizeof(tmp), s->UnderlayProtocol);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_UNDERLAY_PROTOCOL"), tmp);
+ }
+
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_UDP_ACCEL_ENABLED"), (s->IsUdpAccelerationEnabled ? _UU("CM_ST_YES") : _UU("CM_ST_NO")));
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_UDP_ACCEL_USING"), (s->IsUsingUdpAcceleration ? _UU("CM_ST_YES") : _UU("CM_ST_NO")));
+
+ StrToUni(tmp, sizeof(tmp), s->SessionName);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SESSION_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), s->ConnectionName);
+ if (UniStrCmpi(tmp, L"INITING") != 0)
+ {
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_CONNECTION_NAME"), tmp);
+ }
+
+ BinToStr(str, sizeof(str), s->SessionKey, sizeof(s->SessionKey));
+ StrToUni(tmp, sizeof(tmp), str);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SESSION_KEY"), tmp);
+
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_BRIDGE_MODE"), s->IsBridgeMode ? _UU("CM_ST_YES") : _UU("CM_ST_NO"));
+
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_MONITOR_MODE"), s->IsMonitorMode ? _UU("CM_ST_YES") : _UU("CM_ST_NO"));
+
+ ToStr3(vv, sizeof(vv), s->TotalSendSize);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SEND_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->TotalRecvSize);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_RECV_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Send.UnicastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SEND_UCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Send.UnicastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SEND_UCAST_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Send.BroadcastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SEND_BCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Send.BroadcastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_SEND_BCAST_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Recv.UnicastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_RECV_UCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Recv.UnicastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_RECV_UCAST_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Recv.BroadcastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_RECV_BCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Recv.BroadcastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ LvInsertAdd(b, 0, NULL, 2, _UU("CM_ST_RECV_BCAST_SIZE"), tmp);
+ }
+}
+
+// Status dialog procedure
+UINT CmStatusDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ wchar_t tmp[MAX_SIZE];
+ CM_STATUS *s = (CM_STATUS *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetIcon(hWnd, 0, ICO_TOWER);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_TITLE"), s->AccountName);
+ SetText(hWnd, 0, tmp);
+ FormatText(hWnd, S_TITLE, s->AccountName);
+ DlgFont(hWnd, S_TITLE, 0, 1);
+
+ Add(cm->StatusWindowList, hWnd);
+
+ SetTimer(hWnd, 1, 500, NULL);
+
+ LvInitEx(hWnd, L_STATUS, true);
+ ListView_SetImageList(DlgItem(hWnd, L_STATUS), NULL, LVSIL_NORMAL);
+ ListView_SetImageList(DlgItem(hWnd, L_STATUS), NULL, LVSIL_SMALL);
+ LvInsertColumn(hWnd, L_STATUS, 0, _UU("CM_ST_COLUMN_1"), 160);
+ LvInsertColumn(hWnd, L_STATUS, 1, _UU("CM_ST_COLUMN_2"), 270);
+
+ CmStatusDlgPrint(hWnd, s);
+
+ break;
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+ CmStatusDlgPrint(hWnd, s);
+ SetTimer(hWnd, 1, 500, NULL);
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ case IDCANCEL:
+ // Close
+ Close(hWnd);
+ break;
+ case B_POLICY:
+ // Show the policy
+ CmPolicyDlg(hWnd, s);
+ break;
+ case B_SERVER_CERT:
+ CmStatusDlgPrintCert(hWnd, s, true);
+ break;
+ case B_CLIENT_CERT:
+ CmStatusDlgPrintCert(hWnd, s, false);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ Delete(cm->StatusWindowList, hWnd);
+ if (s->hWndPolicy != NULL)
+ {
+ EndDialog(s->hWndPolicy, false);
+ s->hWndPolicy = NULL;
+ }
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Show the status dialog
+void CmStatusDlg(HWND hWnd, wchar_t *account_name)
+{
+ CM_STATUS *s;
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return;
+ }
+
+ s = ZeroMalloc(sizeof(CM_STATUS));
+ UniStrCpy(s->AccountName, sizeof(s->AccountName), account_name);
+
+ Dialog(hWnd, D_CONNECTION_STATUS, CmStatusDlgProc, s);
+
+ Free(s);
+}
+
+// Show the status
+void CmStatus(HWND hWnd, wchar_t *account_name)
+{
+ UINT i;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return;
+ }
+
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_TITLE"), account_name);
+
+ for (i = 0;i < LIST_NUM(cm->StatusWindowList);i++)
+ {
+ HWND h = LIST_DATA(cm->StatusWindowList, i);
+ if (h != NULL)
+ {
+ wchar_t tmp2[MAX_SIZE];
+ if (GetTxt(h, 0, tmp2, sizeof(tmp2)))
+ {
+ if (UniStrCmpi(tmp2, tmp) == 0)
+ {
+ SetActiveWindow(h);
+ return;
+ }
+ }
+ }
+ }
+
+ CmStatusDlg(hWnd, account_name);
+}
+
+// Delete
+void CmDeleteAccount(HWND hWnd, wchar_t *account_name)
+{
+ RPC_CLIENT_DELETE_ACCOUNT c;
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return;
+ }
+ Zero(&c, sizeof(c));
+ UniStrCpy(c.AccountName, sizeof(c.AccountName), account_name);
+
+ CmVoice("delete_config_1");
+ if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_DELETE_ACCOUNT_MSG"), account_name)
+ == IDNO)
+ {
+ return;
+ }
+
+ CALL(hWnd, CcDeleteAccount(cm->Client, &c));
+ CmVoice("delete_config_2");
+}
+
+// Disconnect
+void CmDisconnect(HWND hWnd, wchar_t *account_name)
+{
+ RPC_CLIENT_CONNECT c;
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return;
+ }
+
+ Zero(&c, sizeof(c));
+ UniStrCpy(c.AccountName, sizeof(c.AccountName), account_name);
+
+ cm->PositiveDisconnectFlag = true;
+
+ CALL(hWnd, CcDisconnect(cm->Client, &c));
+}
+
+// Show the promotional window
+void SmShowPublicVpnServerHtml(HWND hWnd)
+{
+ char *langstr = _SS("LANGSTR");
+
+ if(StrCmpi(langstr, "Japanese") == 0)
+ {
+ ShowHtml(hWnd, PUBLIC_SERVER_HTML, PUBLIC_SERVER_TAG);
+ }
+ else
+ {
+ ShowHtml(hWnd, PUBLIC_SERVER_HTML_EN, PUBLIC_SERVER_TAG);
+ }
+}
+
+// Connection
+void CmConnect(HWND hWnd, wchar_t *account_name)
+{
+ RPC_CLIENT_CONNECT c;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || account_name == NULL)
+ {
+ return;
+ }
+
+ if (IsEnable(hWnd, 0) == false)
+ {
+ return;
+ }
+
+ if (hWnd == cm->hMainWnd)
+ {
+ if (LvNum(hWnd, L_VLAN) == 0 && cm->Client->Win9x)
+ {
+ if (MsgBox(hWnd, MB_ICONINFORMATION | MB_YESNO, _UU("CM_NO_VLAN_2")) == IDNO)
+ {
+ return;
+ }
+ else
+ {
+ if (cm->server_name == NULL || cm->Client->Unix)
+ {
+ Command(hWnd, CMD_NEW_VLAN);
+ return;
+ }
+ else
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_VLAN_REMOTE_ERROR"));
+ }
+ return;
+ }
+ }
+ }
+
+ // (If necessary) display a warning
+ if (CmWarningDesktop(hWnd, account_name) == false)
+ {
+ return;
+ }
+
+ if (cm->server_name == NULL)
+ {
+ if (cm->BadProcessChecked == false)
+ {
+ cm->BadProcessChecked = true;
+
+ CheckBadProcesses(hWnd);
+ }
+ }
+
+ if (cm->server_name == NULL)
+ {
+ // Check the Windows version
+ RPC_WINVER winver;
+ wchar_t winver_msg_client[3800];
+
+ GetWinVer(&winver);
+ Zero(winver_msg_client, sizeof(winver_msg_client));
+
+ if (IsSupportedWinVer(&winver) == false)
+ {
+ SYSTEMTIME st;
+
+ LocalTime(&st);
+
+ UniFormat(winver_msg_client, sizeof(winver_msg_client), _UU("WINVER_ERROR_FORMAT"),
+ _UU("WINVER_ERROR_PC_LOCAL"),
+ winver.Title,
+ _UU("WINVER_ERROR_VPNCLIENT"),
+ SUPPORTED_WINDOWS_LIST,
+ _UU("WINVER_ERROR_PC_LOCAL"),
+ _UU("WINVER_ERROR_VPNCLIENT"),
+ _UU("WINVER_ERROR_VPNCLIENT"),
+ _UU("WINVER_ERROR_VPNCLIENT"),
+ st.wYear, st.wMonth);
+ }
+
+ if (UniIsEmptyStr(winver_msg_client) == false)
+ {
+ OnceMsgEx(hWnd, _UU("WINVER_TITLE"), winver_msg_client,
+ true, ICO_WARNING, NULL);
+ }
+ }
+
+ i = LvSearchStr(hWnd, L_ACCOUNT, 0, account_name);
+ if (i != INFINITE)
+ {
+ wchar_t *tmp = LvGetStr(hWnd, L_ACCOUNT, i, 2);
+ if (tmp != NULL)
+ {
+ wchar_t tag[MAX_SIZE];
+ StrToUni(tag, sizeof(tag), PUBLIC_SERVER_NAME);
+
+ if (UniSearchStrEx(tmp, tag, 0, false) != INFINITE)
+ {
+ SmShowPublicVpnServerHtml(hWnd);
+ }
+
+ Free(tmp);
+ }
+ }
+
+ if (cm->CheckedAndShowedAdminPackMessage == false)
+ {
+ cm->CheckedAndShowedAdminPackMessage = true;
+ //CmCheckAndShowAdminPackTrialVersionNoticeMessage(NULL);
+ }
+
+ Zero(&c, sizeof(c));
+ UniStrCpy(c.AccountName, sizeof(c.AccountName), account_name);
+
+ CmSetForegroundProcessToCnService();
+
+ if (CALL(hWnd, CcConnect(cm->Client, &c)))
+ {
+ cm->ConnectStartedFlag = true;
+ }
+}
+
+// Determine whether to bold the specified menu item
+bool CmIsBold(UINT id)
+{
+ return false;
+}
+
+// Determine whether to enable the specified menu item
+bool CmIsEnabled(HWND hWnd, UINT id)
+{
+ UINT index;
+ wchar_t *name;
+ bool locked = false;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return false;
+ }
+
+ locked = cm->CmSetting.LockMode;
+
+ if (locked)
+ {
+ switch (id)
+ {
+ case CMD_NEW:
+ case CMD_CLONE:
+ case CMD_IMPORT_ACCOUNT:
+ case CMD_DELETE:
+ case CMD_OPTION:
+ case CMD_VOIDE_NONE:
+ case CMD_VOICE_NORMAL:
+ case CMD_VOICE_ODD:
+ case CMD_STARTUP:
+ case CMD_NOSTARTUP:
+ case CMD_TRAFFIC:
+ case CMD_MMCSS:
+ return false;
+ case CMD_NEW_VLAN:
+ case CMD_ENABLE_VLAN:
+ case CMD_DISABLE_VLAN:
+ case CMD_DELETE_VLAN:
+ case CMD_REINSTALL:
+ case CMD_WINNET:
+ if (cm->CmEasyModeSupported)
+ {
+ return false;
+ }
+ }
+ }
+
+ switch (id)
+ {
+ case CMD_LANGUAGE:
+ return MsIsNt();
+ case CMD_SHOWPORT:
+ case CMD_GRID:
+ if (cm->IconView)
+ {
+ return false;
+ }
+ return true;
+ case CMD_MMCSS:
+ if (MsIsVista() == false || IsEmptyStr(cm->server_name) == false)
+ {
+ return false;
+ }
+ if (OS_IS_SERVER(GetOsType()))
+ {
+ return false;
+ }
+ return true;
+ case CMD_TRAYICON:
+ case CMD_TRAFFIC:
+ return (cm->server_name == NULL);
+ case CMD_NETIF:
+ if (MsIsNt() == false)
+ {
+ return false;
+ }
+ return (cm->server_name == NULL);
+ case CMD_CM_SETTING:
+ return cm->CmSettingSupported;
+ case CMD_CONNECT:
+ case CMD_DISCONNECT:
+ case CMD_STATUS:
+ case CMD_RENAME:
+ case CMD_DELETE:
+ if (LvIsMultiMasked(hWnd, L_ACCOUNT))
+ {
+ return false;
+ }
+ if (LvIsSelected(hWnd, L_ACCOUNT) == false)
+ {
+ return false;
+ }
+ else
+ {
+ // Determine whether the selected account is under connecting
+ UINT i = LvGetSelected(hWnd, L_ACCOUNT);
+ wchar_t *str = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+ wchar_t *name = LvGetStr(hWnd, L_ACCOUNT, i, 0);
+ bool is_connected = false;
+ if (str != NULL)
+ {
+ if (UniStrCmpi(str, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(str, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+ {
+ is_connected = true;
+ }
+ Free(str);
+ }
+ if (name != NULL)
+ {
+ if (UniStrCmpi(name, _UU("CM_NEW_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_LINK")) == 0)
+ {
+ Free(name);
+ return false;
+ }
+ Free(name);
+ }
+ if (id == CMD_CONNECT || id == CMD_RENAME || id == CMD_DELETE)
+ {
+ return !is_connected;
+ }
+ else
+ {
+ return is_connected;
+ }
+ }
+ break;
+ case CMD_DISCONNECT_ALL:
+ if (CmGetNumConnected(hWnd) == 0)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ case CMD_SHORTCUT:
+ // Create a shortcut
+ if (cm->Client->Rpc->Sock->RemoteIP.addr[0] != 127)
+ {
+ return false;
+ }
+ case CMD_EXPORT_ACCOUNT:
+ if (LvIsMultiMasked(hWnd, L_ACCOUNT))
+ {
+ return false;
+ }
+ name = LvGetSelectedStr(hWnd, L_ACCOUNT, 0);
+ if (name != NULL)
+ {
+ if (UniStrCmpi(name, _UU("CM_NEW_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_LINK")) == 0
+ )
+ {
+ Free(name);
+ return false;
+ }
+ Free(name);
+ }
+ return LvIsSelected(hWnd, L_ACCOUNT);
+ case CMD_CLONE:
+ if (LvIsMultiMasked(hWnd, L_ACCOUNT))
+ {
+ return false;
+ }
+ name = LvGetSelectedStr(hWnd, L_ACCOUNT, 0);
+ if (name != NULL)
+ {
+ if (UniStrCmpi(name, _UU("CM_NEW_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_LINK")) == 0
+ )
+ {
+ Free(name);
+ return false;
+ }
+ Free(name);
+ }
+ return LvIsSelected(hWnd, L_ACCOUNT);
+ case CMD_STARTUP:
+ case CMD_NOSTARTUP:
+ name = LvGetSelectedStr(hWnd, L_ACCOUNT, 0);
+ if (name != NULL)
+ {
+ if (UniStrCmpi(name, _UU("CM_NEW_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_LINK")) == 0
+ )
+ {
+ Free(name);
+ return false;
+ }
+ Free(name);
+ }
+ if (LvIsMultiMasked(hWnd, L_ACCOUNT))
+ {
+ return false;
+ }
+ if (LvIsSelected(hWnd, L_ACCOUNT) == false)
+ {
+ return false;
+ }
+ else
+ {
+ // Determine whether the selected account is a startup account
+ UINT i = LvGetSelected(hWnd, L_ACCOUNT);
+ bool is_startup = (bool)LvGetParam(hWnd, L_ACCOUNT, i);
+ if (id == CMD_STARTUP)
+ {
+ return !is_startup;
+ }
+ else
+ {
+ return is_startup;
+ }
+ }
+ break;
+ case CMD_NEW_VLAN:
+ if (cm->Client->Unix == false && cm->Client->Win9x == false)
+ {
+ if (cm->server_name != NULL)
+ {
+ return false;
+ }
+ }
+ if (cm->Client->Win9x)
+ {
+ if (LvNum(hWnd, L_VLAN) >= 1)
+ {
+ // You can not install two or more virtual LAN cards in Win9x
+ return false;
+ }
+ }
+ break;
+ case CMD_PROPERTY:
+ name = LvGetSelectedStr(hWnd, L_ACCOUNT, 0);
+ if (name != NULL)
+ {
+ if (UniStrCmpi(name, _UU("CM_NEW_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_ICON")) == 0 || UniStrCmpi(name, _UU("CM_VGC_LINK")) == 0)
+ {
+ Free(name);
+ return false;
+ }
+ Free(name);
+ }
+ if (LvIsMultiMasked(hWnd, L_ACCOUNT))
+ {
+ return false;
+ }
+ return LvIsSelected(hWnd, L_ACCOUNT);
+ case CMD_DELETE_VLAN:
+ if (LvIsMultiMasked(hWnd, L_VLAN))
+ {
+ return false;
+ }
+ return LvIsSelected(hWnd, L_VLAN);
+ case CMD_ENABLE_VLAN:
+ if (cm->Client->Win9x)
+ {
+ return false;
+ }
+ if (LvIsMultiMasked(hWnd, L_VLAN))
+ {
+ return false;
+ }
+ index = LvGetSelected(hWnd, L_VLAN);
+ if (index == INFINITE)
+ {
+ return false;
+ }
+ else
+ {
+ wchar_t *s = LvGetStr(hWnd, L_VLAN, index, 1);
+ if (s != NULL)
+ {
+ if (UniStrCmpi(s, _UU("CM_VLAN_DISABLED")) == 0)
+ {
+ Free(s);
+ return true;
+ }
+ Free(s);
+ }
+ return false;
+ }
+ break;
+ case CMD_DISABLE_VLAN:
+ if (cm->Client->Win9x)
+ {
+ return false;
+ }
+ if (LvIsMultiMasked(hWnd, L_VLAN))
+ {
+ return false;
+ }
+ index = LvGetSelected(hWnd, L_VLAN);
+ if (index == INFINITE)
+ {
+ return false;
+ }
+ else
+ {
+ wchar_t *s = LvGetStr(hWnd, L_VLAN, index, 1);
+ if (s != NULL)
+ {
+ if (UniStrCmpi(s, _UU("CM_VLAN_ENABLED")) == 0)
+ {
+ Free(s);
+ return true;
+ }
+ Free(s);
+ }
+ return false;
+ }
+ break;
+ case CMD_REINSTALL:
+ if (cm->server_name != NULL)
+ {
+ return false;
+ }
+ if (cm->Client->Win9x || cm->Client->Unix)
+ {
+ // Upgrading the virtual LAN card on a UNIX system or Win9x is unavailable
+ return false;
+ }
+ if (LvIsMultiMasked(hWnd, L_VLAN))
+ {
+ return false;
+ }
+ return LvIsSelected(hWnd, L_VLAN);
+ case CMD_WINNET:
+ {
+ UINT os_type = GetOsInfo()->OsType;
+
+ if (OS_IS_WINDOWS_NT(os_type) && GET_KETA(os_type, 100) >= 2)
+ {
+ if (cm->server_name != NULL)
+ {
+ return false;
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ break;
+ case CMD_EXIT:
+ return cm->TrayInited;
+ }
+ return true;
+}
+
+// Convert a VLAN device name to the display name
+void CmVLanNameToPrintName(char *str, UINT size, char *name)
+{
+ // Validate arguments
+ if (str == NULL || name == NULL)
+ {
+ return;
+ }
+
+ Format(str, size, VLAN_ADAPTER_NAME_TAG, name);
+}
+
+// Convert a display name to a VLAN device name
+bool CmPrintNameToVLanName(char *name, UINT size, char *str)
+{
+ // Validate arguments
+ if (name == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ if (StartWith(str, VLAN_ADAPTER_NAME))
+ {
+ if (StrLen(str) < (StrLen(VLAN_ADAPTER_NAME) + 3))
+ {
+ return false;
+ }
+
+ StrCpy(name, size, str + StrLen(VLAN_ADAPTER_NAME) + 3);
+
+ return true;
+ }
+
+ if (StartWith(str, VLAN_ADAPTER_NAME_OLD))
+ {
+ if (StrLen(str) < (StrLen(VLAN_ADAPTER_NAME_OLD) + 3))
+ {
+ return false;
+ }
+
+ StrCpy(name, size, str + StrLen(VLAN_ADAPTER_NAME_OLD) + 3);
+
+ return true;
+ }
+
+ return false;
+}
+
+// Initialize the account list
+void CmInitAccountList(HWND hWnd)
+{
+ CmInitAccountListEx(hWnd, false);
+}
+void CmInitAccountListEx(HWND hWnd, bool easy)
+{
+ UINT width[5];
+ BUF *b;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Read the setting
+ b = MsRegReadBin(REG_CURRENT_USER, CM_REG_KEY, "AccountListColumnWidth");
+ if ((b != NULL) && (b->Size == sizeof(width)))
+ {
+ Copy(width, b->Buf, sizeof(width));
+ }
+ else if ((b != NULL) && (b->Size == (sizeof(width) - sizeof(UINT))))
+ {
+ // Migrating from previous versions
+ Zero(width, sizeof(width));
+ Copy(width, b->Buf, sizeof(width) - sizeof(UINT));
+ width[4] = width[3];
+ width[3] = 0;
+ }
+ else
+ {
+ Zero(width, sizeof(width));
+ }
+ FreeBuf(b);
+
+ LvInitEx2(hWnd, L_ACCOUNT, false, easy);
+
+// LvSetStyle(hWnd, L_ACCOUNT, LVS_EX_TRACKSELECT);
+
+ // Initialize the column
+ if (easy == false)
+ {
+ LvInsertColumn(hWnd, L_ACCOUNT, 0, _UU("CM_ACCOUNT_COLUMN_1"), width[0] == 0 ? 215 : width[0]);
+ LvInsertColumn(hWnd, L_ACCOUNT, 1, _UU("CM_ACCOUNT_COLUMN_2"), width[1] == 0 ? 80 : width[1]);
+ LvInsertColumn(hWnd, L_ACCOUNT, 2, _UU("CM_ACCOUNT_COLUMN_3"), width[2] == 0 ? 220 : width[2]);
+ LvInsertColumn(hWnd, L_ACCOUNT, 3, _UU("CM_ACCOUNT_COLUMN_3_2"), width[3] == 0 ? 90 : width[3]);
+ LvInsertColumn(hWnd, L_ACCOUNT, 4, _UU("CM_ACCOUNT_COLUMN_4"), (width[4] == 0 || width[4] == 250) ? 120 : width[4]);
+ }
+ else
+ {
+ LvInsertColumn(hWnd, L_ACCOUNT, 0, _UU("CM_ACCOUNT_COLUMN_1"), 345);
+ LvInsertColumn(hWnd, L_ACCOUNT, 1, _UU("CM_ACCOUNT_COLUMN_2"), 140);
+ LvInsertColumn(hWnd, L_ACCOUNT, 2, _UU("CM_ACCOUNT_COLUMN_3"), 0);
+ LvInsertColumn(hWnd, L_ACCOUNT, 3, _UU("CM_ACCOUNT_COLUMN_3_2"), 0);
+ LvInsertColumn(hWnd, L_ACCOUNT, 4, _UU("CM_ACCOUNT_COLUMN_4"), 0);
+ }
+}
+
+// Release the account list
+void CmSaveAccountListPos(HWND hWnd)
+{
+ UINT width[5];
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < 5;i++)
+ {
+ width[i] = LvGetColumnWidth(hWnd, L_ACCOUNT, i);
+ }
+
+ MsRegWriteBin(REG_CURRENT_USER, CM_REG_KEY, "AccountListColumnWidth", width, sizeof(width));
+}
+
+// Initialize the VLAN list
+void CmInitVLanList(HWND hWnd)
+{
+ UINT width[4];
+ BUF *b;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Read the setting
+ b = MsRegReadBin(REG_CURRENT_USER, CM_REG_KEY, "VLanListColumnWidth");
+ if ((b != NULL) && (b->Size == sizeof(width)))
+ {
+ Copy(width, b->Buf, sizeof(width));
+ }
+ else
+ {
+ Zero(width, sizeof(width));
+ }
+ FreeBuf(b);
+
+ LvInit(hWnd, L_VLAN);
+
+// LvSetStyle(hWnd, L_ACCOUNT, LVS_EX_TRACKSELECT);
+
+ // Initialize the column
+ LvInsertColumn(hWnd, L_VLAN, 0, _UU("CM_VLAN_COLUMN_1"), width[0] == 0 ? 310 : width[0]);
+ LvInsertColumn(hWnd, L_VLAN, 1, _UU("CM_VLAN_COLUMN_2"), width[1] == 0 ? 120 : width[1]);
+ LvInsertColumn(hWnd, L_VLAN, 2, _UU("CM_VLAN_COLUMN_3"), width[2] == 0 ? 175 : width[2]);
+ LvInsertColumn(hWnd, L_VLAN, 3, _UU("CM_VLAN_COLUMN_4"), width[3] == 0 ? 120 : width[3]);
+}
+
+// Release the VLAN list
+void CmSaveVLanListPos(HWND hWnd)
+{
+ UINT width[4];
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < 4;i++)
+ {
+ width[i] = LvGetColumnWidth(hWnd, L_VLAN, i);
+ }
+
+ MsRegWriteBin(REG_CURRENT_USER, CM_REG_KEY, "VLanListColumnWidth", width, sizeof(width));
+}
+
+// Update the account list
+void CmRefreshAccountList(HWND hWnd)
+{
+ CmRefreshAccountListEx(hWnd, false);
+ CmRefreshEasy();
+}
+void CmRefreshAccountListEx(HWND hWnd, bool easy)
+{
+ CmRefreshAccountListEx2(hWnd, easy, false);
+}
+void CmRefreshAccountListEx2(HWND hWnd, bool easy, bool style_changed)
+{
+ UINT num = 0;
+ RPC_CLIENT_ENUM_ACCOUNT a;
+ UINT num_connecting = 0, num_connected = 0;
+ wchar_t tmp[MAX_SIZE];
+ wchar_t new_inserted_item[MAX_ACCOUNT_NAME_LEN + 1];
+ bool select_new_insteted_item = true;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Switching of icon / detail view
+ LvSetView(hWnd, L_ACCOUNT, cm->IconView == false || easy);
+
+ // Show grid
+ if (cm->ShowGrid || easy)
+ {
+ LvSetStyle(hWnd, L_ACCOUNT, LVS_EX_GRIDLINES);
+ }
+ else
+ {
+ LvRemoveStyle(hWnd, L_ACCOUNT, LVS_EX_GRIDLINES);
+ }
+
+ if (style_changed)
+ {
+ // Change the font
+ if (easy == false)
+ {
+ if (cm->VistaStyle)
+ {
+ SetFontMeiryo(hWnd, L_ACCOUNT, 9);
+ }
+ else
+ {
+ SetFontDefault(hWnd, L_ACCOUNT);
+ }
+
+ if (cm->VistaStyle && (cm->IconView == false))
+ {
+ LvSetStyle(hWnd, L_ACCOUNT, LVS_EX_FULLROWSELECT);
+ }
+ else
+ {
+ LvRemoveStyle(hWnd, L_ACCOUNT, LVS_EX_FULLROWSELECT);
+ }
+ }
+ }
+
+ Zero(new_inserted_item, sizeof(new_inserted_item));
+
+ if (LvNum(hWnd, L_ACCOUNT) == 0)
+ {
+ select_new_insteted_item = false;
+ }
+
+ // Enumerate the account list
+ if (CALL(hWnd, CcEnumAccount(cm->Client, &a)))
+ {
+ UINT i;
+ LVB *b = LvInsertStart();
+
+ if (cm->CmSetting.LockMode == false && (easy == false))
+ {
+ // Creating a new connection
+ LvInsertAdd(b, ICO_NEW, NULL, 4, _UU("CM_NEW_ICON"), L"", L"", L"");
+
+ if (cm->Client->IsVgcSupported)
+ {
+ // VPN Gate
+ LvInsertAdd(b, ICO_RESEARCH, NULL, 4, _UU("CM_VGC_ICON"), L"", L"", L"");
+ }
+ else if (cm->Client->ShowVgcLink)
+ {
+ // VPN Gate Link
+ LvInsertAdd(b, ICO_INTERNET, NULL, 4, _UU("CM_VGC_LINK"), L"", L"", L"");
+ }
+ }
+
+ for (i = 0;i < a.NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *t = a.Items[i];
+ UINT icon;
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ char tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ IP ip;
+ char ip_str[MAX_SIZE];
+
+ // Special treatment in the case of IPv6 address
+ if (StrToIP6(&ip, t->ServerName) && StartWith(t->ServerName, "[") == false)
+ {
+ Format(ip_str, sizeof(ip_str),
+ "[%s]", t->ServerName);
+ }
+ else
+ {
+ StrCpy(ip_str, sizeof(ip_str), t->ServerName);
+ }
+
+ // Determine the icon
+ if (t->Active == false)
+ {
+ if (t->StartupAccount == false)
+ {
+ icon = ICO_SERVER_OFFLINE;
+ }
+ else
+ {
+ icon = ICO_SERVER_OFFLINE_EX;
+ }
+ }
+ else
+ {
+ num++;
+ if (t->StartupAccount == false)
+ {
+ icon = ICO_SERVER_ONLINE;
+ }
+ else
+ {
+ icon = ICO_SERVER_ONLINE_EX;
+ }
+ }
+
+ // Adding
+ if (easy == false)
+ {
+ //CmVLanNameToPrintName(tmp3, sizeof(tmp3), t->DeviceName);
+ StrCpy(tmp3, sizeof(tmp3), t->DeviceName);
+ StrToUni(tmp, sizeof(tmp), tmp3);
+ }
+ else
+ {
+ StrToUni(tmp, sizeof(tmp), t->DeviceName);
+ }
+
+ if (t->Port == 0 || cm->ShowPort == false)
+ {
+ // Port number is unknown
+ UniFormat(tmp2, sizeof(tmp2), L"%S (%s)", ip_str, CmGetProtocolName(t->ProxyType));
+ }
+ else
+ {
+ // Port number are also shown
+ UniFormat(tmp2, sizeof(tmp2), L"%S:%u (%s)", ip_str, t->Port, CmGetProtocolName(t->ProxyType));
+ }
+
+ if (LvSearchStr(hWnd, L_ACCOUNT, 0, t->AccountName) == INFINITE)
+ {
+ UniStrCpy(new_inserted_item, sizeof(new_inserted_item), t->AccountName);
+ }
+
+ // Virtual HUB name
+ StrToUni(tmp4, sizeof(tmp4), t->HubName);
+
+ if (easy == false)
+ {
+ LvInsertAdd(b, icon, (void *)t->StartupAccount, 5, t->AccountName,
+ t->Active == false ? _UU("CM_ACCOUNT_OFFLINE") :
+ (t->Connected ? _UU("CM_ACCOUNT_ONLINE") : _UU("CM_ACCOUNT_CONNECTING")),
+ tmp2, tmp4,
+ tmp);
+ }
+ else
+ {
+ LvInsertAdd(b, icon, (void *)t->StartupAccount, 5, t->AccountName,
+ t->Active == false ? _UU("CM_ACCOUNT_OFFLINE") :
+ (t->Connected ? _UU("CM_ACCOUNT_ONLINE") : _UU("CM_ACCOUNT_CONNECTING")),
+ tmp2, tmp4,
+ tmp);
+ }
+
+ if (t->Active)
+ {
+ if (t->Connected)
+ {
+ num_connected++;
+ }
+ else
+ {
+ num_connecting++;
+ }
+ }
+ }
+
+ LvInsertEnd(b, hWnd, L_ACCOUNT);
+
+ CiFreeClientEnumAccount(&a);
+
+ if (select_new_insteted_item)
+ {
+ if (UniStrLen(new_inserted_item) >= 1)
+ {
+ LvSelect(hWnd, L_ACCOUNT, INFINITE);
+ LvSelect(hWnd, L_ACCOUNT, LvSearchStr(hWnd, L_ACCOUNT, 0, new_inserted_item));
+ }
+ }
+ }
+
+ if (easy == false)
+ {
+ // For voice guidance, detect new connection and connection lost
+ if (cm->UpdateConnectedNumFlag == false)
+ {
+ cm->UpdateConnectedNumFlag = true;
+ cm->OldConnectedNum = num;
+ }
+ else
+ {
+ if (cm->OldConnectedNum != num)
+ {
+ if (cm->OldConnectedNum < num)
+ {
+ CmVoice("connect");
+ }
+ else
+ {
+ CmVoice("disconnect");
+
+ if (cm->CmSetting.EasyMode && cm->PositiveDisconnectFlag == false)
+ {
+ CmShowEasy();
+ }
+
+ cm->PositiveDisconnectFlag = false;
+ }
+ cm->OldConnectedNum = num;
+ }
+ }
+
+ if (num_connecting == 0 && num_connected == 0)
+ {
+ // There is no connecting or connected account
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_TRAY_NOT_CONNECTED"));
+ }
+ else if (num_connected == 0)
+ {
+ // There is only connecting account
+ UniFormat(tmp, sizeof(tmp), _UU("CM_TRAY_CONNECTED_1"), num_connecting);
+ }
+ else if (num_connecting == 0)
+ {
+ // There is only connected account
+ UniFormat(tmp, sizeof(tmp), _UU("CM_TRAY_CONNECTED_2"), num_connected);
+ }
+ else
+ {
+ // There are both
+ UniFormat(tmp, sizeof(tmp), _UU("CM_TRAY_CONNECTED_0"), num_connected, num_connecting);
+ }
+
+ if (num_connecting == 0 && num_connected == 0)
+ {
+ cm->TrayAnimation = false;
+ cm->TraySpeedAnimation = false;
+ }
+ else
+ {
+ cm->TrayAnimation = true;
+
+ if (num_connecting == 0)
+ {
+ cm->TraySpeedAnimation = false;
+ }
+ else
+ {
+ cm->TraySpeedAnimation = true;
+ }
+ }
+
+ CmChangeTrayString(hWnd, tmp);
+ }
+
+ Refresh(hWnd);
+
+ //Updated the Jump List
+ CmUpdateJumpList(0);
+}
+
+// Updating the VLAN list
+void CmRefreshVLanList(HWND hWnd)
+{
+ CmRefreshVLanListEx(hWnd, false);
+}
+void CmRefreshVLanListEx(HWND hWnd, bool style_changed)
+{
+ RPC_CLIENT_ENUM_VLAN e;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ LvSetView(hWnd, L_VLAN, cm->IconView == false);
+
+ // Show grid
+ if (cm->ShowGrid)
+ {
+ LvSetStyle(hWnd, L_VLAN, LVS_EX_GRIDLINES);
+ }
+ else
+ {
+ LvRemoveStyle(hWnd, L_VLAN, LVS_EX_GRIDLINES);
+ }
+
+ if (style_changed)
+ {
+ // Change the font
+ if (cm->VistaStyle)
+ {
+ SetFontMeiryo(hWnd, L_VLAN, 9);
+ }
+ else
+ {
+ SetFontDefault(hWnd, L_VLAN);
+ }
+
+ if (cm->VistaStyle && (cm->IconView == false))
+ {
+ LvSetStyle(hWnd, L_VLAN, LVS_EX_FULLROWSELECT);
+ }
+ else
+ {
+ LvRemoveStyle(hWnd, L_VLAN, LVS_EX_FULLROWSELECT);
+ }
+ }
+
+ // Enumeration
+ Zero(&e, sizeof(e));
+ if (CALL(hWnd, CcEnumVLan(cm->Client, &e)))
+ {
+ LVB *b = LvInsertStart();
+ UINT i;
+ for (i = 0;i < e.NumItem;i++)
+ {
+ wchar_t name[MAX_SIZE];
+ wchar_t mac[MAX_SIZE];
+ wchar_t ver[MAX_SIZE];
+ char str[MAX_SIZE];
+ wchar_t *status;
+ RPC_CLIENT_ENUM_VLAN_ITEM *v = e.Items[i];
+
+ // Device name
+ CmVLanNameToPrintName(str, sizeof(str), v->DeviceName);
+ StrToUni(name, sizeof(name), str);
+
+ // Status
+ status = v->Enabled ? _UU("CM_VLAN_ENABLED") : _UU("CM_VLAN_DISABLED");
+
+ // MAC address
+ StrToUni(mac, sizeof(mac), v->MacAddress);
+
+ // Version
+ StrToUni(ver, sizeof(ver), v->Version);
+
+ LvInsertAdd(b, v->Enabled ? ICO_NIC_ONLINE : ICO_NIC_OFFLINE, NULL, 4,
+ name, status, mac, ver);
+ }
+ LvInsertEnd(b, hWnd, L_VLAN);
+
+ CiFreeClientEnumVLan(&e);
+ }
+}
+
+// Get a protocol name string
+wchar_t *CmGetProtocolName(UINT n)
+{
+ return GetProtocolName(n);
+}
+
+// Display update
+void CmRefresh(HWND hWnd)
+{
+ CmRefreshEx(hWnd, false);
+}
+void CmRefreshEx(HWND hWnd, bool style_changed)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Update size
+ CmMainWindowOnSize(hWnd);
+
+ // Updating the VLAN list
+ CmRefreshVLanListEx(hWnd, style_changed);
+
+ // Update the account list
+ CmRefreshAccountListEx2(hWnd, false, style_changed);
+
+ // Update the status bar
+ CmRefreshStatusBar(hWnd);
+}
+
+// Determine whether to check the specified menu item
+bool CmIsChecked(UINT id)
+{
+ switch (id)
+ {
+ case CMD_TRAYICON:
+ return cm->HideTrayIcon == false;
+ case CMD_STATUSBAR:
+ return cm->HideStatusBar == false;
+ case CMD_VISTASTYLE:
+ return cm->VistaStyle;
+ case CMD_ICON:
+ return cm->IconView;
+ case CMD_DETAIL:
+ return cm->IconView == false;
+ case CMD_GRID:
+ return cm->ShowGrid;
+ case CMD_VOIDE_NONE:
+ return cm->DisableVoice;
+ case CMD_SHOWPORT:
+ return cm->ShowPort;
+ case CMD_VOICE_NORMAL:
+ if (cm->DisableVoice)
+ {
+ return false;
+ }
+ else
+ {
+ return cm->VoiceId == VOICE_SSK;
+ }
+ case CMD_VOICE_ODD:
+ if (cm->DisableVoice)
+ {
+ return false;
+ }
+ else
+ {
+ return cm->VoiceId == VOICE_AHO;
+ }
+ }
+ return false;
+}
+
+// The menu popped-up
+void CmMainWindowOnPopupMenu(HWND hWnd, HMENU hMenu, UINT pos)
+{
+ UINT num_menu, i, id;
+ // Validate arguments
+ if (hWnd == NULL || hMenu == NULL)
+ {
+ return;
+ }
+
+ num_menu = GetMenuItemCount(hMenu);
+ for (i = 0;i < num_menu;i++)
+ {
+ id = GetMenuItemID(hMenu, i);
+
+ if (id != INFINITE)
+ {
+ bool enable_flag = CmIsEnabled(hWnd, id);
+ bool checked_flag = CmIsChecked(id);
+ bool bold_flag = CmIsBold(id);
+ MENUITEMINFO info;
+
+ Zero(&info, sizeof(info));
+ info.cbSize = sizeof(info);
+ info.fMask = MIIM_STATE;
+ info.fState = (enable_flag ? MFS_ENABLED : MFS_DISABLED) |
+ (checked_flag ? MFS_CHECKED : MFS_UNCHECKED) |
+ (bold_flag ? MFS_DEFAULT : 0);
+
+ if (id == CMD_ICON || id == CMD_DETAIL || id == CMD_VOIDE_NONE ||
+ id == CMD_VOICE_NORMAL || id == CMD_VOICE_ODD)
+ {
+ info.fMask |= MIIM_FTYPE;
+ info.fType = MFT_RADIOCHECK;
+ }
+
+ SetMenuItemInfo(hMenu, id, false, &info);
+ }
+
+ if (id == CMD_RECENT)
+ {
+ HMENU sub = CmCreateRecentSubMenu(hWnd, CM_TRAY_MENU_RECENT_ID_START);
+
+ if (sub != NULL)
+ {
+ DeleteMenu(hMenu, i, MF_BYPOSITION);
+ MsInsertMenu(hMenu, i, MF_BYPOSITION | MF_ENABLED | MF_POPUP | MF_STRING,
+ (UINT_PTR)sub, _UU("CM_TRAY_MENU_RECENT"));
+ }
+ else
+ {
+ MENUITEMINFO info;
+
+ Zero(&info, sizeof(info));
+ info.cbSize = sizeof(info);
+ info.fMask = MIIM_STATE;
+ info.fState = MFS_DISABLED;
+
+ SetMenuItemInfo(hMenu, id, false, &info);
+ }
+ }
+ }
+}
+
+// Set the main window title
+wchar_t *CmGenerateMainWindowTitle()
+{
+ wchar_t tmp[MAX_SIZE];
+ if (cm->server_name == NULL)
+ {
+ UniFormat(tmp, sizeof(tmp), L"%s", _UU("CM_TITLE"));
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), L"%s - %S", _UU("CM_TITLE"), cm->server_name);
+ }
+
+ return CopyUniStr(tmp);
+}
+
+// Initialize the task tray
+void CmInitTray(HWND hWnd)
+{
+ bool ret;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (cm->server_name != NULL)
+ {
+ return;
+ }
+
+ if (cm->TrayInited)
+ {
+ return;
+ }
+
+ ret = MsShowIconOnTray(hWnd, LoadSmallIcon(CmGetTrayIconId(false, 0)), _UU("CM_TRAY_INITING"), WM_CM_TRAY_MESSAGE);
+
+ cm->TrayInited = true;
+ cm->TrayAnimation = false;
+ cm->TraySucceed = ret;
+
+ SetTimer(hWnd, 2, CM_TRAY_ANIMATION_INTERVAL / 4, NULL);
+}
+
+// Change the string in the task tray
+void CmChangeTrayString(HWND hWnd, wchar_t *str)
+{
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return;
+ }
+ if (cm->TrayInited == false)
+ {
+ return;
+ }
+
+ MsChangeIconOnTray(NULL, str);
+}
+
+// Release the task tray
+void CmFreeTray(HWND hWnd)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (cm->TrayInited == false)
+ {
+ return;
+ }
+
+ MsHideIconOnTray();
+
+ cm->TrayInited = false;
+}
+void CmFreeTrayExternal(void *hWnd)
+{
+ CmFreeTray((HWND)hWnd);
+}
+
+// Periodical processing to the task tray
+void CmPollingTray(HWND hWnd)
+{
+ UINT interval;
+ bool ret;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (cm->TrayInited == false)
+ {
+ return;
+ }
+
+ ret = MsChangeIconOnTrayEx(LoadSmallIcon(CmGetTrayIconId(cm->TrayAnimation, cm->TrayAnimationCounter)),
+ NULL, NULL, NULL, NIIF_NONE, !cm->TraySucceed);
+
+ if (cm->TraySucceed == false)
+ {
+ cm->TraySucceed = ret;
+ }
+
+ cm->TrayAnimationCounter++;
+
+ KillTimer(hWnd, 2);
+ interval = CM_TRAY_ANIMATION_INTERVAL / 4;
+ if (cm->TraySpeedAnimation)
+ {
+ interval /= 4;
+ }
+ SetTimer(hWnd, 2, interval, NULL);
+}
+
+// Get the icon ID of the task tray for animation
+UINT CmGetTrayIconId(bool animation, UINT animation_counter)
+{
+ if (animation == false)
+ {
+ return ICO_TRAY0;
+ }
+ else
+ {
+ switch (animation_counter % 4)
+ {
+ case 0:
+ return ICO_TRAY1;
+
+ case 1:
+ return ICO_TRAY2;
+
+ case 2:
+ return ICO_TRAY3;
+
+ default:
+ return ICO_TRAY4;
+ }
+ }
+}
+
+// Initialize the main window
+void CmMainWindowOnInit(HWND hWnd)
+{
+ wchar_t *s;
+ BUF *b;
+ bool startup_mode = cm->StartupMode;
+ CM_SETTING a;
+ bool fake = false;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Font settings of list
+ SetFontMeiryo(hWnd, L_ACCOUNT, 9);
+ SetFontMeiryo(hWnd, L_VLAN, 9);
+
+ // Get the configuration of the current vpnclient
+ Zero(&a, sizeof(a));
+ CcGetCmSetting(cm->Client, &a);
+
+ if (a.EasyMode)
+ {
+ fake = true;
+ }
+
+ InitMenuInternational(GetMenu(hWnd), "CM_MENU");
+
+ cm->HideStatusBar = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "HideStatusBar");
+ cm->HideTrayIcon = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "HideTrayIcon");
+ cm->IconView = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "IconView");
+ cm->ShowGrid = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "ShowGrid");
+
+ if (MsRegIsValue(REG_CURRENT_USER, CM_REG_KEY, "VistaStyle"))
+ {
+ cm->VistaStyle = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "VistaStyle");
+ }
+ else
+ {
+ cm->VistaStyle = MsIsVista();
+ }
+
+ if (MsRegIsValue(REG_CURRENT_USER, CM_REG_KEY, "ShowPort"))
+ {
+ cm->ShowPort = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "ShowPort");
+ }
+ else
+ {
+ cm->ShowPort = false;
+ }
+
+ if (MsRegIsValue(REG_CURRENT_USER, CM_REG_KEY, "DisableVoice"))
+ {
+ cm->DisableVoice = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "DisableVoice");
+ }
+ else
+ {
+ cm->DisableVoice = true;
+ }
+ cm->VoiceId = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "VoiceId");
+
+ cm->StatusWindowList = NewList(NULL);
+
+ SetIcon(hWnd, 0, ICO_VPN);
+
+ s = CmGenerateMainWindowTitle();
+ SetText(hWnd, 0, s);
+ Free(s);
+
+ // Initialize the window position
+ b = MsRegReadBin(REG_CURRENT_USER, CM_REG_KEY, "WindowPlacement");
+ if (b != NULL && b->Size == sizeof(WINDOWPLACEMENT))
+ {
+ // Restore the window position
+ WINDOWPLACEMENT *p;
+ p = ZeroMalloc(b->Size);
+ Copy(p, b->Buf, b->Size);
+
+ if (startup_mode)
+ {
+ p->showCmd = SW_SHOWMINIMIZED;
+ }
+
+ if (fake)
+ {
+ Copy(&cm->FakeWindowPlacement, p, sizeof(WINDOWPLACEMENT));
+ }
+ else
+ {
+ SetWindowPlacement(hWnd, p);
+ }
+ Free(p);
+ }
+ else
+ {
+ // Initialize the window position
+ SetWindowPos(hWnd, NULL, 0, 0, CM_DEFAULT_WIDTH, CM_DEFAULT_HEIGHT, SWP_NOREDRAW);
+ Center(hWnd);
+ if (startup_mode)
+ {
+ ShowWindow(hWnd, SW_SHOWMINIMIZED);
+ }
+
+ if (fake)
+ {
+ WINDOWPLACEMENT p;
+
+ Zero(&p, sizeof(p));
+ p.length = sizeof(p);
+ GetWindowPlacement(hWnd, &p);
+ Copy(&cm->FakeWindowPlacement, &p, sizeof(WINDOWPLACEMENT));
+ }
+ }
+ FreeBuf(b);
+
+ if (fake)
+ {
+ SetWindowPos(hWnd, NULL, -200, -200, 100, 100,
+ SWP_NOREDRAW | SWP_SHOWWINDOW);
+ }
+
+ // Initialize the status bar related items
+ cm->hMainWnd = hWnd;
+ cm->hStatusBar = CreateStatusWindowW(WS_CHILD |
+ (cm->HideStatusBar == false ? WS_VISIBLE : 0),
+ _UU("CM_TITLE"),
+ hWnd, S_STATUSBAR);
+
+ UniStrCpy(cm->StatudBar1, sizeof(cm->StatudBar1), _UU("CM_TITLE"));
+ UniStrCpy(cm->StatudBar2, sizeof(cm->StatudBar2), _UU("CM_CONN_NO"));
+ UniFormat(cm->StatudBar3, sizeof(cm->StatudBar3), _UU("CM_PRODUCT_NAME"), CEDAR_BUILD);
+
+ cm->Icon2 = LoadSmallIcon(ICO_SERVER_OFFLINE);
+ cm->Icon3 = LoadSmallIcon(ICO_VPN);
+
+ // Initialize the account list
+ CmInitAccountList(hWnd);
+
+ // Initialize the VLAN list
+ CmInitVLanList(hWnd);
+
+ // Display update
+ CmRefreshEx(hWnd, true);
+
+ // Start a thread of notification client
+ CmInitNotifyClientThread();
+
+ // Timer setting
+ SetTimer(hWnd, 1, 128, NULL);
+ SetTimer(hWnd, 6, 5000, NULL);
+
+ // Initialize the task tray
+ if (cm->server_name == NULL)
+ {
+ if (cm->HideTrayIcon == false)
+ {
+ CmInitTray(hWnd);
+ }
+ }
+
+ CmVoice("start");
+
+ if (startup_mode || a.EasyMode)
+ {
+ SetTimer(hWnd, 3, 1, NULL);
+ }
+
+ if (cm->import_file_name != NULL)
+ {
+ // Import a file specified as an argument
+ CmSendImportMessage(hWnd, cm->import_file_name, cm->CmSettingInitialFlag == CM_SETTING_INIT_NONE ? CM_IMPORT_FILENAME_MSG : CM_IMPORT_FILENAME_MSG_OVERWRITE);
+ /*if (a.LockMode == false)
+ {
+ CmImportAccountMainEx(hWnd, cm->import_file_name, cm->CmSettingInitialFlag != CM_SETTING_INIT_NONE);
+ }
+ else
+ {
+ MsgBox(cm->hEasyWnd ? cm->hEasyWnd : hWnd, MB_ICONEXCLAMATION, _UU("CM_VPN_FILE_IMPORT_NG"));
+ }*/
+ }
+
+ // Apply the CM_SETTING
+ CmApplyCmSetting();
+
+ cm->StartupFinished = true;
+}
+
+// Start a thread of notification client
+void CmInitNotifyClientThread()
+{
+ cm->NotifyClient = CcConnectNotify(cm->Client);
+ if (cm->NotifyClient == false)
+ {
+ Close(cm->hMainWnd);
+ exit(0);
+ }
+ cm->NotifyClientThread = NewThread(CmNotifyClientThread, NULL);
+}
+
+// Notification client thread
+void CmNotifyClientThread(THREAD *thread, void *param)
+{
+ NOTIFY_CLIENT *nc;
+ // Validate arguments
+ if (thread == NULL)
+ {
+ return;
+ }
+
+ nc = cm->NotifyClient;
+
+ // Wait for the next notification
+ while (cm->Halt == false)
+ {
+ if (CcWaitNotify(nc))
+ {
+ // Send a message
+ PostMessage(cm->hMainWnd, WM_CM_NOTIFY, 0, 0);
+ }
+ else
+ {
+ // Disconnected
+ if (cm->Halt == false)
+ {
+ if (cm != NULL)
+ {
+ CmFreeTrayExternal((void *)cm->hMainWnd);
+ }
+ CncExit();
+ exit(0);
+ }
+ break;
+ }
+ }
+}
+
+// Stop the thread of the notification client
+void CmFreeNotifyClientThread()
+{
+ cm->Halt = true;
+
+ // Disconnect
+ CcStopNotify(cm->NotifyClient);
+
+ // Wait for the termination of the thread
+ WaitThread(cm->NotifyClientThread, INFINITE);
+
+ // Connection termination
+ CcDisconnectNotify(cm->NotifyClient);
+ ReleaseThread(cm->NotifyClientThread);
+}
+
+// Resize the main window
+void CmMainWindowOnSize(HWND hWnd)
+{
+ RECT r;
+ UINT client_width, client_height;
+ UINT status_height;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Get the size of the client area of the main window
+ GetClientRect(hWnd, &r);
+ client_width = MAX(r.right - r.left, 0);
+ client_height = MAX(r.bottom - r.top, 0);
+
+ SendMsg(hWnd, S_STATUSBAR, WM_SIZE, 0, 0);
+
+ // Get the size of the status bar
+ GetWindowRect(DlgItem(hWnd, S_STATUSBAR), &r);
+ status_height = MAX(r.bottom - r.top, 0);
+
+ if (cm->HideStatusBar == false)
+ {
+ client_height = MAX(client_height - status_height, 0);
+ }
+
+ MoveWindow(DlgItem(hWnd, L_ACCOUNT), 0, 0, client_width, client_height * 3 / 5 - 3, true);
+ MoveWindow(DlgItem(hWnd, L_VLAN), 0, client_height * 3 / 5, client_width, client_height * 2 / 5, true);
+
+ // Re-draw the status bar
+ CmRedrawStatusBar(hWnd);
+}
+
+// Disconnect all accounts currently connected
+void CmDisconnectAll(HWND hWnd)
+{
+ UINT i, num;
+ LIST *o;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Display a warning
+ num = CmGetNumConnected(hWnd);
+ if (num == 0)
+ {
+ return;
+ }
+
+ if (MsgBoxEx(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_DISCONNECT_ALL"), num) == IDNO)
+ {
+ return;
+ }
+
+ cm->PositiveDisconnectFlag = true;
+
+ // Create a list of connected items
+ o = NewListFast(NULL);
+
+ num = LvNum(hWnd, L_ACCOUNT);
+ for (i = 0;i < num;i++)
+ {
+ wchar_t *s = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+ if (s != NULL)
+ {
+ if (UniStrCmpi(s, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(s, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+ {
+ Add(o, LvGetStr(hWnd, L_ACCOUNT, i, 0));
+ }
+ Free(s);
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ wchar_t *s = LIST_DATA(o, i);
+ if (s != NULL)
+ {
+ CmDisconnect(hWnd, s);
+ Free(s);
+ }
+ }
+
+ ReleaseList(o);
+}
+
+// Get a number of currently connected connection settings
+UINT CmGetNumConnected(HWND hWnd)
+{
+ UINT i, num, num_active;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ num_active = 0;
+ num = LvNum(hWnd, L_ACCOUNT);
+ for (i = 0;i < num;i++)
+ {
+ wchar_t *s = LvGetStr(hWnd, L_ACCOUNT, i, 1);
+ if (s != NULL)
+ {
+ if (UniStrCmpi(s, _UU("CM_ACCOUNT_ONLINE")) == 0 || UniStrCmpi(s, _UU("CM_ACCOUNT_CONNECTING")) == 0)
+ {
+ num_active++;
+ }
+ Free(s);
+ }
+ }
+
+ return num_active;
+}
+
+// Update the status bar information
+void CmRefreshStatusBar(HWND hWnd)
+{
+ UINT num_active = CmGetNumConnected(hWnd);
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (num_active == 0)
+ {
+ UniStrCpy(cm->StatudBar2, sizeof(cm->StatudBar2), _UU("CM_CONN_NO"));
+ cm->Icon2 = LoadSmallIcon(ICO_SERVER_OFFLINE);
+ }
+ else
+ {
+ UniFormat(cm->StatudBar2, sizeof(cm->StatudBar2), _UU("CM_NUM_CONN_COUNT"), num_active);
+ cm->Icon2 = LoadSmallIcon(ICO_SERVER_ONLINE);
+ }
+
+ CmRedrawStatusBar(hWnd);
+}
+
+// Re-draw the status bar
+void CmRedrawStatusBar(HWND hWnd)
+{
+ HWND h;
+ RECT r;
+ int width;
+ int x1, x2, x3;
+ int xx[3];
+ wchar_t tmp[MAX_SIZE];
+ HICON icon;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ h = cm->hStatusBar;
+
+ // Get the width of the status bar
+ GetWindowRect(h, &r);
+ width = MAX(r.right - r.left, 0);
+ x2 = (UINT)(180.0 * GetTextScalingFactor());
+ x3 = (UINT)(245.0 * GetTextScalingFactor());
+ x1 = MAX(width - x2 - x3, 0);
+
+ // Divide into three parts
+ xx[0] = x1;
+ xx[1] = x2 + x1;
+ xx[2] = x3 + x2 + x1;
+ SendMsg(h, 0, SB_SETPARTS, 3, (LPARAM)xx);
+
+ // Set an icon
+ icon = (HICON)SendMsg(h, 0, SB_GETICON, 1, 0);
+ if (icon != cm->Icon2)
+ {
+ SendMsg(h, 0, SB_SETICON, 1, (LPARAM)cm->Icon2);
+ }
+
+ icon = (HICON)SendMsg(h, 0, SB_GETICON, 2, 0);
+ if (icon != cm->Icon3)
+ {
+ SendMsg(h, 0, SB_SETICON, 2, (LPARAM)cm->Icon3);
+ }
+
+ // Set a string
+ SendMsg(h, 0, SB_GETTEXTW, 0, (LPARAM)tmp);
+ if (UniStrCmp(tmp, cm->StatudBar1))
+ {
+ SendMsg(h, 0, SB_SETTEXTW, 0, (LPARAM)cm->StatudBar1);
+ }
+
+ SendMsg(h, 0, SB_GETTEXTW, 1, (LPARAM)tmp);
+ if (UniStrCmp(tmp, cm->StatudBar2))
+ {
+ SendMsg(h, 0, SB_SETTEXTW, 1, (LPARAM)cm->StatudBar2);
+ }
+
+ SendMsg(h, 0, SB_GETTEXTW, 2, (LPARAM)tmp);
+ if (UniStrCmp(tmp, cm->StatudBar3))
+ {
+ SendMsg(h, 0, SB_SETTEXTW, 2, (LPARAM)cm->StatudBar3);
+ }
+}
+
+// Save the position information of the main window
+void CmSaveMainWindowPos(HWND hWnd)
+{
+ WINDOWPLACEMENT p;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ // Save settings
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "HideStatusBar", cm->HideStatusBar);
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "HideTrayIcon", cm->HideTrayIcon);
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "IconView", cm->IconView);
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "ShowGrid", cm->ShowGrid);
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "DisableVoice", cm->DisableVoice);
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "VoiceId", cm->VoiceId);
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "VistaStyle", cm->VistaStyle);
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY, "ShowPort", cm->ShowPort);
+
+ // Save the window position
+ Zero(&p, sizeof(p));
+ p.length = sizeof(p);
+ GetWindowPlacement(hWnd, &p);
+
+ if (IsZero(&cm->FakeWindowPlacement, sizeof(cm->FakeWindowPlacement)) == false)
+ {
+ Copy(&p, &cm->FakeWindowPlacement, sizeof(cm->FakeWindowPlacement));
+ }
+
+ MsRegWriteBin(REG_CURRENT_USER, CM_REG_KEY, "WindowPlacement", &p, sizeof(p));
+
+ CmSaveAccountListPos(hWnd);
+ CmSaveVLanListPos(hWnd);
+}
+
+// Close the main window
+void CmMainWindowOnQuit(HWND hWnd)
+{
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (cm->TrayInited)
+ {
+ if (MsgBox(hWnd, MB_YESNO | MB_ICONQUESTION,
+ _UU("CM_EXIT_MESSAGE")) == IDNO)
+ {
+ return;
+ }
+ }
+
+ if (cm->OnCloseDispatched)
+ {
+ return;
+ }
+ cm->OnCloseDispatched = true;
+
+ CmCloseEasy();
+
+ // Release the tray icon
+ CmFreeTray(hWnd);
+
+ // Save the position information of the main window
+ CmSaveMainWindowPos(hWnd);
+
+ // Close the status window
+ for (i = 0;i < LIST_NUM(cm->StatusWindowList);i++)
+ {
+ HWND h = LIST_DATA(cm->StatusWindowList, i);
+ //EndDialog(h, 0);
+ PostMessage(h, WM_CLOSE, 0, 0);
+ }
+
+ ReleaseList(cm->StatusWindowList);
+ cm->StatusWindowList = NULL;
+
+ if (cm->WindowCount != 0)
+ {
+ // Abort
+ exit(0);
+ }
+
+ // Close
+ CmFreeNotifyClientThread();
+
+ EndDialog(hWnd, false);
+}
+
+// Start the mutex to be used in starting
+bool CmStartStartupMutex()
+{
+ INSTANCE *o = NewSingleInstance(STARTUP_MUTEX_NAME);
+
+ if (o == NULL)
+ {
+ return false;
+ }
+
+ cm->StartupMutex = o;
+
+ return true;
+}
+
+// Release the mutex to be used in starting
+void CmEndStartupMutex()
+{
+ if (cm->StartupMutex != NULL)
+ {
+ FreeSingleInstance(cm->StartupMutex);
+
+ cm->StartupMutex = NULL;
+ }
+}
+
+// Main window
+void MainCMWindow()
+{
+ HWND h;
+ wchar_t *s;
+ CM_SETTING a;
+
+ if (CmStartStartupMutex() == false)
+ {
+ return;
+ }
+
+ s = CmGenerateMainWindowTitle();
+ h = SearchWindow(s);
+ Free(s);
+
+ Zero(&a, sizeof(a));
+ CcGetCmSetting(cm->Client, &a);
+ if (cm->server_name != NULL && a.EasyMode)
+ {
+ CmEndStartupMutex();
+ MsgBox(NULL, MB_ICONEXCLAMATION, _UU("CM_EASY_MODE_NOT_ON_REMOTE"));
+ return;
+ }
+
+ // Change the operating mode
+ if (cm->CmSettingSupported)
+ {
+ if (cm->CmSettingInitialFlag == CM_SETTING_INIT_SELECT)
+ {
+ if (h != NULL)
+ {
+ CmEndStartupMutex();
+ }
+
+ // Show the selection screen
+ CmSetting(NULL);
+
+ if (h != NULL)
+ {
+ goto SEND_MESSAGES;
+ }
+ else
+ {
+ return;
+ }
+ }
+ else if ((cm->CmSettingInitialFlag == CM_SETTING_INIT_EASY && cm->CmEasyModeSupported) || cm->CmSettingInitialFlag == CM_SETTING_INIT_NORMAL)
+ {
+ // State transition
+ CM_SETTING a;
+
+ Zero(&a, sizeof(a));
+ CcGetCmSetting(cm->Client, &a);
+
+ if (cm->CmSettingInitialFlag == CM_SETTING_INIT_EASY)
+ {
+ a.EasyMode = true;
+ }
+ else
+ {
+ a.EasyMode = false;
+ }
+
+ CcSetCmSetting(cm->Client, &a);
+ }
+ }
+
+ if (h == NULL)
+ {
+ // Create a window because there is no window of the same title
+ if (cm->server_name == NULL)
+ {
+ CmInitTryToExecUiHelper();
+
+ if (IsDebug() == false)
+ {
+ CnWaitForCnServiceReady();
+ }
+ }
+ Dialog(NULL, D_CM_MAIN, CmMainWindowProc, NULL);
+ CmFreeTryToExecUiHelper();
+ }
+ else
+ {
+SEND_MESSAGES:
+ CmEndStartupMutex();
+
+ // If a window of the same title already exists, activate it and exit itself
+ SetForegroundWindow(h);
+ SendMessage(h, WM_CM_SHOW, 0, 0);
+ SetForegroundWindow(h);
+
+ if (cm->CmSettingInitialFlag != CM_SETTING_INIT_NONE && cm->CmSettingInitialFlag != CM_SETTING_INIT_CONNECT)
+ {
+ // Notify since CM_SETTING has been changed
+ SendMessage(h, WM_CM_SETTING_CHANGED_MESSAGE, 0, 0);
+ }
+
+ if (cm->import_file_name != NULL)
+ {
+ UINT msg;
+ if (cm->CmSettingInitialFlag == CM_SETTING_INIT_NONE)
+ {
+ msg = CM_IMPORT_FILENAME_MSG;
+ }
+ else
+ {
+ msg = CM_IMPORT_FILENAME_MSG_OVERWRITE;
+ }
+
+ CmSendImportMessage(h, cm->import_file_name, msg);
+ }
+ }
+
+ CmEndStartupMutex();
+}
+
+// Send an import message
+void CmSendImportMessage(HWND hWnd, wchar_t *filename, UINT msg)
+{
+ COPYDATASTRUCT cpy;
+ // Validate arguments
+ if (hWnd == NULL || filename == NULL)
+ {
+ return;
+ }
+
+ // Specify the file to be imported
+ Zero(&cpy, sizeof(cpy));
+
+ cpy.cbData = UniStrSize(filename);
+ cpy.lpData = filename;
+ cpy.dwData = msg;
+
+ SendMessage(hWnd, WM_COPYDATA, 0, (LPARAM)&cpy);
+}
+
+// Login dialog
+UINT CmLoginDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ // Validate arguments
+ wchar_t server_name[MAX_SIZE];
+ char password[MAX_PASSWORD_LEN + 1];
+ bool bad_pass;
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ if (cm->server_name != NULL)
+ {
+ StrToUni(server_name, sizeof(server_name), cm->server_name);
+ }
+ else
+ {
+ UniStrCpy(server_name, sizeof(server_name), _UU("CM_PW_LOCALMACHINE"));
+ }
+ FormatText(hWnd, S_TITLE, server_name);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ if (cm->server_name != NULL)
+ {
+ StrToUni(server_name, sizeof(server_name), cm->server_name);
+ }
+ else
+ {
+ UniStrCpy(server_name, sizeof(server_name), _UU("CM_PW_LOCALMACHINE"));
+ }
+ GetTxtA(hWnd, E_PASSWORD, password, sizeof(password));
+ cm->Client = CcConnectRpc(cm->server_name == NULL ? "127.0.0.1" : cm->server_name,
+ password, &bad_pass, NULL, 0);
+ if (cm->Client == NULL)
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("CM_BAD_PASSWORD"));
+ FocusEx(hWnd, E_PASSWORD);
+ }
+ else
+ {
+ EndDialog(hWnd, true);
+ }
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Login
+bool LoginCM()
+{
+ // Try to login with an empty password first
+ bool bad_pass, no_remote;
+ wchar_t server_name[MAX_SIZE];
+ RPC_CLIENT_VERSION a;
+
+RETRY:
+ if (cm->server_name != NULL)
+ {
+ StrToUni(server_name, sizeof(server_name), cm->server_name);
+ }
+ else
+ {
+ UniStrCpy(server_name, sizeof(server_name), _UU("CM_PW_LOCALMACHINE"));
+ }
+
+ // Attempt to connect
+ if ((cm->Client = CcConnectRpc(
+ cm->server_name == NULL ? "localhost" : cm->server_name,
+ "", &bad_pass, &no_remote, cm->StartupMode == false ? 0 : 60000)) == NULL)
+ {
+ if (no_remote)
+ {
+ // Remote connection was denied
+ if (MsgBoxEx(NULL, MB_ICONEXCLAMATION | MB_RETRYCANCEL, _UU("CM_NO_REMOTE"), server_name) == IDRETRY)
+ {
+ // Retry
+ goto RETRY;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if (bad_pass)
+ {
+ if (Dialog(NULL, D_CM_LOGIN, CmLoginDlgProc, NULL) == false)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // Connection failure
+ if (cm->StartupMode == false && MsgBoxEx(NULL, MB_ICONEXCLAMATION | MB_RETRYCANCEL, _UU("CM_CONNECT_FAILED"), server_name) == IDRETRY)
+ {
+ // Retry
+ goto RETRY;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ Zero(&a, sizeof(a));
+ CcGetClientVersion(cm->Client, &a);
+ if (a.ClientBuildInt >= 5192)
+ {
+ cm->CmSettingSupported = true;
+ cm->CmEasyModeSupported = true;
+ if (OS_IS_WINDOWS_9X(a.OsType))
+ {
+ cm->CmEasyModeSupported = false;
+ }
+ }
+
+ return true;
+}
+
+// Main process
+void MainCM()
+{
+ // If there is /remote in the argument, show the screen of the remote connection
+ char *cmdline = GetCommandLineStr();
+
+ if (StrCmpi(cmdline, "/remote") == 0)
+ {
+ char *hostname = RemoteDlg(NULL, CM_REG_KEY, ICO_VPN, _UU("CM_TITLE"), _UU("CM_REMOTE_TITLE"), NULL);
+ if (hostname == NULL)
+ {
+ return;
+ }
+ if (cm->server_name != NULL)
+ {
+ Free(cm->server_name);
+ }
+ cm->server_name = NULL;
+ if (StrCmpi(hostname, "localhost") != 0 && StrCmpi(hostname, "127.0.0.1") != 0 )
+ {
+ cm->server_name = hostname;
+ }
+ }
+
+ if (StrCmpi(cmdline, "/startup") == 0)
+ {
+ // Startup mode
+ cm->StartupMode = true;
+ }
+
+ Free(cmdline);
+
+ if (IsZero(cm->ShortcutKey, SHA1_SIZE) == false)
+ {
+ //if (MsGetCurrentTerminalSessionId() == 0)
+ {
+ // Start the shortcut connection
+ CmConnectShortcut(cm->ShortcutKey);
+ }/*
+ else
+ {
+ MsgBoxEx(NULL, MB_ICONEXCLAMATION, _UU("CM_SHORTCUT_DESKTOP_MSG"),
+ MsGetCurrentTerminalSessionId());
+ }*/
+ return;
+ }
+
+ // Login
+ if (LoginCM() == false)
+ {
+ return;
+ }
+
+ //Update the jump list
+ CmUpdateJumpList(0);
+
+ // Main window
+ MainCMWindow();
+
+ // Log out
+ LogoutCM();
+
+ if (cm->Update != NULL)
+ {
+ FreeUpdateUi(cm->Update);
+ cm->Update = NULL;
+ }
+}
+
+// Log out
+void LogoutCM()
+{
+ if (cm->Client != NULL)
+ {
+ CcDisconnectRpc(cm->Client);
+ }
+}
+
+// Client Connection Manager start function
+void CMExec()
+{
+ // Initialize
+ InitCM(true);
+
+ // Main process
+ MainCM();
+
+ // Release
+ FreeCM();
+}
+
+// HUB enumeration thread
+void CmEnumHubThread(THREAD *t, void *param)
+{
+ CM_ENUM_HUB *e = (CM_ENUM_HUB *)param;
+ HWND hWnd;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ e->Thread = t;
+ hWnd = e->hWnd;
+ LockList(cm->EnumHubList);
+ {
+ Add(cm->EnumHubList, e);
+ }
+ UnlockList(cm->EnumHubList);
+
+ // Thread initialization is completed
+ NoticeThreadInit(t);
+
+ // Create a session
+ e->Session = NewRpcSession(cm->Cedar, e->ClientOption);
+ if (e->Session)
+ {
+ // Enumeration of HUB
+ e->Hub = EnumHub(e->Session);
+
+ if (e->Hub != NULL)
+ {
+ // Enumeration completed
+ // Add to the combo box
+ if (CbNum(hWnd, C_HUBNAME) == 0)
+ {
+ UINT i;
+ wchar_t tmp[MAX_SIZE];
+ for (i = 0;i < e->Hub->NumTokens;i++)
+ {
+ StrToUni(tmp, sizeof(tmp), e->Hub->Token[i]);
+ CbAddStr(hWnd, C_HUBNAME, tmp, 0);
+ }
+ }
+
+ // Release the memory
+ FreeToken(e->Hub);
+ }
+
+ // Release the session
+ ReleaseSession(e->Session);
+ }
+
+ LockList(cm->EnumHubList);
+ {
+ Delete(cm->EnumHubList, e);
+ }
+ UnlockList(cm->EnumHubList);
+
+ Free(e->ClientOption);
+ Free(e);
+}
+
+// The start of the HUB enumeration
+void CmEnumHubStart(HWND hWnd, CLIENT_OPTION *o)
+{
+ CM_ENUM_HUB *e;
+ THREAD *t;
+ // Validate arguments
+ if (hWnd == NULL || o == NULL)
+ {
+ return;
+ }
+
+ if (StrLen(o->Hostname) == 0 ||
+ o->Port == 0)
+ {
+ return;
+ }
+
+ if (o->ProxyType != PROXY_DIRECT)
+ {
+ if (StrLen(o->ProxyName) == 0 ||
+ o->ProxyPort == 0)
+ {
+ return;
+ }
+ }
+
+ if (LvNum(hWnd, C_HUBNAME) != 0)
+ {
+ return;
+ }
+
+ e = ZeroMalloc(sizeof(CM_ENUM_HUB));
+ e->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ e->hWnd = hWnd;
+ Copy(e->ClientOption, o, sizeof(CLIENT_OPTION));
+
+ t = NewThread(CmEnumHubThread, e);
+ WaitThreadInit(t);
+ ReleaseThread(t);
+}
+
+// Initialize the HUB enumeration process
+void CmInitEnumHub()
+{
+ cm->EnumHubList = NewList(NULL);
+}
+
+// Release the HUB enumeration process
+void CmFreeEnumHub()
+{
+ LIST *o;
+ UINT i;
+ if (cm->EnumHubList == NULL)
+ {
+ return;
+ }
+
+ o = NewList(NULL);
+ LockList(cm->EnumHubList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(cm->EnumHubList);i++)
+ {
+ CM_ENUM_HUB *e = LIST_DATA(cm->EnumHubList, i);
+ Add(o, e->Thread);
+ AddRef(e->Thread->ref);
+ }
+ }
+ UnlockList(cm->EnumHubList);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ THREAD *t = LIST_DATA(o, i);
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+ }
+ ReleaseList(o);
+
+ ReleaseList(cm->EnumHubList);
+}
+
+// Initialize the Client Connection Manager
+
+void InitCM(bool set_app_id)
+{
+ UNI_TOKEN_LIST *ut;
+ if (cm != NULL)
+ {
+ return;
+ }
+
+ if (set_app_id)
+ {
+ if(JL_SetCurrentProcessExplicitAppUserModelID(APPID_CM) != S_OK)
+ {
+ }
+ }
+
+ CmDeleteOldStartupTrayFile();
+
+ MsSetShutdownParameters(0x4ff, SHUTDOWN_NORETRY);
+
+ // Memory allocation
+ cm = ZeroMalloc(sizeof(CM));
+
+ // If the command line argument is set treat it as a server name
+ ut = GetCommandLineUniToken();
+
+ if (ut->NumTokens >= 1)
+ {
+ if (UniStrLen(ut->Token[0]) != 0)
+ {
+ if (UniStrCmpi(ut->Token[0], L"cm") != 0 && ut->Token[0][0] != L'/')
+ {
+ BUF *b = UniStrToBin(ut->Token[0]);
+ if (b->Size == SHA1_SIZE)
+ {
+ // Treated as a shortcut key for the connection settings
+ Copy(cm->ShortcutKey, b->Buf, SHA1_SIZE);
+ }
+ else
+ {
+ if (UniEndWith(ut->Token[0], L".vpn") == false)
+ {
+ // Treated as a server name
+ cm->server_name = CopyUniToStr(ut->Token[0]);
+ }
+ else
+ {
+ // Treated as import file name
+ cm->import_file_name = CopyUniStr(ut->Token[0]);
+ }
+ }
+ FreeBuf(b);
+ }
+ else if (UniStrCmpi(ut->Token[0], L"/easy") == 0)
+ {
+ // Simple mode
+ if (ut->NumTokens >= 2)
+ {
+ // Connection settings to be imported is specified
+ cm->import_file_name = CopyUniStr(ut->Token[1]);
+ }
+
+ cm->CmSettingInitialFlag = CM_SETTING_INIT_EASY;
+ }
+ else if (UniStrCmpi(ut->Token[0], L"/normal") == 0)
+ {
+ // Normal mode
+ if (ut->NumTokens >= 2)
+ {
+ // Connection settings to be imported is specified
+ cm->import_file_name = CopyUniStr(ut->Token[1]);
+ }
+
+ cm->CmSettingInitialFlag = CM_SETTING_INIT_NORMAL;
+ }
+ else if (UniStrCmpi(ut->Token[0], L"/connect") == 0)
+ {
+ // Import process by the simple installer
+ if (ut->NumTokens >= 2)
+ {
+ // Connection settings to be imported is specified
+ cm->import_file_name = CopyUniStr(ut->Token[1]);
+ }
+
+ cm->CmSettingInitialFlag = CM_SETTING_INIT_CONNECT;
+ }
+ else if (UniStrCmpi(ut->Token[0], L"/select") == 0)
+ {
+ // Selection screen
+ cm->CmSettingInitialFlag = CM_SETTING_INIT_SELECT;
+ }
+ }
+ }
+
+ UniFreeToken(ut);
+
+ InitWinUi(_UU("CM_TITLE"), _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+
+ // Alpha blending related
+ UseAlpha = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "UseAlpha");
+ AlphaValue = MsRegReadInt(REG_CURRENT_USER, CM_REG_KEY, "AlphaValue");
+
+ cm->Cedar = NewCedar(NULL, NULL);
+ CmInitEnumHub();
+}
+
+// Stop the Client Connection Manager
+void FreeCM()
+{
+ if (cm == NULL)
+ {
+ return;
+ }
+
+ CmFreeEnumHub();
+ ReleaseCedar(cm->Cedar);
+
+ FreeWinUi();
+
+ // Release the memory
+ if (cm->server_name != NULL)
+ {
+ Free(cm->server_name);
+ }
+ Free(cm);
+ cm = NULL;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+//JumpList ToDo
+// By Takao Ito
+void *CmUpdateJumpList(UINT start_id)
+{
+ HMENU h = NULL;
+ UINT i;
+ RPC_CLIENT_ENUM_ACCOUNT a;
+ LIST *o;
+ bool easy;
+
+ JL_PCustomDestinationList pcdl;
+ JL_PObjectCollection poc;
+ JL_PShellLink shell;
+ JL_PObjectArray poaRemoved;
+
+ HRESULT hr;
+
+ if (cm->server_name != NULL)
+ {
+ // Is not used in the case of an external PC
+ return NULL;
+ }
+
+ //Try to add
+ if(SUCCEEDED(JL_CreateCustomDestinationList(&pcdl,APPID_CM)))
+ {
+
+ JL_DeleteJumpList(pcdl,APPID_CM);
+
+ easy = cm->CmSetting.EasyMode;
+
+ Zero(&a, sizeof(a));
+
+
+ if (CcEnumAccount(cm->Client, &a) == ERR_NO_ERROR)
+ {
+ o = NewListFast(CiCompareClientAccountEnumItemByLastConnectDateTime);
+
+ for (i = 0;i < a.NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = a.Items[i];
+
+ item->tmp1 = i;
+
+ if (item->LastConnectDateTime != 0)
+ {
+ Add(o, item);
+ }
+ }
+
+ Sort(o);
+
+ if(LIST_NUM(o) > 0)
+ {
+
+ if(SUCCEEDED(JL_BeginList(pcdl, &poaRemoved)))
+ {
+
+
+ //Create a collection
+ if(SUCCEEDED(JL_CreateObjectCollection(&poc)))
+ {
+
+ for (i = 0;i < MIN(LIST_NUM(o), CM_NUM_RECENT);i++)
+ {
+
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = (RPC_CLIENT_ENUM_ACCOUNT_ITEM *)LIST_DATA(o, i);
+// wchar_t tmp[MAX_PATH];
+ wchar_t *account_name;
+ char *server_name;
+ char *hub_name;
+// CM_ACCOUNT *a;
+ UCHAR key[SHA1_SIZE];
+ RPC_CLIENT_GET_ACCOUNT c;
+
+
+ account_name = item->AccountName;
+ server_name = item->ServerName;
+ hub_name = item->HubName;
+
+
+
+ //
+ //a = CmGetExistAccountObject(hWnd, account_name);
+
+
+ //if (a == NULL)
+ //{
+ //continue;
+ //}
+
+ //Copy(key, a->ShortcutKey, SHA1_SIZE);
+ //
+
+ Zero(&c, sizeof(c));
+ UniStrCpy(c.AccountName, sizeof(c.AccountName), account_name);
+ if (CALL(NULL, CcGetAccount(cm->Client, &c)) == false)
+ {
+ break;
+ }
+
+ Copy(key, c.ShortcutKey, SHA1_SIZE);
+
+ if (IsZero(key, SHA1_SIZE))
+ {
+ //MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_SHORTCUT_UNSUPPORTED"));
+ }
+ else
+ {
+
+ //wchar_t target[MAX_PATH];
+ ////wchar_t workdir[MAX_PATH];
+ //wchar_t args[MAX_PATH];
+ ////wchar_t comment[MAX_SIZE];
+ //wchar_t icon[MAX_PATH];
+
+ char key_str[64];
+ wchar_t target[MAX_PATH];
+ //wchar_t workdir[MAX_PATH];
+ wchar_t args[MAX_PATH];
+ wchar_t commentW[MAX_SIZE];
+ wchar_t icon[MAX_PATH];
+ int iconNum;
+
+ //char icon = "C:\\Server.ico";
+
+ BinToStr(key_str, sizeof(key_str), key, SHA1_SIZE);
+ UniStrCpy(target, sizeof(target), MsGetExeFileNameW());
+ StrToUni(args, sizeof(args), key_str);
+ UniStrCpy(icon, sizeof(icon), MsGetExeFileNameW());
+ UniFormat(commentW, sizeof(commentW), _UU("CM_SHORTCUT_COMMENT"), account_name);
+
+ if(item->Connected)
+ {
+ iconNum = 1;
+ }
+ else
+ {
+ iconNum = 2;
+ }
+
+ hr = JL_CreateShellLink(
+ target,
+ args,
+ account_name,
+ icon,iconNum,
+ commentW,
+ &shell);
+
+ if(SUCCEEDED(hr))
+ {
+
+ if(SUCCEEDED(JL_ObjectCollectionAddShellLink(poc, shell)))
+ {
+ //Print("Add JumpList %d c:%s\n",i, comment);
+ //wprintf(comment);
+ }
+ JL_ReleaseShellLink(shell);
+ }
+ }
+
+ CiFreeClientGetAccount(&c);
+ }
+
+ hr = JL_AddCategoryToList(pcdl,poc,_UU("CM_JUMPLIST_RCCONNECT"),poaRemoved);
+
+ if(SUCCEEDED(hr))
+ {
+ //wprintf(L"AddCategory\n");
+
+ hr = JL_CommitList(pcdl);
+ if(SUCCEEDED(hr))
+ {
+ //wprintf(L"JumpList Commit\n");
+ }
+ }
+ else
+ {
+ //wprintf(L"Erro JumpList AddCategory %x\n", hr);
+ }
+
+ //Release
+ JL_ReleaseObjectCollection(poc);
+ }
+ }
+
+ }
+
+
+ ReleaseList(o);
+
+ CiFreeClientEnumAccount(&a);
+ }
+
+
+
+
+ /*
+ JL_BeginList(pcdl, &poaRemoved);
+
+ JL_CreateObjectCollection(&poc);
+
+ // Tesht
+ for (i = 0; i < 5; i++)
+ {
+
+ JL_CreateShellLink(
+ "",
+ "",
+ L"Connect",
+ NULL,0,
+ NULL,
+ &shell);
+ JL_ObjectCollectionAddShellLink(poc, shell);
+
+ JL_ReleaseShellLink(shell);
+
+ }
+
+ JL_AddCategoryToList(pcdl,poc,_UU("CM_JUMPLIST_RCCONNECT"),poaRemoved);
+ JL_CommitList(pcdl);
+ JL_ReleaseObjectCollection(poc);
+
+ JL_ReleaseCustomDestinationList(pcdl);
+ */
+
+ }
+
+ return h;
+}
+
+
+
+#endif // WIN32
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/CM.h b/src/Cedar/CM.h
new file mode 100644
index 00000000..3aae95c0
--- /dev/null
+++ b/src/Cedar/CM.h
@@ -0,0 +1,132 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// CM.h
+// Header of CM.c
+
+#ifndef CM_H
+#define CM_H
+
+// Constants
+#define CM_REG_KEY "Software\\" GC_REG_COMPANY_NAME "\\" CEDAR_PRODUCT_STR " VPN\\Client Manager"
+#define SECURE_MANAGER_KEY "Software\\" GC_REG_COMPANY_NAME "\\" CEDAR_PRODUCT_STR " VPN\\SmartCard Manager"
+#define CM_TRAFFIC_REG_KEY "Software\\" GC_REG_COMPANY_NAME "\\" CEDAR_PRODUCT_STR " VPN\\Traffic Test Tool"
+#define CM_VGC_REG_KEY "Software\\University of Tsukuba\\VPN Gate Client Plugin"
+
+
+#define CM_TRY_EXEC_UI_HELPER_INTERVAL 5000
+
+#define CM_DEFAULT_WIDTH 800
+#define CM_DEFAULT_HEIGHT 600
+
+#define WM_CM_NOTIFY (WM_APP + 999)
+
+#define CM_IMPORT_FILENAME_MSG 1267
+#define CM_IMPORT_FILENAME_MSG_OVERWRITE 1268
+
+#define CM_NUM_RECENT 8
+
+#define PUBLIC_SERVER_HTML "http://www.softether.com/jp/special/se2hub.aspx"
+#define PUBLIC_SERVER_HTML_EN "http://www.softether.com/jp/special/se2hub_en.aspx"
+#define PUBLIC_SERVER_TAG L"help:no; status:no; DialogWidth:600px; dialogHeight=700px"
+#define PUBLIC_SERVER_NAME "public.softether.com"
+
+#define VOICE_SSK 0 // ssk
+#define VOICE_AHO 1 // aho
+
+// The code for external export
+
+// Structure
+
+// Function prototype
+void CMExec();
+void CmTraffic(HWND hWnd);
+void *CmStartUacHelper();
+void CmStopUacHelper(void *p);
+void *CmExecUiHelperMain();
+UINT CmGetSecureBitmapId(char *dest_hostname);
+
+#endif // CM_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/CMInner.h b/src/Cedar/CMInner.h
new file mode 100644
index 00000000..cc65d259
--- /dev/null
+++ b/src/Cedar/CMInner.h
@@ -0,0 +1,612 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// CMInner.h
+// Internal header for the CM.c
+
+#define STARTUP_MUTEX_NAME GC_SW_SOFTETHER_PREFIX "vpncmgr_startup_mutex"
+
+#define NAME_OF_VPN_CLIENT_MANAGER "vpncmgr"
+
+void CmVoice(char *name);
+
+typedef struct CM_UAC_HELPER
+{
+ THREAD *Thread;
+ volatile bool Halt;
+ EVENT *HaltEvent;
+} CM_UAC_HELPER;
+
+typedef struct CM_VOICE
+{
+ UINT voice_id;
+ char *perfix;
+} CM_VOICE;
+
+static CM_VOICE cm_voice[] =
+{
+ {VOICE_SSK, "ssk" },
+ {VOICE_AHO, "aho" },
+};
+
+typedef struct CM_ENUM_HUB
+{
+ HWND hWnd;
+ THREAD *Thread;
+ SESSION *Session;
+ CLIENT_OPTION *ClientOption;
+ TOKEN_LIST *Hub;
+} CM_ENUM_HUB;
+
+#define CM_SETTING_INIT_NONE 0
+#define CM_SETTING_INIT_EASY 1 // Transition to the simple mode
+#define CM_SETTING_INIT_NORMAL 2 // Transition to the normal mode
+#define CM_SETTING_INIT_SELECT 3 // Show a selection screen
+#define CM_SETTING_INIT_CONNECT 4 // Import process by the simple installer
+
+typedef struct CM
+{
+ HWND hMainWnd;
+ HWND hStatusBar;
+ REMOTE_CLIENT *Client;
+ char *server_name;
+ wchar_t *import_file_name;
+ bool HideStatusBar;
+ bool HideTrayIcon;
+ bool ShowGrid;
+ bool VistaStyle;
+ bool ShowPort;
+ wchar_t StatudBar1[MAX_SIZE];
+ wchar_t StatudBar2[MAX_SIZE];
+ wchar_t StatudBar3[MAX_SIZE];
+ HICON Icon2, Icon3;
+ bool IconView;
+ THREAD *NotifyClientThread;
+ NOTIFY_CLIENT *NotifyClient;
+ volatile bool Halt;
+ bool OnCloseDispatched;
+ LIST *StatusWindowList;
+ CEDAR *Cedar;
+ LIST *EnumHubList;
+ UINT WindowCount;
+ bool DisableVoice;
+ UINT VoiceId;
+ UINT OldConnectedNum;
+ bool UpdateConnectedNumFlag;
+ UCHAR ShortcutKey[SHA1_SIZE];
+ bool TrayInited;
+ bool TraySucceed;
+ bool TrayAnimation;
+ bool TraySpeedAnimation;
+ UINT TrayAnimationCounter;
+ bool StartupMode;
+ THREAD *TryExecUiHelperThread;
+ volatile bool TryExecUiHelperHalt;
+ HANDLE TryExecUiHelperProcessHandle;
+ EVENT *TryExecUiHelperHaltEvent;
+ bool WindowsShutdowning;
+ bool CmSettingSupported;
+ bool CmEasyModeSupported;
+ bool CmSettingInitialFlag;
+ CM_SETTING CmSetting;
+ HWND hEasyWnd;
+ bool StartupFinished;
+ bool ConnectStartedFlag;
+ bool PositiveDisconnectFlag;
+ wchar_t EasyLastSelectedAccountName[MAX_ACCOUNT_NAME_LEN + 1];
+ WINDOWPLACEMENT FakeWindowPlacement;
+ bool CheckedAndShowedAdminPackMessage;
+ INSTANCE *StartupMutex;
+ bool BadProcessChecked;
+ bool MenuPopuping;
+ WINUI_UPDATE *Update;
+} CM;
+
+typedef struct CM_STATUS
+{
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+ HWND hWndPolicy; // Policy dialog
+} CM_STATUS;
+
+typedef struct CM_POLICY
+{
+ HWND hWnd;
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+ POLICY *Policy; // Policy dialog
+ CM_STATUS *CmStatus; // CM_STATUS
+ bool Extension; // Extension
+} CM_POLICY;
+
+typedef struct CM_ACCOUNT
+{
+ bool EditMode; // Edit mode (false: New mode)
+ bool LinkMode; // Link mode
+ bool NatMode; // NAT mode
+ CLIENT_OPTION *ClientOption; // Client option
+ CLIENT_AUTH *ClientAuth; // Authentication data
+ bool Startup; // Startup account
+ bool CheckServerCert; // Check the server certificate
+ X *ServerCert; // Server certificate
+ char old_server_name[MAX_HOST_NAME_LEN + 1]; // Old server name
+ bool Inited; // Initialization flag
+ POLICY Policy; // Policy (only link mode)
+ struct SM_HUB *Hub; // HUB
+ RPC *Rpc; // RPC
+ bool OnlineFlag; // Online flag
+ bool Flag1; // Flag 1
+ bool HideClientCertAuth; // Hide the client authentication
+ bool HideSecureAuth; // Hide the smart card authentication
+ bool HideTrustCert; // Hide the trusted certificate authority button
+ UCHAR ShortcutKey[SHA1_SIZE]; // Shortcut key
+ bool LockMode; // Setting lock mode
+ bool Link_ConnectNow; // Start the connection immediately
+ UINT PolicyVer; // Policy version
+} CM_ACCOUNT;
+
+typedef struct CM_CHANGE_PASSWORD
+{
+ CLIENT_OPTION *ClientOption; // Client Option
+ char Username[MAX_USERNAME_LEN + 1]; // User name
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB name
+} CM_CHANGE_PASSWORD;
+
+typedef struct CM_TRAFFIC
+{
+ bool ServerMode; // Server mode
+ bool Double; // 2x mode
+ bool Raw; // Raw data mode
+ UINT Port; // Port number
+ char Host[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT NumTcp; // Number of TCP connections
+ UINT Type; // Type
+ UINT Span; // Period
+} CM_TRAFFIC;
+
+typedef struct CM_TRAFFIC_DLG
+{
+ HWND hWnd; // Window handle
+ CM_TRAFFIC *Setting; // Setting
+ TTS *Tts; // Measurement server
+ TTC *Ttc; // Measurement client
+ THREAD *HaltThread; // Thread for stopping
+ THREAD *ClientEndWaitThread; // Thread to wait for the client to finish
+ bool Started; // Started flag
+ bool Stopping; // Stopping
+ UINT RetCode; // Return value
+ TT_RESULT Result; // Result
+ EVENT *ResultShowEvent; // Display result event
+ bool CloseDialogAfter; // Flag of whether or not to close the dialog
+} CM_TRAFFIC_DLG;
+
+// Internet connection settings
+typedef struct CM_INTERNET_SETTING
+{
+ UINT ProxyType; // Type of proxy server
+ char ProxyHostName[MAX_HOST_NAME_LEN + 1]; // Proxy server host name
+ UINT ProxyPort; // Proxy server port number
+ char ProxyUsername[MAX_USERNAME_LEN + 1]; // Proxy server user name
+ char ProxyPassword[MAX_USERNAME_LEN + 1]; // Proxy server password
+} CM_INTERNET_SETTING;
+
+static CM *cm = NULL;
+
+void CmFreeTrayExternal(void *hWnd);
+
+// Normal RPC call macro
+__forceinline static bool CALL(HWND hWnd, UINT code)
+{
+ UINT ret = code;
+ if (ret != ERR_NO_ERROR)
+ {
+ if (ret == ERR_DISCONNECTED)
+ {
+ if (cm != NULL)
+ {
+ Close(cm->hMainWnd);
+ }
+ else
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("SM_DISCONNECTED"));
+ }
+
+ if (cm != NULL)
+ {
+ CmFreeTrayExternal((void *)cm->hMainWnd);
+ }
+ exit(0);
+ }
+ else
+ {
+ UINT flag = MB_ICONEXCLAMATION;
+ if (ret == ERR_VLAN_IS_USED)
+ {
+ CmVoice("using_vlan");
+ }
+ if (hWnd != NULL && cm != NULL && cm->hEasyWnd != NULL)
+ {
+ hWnd = cm->hEasyWnd;
+ }
+ if (hWnd != NULL && cm != NULL && hWnd == cm->hEasyWnd)
+ {
+ flag |= MB_SETFOREGROUND | MB_TOPMOST;
+ }
+ MsgBox(hWnd, flag, _E(ret));
+ }
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// Extended RPC call macro (get an error value)
+__forceinline static UINT CALLEX(HWND hWnd, UINT code)
+{
+ UINT ret = code;
+ if (ret != ERR_NO_ERROR)
+ {
+ if (ret == ERR_DISCONNECTED)
+ {
+ if (cm != NULL)
+ {
+ Close(cm->hMainWnd);
+ }
+ else
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("SM_DISCONNECTED"));
+ }
+ if (cm != NULL)
+ {
+ CmFreeTrayExternal((void *)cm->hMainWnd);
+ }
+ exit(0);
+ }
+ }
+
+ return ret;
+}
+
+typedef struct CM_LOADX
+{
+ X *x;
+} CM_LOADX;
+
+typedef struct CM_SETTING_DLG
+{
+ bool CheckPassword;
+ UCHAR HashedPassword[SHA1_SIZE];
+} CM_SETTING_DLG;
+
+typedef struct CM_EASY_DLG
+{
+ bool EndDialogCalled;
+} CM_EASY_DLG;
+
+
+
+// Task tray related
+#define WM_CM_TRAY_MESSAGE (WM_APP + 44)
+#define WM_CM_SETTING_CHANGED_MESSAGE (WM_APP + 45)
+#define WM_CM_EASY_REFRESH (WM_APP + 46)
+#define WM_CM_SHOW (WM_APP + 47)
+#define CMD_EASY_DBLCLICK 40697
+#define CMD_VGC_CONNECT 40698
+#define CM_TRAY_ANIMATION_INTERVAL 3000
+#define CM_TRAY_MAX_ITEMS 4096
+#define CM_TRAY_MENU_ID_START 12000
+#define CM_TRAY_MENU_CONNECT_ID_START (CM_TRAY_MENU_ID_START + CM_TRAY_MAX_ITEMS)
+#define CM_TRAY_MENU_STATUS_ID_START (CM_TRAY_MENU_CONNECT_ID_START + CM_TRAY_MAX_ITEMS)
+#define CM_TRAY_MENU_DISCONNECT_ID_START (CM_TRAY_MENU_STATUS_ID_START + CM_TRAY_MAX_ITEMS)
+#define CM_TRAY_MENU_RECENT_ID_START (CM_TRAY_MENU_DISCONNECT_ID_START + CM_TRAY_MAX_ITEMS)
+#define CM_TRAY_IS_CONNECT_ID(id) (((id) >= CM_TRAY_MENU_CONNECT_ID_START) && (id) < CM_TRAY_MENU_STATUS_ID_START)
+#define CM_TRAY_IS_STATUS_ID(id) (((id) >= CM_TRAY_MENU_STATUS_ID_START) && (id) < CM_TRAY_MENU_DISCONNECT_ID_START)
+#define CM_TRAY_IS_DISCONNECT_ID(id) (((id) >= CM_TRAY_MENU_DISCONNECT_ID_START) && (id) < (CM_TRAY_MENU_DISCONNECT_ID_START + CM_TRAY_MAX_ITEMS))
+#define CM_TRAY_IS_RECENT_ID(id) (((id) >= CM_TRAY_MENU_RECENT_ID_START) && (id) < (CM_TRAY_MENU_RECENT_ID_START + CM_TRAY_MAX_ITEMS))
+
+
+// Function prototype
+void InitCM(bool set_app_id);
+void FreeCM();
+void MainCM();
+bool LoginCM();
+void LogoutCM();
+UINT CmLoginDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void MainCMWindow();
+void CmSendImportMessage(HWND hWnd, wchar_t *filename, UINT msg);
+UINT CmMainWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmMainWindowOnSize(HWND hWnd);
+void CmMainWindowOnInit(HWND hWnd);
+void CmMainWindowOnQuit(HWND hWnd);
+void CmSaveMainWindowPos(HWND hWnd);
+void CmMainWindowOnCommand(HWND hWnd, WPARAM wParam, LPARAM lParam);
+void CmMainWindowOnCommandEx(HWND hWnd, WPARAM wParam, LPARAM lParam, bool easy);
+bool CmIsEnabled(HWND hWnd, UINT id);
+bool CmIsChecked(UINT id);
+bool CmIsBold(UINT id);
+void CmMainWindowOnPopupMenu(HWND hWnd, HMENU hMenu, UINT pos);
+void CmSaveMainWindowPos(HWND hWnd);
+void CmRedrawStatusBar(HWND hWnd);
+void CmRefresh(HWND hWnd);
+void CmRefreshEx(HWND hWnd, bool style_changed);
+void CmSetForegroundProcessToCnService();
+void CmInitAccountList(HWND hWnd);
+void CmInitAccountListEx(HWND hWnd, bool easy);
+void CmInitVLanList(HWND hWnd);
+void CmRefreshAccountList(HWND hWnd);
+void CmRefreshAccountListEx(HWND hWnd, bool easy);
+void CmRefreshAccountListEx2(HWND hWnd, bool easy, bool style_changed);
+void CmRefreshVLanList(HWND hWnd);
+void CmRefreshVLanListEx(HWND hWnd, bool style_changed);
+void CmSaveAccountListPos(HWND hWnd);
+void CmSaveVLanListPos(HWND hWnd);
+wchar_t *CmGetProtocolName(UINT n);
+void CmVLanNameToPrintName(char *str, UINT size, char *name);
+bool CmPrintNameToVLanName(char *name, UINT size, char *str);
+void CmMainWindowOnNotify(HWND hWnd, NMHDR *n);
+void CmOnKey(HWND hWnd, bool ctrl, bool alt, UINT key);
+void CmAccountListRightClick(HWND hWnd);
+void CmVLanListRightClick(HWND hWnd);
+void CmConnect(HWND hWnd, wchar_t *account_name);
+void CmDisconnect(HWND hWnd, wchar_t *account_name);
+void CmInitNotifyClientThread();
+void CmFreeNotifyClientThread();
+void CmNotifyClientThread(THREAD *thread, void *param);
+void CmDeleteAccount(HWND hWnd, wchar_t *account_name);
+void CmStatus(HWND hWnd, wchar_t *account_name);
+void CmStatusDlg(HWND hWnd, wchar_t *account_name);
+UINT CmStatusDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmStatusDlgPrint(HWND hWnd, CM_STATUS *cmst);
+void CmPrintStatusToListView(LVB *b, RPC_CLIENT_GET_CONNECTION_STATUS *s);
+void CmPrintStatusToListViewEx(LVB *b, RPC_CLIENT_GET_CONNECTION_STATUS *s, bool server_mode);
+void CmStatusDlgPrintCert(HWND hWnd, CM_STATUS *st, bool server);
+void CmPolicyDlg(HWND hWnd, CM_STATUS *st);
+UINT CmPolicyDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmPolicyDlgPrint(HWND hWnd, CM_POLICY *p);
+void CmPolicyDlgPrintEx(HWND hWnd, CM_POLICY *p, bool cascade_mode);
+void CmPolicyDlgPrintEx2(HWND hWnd, CM_POLICY *p, bool cascade_mode, bool ver);
+void CmNewAccount(HWND hWnd);
+void CmEditAccount(HWND hWnd, wchar_t *account_name);
+void CmGenerateNewAccountName(HWND hWnd, wchar_t *name, UINT size);
+void CmGenerateCopyName(HWND hWnd, wchar_t *name, UINT size, wchar_t *old_name);
+void CmGenerateImportName(HWND hWnd, wchar_t *name, UINT size, wchar_t *old_name);
+CM_ACCOUNT *CmCreateNewAccountObject(HWND hWnd);
+CM_ACCOUNT *CmGetExistAccountObject(HWND hWnd, wchar_t *account_name);
+void CmEnumHubStart(HWND hWnd, CLIENT_OPTION *o);
+void CmInitEnumHub();
+void CmFreeEnumHub();
+void CmFreeAccountObject(HWND hWnd, CM_ACCOUNT *a);
+bool CmEditAccountDlg(HWND hWnd, CM_ACCOUNT *a);
+UINT CmEditAccountDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmEditAccountDlgUpdate(HWND hWnd, CM_ACCOUNT *a);
+void CmEditAccountDlgInit(HWND hWnd, CM_ACCOUNT *a);
+void CmEditAccountDlgOnOk(HWND hWnd, CM_ACCOUNT *a);
+void CmEditAccountDlgStartEnumHub(HWND hWnd, CM_ACCOUNT *a);
+bool CmLoadXAndK(HWND hWnd, X **x, K **k);
+bool CmLoadK(HWND hWnd, K **k);
+bool CmLoadKEx(HWND hWnd, K **k, char *filename, UINT size);
+bool CmLoadKExW(HWND hWnd, K **k, wchar_t *filename, UINT size);
+bool CmLoadXFromFileOrSecureCard(HWND hWnd, X **x);
+void CmLoadXFromFileOrSecureCardDlgInit(HWND hWnd, CM_LOADX *p);
+void CmLoadXFromFileOrSecureCardDlgUpdate(HWND hWnd, CM_LOADX *p);
+UINT CmLoadXFromFileOrSecureCardDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+bool CmLoadX(HWND hWnd, X **x);
+bool CmLoadXEx(HWND hWnd, X **x, char *filename, UINT size);
+bool CmLoadXExW(HWND hWnd, X **x, wchar_t *filename, UINT size);
+X *CmGetIssuer(X *x);
+bool CmProxyDlg(HWND hWnd, CLIENT_OPTION *a);
+void CmProxyDlgUpdate(HWND hWnd, CLIENT_OPTION *a);
+UINT CmProxyDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+bool CmDetailDlg(HWND hWnd, CM_ACCOUNT *a);
+UINT CmDetailDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+char *CmNewVLanDlg(HWND hWnd);
+UINT CmNewVLanDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmCopyAccount(HWND hWnd, wchar_t *account_name);
+void CmExportAccount(HWND hWnd, wchar_t *account_name);
+void CmSortcut(HWND hWnd, wchar_t *account_name);
+void CmImportAccount(HWND hWnd);
+void CmImportAccountMain(HWND hWnd, wchar_t *filename);
+void CmImportAccountMainEx(HWND hWnd, wchar_t *filename, bool overwrite);
+void CmTrustDlg(HWND hWnd);
+UINT CmTrustDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmTrustDlgUpdate(HWND hWnd);
+void CmTrustDlgRefresh(HWND hWnd);
+void CmTrustImport(HWND hWnd);
+void CmTrustExport(HWND hWnd);
+void CmTrustView(HWND hWnd);
+void CmPassword(HWND hWnd);
+UINT CmPasswordProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmPasswordRefresh(HWND hWnd);
+void CmRefreshStatusBar(HWND hWnd);
+UINT CmGetNumConnected(HWND hWnd);
+void CmDisconnectAll(HWND hWnd);
+wchar_t *CmGenerateMainWindowTitle();
+void CmConfigDlg(HWND hWnd);
+UINT CmConfigDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmConfigDlgInit(HWND hWnd);
+void CmConfigDlgRefresh(HWND hWnd);
+void CmConfigDlgOnOk(HWND hWnd);
+bool CmWarningDesktop(HWND hWnd, wchar_t *account_name);
+UINT CmDesktopDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmDesktopDlgInit(HWND hWnd, wchar_t *account_name);
+bool CmStopInstallVLan(HWND hWnd);
+void CmChangePassword(HWND hWnd, CLIENT_OPTION *o, char *hubname, char *username);
+UINT CmChangePasswordProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmChangePasswordUpdate(HWND hWnd, CM_CHANGE_PASSWORD *p);
+void SmShowPublicVpnServerHtml(HWND hWnd);
+void CmConnectShortcut(UCHAR *key);
+UINT CmSelectSecure(HWND hWnd, UINT current_id);
+void CmClientSecureManager(HWND hWnd);
+UINT CmClientSelectSecure(HWND hWnd);
+UINT CmSelectSecureDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmSelectSecureDlgInit(HWND hWnd, UINT default_id);
+void CmSelectSecureDlgUpdate(HWND hWnd);
+void CmSecureManager(HWND hWnd, UINT id);
+void CmSecureManagerEx(HWND hWnd, UINT id, bool no_new_cert);
+UINT CmSecureManagerDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmSecureManagerDlgInit(HWND hWnd, UINT id);
+void CmSecureManagerDlgUpdate(HWND hWnd, UINT id);
+void CmSecureManagerDlgRefresh(HWND hWnd, UINT id);
+void CmSecureManagerDlgPrintList(HWND hWnd, LIST *o);
+void CmSecureManagerDlgPrintListEx(HWND hWnd, UINT id, LIST *o, UINT type);
+wchar_t *CmSecureObjTypeToStr(UINT type);
+UINT CmSecureType(HWND hWnd);
+UINT CmSecureTypeDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmSecureManagerDlgImport(HWND hWnd, UINT id);
+void CmSecureManagerDlgDelete(HWND hWnd, UINT id);
+void CmSecureManagerDlgExport(HWND hWnd, UINT id);
+void CmSecureManagerDlgNewCert(HWND hWnd, UINT id);
+void CmSecurePin(HWND hWnd, UINT id);
+UINT CmSecurePinDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmSecurePinDlgUpdate(HWND hWnd);
+void CmInitTray(HWND hWnd);
+void CmPollingTray(HWND hWnd);
+void CmFreeTray(HWND hWnd);
+void CmChangeTrayString(HWND hWnd, wchar_t *str);
+UINT CmGetTrayIconId(bool animation, UINT animation_counter);
+void CmShowOrHideWindow(HWND hWnd);
+void CmShowTrayMenu(HWND hWnd);
+HMENU CmCreateTraySubMenu(HWND hWnd, bool flag, UINT start_id);
+HMENU CmCreateRecentSubMenu(HWND hWnd, UINT start_id);
+bool CmCheckPkcsEula(HWND hWnd, UINT id);
+UINT CmPkcsEulaDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmDeleteOldStartupTrayFile();
+UINT CmTrafficDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmTrafficDlgInit(HWND hWnd);
+bool CmTrafficDlgUpdate(HWND hWnd);
+void CmTrafficDlgOnOk(HWND hWnd);
+bool CmTrafficLoadFromReg(CM_TRAFFIC *t);
+void CmTrafficGetDefaultSetting(CM_TRAFFIC *t);
+void CmTrafficSaveToReg(CM_TRAFFIC *t);
+void CmTrafficDlgToStruct(HWND hWnd, CM_TRAFFIC *t);
+void CmExecTraffic(HWND hWnd, CM_TRAFFIC *t);
+UINT CmTrafficRunDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmTrafficRunDlgInit(HWND hWnd, CM_TRAFFIC_DLG *d);
+void CmTrafficRunDlgStart(HWND hWnd, CM_TRAFFIC_DLG *d);
+void CmTrafficRunDlgPrintProc(void *param, wchar_t *str);
+void CmTrafficRunDlgAddStr(HWND hWnd, wchar_t *str);
+void CmTrafficRunDlgHalt(HWND hWnd, CM_TRAFFIC_DLG *d);
+void CmTrafficRunDlgHaltThread(THREAD *t, void *param);
+void CmTrafficRunDlgClientWaitThread(THREAD *t, void *param);
+void CmTrafficResult(HWND hWnd, TT_RESULT *r);
+UINT CmTrafficResultDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmTrafficResultDlgInit(HWND hWnd, TT_RESULT *res);
+void CmTryToExecUiHelper();
+void CmInitTryToExecUiHelper();
+void CmFreeTryToExecUiHelper();
+void CmTryToExecUiHelperThread(THREAD *thread, void *param);
+bool CmSetting(HWND hWnd);
+UINT CmSettingDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmSettingDlgInit(HWND hWnd, CM_SETTING_DLG *d);
+void CmSettingDlgUpdate(HWND hWnd, CM_SETTING_DLG *d);
+void CmSettingDlgOnOk(HWND hWnd, CM_SETTING_DLG *d);
+void CmApplyCmSetting();
+void CmMainWindowOnTrayClicked(HWND hWnd, WPARAM wParam, LPARAM lParam);
+void CmShowEasy();
+void CmCloseEasy();
+void CmMainWindowOnShowEasy(HWND hWnd);
+UINT CmEasyDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CmEasyDlgInit(HWND hWnd, CM_EASY_DLG *d);
+void CmEasyDlgUpdate(HWND hWnd, CM_EASY_DLG *d);
+void CmEasyDlgRefresh(HWND hWnd, CM_EASY_DLG *d);
+void CmRefreshEasy();
+void CmEasyDlgOnNotify(HWND hWnd, CM_EASY_DLG *d, NMHDR *n);
+void CmEasyDlgOnKey(HWND hWnd, CM_EASY_DLG *d, bool ctrl, bool alt, UINT key);
+void CmEasyDlgOnCommand(HWND hWnd, CM_EASY_DLG *d, WPARAM wParam, LPARAM lParam);
+
+bool CmStartStartupMutex();
+void CmEndStartupMutex();
+void CmSetUacWindowActive();
+void CmUacHelperThread(THREAD *thread, void *param);
+void CmProxyDlgUseForIE(HWND hWnd, CLIENT_OPTION *o);
+void CmGetSystemInternetSetting(CM_INTERNET_SETTING *setting);
+void CmProxyDlgSet(HWND hWnd, CLIENT_OPTION *o, CM_INTERNET_SETTING *setting);
+bool CmGetProxyServerNameAndPortFromIeProxyRegStr(char *name, UINT name_size, UINT *port, char *str, char *server_type);
+void *CmUpdateJumpList(UINT start_id);
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Cedar.c b/src/Cedar/Cedar.c
new file mode 100644
index 00000000..2505dcef
--- /dev/null
+++ b/src/Cedar/Cedar.c
@@ -0,0 +1,1708 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Cedar.c
+// Cedar Communication Module
+
+
+#include "CedarPch.h"
+
+static UINT init_cedar_counter = 0;
+static REF *cedar_log_ref = NULL;
+static LOG *cedar_log;
+
+// Get build date of current code
+UINT64 GetCurrentBuildDate()
+{
+ SYSTEMTIME st;
+
+ Zero(&st, sizeof(st));
+
+ st.wYear = BUILD_DATE_Y;
+ st.wMonth = BUILD_DATE_M;
+ st.wDay = BUILD_DATE_D;
+ st.wHour = BUILD_DATE_HO;
+ st.wMinute = BUILD_DATE_MI;
+ st.wSecond = BUILD_DATE_SE;
+
+ return SystemToUINT64(&st);
+}
+
+// Check current windows version is supported
+bool IsSupportedWinVer(RPC_WINVER *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return false;
+ }
+
+ if (v->IsWindows == false)
+ {
+ return true;
+ }
+
+ if (v->IsNT == false)
+ {
+ return true;
+ }
+
+ if (v->IsBeta)
+ {
+ return true;
+ }
+
+ if (v->VerMajor <= 4)
+ {
+ // Windows NT
+ return true;
+ }
+
+ if (v->VerMajor == 5 && v->VerMinor == 0)
+ {
+ // Windows 2000
+ if (v->ServicePack <= 4)
+ {
+ // SP4 or earlier
+ return true;
+ }
+ }
+
+ if (v->VerMajor == 5 && v->VerMinor == 1)
+ {
+ // Windows XP x86
+ if (v->ServicePack <= 3)
+ {
+ // SP3 or earlier
+ return true;
+ }
+ }
+
+ if (v->VerMajor == 5 && v->VerMinor == 2)
+ {
+ // Windows XP x64, Windows Server 2003
+ if (v->ServicePack <= 2)
+ {
+ // SP2 or earlier
+ return true;
+ }
+ }
+
+ if (v->VerMajor == 6 && v->VerMinor == 0)
+ {
+ // Windows Vista, Server 2008
+ if (v->ServicePack <= 2)
+ {
+ // SP2 or earlier
+ return true;
+ }
+ }
+
+ if (v->VerMajor == 6 && v->VerMinor == 1)
+ {
+ // Windows 7, Server 2008 R2
+ if (v->ServicePack <= 1)
+ {
+ // SP1 or earlier
+ return true;
+ }
+ }
+
+ if (v->VerMajor == 6 && v->VerMinor == 2)
+ {
+ // Windows 8, Server 2012
+ if (v->ServicePack <= 0)
+ {
+ // SP0 only
+ return true;
+ }
+ }
+
+ if (v->VerMajor == 6 && v->VerMinor == 3)
+ {
+ // Windows 8.1, Server 2012 R2
+ if (v->ServicePack <= 0)
+ {
+ // SP0 only
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Get version of Windows
+void GetWinVer(RPC_WINVER *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ Win32GetWinVer(v);
+#else // OS_WIN32
+ Zero(v, sizeof(RPC_WINVER));
+ StrCpy(v->Title, sizeof(v->Title), GetOsInfo()->OsProductName);
+#endif // OS_WIN32
+}
+
+// Close tiny log
+void FreeTinyLog(TINY_LOG *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FileClose(t->io);
+ DeleteLock(t->Lock);
+ Free(t);
+}
+
+// Write to tiny log
+void WriteTinyLog(TINY_LOG *t, char *str)
+{
+ BUF *b;
+ char dt[MAX_PATH];
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ GetDateTimeStrMilli64(dt, sizeof(dt), LocalTime64());
+ StrCat(dt, sizeof(dt), ": ");
+
+ b = NewBuf();
+
+ WriteBuf(b, dt, StrLen(dt));
+ WriteBuf(b, str, StrLen(str));
+ WriteBuf(b, "\r\n", 2);
+
+ Lock(t->Lock);
+ {
+ FileWrite(t->io, b->Buf, b->Size);
+ //FileFlush(t->io);
+ }
+ Unlock(t->Lock);
+
+ FreeBuf(b);
+}
+
+// Initialize tiny log
+TINY_LOG *NewTinyLog()
+{
+ char name[MAX_PATH];
+ SYSTEMTIME st;
+ TINY_LOG *t;
+
+ LocalTime(&st);
+
+ MakeDir(TINY_LOG_DIRNAME);
+
+ Format(name, sizeof(name), TINY_LOG_FILENAME,
+ st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
+
+ t = ZeroMalloc(sizeof(TINY_LOG));
+
+ StrCpy(t->FileName, sizeof(t->FileName), name);
+ t->io = FileCreate(name);
+ t->Lock = NewLock();
+
+ return t;
+}
+
+// Compare entries of No-SSL connection list
+int CompareNoSslList(void *p1, void *p2)
+{
+ NON_SSL *n1, *n2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ n1 = *(NON_SSL **)p1;
+ n2 = *(NON_SSL **)p2;
+ if (n1 == NULL || n2 == NULL)
+ {
+ return 0;
+ }
+ return CmpIpAddr(&n1->IpAddress, &n2->IpAddress);
+}
+
+// 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;
+}
+
+// Decrement connection count of Non-SSL connection list entry
+void DecrementNoSsl(CEDAR *c, IP *ip, UINT num_dec)
+{
+ // Validate arguments
+ if (c == NULL || ip == NULL)
+ {
+ return;
+ }
+
+ LockList(c->NonSslList);
+ {
+ NON_SSL *n = SearchNoSslList(c, ip);
+
+ if (n != NULL)
+ {
+ if (n->Count >= num_dec)
+ {
+ n->Count -= num_dec;
+ }
+ }
+ }
+ UnlockList(c->NonSslList);
+}
+
+// Add new entry to Non-SSL connection list
+bool AddNoSsl(CEDAR *c, IP *ip)
+{
+ NON_SSL *n;
+ bool ret = true;
+ // Validate arguments
+ if (c == NULL || ip == NULL)
+ {
+ return true;
+ }
+
+ LockList(c->NonSslList);
+ {
+ DeleteOldNoSsl(c);
+
+ n = SearchNoSslList(c, ip);
+
+ if (n == NULL)
+ {
+ n = ZeroMalloc(sizeof(NON_SSL));
+ Copy(&n->IpAddress, ip, sizeof(IP));
+ n->Count = 0;
+
+ Add(c->NonSslList, n);
+ }
+
+ n->EntryExpires = Tick64() + (UINT64)NON_SSL_ENTRY_EXPIRES;
+
+ n->Count++;
+
+ if (n->Count > NON_SSL_MIN_COUNT)
+ {
+ ret = false;
+ }
+ }
+ UnlockList(c->NonSslList);
+
+ return ret;
+}
+
+// Delete old entries in Non-SSL connection list
+void DeleteOldNoSsl(CEDAR *c)
+{
+ UINT i;
+ LIST *o;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ o = NewListFast(NULL);
+
+ for (i = 0;i < LIST_NUM(c->NonSslList);i++)
+ {
+ NON_SSL *n = LIST_DATA(c->NonSslList, i);
+
+ if (n->EntryExpires <= Tick64())
+ {
+ Add(o, n);
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ NON_SSL *n = LIST_DATA(o, i);
+
+ Delete(c->NonSslList, n);
+ Free(n);
+ }
+
+ ReleaseList(o);
+}
+
+// Search entry in Non-SSL connection list
+NON_SSL *SearchNoSslList(CEDAR *c, IP *ip)
+{
+ NON_SSL *n, t;
+ // Validate arguments
+ if (c == NULL || ip == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&t, sizeof(t));
+ Copy(&t.IpAddress, ip, sizeof(IP));
+
+ n = Search(c->NonSslList, &t);
+
+ if (n == NULL)
+ {
+ return NULL;
+ }
+
+ return n;
+}
+
+// Initialize Non-SSL connection list
+void InitNoSslList(CEDAR *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->NonSslList = NewList(CompareNoSslList);
+}
+
+// Free Non-SSL connection list
+void FreeNoSslList(CEDAR *c)
+{
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(c->NonSslList);i++)
+ {
+ NON_SSL *n = LIST_DATA(c->NonSslList, i);
+
+ Free(n);
+ }
+
+ ReleaseList(c->NonSslList);
+ c->NonSslList = NULL;
+}
+
+// Write a message into Cedar log
+void CedarLog(char *str)
+{
+ char *tmp;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return;
+ }
+ if (cedar_log_ref == NULL)
+ {
+ return;
+ }
+
+ tmp = CopyStr(str);
+
+ if (StrLen(tmp) > 1)
+ {
+ if (tmp[StrLen(tmp) - 1] == '\n')
+ {
+ tmp[StrLen(tmp) - 1] = 0;
+ }
+ if (StrLen(tmp) > 1)
+ {
+ if (tmp[StrLen(tmp) - 1] == '\r')
+ {
+ tmp[StrLen(tmp) - 1] = 0;
+ }
+ }
+ }
+
+ InsertStringRecord(cedar_log, tmp);
+
+ Free(tmp);
+}
+
+// Start Cedar log
+void StartCedarLog()
+{
+ if (cedar_log_ref == NULL)
+ {
+ cedar_log_ref = NewRef();
+ }
+ else
+ {
+ AddRef(cedar_log_ref);
+ }
+
+ cedar_log = NewLog("debug_log", "debug", LOG_SWITCH_DAY);
+}
+
+// Stop Cedar log
+void StopCedarLog()
+{
+ if (cedar_log_ref == NULL)
+ {
+ return;
+ }
+
+ if (Release(cedar_log_ref) == 0)
+ {
+ FreeLog(cedar_log);
+ cedar_log = NULL;
+ cedar_log_ref = NULL;
+ }
+}
+
+
+// Get sum of traffic data size
+UINT64 GetTrafficPacketSize(TRAFFIC *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return 0;
+ }
+
+ return t->Recv.BroadcastBytes + t->Recv.UnicastBytes +
+ t->Send.BroadcastBytes + t->Send.UnicastBytes;
+}
+
+// Get sum of the number of packets in traffic
+UINT64 GetTrafficPacketNum(TRAFFIC *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return 0;
+ }
+
+ return t->Recv.BroadcastCount + t->Recv.UnicastCount +
+ t->Send.BroadcastCount + t->Send.UnicastCount;
+}
+
+// Get whether hidden password is changed in UI
+bool IsHiddenPasswordChanged(char *str)
+{
+ // Validate arguments
+ if (str == NULL)
+ {
+ return true;
+ }
+
+ if (StrCmpi(str, HIDDEN_PASSWORD) == 0)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// Initialize hidden password in UI
+void InitHiddenPassword(char *str, UINT size)
+{
+ // Validate arguments
+ if (str == NULL)
+ {
+ return;
+ }
+
+ StrCpy(str, size, HIDDEN_PASSWORD);
+}
+
+// Check whether the certificate is signed by CA which is trusted by the hub
+bool CheckSignatureByCaLinkMode(SESSION *s, X *x)
+{
+ LINK *k;
+ HUB *h;
+ bool ret = false;
+ // Validate arguments
+ if (s == NULL || x == NULL)
+ {
+ return false;
+ }
+
+ if (s->LinkModeClient == false || (k = s->Link) == NULL)
+ {
+ return false;
+ }
+
+ h = k->Hub;
+
+ if (h->HubDb != NULL)
+ {
+ LockList(h->HubDb->RootCertList);
+ {
+ X *root_cert;
+ root_cert = GetIssuerFromList(h->HubDb->RootCertList, x);
+ if (root_cert != NULL)
+ {
+ ret = true;
+ }
+ }
+ UnlockList(h->HubDb->RootCertList);
+ }
+
+ return ret;
+}
+
+// Check whether the certificate is signed by CA which is trusted by Cedar
+bool CheckSignatureByCa(CEDAR *cedar, X *x)
+{
+ X *ca;
+ // Validate arguments
+ if (cedar == NULL || x == NULL)
+ {
+ return false;
+ }
+
+ // Get the CA which signed the certificate
+ ca = FindCaSignedX(cedar->CaList, x);
+ if (ca == NULL)
+ {
+ // Not found
+ return false;
+ }
+
+ // Found
+ FreeX(ca);
+ return true;
+}
+
+// Get the CA which signed the certificate
+X *FindCaSignedX(LIST *o, X *x)
+{
+ X *ret;
+ // Validate arguments
+ if (o == NULL || x == NULL)
+ {
+ return NULL;
+ }
+
+ ret = NULL;
+
+ LockList(o);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ X *ca = LIST_DATA(o, i);
+ if (CheckXDateNow(ca))
+ {
+ if (CompareName(ca->subject_name, x->issuer_name))
+ {
+ K *k = GetKFromX(ca);
+ if (k != NULL)
+ {
+ if (CheckSignature(x, k))
+ {
+ ret = CloneX(ca);
+ }
+ FreeK(k);
+ }
+ }
+ else if (CompareX(ca, x))
+ {
+ ret = CloneX(ca);
+ }
+ }
+
+ if (ret != NULL)
+ {
+ break;
+ }
+ }
+ }
+ UnlockList(o);
+
+ return ret;
+}
+
+// Delete trusted CA from Cedar
+bool DeleteCa(CEDAR *cedar, UINT ptr)
+{
+ bool b = false;
+ // Validate arguments
+ if (cedar == NULL || ptr == 0)
+ {
+ return false;
+ }
+
+ LockList(cedar->CaList);
+ {
+ UINT i;
+
+ for (i = 0;i < LIST_NUM(cedar->CaList);i++)
+ {
+ X *x = LIST_DATA(cedar->CaList, i);
+
+ if (POINTER_TO_KEY(x) == ptr)
+ {
+ Delete(cedar->CaList, x);
+ FreeX(x);
+
+ b = true;
+
+ break;
+ }
+ }
+ }
+ UnlockList(cedar->CaList);
+
+ return b;
+}
+
+// Add trusted CA to Cedar
+void AddCa(CEDAR *cedar, X *x)
+{
+ // Validate arguments
+ if (cedar == NULL || x == NULL)
+ {
+ return;
+ }
+
+ LockList(cedar->CaList);
+ {
+ UINT i;
+ bool ok = true;
+
+ for (i = 0;i < LIST_NUM(cedar->CaList);i++)
+ {
+ X *exist_x = LIST_DATA(cedar->CaList, i);
+ if (CompareX(exist_x, x))
+ {
+ ok = false;
+ break;
+ }
+ }
+
+ if (ok)
+ {
+ Insert(cedar->CaList, CloneX(x));
+ }
+ }
+ UnlockList(cedar->CaList);
+}
+
+// Delete connection from Cedar
+void DelConnection(CEDAR *cedar, CONNECTION *c)
+{
+ // Validate arguments
+ if (cedar == NULL || c == NULL)
+ {
+ return;
+ }
+
+ LockList(cedar->ConnectionList);
+ {
+ Debug("Connection %s Deleted from Cedar.\n", c->Name);
+ if (Delete(cedar->ConnectionList, c))
+ {
+ ReleaseConnection(c);
+ }
+ }
+ UnlockList(cedar->ConnectionList);
+}
+
+// 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)
+{
+ char tmp[MAX_SIZE];
+ UINT i;
+ // Validate arguments
+ if (cedar == NULL || c == NULL)
+ {
+ return;
+ }
+
+ // Determine the name of the connection
+ i = Inc(cedar->ConnectionIncrement);
+ Format(tmp, sizeof(tmp), "CID-%u", i);
+ Lock(c->lock);
+ {
+ Free(c->Name);
+ c->Name = CopyStr(tmp);
+ }
+ Unlock(c->lock);
+
+ LockList(cedar->ConnectionList);
+ {
+ Add(cedar->ConnectionList, c);
+ AddRef(c->ref);
+ Debug("Connection %s Inserted to Cedar.\n", c->Name);
+ }
+ UnlockList(cedar->ConnectionList);
+}
+
+// Stop all connections
+void StopAllConnection(CEDAR *c)
+{
+ UINT num;
+ UINT i;
+ CONNECTION **connections;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ LockList(c->ConnectionList);
+ {
+ connections = ToArray(c->ConnectionList);
+ num = LIST_NUM(c->ConnectionList);
+ DeleteAll(c->ConnectionList);
+ }
+ UnlockList(c->ConnectionList);
+
+ for (i = 0;i < num;i++)
+ {
+ StopConnection(connections[i], false);
+ ReleaseConnection(connections[i]);
+ }
+ Free(connections);
+}
+
+// Delete a hub in Cedar
+void DelHub(CEDAR *c, HUB *h)
+{
+ DelHubEx(c, h, false);
+}
+void DelHubEx(CEDAR *c, HUB *h, bool no_lock)
+{
+ // Validate arguments
+ if (c == NULL || h == NULL)
+ {
+ return;
+ }
+
+ if (no_lock == false)
+ {
+ LockHubList(c);
+ }
+
+ if (Delete(c->HubList, h))
+ {
+ ReleaseHub(h);
+ }
+
+ if (no_lock == false)
+ {
+ UnlockHubList(c);
+ }
+}
+
+// Add a new hub to Cedar
+void AddHub(CEDAR *c, HUB *h)
+{
+ // Validate arguments
+ if (c == NULL || h == NULL)
+ {
+ return;
+ }
+
+ LockHubList(c);
+ {
+#if 0
+ // We shall not check here the number of hub
+ if (LIST_NUM(c->HubList) >= MAX_HUBS)
+ {
+ // over limit
+ UnlockHubList(c);
+ return;
+ }
+#endif
+
+ // Confirm there is no hub which have same name
+ if (IsHub(c, h->Name))
+ {
+ // exist
+ UnlockHubList(c);
+ return;
+ }
+
+ // Register the hub
+ Insert(c->HubList, h);
+ AddRef(h->ref);
+ }
+ UnlockHubList(c);
+}
+
+// Stop all hubs in Cedar
+void StopAllHub(CEDAR *c)
+{
+ HUB **hubs;
+ UINT i, num;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ LockHubList(c);
+ {
+ hubs = ToArray(c->HubList);
+ num = LIST_NUM(c->HubList);
+ DeleteAll(c->HubList);
+ }
+ UnlockHubList(c);
+
+ for (i = 0;i < num;i++)
+ {
+ StopHub(hubs[i]);
+ ReleaseHub(hubs[i]);
+ }
+
+ Free(hubs);
+}
+
+// Get reverse listener socket in Cedar
+SOCK *GetReverseListeningSock(CEDAR *c)
+{
+ SOCK *s = NULL;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ LockList(c->ListenerList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(c->ListenerList);i++)
+ {
+ LISTENER *r = LIST_DATA(c->ListenerList, i);
+
+ if (r->Protocol == LISTENER_REVERSE)
+ {
+ Lock(r->lock);
+ {
+ s = r->Sock;
+
+ AddRef(s->ref);
+ }
+ Unlock(r->lock);
+ break;
+ }
+ }
+ }
+ UnlockList(c->ListenerList);
+
+ return s;
+}
+
+// Get in-process listener socket in Cedar
+SOCK *GetInProcListeningSock(CEDAR *c)
+{
+ SOCK *s = NULL;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ LockList(c->ListenerList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(c->ListenerList);i++)
+ {
+ LISTENER *r = LIST_DATA(c->ListenerList, i);
+
+ if (r->Protocol == LISTENER_INPROC)
+ {
+ Lock(r->lock);
+ {
+ s = r->Sock;
+
+ if (s != NULL)
+ {
+ AddRef(s->ref);
+ }
+ }
+ Unlock(r->lock);
+ break;
+ }
+ }
+ }
+ UnlockList(c->ListenerList);
+
+ return s;
+}
+
+// Add a new listener to Cedar
+void AddListener(CEDAR *c, LISTENER *r)
+{
+ // Validate arguments
+ if (c == NULL || r == NULL)
+ {
+ return;
+ }
+
+ LockList(c->ListenerList);
+ {
+ Add(c->ListenerList, r);
+ AddRef(r->ref);
+ }
+ UnlockList(c->ListenerList);
+}
+
+// Stop all listener in Cedar
+void StopAllListener(CEDAR *c)
+{
+ LISTENER **array;
+ UINT i, num;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ LockList(c->ListenerList);
+ {
+ array = ToArray(c->ListenerList);
+ num = LIST_NUM(c->ListenerList);
+ DeleteAll(c->ListenerList);
+ }
+ UnlockList(c->ListenerList);
+
+ for (i = 0;i < num;i++)
+ {
+ StopListener(array[i]);
+ ReleaseListener(array[i]);
+ }
+ Free(array);
+}
+
+// Stop Cedar
+void StopCedar(CEDAR *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Stop flag
+ c->Halt = true;
+
+ // Stop all listener
+ StopAllListener(c);
+ // Stop all connections
+ StopAllConnection(c);
+ // Stop all hubs
+ StopAllHub(c);
+ // Free all virtual L3 switch
+ L3FreeAllSw(c);
+}
+
+// Clean up Cedar
+void CleanupCedar(CEDAR *c)
+{
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ WuFreeWebUI(c->WebUI);
+ FreeCedarLayer3(c);
+
+/*
+ for (i = 0;i < LIST_NUM(c->HubList);i++)
+ {
+ HUB *h = LIST_DATA(c->HubList, i);
+ }
+*/
+ for (i = 0;i < LIST_NUM(c->CaList);i++)
+ {
+ X *x = LIST_DATA(c->CaList, i);
+ FreeX(x);
+ }
+ ReleaseList(c->CaList);
+
+ ReleaseList(c->ListenerList);
+ ReleaseList(c->HubList);
+ ReleaseList(c->ConnectionList);
+ //CleanupUDPEntry(c);
+ ReleaseList(c->UDPEntryList);
+ DeleteLock(c->lock);
+ DeleteCounter(c->ConnectionIncrement);
+ DeleteCounter(c->CurrentSessions);
+
+ if (c->DebugLog != NULL)
+ {
+ FreeLog(c->DebugLog);
+ }
+
+ if (c->ServerX)
+ {
+ FreeX(c->ServerX);
+ }
+ if (c->ServerK)
+ {
+ FreeK(c->ServerK);
+ }
+
+ if (c->CipherList)
+ {
+ Free(c->CipherList);
+ }
+
+ for (i = 0;i < LIST_NUM(c->TrafficDiffList);i++)
+ {
+ TRAFFIC_DIFF *d = LIST_DATA(c->TrafficDiffList, i);
+ Free(d->Name);
+ Free(d->HubName);
+ Free(d);
+ }
+
+ ReleaseList(c->TrafficDiffList);
+
+ Free(c->ServerStr);
+ Free(c->MachineName);
+
+ Free(c->HttpUserAgent);
+ Free(c->HttpAccept);
+ Free(c->HttpAcceptLanguage);
+ Free(c->HttpAcceptEncoding);
+
+ FreeTraffic(c->Traffic);
+
+ DeleteLock(c->TrafficLock);
+
+ FreeNetSvcList(c);
+
+ Free(c->VerString);
+ Free(c->BuildInfo);
+
+ FreeLocalBridgeList(c);
+
+ DeleteCounter(c->AssignedBridgeLicense);
+ DeleteCounter(c->AssignedClientLicense);
+
+ FreeNoSslList(c);
+
+ DeleteLock(c->CedarSuperLock);
+
+ DeleteCounter(c->AcceptingSockets);
+
+ ReleaseIntList(c->UdpPortList);
+
+ DeleteLock(c->OpenVPNPublicPortsLock);
+
+ Free(c);
+}
+
+// Release reference of the Cedar
+void ReleaseCedar(CEDAR *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ if (Release(c->ref) == 0)
+ {
+ CleanupCedar(c);
+ }
+}
+
+// Set cipher list entry
+void SetCedarCipherList(CEDAR *cedar, char *name)
+{
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return;
+ }
+
+ if (cedar->CipherList != NULL)
+ {
+ Free(cedar->CipherList);
+ }
+ if (name != NULL)
+ {
+ cedar->CipherList = CopyStr(name);
+ }
+ else
+ {
+ cedar->CipherList = NULL;
+ }
+}
+
+// Compare net service list entries
+int CompareNetSvc(void *p1, void *p2)
+{
+ NETSVC *n1, *n2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ n1 = *(NETSVC **)p1;
+ n2 = *(NETSVC **)p2;
+ if (n1 == NULL || n2 == NULL)
+ {
+ return 0;
+ }
+ if (n1->Port > n2->Port)
+ {
+ return 1;
+ }
+ else if (n1->Port < n2->Port)
+ {
+ return -1;
+ }
+ else if (n1->Udp > n2->Udp)
+ {
+ return 1;
+ }
+ else if (n1->Udp < n2->Udp)
+ {
+ return -1;
+ }
+ return 0;
+}
+
+// Initialize net service list
+void InitNetSvcList(CEDAR *cedar)
+{
+ char filename[MAX_PATH] = "/etc/services";
+ BUF *b;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ Format(filename, sizeof(filename), "%s\\drivers\\etc\\services", MsGetSystem32Dir());
+#endif
+
+ cedar->NetSvcList = NewList(CompareNetSvc);
+
+ b = ReadDump(filename);
+ if (b == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ char *s = CfgReadNextLine(b);
+ if (s == NULL)
+ {
+ break;
+ }
+
+ Trim(s);
+ if (s[0] != '#')
+ {
+ TOKEN_LIST *t = ParseToken(s, " \t/");
+ if (t->NumTokens >= 3)
+ {
+ NETSVC *n = ZeroMalloc(sizeof(NETSVC));
+ n->Name = CopyStr(t->Token[0]);
+ n->Udp = (StrCmpi(t->Token[2], "udp") == 0 ? true : false);
+ n->Port = ToInt(t->Token[1]);
+ Add(cedar->NetSvcList, n);
+ }
+ FreeToken(t);
+ }
+ Free(s);
+ }
+
+ FreeBuf(b);
+}
+
+// Get net service name
+char *GetSvcName(CEDAR *cedar, bool udp, UINT port)
+{
+ char *ret = NULL;
+ NETSVC t;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ t.Udp = (udp == 0 ? false : true);
+ t.Port = port;
+
+ LockList(cedar->NetSvcList);
+ {
+ NETSVC *n = Search(cedar->NetSvcList, &t);
+ if (n != NULL)
+ {
+ ret = n->Name;
+ }
+ }
+ UnlockList(cedar->NetSvcList);
+
+ return ret;
+}
+
+// Free net service list
+void FreeNetSvcList(CEDAR *cedar)
+{
+ UINT i;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(cedar->NetSvcList);i++)
+ {
+ NETSVC *n = LIST_DATA(cedar->NetSvcList, i);
+ Free(n->Name);
+ Free(n);
+ }
+ ReleaseList(cedar->NetSvcList);
+}
+
+// Change certificate of Cedar
+void SetCedarCert(CEDAR *c, X *server_x, K *server_k)
+{
+ // Validate arguments
+ if (server_x == NULL || server_k == NULL)
+ {
+ return;
+ }
+
+ Lock(c->lock);
+ {
+ if (c->ServerX != NULL)
+ {
+ FreeX(c->ServerX);
+ }
+
+ if (c->ServerK != NULL)
+ {
+ FreeK(c->ServerK);
+ }
+
+ c->ServerX = CloneX(server_x);
+ c->ServerK = CloneK(server_k);
+ }
+ Unlock(c->lock);
+}
+
+// Enable debug log
+void EnableDebugLog(CEDAR *c)
+{
+ // Validate arguments
+ if (c == NULL || c->DebugLog != NULL)
+ {
+ return;
+ }
+
+ c->DebugLog = NewLog("cedar_debug_log", "cedar", LOG_SWITCH_NO);
+}
+
+// Set the Cedar into VPN Bridge mode
+void SetCedarVpnBridge(CEDAR *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->Bridge = true;
+
+ Free(c->ServerStr);
+ c->ServerStr = CopyStr(CEDAR_BRIDGE_STR);
+}
+
+void CedarForceLink()
+{
+}
+
+// Get version of the Cedar
+void GetCedarVersion(char *tmp, UINT size)
+{
+ // Validate arguments
+ if (tmp == NULL)
+ {
+ return;
+ }
+
+ Format(tmp, size, "%u.%02u.%u",
+ CEDAR_VER / 100, CEDAR_VER - (CEDAR_VER / 100) * 100,
+ CEDAR_BUILD);
+}
+
+// Create Cedar object
+CEDAR *NewCedar(X *server_x, K *server_k)
+{
+ CEDAR *c;
+ char tmp[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ char *beta_str;
+
+ CedarForceLink();
+
+ c = ZeroMalloc(sizeof(CEDAR));
+
+ c->AcceptingSockets = NewCounter();
+
+ c->CedarSuperLock = NewLock();
+
+#ifdef BETA_NUMBER
+ c->Beta = BETA_NUMBER;
+#endif // BETA_NUMBER
+
+ InitNoSslList(c);
+
+ c->AssignedBridgeLicense = NewCounter();
+ c->AssignedClientLicense = NewCounter();
+
+ Rand(c->UniqueId, sizeof(c->UniqueId));
+
+ c->CreatedTick = Tick64();
+
+ c->lock = NewLock();
+ c->ref = NewRef();
+
+ c->OpenVPNPublicPortsLock = NewLock();
+ c->CurrentTcpConnections = GetNumTcpConnectionsCounter();
+
+ c->ListenerList = NewList(CompareListener);
+ c->UDPEntryList = NewList(CompareUDPEntry);
+ c->HubList = NewList(CompareHub);
+ c->ConnectionList = NewList(CompareConnection);
+
+ c->ConnectionIncrement = NewCounter();
+ c->CurrentSessions = NewCounter();
+
+ if (server_k && server_x)
+ {
+ c->ServerK = CloneK(server_k);
+ c->ServerX = CloneX(server_x);
+ }
+
+ c->Version = CEDAR_VER;
+ c->Build = CEDAR_BUILD;
+ c->ServerStr = CopyStr(CEDAR_SERVER_STR);
+
+ GetMachineName(tmp, sizeof(tmp));
+ c->MachineName = CopyStr(tmp);
+
+ c->HttpUserAgent = CopyStr(DEFAULT_USER_AGENT);
+ c->HttpAccept = CopyStr(DEFAULT_ACCEPT);
+ c->HttpAcceptLanguage = CopyStr("ja");
+ c->HttpAcceptEncoding = CopyStr(DEFAULT_ENCODING);
+
+ c->Traffic = NewTraffic();
+ c->TrafficLock = NewLock();
+ c->CaList = NewList(CompareCert);
+
+ c->TrafficDiffList = NewList(NULL);
+
+ SetCedarCipherList(c, "RC4-MD5");
+
+ c->ClientId = _II("CLIENT_ID");
+
+ c->UdpPortList = NewIntList(false);
+
+ InitNetSvcList(c);
+
+ InitLocalBridgeList(c);
+
+ InitCedarLayer3(c);
+
+ c->WebUI = WuNewWebUI(c);
+
+#ifdef ALPHA_VERSION
+ beta_str = "Alpha";
+#else // ALPHA_VERSION
+#ifndef RELEASE_CANDIDATE
+ beta_str = "Beta";
+#else // RELEASE_CANDIDATE
+ beta_str = "Release Candidate";
+#endif // RELEASE_CANDIDATE
+#endif // ALPHA_VERSION
+
+ ToStr(tmp2, c->Beta);
+
+ Format(tmp, sizeof(tmp), "Version %u.%02u Build %u %s %s (%s)",
+ CEDAR_VER / 100, CEDAR_VER - (CEDAR_VER / 100) * 100,
+ CEDAR_BUILD,
+ c->Beta == 0 ? "" : beta_str,
+ c->Beta == 0 ? "" : tmp2,
+ _SS("LANGSTR"));
+ Trim(tmp);
+
+ if (true)
+ {
+ SYSTEMTIME st;
+ Zero(&st, sizeof(st));
+
+ st.wYear = BUILD_DATE_Y;
+ st.wMonth = BUILD_DATE_M;
+ st.wDay = BUILD_DATE_D;
+
+ c->BuiltDate = SystemToUINT64(&st);
+ }
+
+ c->VerString = CopyStr(tmp);
+
+ Format(tmp, sizeof(tmp), "Compiled %04u/%02u/%02u %02u:%02u:%02u by %s at %s",
+ BUILD_DATE_Y, BUILD_DATE_M, BUILD_DATE_D, BUILD_DATE_HO, BUILD_DATE_MI, BUILD_DATE_SE, BUILDER_NAME, BUILD_PLACE);
+
+ c->BuildInfo = CopyStr(tmp);
+
+ return c;
+}
+
+// Check whether the Cedar was build after the specified date
+bool IsLaterBuild(CEDAR *c, UINT64 t)
+{
+ SYSTEMTIME sb, st;
+ UINT64 b;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ Zero(&sb, sizeof(sb));
+ Zero(&st, sizeof(st));
+
+ UINT64ToSystem(&sb, c->BuiltDate);
+ UINT64ToSystem(&st, t);
+
+ // Ignore time of the day
+ sb.wHour = sb.wMinute = sb.wSecond = sb.wMilliseconds = 0;
+ st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
+
+ b = SystemToUINT64(&sb);
+ t = SystemToUINT64(&st);
+
+ if (b > t)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// Cumulate traffic size
+void AddTraffic(TRAFFIC *dst, TRAFFIC *diff)
+{
+ // Validate arguments
+ if (dst == NULL || diff == NULL)
+ {
+ return;
+ }
+
+ dst->Recv.BroadcastBytes += diff->Recv.BroadcastBytes;
+ dst->Recv.BroadcastCount += diff->Recv.BroadcastCount;
+ dst->Recv.UnicastBytes += diff->Recv.UnicastBytes;
+ dst->Recv.UnicastCount += diff->Recv.UnicastCount;
+
+ dst->Send.BroadcastBytes += diff->Send.BroadcastBytes;
+ dst->Send.BroadcastCount += diff->Send.BroadcastCount;
+ dst->Send.UnicastBytes += diff->Send.UnicastBytes;
+ dst->Send.UnicastCount += diff->Send.UnicastCount;
+}
+
+// Create new traffic size object
+TRAFFIC *NewTraffic()
+{
+ TRAFFIC *t;
+
+ t = ZeroMalloc(sizeof(TRAFFIC));
+ return t;
+}
+
+// Free traffic size object
+void FreeTraffic(TRAFFIC *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t);
+}
+
+// Initialize Cedar communication module
+void InitCedar()
+{
+ if ((init_cedar_counter++) > 0)
+ {
+ return;
+ }
+
+ // Initialize protocol module
+ InitProtocol();
+}
+
+// Free Cedar communication module
+void FreeCedar()
+{
+ if ((--init_cedar_counter) > 0)
+ {
+ return;
+ }
+
+ // Free protocol module
+ FreeProtocol();
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Cedar.h b/src/Cedar/Cedar.h
new file mode 100644
index 00000000..bdb725bf
--- /dev/null
+++ b/src/Cedar/Cedar.h
@@ -0,0 +1,1194 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Cedar.h
+// Header of Cedar.c
+
+#ifndef CEDAR_H
+#define CEDAR_H
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Products related constants
+//
+//////////////////////////////////////////////////////////////////////
+
+// Replace the function name
+#ifdef VPN_SPEED
+
+#define DecryptSecurePacket __dsp
+#define CreateSecurePacket __csp
+#define GetSecureRandomSize __gsrs
+
+#endif // VPN_SPEED
+
+#define bool UINT
+#define BOOL UINT
+
+
+// Version number
+#define CEDAR_VER 403
+
+// Build Number
+#define CEDAR_BUILD 9408
+
+// Beta number
+//#define BETA_NUMBER 3
+
+// RC or not
+#define RELEASE_CANDIDATE
+
+// Specify the name of the person in charge building
+#ifndef BUILDER_NAME
+#define BUILDER_NAME "yagi"
+#endif // BUILDER_NAME
+
+// Specify the location to build
+#ifndef BUILD_PLACE
+#define BUILD_PLACE "pc25"
+#endif // BUILD_PLACE
+
+// Specifies the build date
+#define BUILD_DATE_Y 2014
+#define BUILD_DATE_M 1
+#define BUILD_DATE_D 4
+#define BUILD_DATE_HO 19
+#define BUILD_DATE_MI 10
+#define BUILD_DATE_SE 55
+
+// Tolerable time difference
+#define ALLOW_TIMESTAMP_DIFF (UINT64)(3 * 24 * 60 * 60 * 1000)
+
+
+// Configuration of communication related control switch
+#define USE_DOS_ATTACK_DETECTION // Enable the DOS attack detection
+//#define USE_SECURE_PACKET // Enable the scrambled packet
+
+// Designate the IDS detection signatures
+#define CEDAR_SIGNATURE_STR "SE-VPN4-PROTOCOL"
+
+// Default RSA certificate name of the smart card
+#define SECURE_DEFAULT_CERT_NAME "VPN_RSA_CERT"
+
+// Default RSA private key name of the smart card
+#define SECURE_DEFAULT_KEY_NAME "VPN_RSA_KEY"
+
+// Hidden password string of 8 characters
+#define HIDDEN_PASSWORD "********"
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Definition of the maximum length of various string
+//
+//////////////////////////////////////////////////////////////////////
+
+#define MAX_ACCOUNT_NAME_LEN 255 // Maximum account name length
+#define MAX_USERNAME_LEN 255 // User name maximum length
+#define MAX_PASSWORD_LEN 255 // Password name maximum length
+#define MAX_PROXY_USERNAME_LEN 255 // Proxy user name maximum length
+#define MAX_PROXY_PASSWORD_LEN 255 // Proxy Password maximum length
+#define MAX_SERVER_STR_LEN 255 // Maximum length of server string
+#define MAX_CLIENT_STR_LEN 255 // Maximum length of client string
+#define MAX_HUBNAME_LEN 255 // Maximum length of HUB name
+#define MAX_SESSION_NAME_LEN 255 // Session name maximum length
+#define MAX_CONNECTION_NAME_LEN 255 // Maximum length of connection name
+#define MAX_DEVICE_NAME_LEN 31 // Device name maximum length
+#define MAX_DEVICE_NAME_LEN_9X 4 // Maximum length of Virtual LAN card name in Win9x
+#define MAX_ACCESSLIST_NOTE_LEN 255 // Maximum length of the note of access list entry
+#define MAX_SECURE_DEVICE_FILE_LEN 255 // Secure device file name maximum length
+#define MAX_ADMIN_OPTION_NAME_LEN 63 // Management option name
+#define MAX_REDIRECT_URL_LEN 255 // URL length to redirect
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Server and session management related constants
+//
+//////////////////////////////////////////////////////////////////////
+
+#define SERVER_MAX_SESSIONS 4096 // Maximum number of sessions that the server supports
+#define SERVER_MAX_SESSIONS_FOR_CARRIER_EDITION 100000 // Maximum number of sessions that the server supports (Carrier Edition)
+#define NAT_MAX_SESSIONS 4096 // Maximum number of sessions that are supported by NAT
+#define NAT_MAX_SESSIONS_KERNEL 65536 // Maximum number of sessions that are supported by NAT (In the case of kernel-mode NAT)
+#define MAX_HUBS 4096 // The maximum number of virtual HUB
+#define MAX_HUBS_FOR_CARRIER_EDITION 100000 // The maximum number of virtual HUB (Carrier Edition)
+#define MAX_ACCESSLISTS (4096 * 8) // Maximum number of access list entries
+#define MAX_USERS 10000 // The maximum number of users
+#define MAX_GROUPS 10000 // Maximum number of groups
+#define MAX_MAC_TABLES 65536 // Maximum number of MAC address table entries
+#define MAX_IP_TABLES 65536 // Maximum number of IP address table entries
+#define MAX_HUB_CERTS 4096 // Maximum number of Root CA that can be registered
+#define MAX_HUB_CRLS 4096 // Maximum number of CRL that can be registered
+#define MAX_HUB_ACS 4096 // Maximum number of AC that can be registered
+#define MAX_HUB_LINKS 128 // Maximum number of Cascade that can be registered
+#define MAX_HUB_ADMIN_OPTIONS 4096 // Maximum number of Virtual HUB management options that can be registered
+
+#define MAX_PACKET_SIZE 1560 // Maximum packet size
+#define UDP_BUF_SIZE (32 * 1024) // Aim of the UDP packet size
+
+#define MAX_SEND_SOCKET_QUEUE_SIZE (1600 * 1600 * 1) // Maximum transmit queue size
+#define MIN_SEND_SOCKET_QUEUE_SIZE (1600 * 200 * 1)
+#define MAX_SEND_SOCKET_QUEUE_NUM 128 // Maximum transmission queue items
+#define MAX_TCP_CONNECTION 32 // The maximum number of TCP connections
+#define NUM_TCP_CONNECTION_FOR_UDP_RECOVERY 2 // Maximum number of connections when using UDP recovery
+#define SELECT_TIME 256
+#define SELECT_TIME_FOR_NAT 30
+#define SELECT_TIME_FOR_DELAYED_PKT 1 // If there is a delayed packet
+#define MAX_STORED_QUEUE_NUM 1024 // The number of queues that can be stored in each session
+#define MAX_BUFFERING_PACKET_SIZE (1600 * 1600) // Maximum packet size can be buffered
+
+#define TIMEOUT_MIN (5 * 1000) // Minimum timeout in seconds
+#define TIMEOUT_MAX (60 * 1000) // Maximum timeout in seconds
+#define TIMEOUT_DEFAULT (30 * 1000) // Default number of seconds to timeout
+#define CONNECTING_TIMEOUT (15 * 1000) // Timeout in seconds of being connected
+#define CONNECTING_TIMEOUT_PROXY (4 * 1000) // Timeout in seconds of being connected (Proxy)
+#define CONNECTING_POOLING_SPAN (3 * 1000) // Polling interval of connected
+#define MIN_RETRY_INTERVAL (5 * 1000) // Minimum retry interval
+#define MAX_RETRY_INTERVAL (300 * 1000) // Maximum retry interval
+#define RETRY_INTERVAL_SPECIAL (60 * 1000) // Reconnection interval of a special case
+
+#define MAX_ADDITONAL_CONNECTION_FAILED_COUNTER 16 // Allowable number that can be serially failed to additional connection
+#define ADDITIONAL_CONNECTION_COUNTER_RESET_INTERVAL (30 * 60 * 1000) // Reset period of additional connection failure counter
+
+#define MAC_MIN_LIMIT_COUNT 3 // Minimum number of MAC addresses
+#define IP_MIN_LIMIT_COUNT 4 // Number of IPv4 addresses minimum
+#define IP_MIN_LIMIT_COUNT_V6 5 // Number of IPv6 addresses minimum
+#define IP_LIMIT_WHEN_NO_ROUTING_V6 15 // Maximum number of IPv6 addresses when NoRouting policy is enabled
+
+#define MAC_TABLE_EXCLUSIVE_TIME (13 * 1000) // Period that can occupy the MAC address
+#define IP_TABLE_EXCLUSIVE_TIME (13 * 1000) // Period that can occupy the IP address
+#define MAC_TABLE_EXPIRE_TIME (600 * 1000) // MAC address table expiration date
+#define IP_TABLE_EXPIRE_TIME (60 * 1000) // IP address table expiration date
+#define IP_TABLE_EXPIRE_TIME_DHCP (5 * 60 * 1000) // IP address table expiration date (In the case of DHCP)
+#define HUB_ARP_SEND_INTERVAL (5 * 1000) // ARP packet transmission interval (alive check)
+
+#define LIMITER_SAMPLING_SPAN 1000 // Sampling interval of the traffic limiting device
+
+#define STORM_CHECK_SPAN 500 // Broadcast storm check interval
+#define STORM_DISCARD_VALUE_START 3 // Broadcast packet discard value start value
+#define STORM_DISCARD_VALUE_END 1024 // Broadcast packet discard value end value
+
+#define KEEP_INTERVAL_MIN 5 // Packet transmission interval minimum value
+#define KEEP_INTERVAL_DEFAULT 50 // Packet transmission interval default value
+#define KEEP_INTERVAL_MAX 600 // Packet transmission interval maximum value
+#define KEEP_TCP_TIMEOUT 1000 // TCP time-out value
+
+#define TICKET_EXPIRES (60 * 1000) // Expiration date of ticket
+
+#define SEND_KILL_NUM_X 256 // Number of 'X' characters to send the Kill
+
+
+#define FARM_BASE_POINT 100000 // Reference value of the cluster score
+#define FARM_DEFAULT_WEIGHT 100 // Standard performance ratio
+
+
+
+#define SE_UDP_SIGN "SE2P" // Not used (only old UDP mode)
+
+// R-UDP service name
+#define VPN_RUDP_SVC_NAME "SoftEther_VPN"
+
+// Traffic information update interval
+#define INCREMENT_TRAFFIC_INTERVAL (10 * 1000)
+
+// State of the client session
+#define CLIENT_STATUS_CONNECTING 0 // Connecting
+#define CLIENT_STATUS_NEGOTIATION 1 // Negotiating
+#define CLIENT_STATUS_AUTH 2 // During user authentication
+#define CLIENT_STATUS_ESTABLISHED 3 // Connection complete
+#define CLIENT_STATUS_RETRY 4 // Wait to retry
+#define CLIENT_STATUS_IDLE 5 // Idle state
+
+// Expiration date of the black list
+#define BLACK_LIST_EXPIRES (30 * 10000)
+
+// Number Blacklist entries
+#define MAX_BLACK_LIST 4096
+#define BLACK_LIST_CHECK_SPAN 1000
+
+// Blocks to be transmitted at one during the file transfer
+#define FTP_BLOCK_SIZE (640 * 1024)
+
+// Syslog configuration
+#define SYSLOG_NONE 0 // Do not use syslog
+#define SYSLOG_SERVER_LOG 1 // Only server log
+#define SYSLOG_SERVER_AND_HUB_SECURITY_LOG 2 // Server and Virtual HUB security log
+#define SYSLOG_SERVER_AND_HUB_ALL_LOG 3 // Server, Virtual HUB security, and packet log
+
+#define SYSLOG_PORT 514 // Syslog port number
+#define SYSLOG_POLL_IP_INTERVAL (UINT64)(3600 * 1000) // Interval to examine the IP address
+#define SYSLOG_POLL_IP_INTERVAL_NG (UINT64)(60 * 1000) // Interval to examine the IP address (previous failure)
+
+//////////////////////////////////////////////////////////////////////
+//
+// Connection-related constant
+//
+//////////////////////////////////////////////////////////////////////
+
+// Internet connection maintenance function (KeepAlive)
+
+#define KEEP_RETRY_INTERVAL (60 * 1000) // Reconnection interval on connection failure
+#define KEEP_MIN_PACKET_SIZE 1 // Minimum packet size
+#define KEEP_MAX_PACKET_SIZE 128 // Maximum packet size
+#define KEEP_POLLING_INTERVAL 250 // KEEP polling interval
+
+// Constants
+#define RECV_BUF_SIZE 65536 // Buffer size to be received at a time
+
+// Type of proxy
+#define PROXY_DIRECT 0 // Direct TCP connection
+#define PROXY_HTTP 1 // Connection via HTTP proxy server
+#define PROXY_SOCKS 2 // Connection via SOCKS proxy server
+
+// Direction of data flow
+#define TCP_BOTH 0 // Bi-directional
+#define TCP_SERVER_TO_CLIENT 1 // Only server -> client direction
+#define TCP_CLIENT_TO_SERVER 2 // Only client -> server direction
+
+// Type of connection
+#define CONNECTION_TYPE_CLIENT 0 // Client
+#define CONNECTION_TYPE_INIT 1 // During initialization
+#define CONNECTION_TYPE_LOGIN 2 // Login connection
+#define CONNECTION_TYPE_ADDITIONAL 3 // Additional connection
+#define CONNECTION_TYPE_FARM_RPC 4 // RPC for server farm
+#define CONNECTION_TYPE_ADMIN_RPC 5 // RPC for Management
+#define CONNECTION_TYPE_ENUM_HUB 6 // HUB enumeration
+#define CONNECTION_TYPE_PASSWORD 7 // Password change
+#define CONNECTION_TYPE_SSTP 8 // SSTP
+#define CONNECTION_TYPE_OPENVPN 9 // OpenVPN
+
+// Protocol
+#define CONNECTION_TCP 0 // TCP protocol
+#define CONNECTION_UDP 1 // UDP protocol
+#define CONNECTION_HUB_LAYER3 6 // Layer-3 switch session
+#define CONNECTION_HUB_BRIDGE 7 // Bridge session
+#define CONNECTION_HUB_SECURE_NAT 8 // Secure NAT session
+#define CONNECTION_HUB_LINK_SERVER 9 // HUB link session
+
+
+// Status
+#define CONNECTION_STATUS_ACCEPTED 0 // The connection is accepted (client side)
+#define CONNECTION_STATUS_NEGOTIATION 1 // Negotiating
+#define CONNECTION_STATUS_USERAUTH 2 // During user authentication
+#define CONNECTION_STATUS_ESTABLISHED 3 // Connection has been established
+#define CONNECTION_STATUS_CONNECTING 0 // Connecting (client side)
+
+// Magic number of KeepAlive packet
+#define KEEP_ALIVE_MAGIC 0xffffffff
+#define MAX_KEEPALIVE_SIZE 512
+
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Virtual HUB-related constant
+//
+//////////////////////////////////////////////////////////////////////
+
+#define SE_HUB_MAC_ADDR_SIGN 0xAE // Sign virtual HUB MAC address
+
+// Traffic difference value
+#define TRAFFIC_DIFF_USER 0 // User
+#define TRAFFIC_DIFF_HUB 1 // Virtual HUB
+#define MAX_TRAFFIC_DIFF 30000 // Maximum number of items
+
+// Type of HUB
+#define HUB_TYPE_STANDALONE 0 // Stand-alone HUB
+#define HUB_TYPE_FARM_STATIC 1 // Static HUB
+#define HUB_TYPE_FARM_DYNAMIC 2 // Dynamic HUB
+
+// Related to delay, jitter, packet loss in the access list
+#define HUB_ACCESSLIST_DELAY_MAX 10000 // Maximum delay
+#define HUB_ACCESSLIST_JITTER_MAX 100 // Maximum jitter
+#define HUB_ACCESSLIST_LOSS_MAX 100 // Maximum packet loss
+
+// Message related
+#define HUB_MAXMSG_LEN 20000 // The maximum number of characters in a message
+
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Type of user authentication
+//
+//////////////////////////////////////////////////////////////////////
+
+// Constant in the server-side
+#define AUTHTYPE_ANONYMOUS 0 // Anonymous authentication
+#define AUTHTYPE_PASSWORD 1 // Password authentication
+#define AUTHTYPE_USERCERT 2 // User certificate authentication
+#define AUTHTYPE_ROOTCERT 3 // Root certificate which is issued by trusted Certificate Authority
+#define AUTHTYPE_RADIUS 4 // Radius authentication
+#define AUTHTYPE_NT 5 // Windows NT authentication
+#define AUTHTYPE_TICKET 99 // Ticket authentication
+
+// Constant of the client side
+#define CLIENT_AUTHTYPE_ANONYMOUS 0 // Anonymous authentication
+#define CLIENT_AUTHTYPE_PASSWORD 1 // Password authentication
+#define CLIENT_AUTHTYPE_PLAIN_PASSWORD 2 // Plain password authentication
+#define CLIENT_AUTHTYPE_CERT 3 // Certificate authentication
+#define CLIENT_AUTHTYPE_SECURE 4 // Secure device authentication
+
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// TCP listener related constants
+//
+//////////////////////////////////////////////////////////////////////
+
+// Retries in case it fails to Listen
+#define LISTEN_RETRY_TIME (2 * 1000) // If fail to Listen normally
+#define LISTEN_RETRY_TIME_NOIPV6 (60 * 1000) // If IPv6 support is disabled
+
+#define DOS_TABLE_EXPIRES_FIRST 250 // Initial value of the expiration date of DOS attack list
+#define DOS_TABLE_EXPIRES_MAX 1000 // Maximum value of the expiration date of DOS attack list
+#define DOS_TABLE_REFRESH_INTERVAL (10 * 1000) // Interval to update the DOS attack list
+#define DOS_TABLE_MAX_LIMIT_PER_IP 16 // Accessible number per an IP
+#define DOS_TABLE_EXPIRES_TOTAL (3000 * 1000) // Time to force delete the entry
+
+
+// Protocol to be used for the listener
+#define LISTENER_TCP 0 // TCP/IP
+#define LISTENER_UDP 1 // UDP/IP (not being used)
+#define LISTENER_INPROC 2 // In-process communication
+#define LISTENER_RUDP 3 // R-UDP with NAT-T
+#define LISTENER_ICMP 4 // VPN over ICMP
+#define LISTENER_DNS 5 // VPN over DNS
+#define LISTENER_REVERSE 6 // Reverse socket
+
+// Status of the listener
+#define LISTENER_STATUS_TRYING 0 // While attempting
+#define LISTENER_STATUS_LISTENING 1 // Listening
+
+// Largest packet size of UDP
+#define UDP_PACKET_SIZE 65536
+
+// Number of standard connections per IP address
+#define DEFAULT_MAX_CONNECTIONS_PER_IP 256
+#define MIN_MAX_CONNECTIONS_PER_IP 10 // Minimum value
+
+// Allowed number of outstanding connections
+#define DEFAULT_MAX_UNESTABLISHED_CONNECTIONS 1000
+#define MIN_MAX_UNESTABLISHED_CONNECTIONS 30 // Minimum value
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Log related constant
+//
+//////////////////////////////////////////////////////////////////////
+
+#define LOG_ENGINE_SAVE_START_CACHE_COUNT 100000 // Number to start saving forcibly
+#define LOG_ENGINE_BUFFER_CACHE_SIZE_MAX (10 * 1024 * 1024) // Write cache size
+
+// Constant such as a file name
+#define SERVER_LOG_DIR_NAME "@server_log"
+#define BRIDGE_LOG_DIR_NAME SERVER_LOG_DIR_NAME
+#define SERVER_LOG_PERFIX "vpn"
+
+#define HUB_SECURITY_LOG_DIR_NAME "@security_log"
+#define HUB_SECURITY_LOG_FILE_NAME "@security_log/%s"
+#define HUB_SECURITY_LOG_PREFIX "sec"
+#define HUB_PACKET_LOG_DIR_NAME "@packet_log"
+#define HUB_PACKET_LOG_FILE_NAME "@packet_log/%s"
+#define HUB_PACKET_LOG_PREFIX "pkt"
+
+#define NAT_LOG_DIR_NAME "@secure_nat_log"
+#define NAT_LOG_FILE_NAME "@secure_nat_log/%s"
+#define NAT_LOG_PREFIX "snat"
+
+#define CLIENT_LOG_DIR_NAME "@client_log"
+#define CLIENT_LOG_PREFIX "client"
+
+// Packet log settings
+#define NUM_PACKET_LOG 16
+#define PACKET_LOG_TCP_CONN 0 // TCP connection log
+#define PACKET_LOG_TCP 1 // TCP packet log
+#define PACKET_LOG_DHCP 2 // DHCP Log
+#define PACKET_LOG_UDP 3 // UDP log
+#define PACKET_LOG_ICMP 4 // ICMP log
+#define PACKET_LOG_IP 5 // IP log
+#define PACKET_LOG_ARP 6 // ARP log
+#define PACKET_LOG_ETHERNET 7 // Ethernet log
+
+#define PACKET_LOG_NONE 0 // Not save
+#define PACKET_LOG_HEADER 1 // Only header
+#define PACKET_LOG_ALL 2 // Store also data
+
+// Timing of log switching
+#define LOG_SWITCH_NO 0 // Without switching
+#define LOG_SWITCH_SECOND 1 // Secondly basis
+#define LOG_SWITCH_MINUTE 2 // Minutely basis
+#define LOG_SWITCH_HOUR 3 // Hourly basis
+#define LOG_SWITCH_DAY 4 // Daily basis
+#define LOG_SWITCH_MONTH 5 // Monthly basis
+
+// Minimum amount of free disk space
+#define DISK_FREE_SPACE_MIN 1048576 // 1 MBytes
+#define DISK_FREE_SPACE_DEFAULT (DISK_FREE_SPACE_MIN * 100) // 100 Mbytes
+#define DISK_FREE_SPACE_DEFAULT_WINDOWS ((UINT64)(8ULL * 1024ULL * 1024ULL * 1024ULL)) // 8GBytes
+
+// Interval to check the free space
+#define DISK_FREE_CHECK_INTERVAL (5 * 60 * 1000)
+
+// Simple log
+#define TINY_LOG_DIRNAME "@tiny_log"
+#define TINY_LOG_FILENAME "@tiny_log/%04u%02u%02u_%02u%02u%02u.log"
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Constant related to Carrier Edition
+//
+//////////////////////////////////////////////////////////////////////
+
+#define CE_SNAPSHOT_INTERVAL ((UINT64)(3600 * 1000))
+//#define CE_SNAPSHOT_INTERVAL ((UINT64)(3000))
+#define CE_SNAPSHOT_POLLING_INTERVAL (1 * 1000)
+#define CE_SNAPSHOT_POLLING_INTERVAL_LICENSE (30 * 1000)
+#define CE_SNAPSHOT_DIR_NAME "@carrier_log"
+#define CE_SNAPSHOT_PREFIX "carrier"
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Communication protocol related constant
+//
+//////////////////////////////////////////////////////////////////////
+
+// Administrator Username
+#define ADMINISTRATOR_USERNAME "administrator"
+// Maximum value of random size
+#define RAND_SIZE_MAX 4096
+// Expiration date of random size cache
+#define RAND_SIZE_CACHE_EXPIRE (24 * 60 * 60 * 1000)
+// Management allowed IP address list file name
+#define ADMINIP_TXT "@adminip.txt"
+
+#define NON_SSL_MIN_COUNT 60
+#define NON_SSL_ENTRY_EXPIRES (10 * 60 * 1000)
+
+//////////////////////////////////////////////////////////////////////
+//
+// The cascade related constants
+//
+//////////////////////////////////////////////////////////////////////
+
+#define LINK_DEVICE_NAME "_SEHUBLINKCLI_"
+#define LINK_USER_NAME "link"
+#define LINK_USER_NAME_PRINT "Cascade"
+
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Constant related to SecureNAT connection
+//
+//////////////////////////////////////////////////////////////////////
+
+#define SNAT_DEVICE_NAME "_SEHUBSECURENAT_"
+#define SNAT_USER_NAME "securenat"
+#define SNAT_USER_NAME_PRINT "SecureNAT"
+
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Constant related to bridge connection
+//
+//////////////////////////////////////////////////////////////////////
+
+#define BRIDGE_DEVICE_NAME "_SEHUBBRIDGE_"
+#define BRIDGE_USER_NAME "localbridge"
+#define BRIDGE_USER_NAME_PRINT "Local Bridge"
+#define BRIDGE_TRY_SPAN 1000
+#define BRIDGE_NUM_DEVICE_CHECK_SPAN (5 * 60 * 1000)
+#define BRIDGE_NETWORK_CONNECTION_STR L"%s [%S]"
+
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// EtherLogger related constants
+//
+//////////////////////////////////////////////////////////////////////
+
+#define EL_ADMIN_PORT 22888
+#define EL_CONFIG_FILENAME "@etherlogger.config"
+#define EL_PACKET_LOG_DIR_NAME "@etherlogger_log"
+#define EL_PACKET_LOG_FILE_NAME "@etherlogger_log/%s"
+#define EL_PACKET_LOG_PREFIX "pkt"
+#define EL_LICENSE_CHECK_SPAN (10 * 1000)
+
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Layer-3 Switch related constants
+//
+//////////////////////////////////////////////////////////////////////
+
+#define MAX_NUM_L3_SWITCH 4096
+#define MAX_NUM_L3_IF 4096
+#define MAX_NUM_L3_TABLE 4096
+
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Constant related to User-mode Router
+//
+//////////////////////////////////////////////////////////////////////
+
+#define ARP_ENTRY_EXPIRES (30 * 1000) // ARP table expiration date
+#define ARP_ENTRY_POLLING_TIME (1 * 1000) // ARP table cleaning timer
+#define ARP_REQUEST_TIMEOUT (200) // ARP request time-out period
+#define ARP_REQUEST_GIVEUP (5 * 1000) // Time to give up sending the ARP request
+#define IP_WAIT_FOR_ARP_TIMEOUT (5 * 1000) // Total time that an IP packet waiting for ARP table
+#define IP_COMBINE_TIMEOUT (10 * 1000) // Time-out of IP packet combining
+#define NAT_TCP_MAX_TIMEOUT (2000000 * 1000) // Maximum TCP session timeout in seconds
+#define NAT_UDP_MAX_TIMEOUT (2000000 * 1000) // Maximum UDP session timeout in seconds
+#define NAT_TCP_MIN_TIMEOUT (1 * 60 * 1000) // Minimum TCP session timeout in seconds
+#define NAT_UDP_MIN_TIMEOUT (10 * 1000) // Minimum UDP session timeout in seconds
+#define NAT_TCP_RECV_WINDOW_SIZE 64512 // TCP receive window size
+#define NAT_TCP_SYNACK_SEND_TIMEOUT 250 // Sending TCP SYN+ACK interval
+#define NAT_ICMP_TIMEOUT (10 * 1000) // ICMP timeout in seconds
+#define NAT_ICMP_TIMEOUT_WITH_API (3 * 1000) // Timeout in seconds in the case of using the ICMP API
+#define NAT_SEND_BUF_SIZE (64 * 1024) // TCP send buffer size
+#define NAT_RECV_BUF_SIZE (64 * 1024) // TCP receive buffer size
+#define NAT_TMPBUF_SIZE (128 * 1024) // TCP temporally memory area size
+#define NAT_ACK_KEEPALIVE_SPAN (5 * 1000) // ACK transmission interval for TCP keep alive
+#define NAT_INITIAL_RTT_VALUE 500 // Initial RTT value
+#define NAT_FIN_SEND_INTERVAL 1000 // FIN transmission interval
+#define NAT_FIN_SEND_MAX_COUNT 5 // Total number of FIN transmissions
+#define NAT_DNS_PROXY_PORT 53 // DNS proxy port number
+#define NAT_DNS_RESPONSE_TTL (20 * 60) // TTL of the DNS response
+#define NAT_DHCP_SERVER_PORT 67 // DHCP server port number
+#define NAT_DHCP_CLIENT_PORT 68 // DHCP client port number
+#define DHCP_MIN_EXPIRE_TIMESPAN (15 * 1000) // DHCP minimum expiration date
+#define DHCP_POLLING_INTERVAL 1000 // DHCP polling interval
+#define X32 ((UINT64)4294967296ULL) // 32bit + 1
+#define NAT_DNS_QUERY_TIMEOUT (512) // Time-out value of DNS queries
+
+// Beacon transmission interval
+#define BEACON_SEND_INTERVAL (5 * 1000)
+
+// Total size quota allowed in the queue for the combining the IP packet
+#define IP_COMBINE_WAIT_QUEUE_SIZE_QUOTA (50 * 1024 * 1024)
+
+// Header size constant
+#define MAC_HEADER_SIZE (sizeof(MAC_HEADER))
+#define ARP_HEADER_SIZE (sizeof(ARP_HEADER))
+#define IP_HEADER_SIZE (sizeof(IPV4_HEADER))
+#define TCP_HEADER_SIZE (sizeof(TCP_HEADER))
+#define UDP_HEADER_SIZE (sizeof(UDP_HEADER))
+
+// Data maximum size constant
+#define MAX_L3_DATA_SIZE (1500)
+#define MAX_IP_DATA_SIZE (MAX_L3_DATA_SIZE - IP_HEADER_SIZE)
+#define MAX_TCP_DATA_SIZE (MAX_IP_DATA_SIZE - TCP_HEADER_SIZE)
+#define MAX_UDP_DATA_SIZE (MAX_IP_DATA_SIZE - UDP_HEADER_SIZE)
+#define MAX_IP_DATA_SIZE_TOTAL (65535)
+
+// IP packet option constant
+#define DEFAULT_IP_TOS 0 // TOS in the IP header
+#define DEFAULT_IP_TTL 128 // TTL in the IP header
+
+// Type of NAT session
+#define NAT_TCP 0 // TCP NAT
+#define NAT_UDP 1 // UDP NAT
+#define NAT_DNS 2 // DNS NAT
+#define NAT_ICMP 3 // ICMP NAT
+
+// State of NAT session
+#define NAT_TCP_CONNECTING 0 // Connecting
+#define NAT_TCP_SEND_RESET 1 // Send the RST (Connection failure or disconnected)
+#define NAT_TCP_CONNECTED 2 // Connection complete
+#define NAT_TCP_ESTABLISHED 3 // Connection established
+#define NAT_TCP_WAIT_DISCONNECT 4 // Wait for socket disconnection
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// For UNIX virtual LAN card related constant
+//
+//////////////////////////////////////////////////////////////////////
+
+#define TAP_FILENAME_1 "/dev/net/tun"
+#define TAP_FILENAME_2 "/dev/tun"
+#define TAP_MACOS_FILENAME "/dev/tap0"
+
+
+
+
+
+#define LICENSE_EDITION_VPN3_NO_LICENSE 0 // Without license
+
+#define LICENSE_MAX_PRODUCT_NAME_LEN 255 // Maximum length of license product name
+#define LICENSE_NUM_SHA 10000 // Number of times to hash with SHA
+#define LICENSE_SYSTEM_KEY_NUM 2048 // Key number for system
+#define LICENSE_SYSTEM_KEYSIZE_BIT 144 // Number of key bits for system
+#define LICENSE_PRODUCT_KEY_NUM 16384 // Number of keys for product
+#define LICENSE_PRODUCT_KEYSIZE_BIT 56 // Number of key bits for product
+#define LICENSE_PRODUCT_COMMON_KEYSIZE_BIT 48 // Number of common key bits for product
+#define LICENSE_MASTER_KEYSIZE_BIT 1024 // Number of master key bits
+#define LICENSE_SYSTEM_ID_MIN 0ULL // System ID minimum value
+#define LICENSE_SYSTEM_ID_MAX 549755813887ULL // System ID maximum value
+#define LICENSE_SERIAL_ID_MIN 0 // Serial ID minimum value
+#define LICENSE_SERIAL_ID_MAX 65535 // Serial ID maximum value
+#define LICENSE_EXPIRES_MIN 0 // Expiration date minimum
+#define LICENSE_EXPIRES_MAX 16383 // Expiration date maximum
+#define LICENSE_KEYSTR_LEN 41 // Length of the license key
+#define LICENSE_LICENSEID_STR_LEN 33 // Length of the license ID
+
+#define LICENSE_STATUS_OK 0 // Enabled
+#define LICENSE_STATUS_EXPIRED 1 // Invalid (expired)
+#define LICENSE_STATUS_ID_DIFF 2 // Invalid (System ID mismatch)
+#define LICENSE_STATUS_DUP 3 // Invalid (duplicated)
+#define LICENSE_STATUS_INSUFFICIENT 4 // Invalid (other necessary license shortage)
+#define LICENSE_STATUS_COMPETITION 5 // Invalid (conflict with other licenses)
+#define LICENSE_STATUS_NONSENSE 6 // Invalid (meaningless in the current edition)
+#define LICENSE_STATUS_CPU 7 // Invalid (CPU type mismatch)
+
+#define BIT_TO_BYTE(x) (((x) + 7) / 8)
+#define BYTE_TO_BIT(x) ((x) * 8)
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Error code
+//
+//////////////////////////////////////////////////////////////////////
+
+#define ERR_NO_ERROR 0 // No error
+#define ERR_CONNECT_FAILED 1 // Connection to the server has failed
+#define ERR_SERVER_IS_NOT_VPN 2 // The destination server is not a VPN server
+#define ERR_DISCONNECTED 3 // The connection has been interrupted
+#define ERR_PROTOCOL_ERROR 4 // Protocol error
+#define ERR_CLIENT_IS_NOT_VPN 5 // Connecting client is not a VPN client
+#define ERR_USER_CANCEL 6 // User cancel
+#define ERR_AUTHTYPE_NOT_SUPPORTED 7 // Specified authentication method is not supported
+#define ERR_HUB_NOT_FOUND 8 // The HUB does not exist
+#define ERR_AUTH_FAILED 9 // Authentication failure
+#define ERR_HUB_STOPPING 10 // HUB is stopped
+#define ERR_SESSION_REMOVED 11 // Session has been deleted
+#define ERR_ACCESS_DENIED 12 // Access denied
+#define ERR_SESSION_TIMEOUT 13 // Session times out
+#define ERR_INVALID_PROTOCOL 14 // Protocol is invalid
+#define ERR_TOO_MANY_CONNECTION 15 // Too many connections
+#define ERR_HUB_IS_BUSY 16 // Too many sessions of the HUB
+#define ERR_PROXY_CONNECT_FAILED 17 // Connection to the proxy server fails
+#define ERR_PROXY_ERROR 18 // Proxy Error
+#define ERR_PROXY_AUTH_FAILED 19 // Failed to authenticate on the proxy server
+#define ERR_TOO_MANY_USER_SESSION 20 // Too many sessions of the same user
+#define ERR_LICENSE_ERROR 21 // License error
+#define ERR_DEVICE_DRIVER_ERROR 22 // Device driver error
+#define ERR_INTERNAL_ERROR 23 // Internal error
+#define ERR_SECURE_DEVICE_OPEN_FAILED 24 // The secure device cannot be opened
+#define ERR_SECURE_PIN_LOGIN_FAILED 25 // PIN code is incorrect
+#define ERR_SECURE_NO_CERT 26 // Specified certificate is not stored
+#define ERR_SECURE_NO_PRIVATE_KEY 27 // Specified private key is not stored
+#define ERR_SECURE_CANT_WRITE 28 // Write failure
+#define ERR_OBJECT_NOT_FOUND 29 // Specified object can not be found
+#define ERR_VLAN_ALREADY_EXISTS 30 // Virtual LAN card with the specified name already exists
+#define ERR_VLAN_INSTALL_ERROR 31 // Specified virtual LAN card cannot be created
+#define ERR_VLAN_INVALID_NAME 32 // Specified name of the virtual LAN card is invalid
+#define ERR_NOT_SUPPORTED 33 // Unsupported
+#define ERR_ACCOUNT_ALREADY_EXISTS 34 // Account already exists
+#define ERR_ACCOUNT_ACTIVE 35 // Account is operating
+#define ERR_ACCOUNT_NOT_FOUND 36 // Specified account doesn't exist
+#define ERR_ACCOUNT_INACTIVE 37 // Account is offline
+#define ERR_INVALID_PARAMETER 38 // Parameter is invalid
+#define ERR_SECURE_DEVICE_ERROR 39 // Error has occurred in the operation of the secure device
+#define ERR_NO_SECURE_DEVICE_SPECIFIED 40 // Secure device is not specified
+#define ERR_VLAN_IS_USED 41 // Virtual LAN card in use by account
+#define ERR_VLAN_FOR_ACCOUNT_NOT_FOUND 42 // Virtual LAN card of the account can not be found
+#define ERR_VLAN_FOR_ACCOUNT_USED 43 // Virtual LAN card of the account is already in use
+#define ERR_VLAN_FOR_ACCOUNT_DISABLED 44 // Virtual LAN card of the account is disabled
+#define ERR_INVALID_VALUE 45 // Value is invalid
+#define ERR_NOT_FARM_CONTROLLER 46 // Not a farm controller
+#define ERR_TRYING_TO_CONNECT 47 // Attempting to connect
+#define ERR_CONNECT_TO_FARM_CONTROLLER 48 // Failed to connect to the farm controller
+#define ERR_COULD_NOT_HOST_HUB_ON_FARM 49 // A virtual HUB on farm could not be created
+#define ERR_FARM_MEMBER_HUB_ADMIN 50 // HUB cannot be managed on a farm member
+#define ERR_NULL_PASSWORD_LOCAL_ONLY 51 // Accepting only local connections for an empty password
+#define ERR_NOT_ENOUGH_RIGHT 52 // Right is insufficient
+#define ERR_LISTENER_NOT_FOUND 53 // Listener can not be found
+#define ERR_LISTENER_ALREADY_EXISTS 54 // Listener already exists
+#define ERR_NOT_FARM_MEMBER 55 // Not a farm member
+#define ERR_CIPHER_NOT_SUPPORTED 56 // Encryption algorithm is not supported
+#define ERR_HUB_ALREADY_EXISTS 57 // HUB already exists
+#define ERR_TOO_MANY_HUBS 58 // Too many HUBs
+#define ERR_LINK_ALREADY_EXISTS 59 // Link already exists
+#define ERR_LINK_CANT_CREATE_ON_FARM 60 // The link can not be created on the server farm
+#define ERR_LINK_IS_OFFLINE 61 // Link is off-line
+#define ERR_TOO_MANY_ACCESS_LIST 62 // Too many access list
+#define ERR_TOO_MANY_USER 63 // Too many users
+#define ERR_TOO_MANY_GROUP 64 // Too many Groups
+#define ERR_GROUP_NOT_FOUND 65 // Group can not be found
+#define ERR_USER_ALREADY_EXISTS 66 // User already exists
+#define ERR_GROUP_ALREADY_EXISTS 67 // Group already exists
+#define ERR_USER_AUTHTYPE_NOT_PASSWORD 68 // Authentication method of the user is not a password authentication
+#define ERR_OLD_PASSWORD_WRONG 69 // The user does not exist or the old password is wrong
+#define ERR_LINK_CANT_DISCONNECT 73 // Cascade session cannot be disconnected
+#define ERR_ACCOUNT_NOT_PRESENT 74 // Not completed configure the connection to the VPN server
+#define ERR_ALREADY_ONLINE 75 // It is already online
+#define ERR_OFFLINE 76 // It is offline
+#define ERR_NOT_RSA_1024 77 // The certificate is not RSA 1024bit
+#define ERR_SNAT_CANT_DISCONNECT 78 // SecureNAT session cannot be disconnected
+#define ERR_SNAT_NEED_STANDALONE 79 // SecureNAT works only in stand-alone HUB
+#define ERR_SNAT_NOT_RUNNING 80 // SecureNAT function is not working
+#define ERR_SE_VPN_BLOCK 81 // Stopped by PacketiX VPN Block
+#define ERR_BRIDGE_CANT_DISCONNECT 82 // Bridge session can not be disconnected
+#define ERR_LOCAL_BRIDGE_STOPPING 83 // Bridge function is stopped
+#define ERR_LOCAL_BRIDGE_UNSUPPORTED 84 // Bridge feature is not supported
+#define ERR_CERT_NOT_TRUSTED 85 // Certificate of the destination server can not be trusted
+#define ERR_PRODUCT_CODE_INVALID 86 // Product code is different
+#define ERR_VERSION_INVALID 87 // Version is different
+#define ERR_CAPTURE_DEVICE_ADD_ERROR 88 // Adding capture device failure
+#define ERR_VPN_CODE_INVALID 89 // VPN code is different
+#define ERR_CAPTURE_NOT_FOUND 90 // Capture device can not be found
+#define ERR_LAYER3_CANT_DISCONNECT 91 // Layer-3 session cannot be disconnected
+#define ERR_LAYER3_SW_EXISTS 92 // L3 switch of the same already exists
+#define ERR_LAYER3_SW_NOT_FOUND 93 // Layer-3 switch can not be found
+#define ERR_INVALID_NAME 94 // Name is invalid
+#define ERR_LAYER3_IF_ADD_FAILED 95 // Failed to add interface
+#define ERR_LAYER3_IF_DEL_FAILED 96 // Failed to delete the interface
+#define ERR_LAYER3_IF_EXISTS 97 // Interface that you specified already exists
+#define ERR_LAYER3_TABLE_ADD_FAILED 98 // Failed to add routing table
+#define ERR_LAYER3_TABLE_DEL_FAILED 99 // Failed to delete the routing table
+#define ERR_LAYER3_TABLE_EXISTS 100 // Routing table entry that you specified already exists
+#define ERR_BAD_CLOCK 101 // Time is queer
+#define ERR_LAYER3_CANT_START_SWITCH 102 // The Virtual Layer 3 Switch can not be started
+#define ERR_CLIENT_LICENSE_NOT_ENOUGH 103 // Client connection licenses shortage
+#define ERR_BRIDGE_LICENSE_NOT_ENOUGH 104 // Bridge connection licenses shortage
+#define ERR_SERVER_CANT_ACCEPT 105 // Not Accept on the technical issues
+#define ERR_SERVER_CERT_EXPIRES 106 // Destination VPN server has expired
+#define ERR_MONITOR_MODE_DENIED 107 // Monitor port mode was rejected
+#define ERR_BRIDGE_MODE_DENIED 108 // Bridge-mode or Routing-mode was rejected
+#define ERR_IP_ADDRESS_DENIED 109 // Client IP address is denied
+#define ERR_TOO_MANT_ITEMS 110 // Too many items
+#define ERR_MEMORY_NOT_ENOUGH 111 // Out of memory
+#define ERR_OBJECT_EXISTS 112 // Object already exists
+#define ERR_FATAL 113 // A fatal error occurred
+#define ERR_SERVER_LICENSE_FAILED 114 // License violation has occurred on the server side
+#define ERR_SERVER_INTERNET_FAILED 115 // Server side is not connected to the Internet
+#define ERR_CLIENT_LICENSE_FAILED 116 // License violation occurs on the client side
+#define ERR_BAD_COMMAND_OR_PARAM 117 // Command or parameter is invalid
+#define ERR_INVALID_LICENSE_KEY 118 // License key is invalid
+#define ERR_NO_VPN_SERVER_LICENSE 119 // There is no valid license for the VPN Server
+#define ERR_NO_VPN_CLUSTER_LICENSE 120 // There is no cluster license
+#define ERR_NOT_ADMINPACK_SERVER 121 // Not trying to connect to a server with the Administrator Pack license
+#define ERR_NOT_ADMINPACK_SERVER_NET 122 // Not trying to connect to a server with the Administrator Pack license (for .NET)
+#define ERR_BETA_EXPIRES 123 // Destination Beta VPN Server has expired
+#define ERR_BRANDED_C_TO_S 124 // Branding string of connection limit is different (Authentication on the server side)
+#define ERR_BRANDED_C_FROM_S 125 // Branding string of connection limit is different (Authentication for client-side)
+#define ERR_AUTO_DISCONNECTED 126 // VPN session is disconnected for a certain period of time has elapsed
+#define ERR_CLIENT_ID_REQUIRED 127 // Client ID does not match
+#define ERR_TOO_MANY_USERS_CREATED 128 // Too many created users
+#define ERR_SUBSCRIPTION_IS_OLDER 129 // Subscription expiration date Is earlier than the build date of the VPN Server
+#define ERR_ILLEGAL_TRIAL_VERSION 130 // Many trial license is used continuously
+#define ERR_NAT_T_TWO_OR_MORE 131 // There are multiple servers in the back of a global IP address in the NAT-T connection
+#define ERR_DUPLICATE_DDNS_KEY 132 // DDNS host key duplicate
+#define ERR_DDNS_HOSTNAME_EXISTS 133 // Specified DDNS host name already exists
+#define ERR_DDNS_HOSTNAME_INVALID_CHAR 134 // Characters that can not be used for the host name is included
+#define ERR_DDNS_HOSTNAME_TOO_LONG 135 // Host name is too long
+#define ERR_DDNS_HOSTNAME_IS_EMPTY 136 // Host name is not specified
+#define ERR_DDNS_HOSTNAME_TOO_SHORT 137 // Host name is too short
+#define ERR_MSCHAP2_PASSWORD_NEED_RESET 138 // Necessary that password is changed
+#define ERR_DDNS_DISCONNECTED 139 // Communication to the dynamic DNS server is disconnected
+#define ERR_SPECIAL_LISTENER_ICMP_ERROR 140 // The ICMP socket can not be opened
+#define ERR_SPECIAL_LISTENER_DNS_ERROR 141 // Socket for DNS port can not be opened
+#define ERR_OPENVPN_IS_NOT_ENABLED 142 // OpenVPN server feature is not enabled
+#define ERR_NOT_SUPPORTED_AUTH_ON_OPENSOURCE 143 // It is the type of user authentication that are not supported in the open source version
+#define ERR_VPNGATE 144 // Operation on VPN Gate Server is not available
+#define ERR_VPNGATE_CLIENT 145 // Operation on VPN Gate Client is not available
+#define ERR_VPNGATE_INCLIENT_CANT_STOP 146 // Can not be stopped if operating within VPN Client mode
+#define ERR_NOT_SUPPORTED_FUNCTION_ON_OPENSOURCE 147 // It is a feature that is not supported in the open source version
+
+
+////////////////////////////
+// Generally used structure
+
+// Network Services
+typedef struct NETSVC
+{
+ bool Udp; // false=TCP, true=UDP
+ UINT Port; // Port number
+ char *Name; // Name
+} NETSVC;
+
+// Traffic data entry
+typedef struct TRAFFIC_ENTRY
+{
+ UINT64 BroadcastCount; // Number of broadcast packets
+ UINT64 BroadcastBytes; // Broadcast bytes
+ UINT64 UnicastCount; // Unicast count
+ UINT64 UnicastBytes; // Unicast bytes
+} TRAFFIC_ENTRY;
+
+// Traffic data
+typedef struct TRAFFIC
+{
+ TRAFFIC_ENTRY Send; // Transmitted data
+ TRAFFIC_ENTRY Recv; // Received data
+} TRAFFIC;
+
+// Non-SSL connection source
+typedef struct NON_SSL
+{
+ IP IpAddress; // IP address
+ UINT64 EntryExpires; // Expiration date of entry
+ UINT Count; // Number of connection count
+} NON_SSL;
+
+// Simple log storage
+typedef struct TINY_LOG
+{
+ char FileName[MAX_PATH]; // File name
+ IO *io; // File
+ LOCK *Lock; // Lock
+} TINY_LOG;
+
+// CEDAR structure
+typedef struct CEDAR
+{
+ LOCK *lock; // Lock
+ REF *ref; // Reference counter
+ COUNTER *AcceptingSockets; // Number of sockets in Accept
+ UINT Type; // Type
+ LIST *ListenerList; // Listener list
+ LIST *HubList; // HUB list
+ LIST *ConnectionList; // Negotiating connection list
+ LIST *CaList; // List of CA
+ volatile bool Halt; // Halt flag
+ COUNTER *ConnectionIncrement; // Connection increment counter
+ X *ServerX; // Server certificate
+ K *ServerK; // Private key of the server certificate
+ char *CipherList; // List of encryption algorithms
+ UINT Version; // Version information
+ UINT Build; // Build Number
+ char *ServerStr; // Server string
+ char *MachineName; // Computer name
+ char *HttpUserAgent; // HTTP user agent
+ char *HttpAccept; // HTTP Accept
+ char *HttpAcceptLanguage; // HTTP Accept Language
+ char *HttpAcceptEncoding; // HTTP Accept Encoding
+ TRAFFIC *Traffic; // Traffic information
+ LOCK *TrafficLock; // Traffic information lock
+ LIST *UDPEntryList; // UDP entry list
+ COUNTER *CurrentSessions; // The current number of sessions
+ COUNTER *CurrentTcpConnections; // Number of current TCP connections
+ LIST *NetSvcList; // Network service list
+ char *VerString; // Version string
+ char *BuildInfo; // Build Information
+ struct CLIENT *Client; // Client
+ struct SERVER *Server; // Server
+ UINT64 CreatedTick; // Generation date and time
+ bool CheckExpires; // Check the expiration date
+ LIST *TrafficDiffList; // Traffic difference list
+ struct LOG *DebugLog; // Debug log
+ UCHAR UniqueId[16]; // Unique ID
+ LIST *LocalBridgeList; // Local bridge list
+ bool Bridge; // Bridge version
+ LIST *L3SwList; // Layer-3 switch list
+ COUNTER *AssignedClientLicense; // Number of assigned client licenses
+ COUNTER *AssignedBridgeLicense; // Number of assigned bridge licenses
+ UINT64 LicenseViolationTick; // License violation occurs
+ LIST *NonSslList; // Non-SSL connection list
+ struct WEBUI *WebUI; // Data for WebUI service
+ UINT Beta; // Beta number
+ LOCK *CedarSuperLock; // Cedar super lock!
+ bool DisableIPv6Listener; // Disable IPv6 listener
+ UINT ClientId; // Client ID
+ UINT64 BuiltDate; // Build Date
+ LIST *UdpPortList; // UDP port list in use
+ char CurrentDDnsFqdn[MAX_SIZE]; // FQDN of the current DDNS
+ char OpenVPNPublicPorts[MAX_SIZE]; // OpenVPN public UDP port list
+ LOCK *OpenVPNPublicPortsLock; // Lock of OpenVPN public UDP port list
+} CEDAR;
+
+// Type of CEDAR
+#define CEDAR_CLIENT 0 // Client
+#define CEDAR_STANDALONE_SERVER 1 // Stand-alone server
+#define CEDAR_FARM_CONTROLLER 2 // Server farm controller
+#define CEDAR_FARM_MEMBER 3 // Server farm member
+
+
+////////////////////////////
+// Read the header file
+
+// Type
+#include <Cedar/CedarType.h>
+// Account Manager
+#include <Cedar/Account.h>
+// Listener module
+#include <Cedar/Listener.h>
+// Log storage module
+#include <Cedar/Logging.h>
+// Connection management
+#include <Cedar/Connection.h>
+// Session Management
+#include <Cedar/Session.h>
+// RPC
+#include <Cedar/Remote.h>
+// HUB management
+#include <Cedar/Hub.h>
+// Security Accounts Manager
+#include <Cedar/Sam.h>
+// Radius authentication module
+#include <Cedar/Radius.h>
+// Protocol
+#include <Cedar/Protocol.h>
+// Inter-HUB link
+#include <Cedar/Link.h>
+// User-mode virtual host
+#include <Cedar/Virtual.h>
+// SecureNAT
+#include <Cedar/SecureNAT.h>
+// Digital watermark
+#include <Cedar/WaterMark.h>
+// Secure data
+#include <Cedar/SecureInfo.h>
+// Console service
+#include <Cedar/Console.h>
+// Vpncmd utility
+#include <Cedar/Command.h>
+// RPC over HTTP
+#include <Cedar/Wpc.h>
+// IPsec
+#include <Cedar/IPsec.h>
+#include <Cedar/IPsec_L2TP.h>
+#include <Cedar/IPsec_PPP.h>
+#include <Cedar/IPsec_IPC.h>
+#include <Cedar/IPsec_IkePacket.h>
+#include <Cedar/IPsec_IKE.h>
+#include <Cedar/IPsec_Win7.h>
+#include <Cedar/IPsec_EtherIP.h>
+// SSTP
+#include <Cedar/Interop_SSTP.h>
+// OpenVPN
+#include <Cedar/Interop_OpenVPN.h>
+// UDP Acceleration
+#include <Cedar/UdpAccel.h>
+// DDNS Client
+#include <Cedar/DDNS.h>
+// VPN Azure Client
+#include <Cedar/AzureClient.h>
+// VPN Azure Server
+#include <Cedar/AzureServer.h>
+// Native IP Stack
+#include <Cedar/NativeStack.h>
+
+#ifdef OS_WIN32
+// Neo device driver
+#include <Neo/Neo.h>
+// SeLow User-mode
+#include <Cedar/SeLowUser.h>
+#endif // OS_WIN32
+
+// Neo device driver manipulation library
+#include <Cedar/VLan.h>
+// Bridge
+#include <Cedar/Bridge.h>
+// Layer-3 switch
+#include <Cedar/Layer3.h>
+// Virtual LAN card for test
+#include <Cedar/NullLan.h>
+// Client
+#include <Cedar/Client.h>
+// Server
+#include <Cedar/Server.h>
+// License database
+#include <Cedar/Database.h>
+// EtherLogger
+#include <Cedar/EtherLog.h>
+// Management RPC
+#include <Cedar/Admin.h>
+// User-mode Router
+#include <Cedar/Nat.h>
+
+// Web UI
+#include <Cedar/WebUI.h>
+
+// VPN Gate Plugin DLL
+#include <VGate/VGateCommon.h>
+
+// VPN Gate Main Implementation
+#include <Cedar/VG.h>
+
+
+#ifdef OS_WIN32
+
+// Win32 user interface
+#include <Cedar/WinUi.h>
+// Win32 Client Connection Manager
+#include <Cedar/CM.h>
+// Win32 Server Manager
+#include <Cedar/SM.h>
+// Win32 User-mode Router Manager
+#include <Cedar/NM.h>
+// Win32 EtherLogger Manager
+#include <Cedar/EM.h>
+// Win32 Network Utility
+#include <Cedar/UT.h>
+// Win32 Setup Wizard
+#include <Cedar/SW.h>
+// Win32 COM calling module
+#include <Cedar/Win32Com.h>
+
+#endif
+
+
+
+
+////////////////////////////
+// Function prototype
+
+TRAFFIC *NewTraffic();
+void FreeTraffic(TRAFFIC *t);
+CEDAR *NewCedar(X *server_x, K *server_k);
+void CedarForceLink();
+void SetCedarVpnBridge(CEDAR *c);
+void SetCedarCert(CEDAR *c, X *server_x, K *server_k);
+void ReleaseCedar(CEDAR *c);
+void CleanupCedar(CEDAR *c);
+void StopCedar(CEDAR *c);
+void AddListener(CEDAR *c, LISTENER *r);
+void StopAllListener(CEDAR *c);
+void AddTraffic(TRAFFIC *dst, TRAFFIC *diff);
+void AddHub(CEDAR *c, HUB *h);
+void DelHub(CEDAR *c, HUB *h);
+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();
+void FreeCedar();
+void AddCa(CEDAR *cedar, X *x);
+bool DeleteCa(CEDAR *cedar, UINT ptr);
+bool CheckSignatureByCa(CEDAR *cedar, X *x);
+bool CheckSignatureByCaLinkMode(SESSION *s, X *x);
+X *FindCaSignedX(LIST *o, X *x);
+void InitNetSvcList(CEDAR *cedar);
+void FreeNetSvcList(CEDAR *cedar);
+int CompareNetSvc(void *p1, void *p2);
+char *GetSvcName(CEDAR *cedar, bool udp, UINT port);
+void InitHiddenPassword(char *str, UINT size);
+bool IsHiddenPasswordChanged(char *str);
+UINT64 GetTrafficPacketSize(TRAFFIC *t);
+UINT64 GetTrafficPacketNum(TRAFFIC *t);
+void EnableDebugLog(CEDAR *c);
+void StartCedarLog();
+void StopCedarLog();
+void CedarLog(char *str);
+int CompareNoSslList(void *p1, void *p2);
+void InitNoSslList(CEDAR *c);
+void FreeNoSslList(CEDAR *c);
+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();
+void GetWinVer(RPC_WINVER *v);
+bool IsSupportedWinVer(RPC_WINVER *v);
+bool IsLaterBuild(CEDAR *c, UINT64 t);
+SOCK *GetInProcListeningSock(CEDAR *c);
+SOCK *GetReverseListeningSock(CEDAR *c);
+void GetCedarVersion(char *tmp, UINT size);
+UINT64 GetCurrentBuildDate();
+
+
+
+#endif // CEDAR_H
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Cedar.vcproj b/src/Cedar/Cedar.vcproj
new file mode 100644
index 00000000..c84d7379
--- /dev/null
+++ b/src/Cedar/Cedar.vcproj
@@ -0,0 +1,1529 @@
+<?xml version="1.0" encoding="shift_jis"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="Cedar"
+ ProjectGUID="{2928D768-DEC3-40D3-8E51-26E364497C9B}"
+ RootNamespace="Cedar"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)tmp\lib\$(PlatformName)_$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)_$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ WholeProgramOptimization="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(SolutionDir)Mayaqua\win32_inc;.;$(SolutionDir);WinPcap"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;_USE_32BIT_TIME_T"
+ MinimalRebuild="true"
+ ExceptionHandling="0"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ StructMemberAlignment="4"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="CedarPch.h"
+ WarningLevel="3"
+ DebugInformationFormat="4"
+ CompileAs="1"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalLibraryDirectories="$(SolutionDir)BuildFiles\Library\$(PlatformName)_$(ConfigurationName)"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ OutputDirectory="$(SolutionDir)tmp\lib\$(PlatformName)_$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)_$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ WholeProgramOptimization="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="$(SolutionDir)Mayaqua\win32_inc;.;$(SolutionDir);WinPcap"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;CPU_64"
+ MinimalRebuild="true"
+ ExceptionHandling="0"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ StructMemberAlignment="4"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="CedarPch.h"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalLibraryDirectories="$(SolutionDir)BuildFiles\Library\$(PlatformName)_$(ConfigurationName)"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)tmp\lib\$(PlatformName)_$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)_$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ WholeProgramOptimization="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ InlineFunctionExpansion="0"
+ EnableIntrinsicFunctions="false"
+ FavorSizeOrSpeed="0"
+ AdditionalIncludeDirectories="$(SolutionDir)Mayaqua\win32_inc;.;$(SolutionDir);WinPcap"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;_USE_32BIT_TIME_T;VPN_SPEED"
+ StringPooling="false"
+ ExceptionHandling="0"
+ RuntimeLibrary="0"
+ StructMemberAlignment="4"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="false"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="CedarPch.h"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalLibraryDirectories="$(SolutionDir)BuildFiles\Library\$(PlatformName)_$(ConfigurationName)"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ OutputDirectory="$(SolutionDir)tmp\lib\$(PlatformName)_$(ConfigurationName)"
+ IntermediateDirectory="$(PlatformName)_$(ConfigurationName)"
+ ConfigurationType="4"
+ CharacterSet="2"
+ WholeProgramOptimization="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="3"
+ InlineFunctionExpansion="0"
+ EnableIntrinsicFunctions="false"
+ FavorSizeOrSpeed="0"
+ AdditionalIncludeDirectories="$(SolutionDir)Mayaqua\win32_inc;.;$(SolutionDir);WinPcap"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;VPN_SPEED;CPU_64"
+ StringPooling="false"
+ ExceptionHandling="0"
+ RuntimeLibrary="0"
+ StructMemberAlignment="4"
+ BufferSecurityCheck="false"
+ EnableFunctionLevelLinking="false"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderThrough="CedarPch.h"
+ WarningLevel="3"
+ DebugInformationFormat="3"
+ CompileAs="1"
+ DisableSpecificWarnings="4996"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalLibraryDirectories="$(SolutionDir)BuildFiles\Library\$(PlatformName)_$(ConfigurationName)"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\Account.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Admin.c"
+ >
+ </File>
+ <File
+ RelativePath=".\AzureClient.c"
+ >
+ </File>
+ <File
+ RelativePath=".\AzureServer.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Bridge.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\BridgeUnix.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\BridgeWin32.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\Cedar.c"
+ >
+ </File>
+ <File
+ RelativePath=".\CedarPch.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\Client.c"
+ >
+ </File>
+ <File
+ RelativePath=".\CM.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\Command.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Connection.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Console.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Database.c"
+ >
+ </File>
+ <File
+ RelativePath=".\DDNS.c"
+ >
+ </File>
+ <File
+ RelativePath=".\EM.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\EtherLog.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Hub.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Interop_OpenVPN.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Interop_SSTP.c"
+ >
+ </File>
+ <File
+ RelativePath=".\IPsec.c"
+ >
+ </File>
+ <File
+ RelativePath=".\IPsec_EtherIP.c"
+ >
+ </File>
+ <File
+ RelativePath=".\IPsec_IKE.c"
+ >
+ </File>
+ <File
+ RelativePath=".\IPsec_IkePacket.c"
+ >
+ </File>
+ <File
+ RelativePath=".\IPsec_IPC.c"
+ >
+ </File>
+ <File
+ RelativePath=".\IPsec_L2TP.c"
+ >
+ </File>
+ <File
+ RelativePath=".\IPsec_PPP.c"
+ >
+ </File>
+ <File
+ RelativePath=".\IPsec_Win7.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\Layer3.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Link.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Listener.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Logging.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Nat.c"
+ >
+ </File>
+ <File
+ RelativePath=".\NativeStack.c"
+ >
+ </File>
+ <File
+ RelativePath=".\NM.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\NullLan.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Protocol.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Radius.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Remote.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Sam.c"
+ >
+ </File>
+ <File
+ RelativePath=".\SecureInfo.c"
+ >
+ </File>
+ <File
+ RelativePath=".\SecureNAT.c"
+ >
+ </File>
+ <File
+ RelativePath=".\SeLowUser.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\Server.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Session.c"
+ >
+ </File>
+ <File
+ RelativePath=".\SM.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\SW.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\UdpAccel.c"
+ >
+ </File>
+ <File
+ RelativePath=".\UT.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\VG.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Virtual.c"
+ >
+ </File>
+ <File
+ RelativePath=".\VLan.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\VLanUnix.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\VLanWin32.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\WaterMark.c"
+ >
+ </File>
+ <File
+ RelativePath=".\WebUI.c"
+ >
+ </File>
+ <File
+ RelativePath=".\Win32Com.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ ExceptionHandling="2"
+ UsePrecompiledHeader="0"
+ CompileAs="2"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ ExceptionHandling="2"
+ UsePrecompiledHeader="0"
+ CompileAs="2"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ ExceptionHandling="2"
+ UsePrecompiledHeader="0"
+ CompileAs="2"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ ExceptionHandling="2"
+ UsePrecompiledHeader="0"
+ CompileAs="2"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\WinJumpList.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ CompileAs="2"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ CompileAs="2"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ CompileAs="2"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ CompileAs="2"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\WinUi.c"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|x64"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\Wpc.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\Account.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Admin.h"
+ >
+ </File>
+ <File
+ RelativePath=".\AzureClient.h"
+ >
+ </File>
+ <File
+ RelativePath=".\AzureServer.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Bridge.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BridgeUnix.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BridgeWin32.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Cedar.h"
+ >
+ </File>
+ <File
+ RelativePath=".\CedarPch.h"
+ >
+ </File>
+ <File
+ RelativePath=".\CedarType.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Client.h"
+ >
+ </File>
+ <File
+ RelativePath=".\CM.h"
+ >
+ </File>
+ <File
+ RelativePath=".\CMInner.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Command.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Connection.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Console.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Database.h"
+ >
+ </File>
+ <File
+ RelativePath=".\DDNS.h"
+ >
+ </File>
+ <File
+ RelativePath=".\EM.h"
+ >
+ </File>
+ <File
+ RelativePath=".\EMInner.h"
+ >
+ </File>
+ <File
+ RelativePath=".\EtherLog.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Hub.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Interop_OpenVPN.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Interop_SSTP.h"
+ >
+ </File>
+ <File
+ RelativePath=".\IPsec.h"
+ >
+ </File>
+ <File
+ RelativePath=".\IPsec_EtherIP.h"
+ >
+ </File>
+ <File
+ RelativePath=".\IPsec_IKE.h"
+ >
+ </File>
+ <File
+ RelativePath=".\IPsec_IkePacket.h"
+ >
+ </File>
+ <File
+ RelativePath=".\IPsec_IPC.h"
+ >
+ </File>
+ <File
+ RelativePath=".\IPsec_L2TP.h"
+ >
+ </File>
+ <File
+ RelativePath=".\IPsec_PPP.h"
+ >
+ </File>
+ <File
+ RelativePath=".\IPsec_Win7.h"
+ >
+ </File>
+ <File
+ RelativePath=".\IPsec_Win7Inner.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Layer3.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Link.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Listener.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Logging.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Nat.h"
+ >
+ </File>
+ <File
+ RelativePath=".\NativeStack.h"
+ >
+ </File>
+ <File
+ RelativePath=".\NM.h"
+ >
+ </File>
+ <File
+ RelativePath=".\NMInner.h"
+ >
+ </File>
+ <File
+ RelativePath=".\NullLan.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Protocol.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Radius.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Remote.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Sam.h"
+ >
+ </File>
+ <File
+ RelativePath=".\SecureInfo.h"
+ >
+ </File>
+ <File
+ RelativePath=".\SecureNAT.h"
+ >
+ </File>
+ <File
+ RelativePath=".\SeLowUser.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Server.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Session.h"
+ >
+ </File>
+ <File
+ RelativePath=".\SM.h"
+ >
+ </File>
+ <File
+ RelativePath=".\SMInner.h"
+ >
+ </File>
+ <File
+ RelativePath=".\SW.h"
+ >
+ </File>
+ <File
+ RelativePath=".\SWInner.h"
+ >
+ </File>
+ <File
+ RelativePath=".\UdpAccel.h"
+ >
+ </File>
+ <File
+ RelativePath=".\UT.h"
+ >
+ </File>
+ <File
+ RelativePath=".\VG.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Virtual.h"
+ >
+ </File>
+ <File
+ RelativePath=".\VLan.h"
+ >
+ </File>
+ <File
+ RelativePath=".\VLanUnix.h"
+ >
+ </File>
+ <File
+ RelativePath=".\VLanWin32.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WaterMark.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WebUI.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Win32Com.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinUi.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Wpc.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ <Filter
+ Name="winpcap"
+ >
+ <File
+ RelativePath=".\WinPcap\bittypes.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\bucket_lookup.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\count_packets.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\Devioctl.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\Gnuc.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\ip6_misc.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\memory_t.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\normal_lookup.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\Ntddndis.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\Ntddpack.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\Packet32.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\pcap-bpf.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\pcap-int.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\pcap-stdinc.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\pcap.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\pthread.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\remote-ext.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\sched.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\semaphore.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\tcp_session.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\time_calls.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\tme.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinPcap\Win32-Extensions.h"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/Cedar/CedarPch.c b/src/Cedar/CedarPch.c
new file mode 100644
index 00000000..af2b83c7
--- /dev/null
+++ b/src/Cedar/CedarPch.c
@@ -0,0 +1,89 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// CedarPch.c
+// Cedar Pre-compile Header Generating Code
+
+#include "CedarPch.h"
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/CedarPch.h b/src/Cedar/CedarPch.h
new file mode 100644
index 00000000..c71673b3
--- /dev/null
+++ b/src/Cedar/CedarPch.h
@@ -0,0 +1,100 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// CedarPch.h
+// Header file for grecompile header generation for Cedar
+
+#include <GlobalConst.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/CedarType.h b/src/Cedar/CedarType.h
new file mode 100644
index 00000000..0937db60
--- /dev/null
+++ b/src/Cedar/CedarType.h
@@ -0,0 +1,720 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// CedarType.h
+// List of types that Cedar using
+
+#ifndef CEDARTYPE_H
+#define CEDARTYPE_H
+
+
+// ==============================================================
+// Remote Procedure Call
+// ==============================================================
+
+typedef struct RPC RPC;
+
+
+// ==============================================================
+// Account
+// ==============================================================
+
+typedef struct POLICY_ITEM POLICY_ITEM;
+typedef struct POLICY POLICY;
+typedef struct USERGROUP USERGROUP;
+typedef struct USER USER;
+typedef struct AUTHPASSWORD AUTHPASSWORD;
+typedef struct AUTHUSERCERT AUTHUSERCERT;
+typedef struct AUTHROOTCERT AUTHROOTCERT;
+typedef struct AUTHRADIUS AUTHRADIUS;
+typedef struct AUTHNT AUTHNT;
+
+
+// ==============================================================
+// Listener
+// ==============================================================
+
+typedef struct DOS DOS;
+typedef struct LISTENER LISTENER;
+typedef struct TCP_ACCEPTED_PARAM TCP_ACCEPTED_PARAM;
+typedef struct UDP_ENTRY UDP_ENTRY;
+typedef struct DYNAMIC_LISTENER DYNAMIC_LISTENER;
+
+
+// ==============================================================
+// Logging
+// ==============================================================
+
+typedef struct PACKET_LOG PACKET_LOG;
+typedef struct HUB_LOG HUB_LOG;
+typedef struct RECORD RECORD;
+typedef struct LOG LOG;
+typedef struct ERASER ERASER;
+typedef struct SLOG SLOG;
+
+
+// ==============================================================
+// Connection
+// ==============================================================
+
+typedef struct KEEP KEEP;
+typedef struct SECURE_SIGN SECURE_SIGN;
+typedef struct RC4_KEY_PAIR RC4_KEY_PAIR;
+typedef struct CLIENT_OPTION CLIENT_OPTION;
+typedef struct CLIENT_AUTH CLIENT_AUTH;
+typedef struct TCPSOCK TCPSOCK;
+typedef struct TCP TCP;
+typedef struct UDP UDP;
+typedef struct BLOCK BLOCK;
+typedef struct CONNECTION CONNECTION;
+
+
+// ==============================================================
+// Session
+// ==============================================================
+
+typedef struct NODE_INFO NODE_INFO;
+typedef struct PACKET_ADAPTER PACKET_ADAPTER;
+typedef struct SESSION SESSION;
+typedef struct UI_PASSWORD_DLG UI_PASSWORD_DLG;
+typedef struct UI_MSG_DLG UI_MSG_DLG;
+typedef struct UI_NICINFO UI_NICINFO;
+typedef struct UI_CONNECTERROR_DLG UI_CONNECTERROR_DLG;
+typedef struct UI_CHECKCERT UI_CHECKCERT;
+
+
+// ==============================================================
+// Hub
+// ==============================================================
+
+typedef struct SE_LINK SE_LINK;
+typedef struct TEST_HISTORY TEST_HISTORY;
+typedef struct SE_TEST SE_TEST;
+typedef struct HUBDB HUBDB;
+typedef struct TRAFFIC_LIMITER TRAFFIC_LIMITER;
+typedef struct STORM STORM;
+typedef struct HUB_PA HUB_PA;
+typedef struct HUB_OPTION HUB_OPTION;
+typedef struct MAC_TABLE_ENTRY MAC_TABLE_ENTRY;
+typedef struct IP_TABLE_ENTRY IP_TABLE_ENTRY;
+typedef struct LOOP_LIST LOOP_LIST;
+typedef struct ACCESS ACCESS;
+typedef struct TICKET TICKET;
+typedef struct TRAFFIC_DIFF TRAFFIC_DIFF;
+typedef struct HUB HUB;
+typedef struct ADMIN_OPTION ADMIN_OPTION;
+typedef struct CRL CRL;
+typedef struct AC AC;
+typedef struct USERLIST USERLIST;
+
+
+// ==============================================================
+// Protocol
+// ==============================================================
+
+typedef struct CHECK_CERT_THREAD_PROC CHECK_CERT_THREAD_PROC;
+typedef struct SECURE_SIGN_THREAD_PROC SECURE_SIGN_THREAD_PROC;
+typedef struct RAND_CACHE RAND_CACHE;
+typedef struct BLACK BLACK;
+typedef struct SEND_SIGNATURE_PARAM SEND_SIGNATURE_PARAM;
+typedef struct UPDATE_CLIENT UPDATE_CLIENT;
+typedef struct UPDATE_CLIENT_SETTING UPDATE_CLIENT_SETTING;
+
+
+// ==============================================================
+// Link
+// ==============================================================
+
+typedef struct LINK LINK;
+
+
+// ==============================================================
+// Virtual
+// ==============================================================
+
+typedef struct ARP_ENTRY ARP_ENTRY;
+typedef struct ARP_WAIT ARP_WAIT;
+typedef struct IP_WAIT IP_WAIT;
+typedef struct IP_PART IP_PART;
+typedef struct IP_COMBINE IP_COMBINE;
+typedef struct NAT_ENTRY NAT_ENTRY;
+typedef struct TCP_OPTION TCP_OPTION;
+typedef struct VH VH;
+typedef struct VH_OPTION VH_OPTION;
+typedef struct DHCP_LEASE DHCP_LEASE;
+typedef struct NATIVE_NAT NATIVE_NAT;
+typedef struct NATIVE_NAT_ENTRY NATIVE_NAT_ENTRY;
+typedef struct DNS_PARSED_PACKET DNS_PARSED_PACKET;
+
+
+// ==============================================================
+// WPC
+// ==============================================================
+
+typedef struct INTERNET_SETTING INTERNET_SETTING;
+typedef struct URL_DATA URL_DATA;
+typedef struct WPC_ENTRY WPC_ENTRY;
+typedef struct WPC_PACKET WPC_PACKET;
+typedef struct WPC_CONNECT WPC_CONNECT;
+
+// ==============================================================
+// VLAN
+// ==============================================================
+
+typedef struct ROUTE_TRACKING ROUTE_TRACKING;
+typedef struct VLAN VLAN;
+typedef struct INSTANCE_LIST INSTANCE_LIST;
+typedef struct VLAN_PARAM VLAN_PARAM;
+
+#ifdef OS_UNIX
+typedef struct UNIX_VLAN_LIST UNIX_VLAN_LIST;
+#endif // OS_UNIX
+
+// ==============================================================
+// Null LAN
+// ==============================================================
+
+typedef struct NULL_LAN NULL_LAN;
+
+
+// ==============================================================
+// Bridge
+// ==============================================================
+
+typedef struct ETH ETH;
+typedef struct BRIDGE BRIDGE;
+typedef struct LOCALBRIDGE LOCALBRIDGE;
+
+
+// ==============================================================
+// Layer-3 Switch
+// ==============================================================
+
+typedef struct L3IF L3IF;
+typedef struct L3SW L3SW;
+typedef struct L3TABLE L3TABLE;
+typedef struct L3ARPENTRY L3ARPENTRY;
+typedef struct L3ARPWAIT L3ARPWAIT;
+typedef struct L3PACKET L3PACKET;
+
+
+// ==============================================================
+// Client
+// ==============================================================
+
+typedef struct ACCOUNT ACCOUNT;
+typedef struct CLIENT_CONFIG CLIENT_CONFIG;
+typedef struct RPC_CLIENT_VERSION RPC_CLIENT_VERSION;
+typedef struct RPC_CLIENT_PASSWORD RPC_CLIENT_PASSWORD;
+typedef struct RPC_CLIENT_PASSWORD_SETTING RPC_CLIENT_PASSWORD_SETTING;
+typedef struct RPC_CLIENT_ENUM_CA_ITEM RPC_CLIENT_ENUM_CA_ITEM;
+typedef struct RPC_CLIENT_ENUM_CA RPC_CLIENT_ENUM_CA;
+typedef struct RPC_CERT RPC_CERT;
+typedef struct RPC_CLIENT_DELETE_CA RPC_CLIENT_DELETE_CA;
+typedef struct RPC_GET_CA RPC_GET_CA;
+typedef struct RPC_GET_ISSUER RPC_GET_ISSUER;
+typedef struct RPC_CLIENT_ENUM_SECURE_ITEM RPC_CLIENT_ENUM_SECURE_ITEM;
+typedef struct RPC_CLIENT_ENUM_SECURE RPC_CLIENT_ENUM_SECURE;
+typedef struct RPC_USE_SECURE RPC_USE_SECURE;
+typedef struct RPC_ENUM_OBJECT_IN_SECURE RPC_ENUM_OBJECT_IN_SECURE;
+typedef struct RPC_CLIENT_CREATE_VLAN RPC_CLIENT_CREATE_VLAN;
+typedef struct RPC_CLIENT_GET_VLAN RPC_CLIENT_GET_VLAN;
+typedef struct RPC_CLIENT_SET_VLAN RPC_CLIENT_SET_VLAN;
+typedef struct RPC_CLIENT_ENUM_VLAN_ITEM RPC_CLIENT_ENUM_VLAN_ITEM;
+typedef struct RPC_CLIENT_ENUM_VLAN RPC_CLIENT_ENUM_VLAN;
+typedef struct RPC_CLIENT_CREATE_ACCOUNT RPC_CLIENT_CREATE_ACCOUNT;
+typedef struct RPC_CLIENT_ENUM_ACCOUNT_ITEM RPC_CLIENT_ENUM_ACCOUNT_ITEM;
+typedef struct RPC_CLIENT_ENUM_ACCOUNT RPC_CLIENT_ENUM_ACCOUNT;
+typedef struct RPC_CLIENT_DELETE_ACCOUNT RPC_CLIENT_DELETE_ACCOUNT;
+typedef struct RPC_RENAME_ACCOUNT RPC_RENAME_ACCOUNT;
+typedef struct RPC_CLIENT_GET_ACCOUNT RPC_CLIENT_GET_ACCOUNT;
+typedef struct RPC_CLIENT_CONNECT RPC_CLIENT_CONNECT;
+typedef struct RPC_CLIENT_GET_CONNECTION_STATUS RPC_CLIENT_GET_CONNECTION_STATUS;
+typedef struct CLIENT_RPC_CONNECTION CLIENT_RPC_CONNECTION;
+typedef struct CLIENT CLIENT;
+typedef struct RPC_CLIENT_NOTIFY RPC_CLIENT_NOTIFY;
+typedef struct REMOTE_CLIENT REMOTE_CLIENT;
+typedef struct NOTIFY_CLIENT NOTIFY_CLIENT;
+typedef struct UNIX_VLAN UNIX_VLAN;
+typedef struct CM_SETTING CM_SETTING;
+
+
+// ==============================================================
+// Server
+// ==============================================================
+
+typedef struct HUB_LIST HUB_LIST;
+typedef struct FARM_TASK FARM_TASK;
+typedef struct FARM_MEMBER FARM_MEMBER;
+typedef struct FARM_CONTROLLER FARM_CONTROLLER;
+typedef struct SERVER_LISTENER SERVER_LISTENER;
+typedef struct SERVER SERVER;
+typedef struct RPC_ENUM_SESSION RPC_ENUM_SESSION;
+typedef struct RPC_SESSION_STATUS RPC_SESSION_STATUS;
+typedef struct CAPS CAPS;
+typedef struct CAPSLIST CAPSLIST;
+typedef struct LOG_FILE LOG_FILE;
+typedef struct SYSLOG_SETTING SYSLOG_SETTING;
+typedef struct HUB_SNAPSHOT HUB_SNAPSHOT;
+typedef struct SERVER_SNAPSHOT SERVER_SNAPSHOT;
+typedef struct SERVER_HUB_CREATE_HISTORY SERVER_HUB_CREATE_HISTORY;
+typedef struct OPENVPN_SSTP_CONFIG OPENVPN_SSTP_CONFIG;
+
+// ==============================================================
+// Server Admin Tool
+// ==============================================================
+
+typedef struct ADMIN ADMIN;
+typedef struct RPC_TEST RPC_TEST;
+typedef struct RPC_SERVER_INFO RPC_SERVER_INFO;
+typedef struct RPC_SERVER_STATUS RPC_SERVER_STATUS;
+typedef struct RPC_LISTENER RPC_LISTENER;
+typedef struct RPC_LISTENER_LIST RPC_LISTENER_LIST;
+typedef struct RPC_STR RPC_STR;
+typedef struct RPC_SET_PASSWORD RPC_SET_PASSWORD;
+typedef struct RPC_FARM RPC_FARM;
+typedef struct RPC_FARM_HUB RPC_FARM_HUB;
+typedef struct RPC_FARM_INFO RPC_FARM_INFO;
+typedef struct RPC_ENUM_FARM_ITEM RPC_ENUM_FARM_ITEM;
+typedef struct RPC_ENUM_FARM RPC_ENUM_FARM;
+typedef struct RPC_FARM_CONNECTION_STATUS RPC_FARM_CONNECTION_STATUS;
+typedef struct RPC_KEY_PAIR RPC_KEY_PAIR;
+typedef struct RPC_HUB_OPTION RPC_HUB_OPTION;
+typedef struct RPC_RADIUS RPC_RADIUS;
+typedef struct RPC_HUB RPC_HUB;
+typedef struct RPC_CREATE_HUB RPC_CREATE_HUB;
+typedef struct RPC_ENUM_HUB_ITEM RPC_ENUM_HUB_ITEM;
+typedef struct RPC_ENUM_HUB RPC_ENUM_HUB;
+typedef struct RPC_DELETE_HUB RPC_DELETE_HUB;
+typedef struct RPC_ENUM_CONNECTION_ITEM RPC_ENUM_CONNECTION_ITEM;
+typedef struct RPC_ENUM_CONNECTION RPC_ENUM_CONNECTION;
+typedef struct RPC_DISCONNECT_CONNECTION RPC_DISCONNECT_CONNECTION;
+typedef struct RPC_CONNECTION_INFO RPC_CONNECTION_INFO;
+typedef struct RPC_SET_HUB_ONLINE RPC_SET_HUB_ONLINE;
+typedef struct RPC_HUB_STATUS RPC_HUB_STATUS;
+typedef struct RPC_HUB_LOG RPC_HUB_LOG;
+typedef struct RPC_HUB_ADD_CA RPC_HUB_ADD_CA;
+typedef struct RPC_HUB_ENUM_CA_ITEM RPC_HUB_ENUM_CA_ITEM;
+typedef struct RPC_HUB_ENUM_CA RPC_HUB_ENUM_CA;
+typedef struct RPC_HUB_GET_CA RPC_HUB_GET_CA;
+typedef struct RPC_HUB_DELETE_CA RPC_HUB_DELETE_CA;
+typedef struct RPC_CREATE_LINK RPC_CREATE_LINK;
+typedef struct RPC_ENUM_LINK_ITEM RPC_ENUM_LINK_ITEM;
+typedef struct RPC_ENUM_LINK RPC_ENUM_LINK;
+typedef struct RPC_LINK_STATUS RPC_LINK_STATUS;
+typedef struct RPC_LINK RPC_LINK;
+typedef struct RPC_ENUM_ACCESS_LIST RPC_ENUM_ACCESS_LIST;
+typedef struct RPC_ADD_ACCESS RPC_ADD_ACCESS;
+typedef struct RPC_DELETE_ACCESS RPC_DELETE_ACCESS;
+typedef struct RPC_SET_USER RPC_SET_USER;
+typedef struct RPC_ENUM_USER_ITEM RPC_ENUM_USER_ITEM;
+typedef struct RPC_ENUM_USER RPC_ENUM_USER;
+typedef struct RPC_SET_GROUP RPC_SET_GROUP;
+typedef struct RPC_ENUM_GROUP_ITEM RPC_ENUM_GROUP_ITEM;
+typedef struct RPC_ENUM_GROUP RPC_ENUM_GROUP;
+typedef struct RPC_DELETE_USER RPC_DELETE_USER;
+typedef struct RPC_ENUM_SESSION_ITEM RPC_ENUM_SESSION_ITEM;
+typedef struct RPC_DELETE_SESSION RPC_DELETE_SESSION;
+typedef struct RPC_ENUM_MAC_TABLE_ITEM RPC_ENUM_MAC_TABLE_ITEM;
+typedef struct RPC_ENUM_MAC_TABLE RPC_ENUM_MAC_TABLE;
+typedef struct RPC_ENUM_IP_TABLE_ITEM RPC_ENUM_IP_TABLE_ITEM;
+typedef struct RPC_ENUM_IP_TABLE RPC_ENUM_IP_TABLE;
+typedef struct RPC_DELETE_TABLE RPC_DELETE_TABLE;
+typedef struct RPC_KEEP RPC_KEEP;
+typedef struct RPC_ENUM_ETH_ITEM RPC_ENUM_ETH_ITEM;
+typedef struct RPC_ENUM_ETH RPC_ENUM_ETH;
+typedef struct RPC_LOCALBRIDGE RPC_LOCALBRIDGE;
+typedef struct RPC_ENUM_LOCALBRIDGE RPC_ENUM_LOCALBRIDGE;
+typedef struct RPC_BRIDGE_SUPPORT RPC_BRIDGE_SUPPORT;
+typedef struct RPC_CONFIG RPC_CONFIG;
+typedef struct RPC_ADMIN_OPTION RPC_ADMIN_OPTION;
+typedef struct RPC_L3SW RPC_L3SW;
+typedef struct RPC_L3IF RPC_L3IF;
+typedef struct RPC_L3TABLE RPC_L3TABLE;
+typedef struct RPC_ENUM_L3SW_ITEM RPC_ENUM_L3SW_ITEM;
+typedef struct RPC_ENUM_L3SW RPC_ENUM_L3SW;
+typedef struct RPC_ENUM_L3IF RPC_ENUM_L3IF;
+typedef struct RPC_ENUM_L3TABLE RPC_ENUM_L3TABLE;
+typedef struct RPC_CRL RPC_CRL;
+typedef struct RPC_ENUM_CRL_ITEM RPC_ENUM_CRL_ITEM;
+typedef struct RPC_ENUM_CRL RPC_ENUM_CRL;
+typedef struct RPC_INT RPC_INT;
+typedef struct RPC_AC_LIST RPC_AC_LIST;
+typedef struct RPC_ENUM_LOG_FILE_ITEM RPC_ENUM_LOG_FILE_ITEM;
+typedef struct RPC_ENUM_LOG_FILE RPC_ENUM_LOG_FILE;
+typedef struct RPC_READ_LOG_FILE RPC_READ_LOG_FILE;
+typedef struct DOWNLOAD_PROGRESS DOWNLOAD_PROGRESS;
+typedef struct RPC_RENAME_LINK RPC_RENAME_LINK;
+typedef struct RPC_ENUM_LICENSE_KEY RPC_ENUM_LICENSE_KEY;
+typedef struct RPC_ENUM_LICENSE_KEY_ITEM RPC_ENUM_LICENSE_KEY_ITEM;
+typedef struct RPC_LICENSE_STATUS RPC_LICENSE_STATUS;
+typedef struct RPC_ENUM_ETH_VLAN_ITEM RPC_ENUM_ETH_VLAN_ITEM;
+typedef struct RPC_ENUM_ETH_VLAN RPC_ENUM_ETH_VLAN;
+typedef struct RPC_MSG RPC_MSG;
+typedef struct RPC_WINVER RPC_WINVER;
+typedef struct RPC_ENUM_ETHERIP_ID RPC_ENUM_ETHERIP_ID;
+typedef struct RPC_SPECIAL_LISTENER RPC_SPECIAL_LISTENER;
+typedef struct RPC_AZURE_STATUS RPC_AZURE_STATUS;
+
+
+// ==============================================================
+// NAT
+// ==============================================================
+
+typedef struct NAT NAT;
+typedef struct NAT_ADMIN NAT_ADMIN;
+typedef struct RPC_DUMMY RPC_DUMMY;
+typedef struct RPC_NAT_STATUS RPC_NAT_STATUS;
+typedef struct RPC_NAT_INFO RPC_NAT_INFO;
+typedef struct RPC_ENUM_NAT_ITEM RPC_ENUM_NAT_ITEM;
+typedef struct RPC_ENUM_NAT RPC_ENUM_NAT;
+typedef struct RPC_ENUM_DHCP_ITEM RPC_ENUM_DHCP_ITEM;
+typedef struct RPC_ENUM_DHCP RPC_ENUM_DHCP;
+
+
+// ==============================================================
+// SecureNAT
+// ==============================================================
+
+typedef struct SNAT SNAT;
+
+
+// ==============================================================
+// WinUI
+// ==============================================================
+
+typedef struct LED LED;
+typedef struct WIZARD WIZARD;
+typedef struct WIZARD_PAGE WIZARD_PAGE;
+typedef struct WINUI_UPDATE WINUI_UPDATE;
+typedef struct WINUI_UPDATE_DLG_PARAM WINUI_UPDATE_DLG_PARAM;
+
+
+
+// ==============================================================
+// Console
+// ==============================================================
+
+typedef struct PARAM PARAM;
+typedef struct PARAM_VALUE PARAM_VALUE;
+typedef struct CONSOLE CONSOLE;
+typedef struct LOCAL_CONSOLE_PARAM LOCAL_CONSOLE_PARAM;
+typedef struct CMD CMD;
+typedef struct CMD_EVAL_MIN_MAX CMD_EVAL_MIN_MAX;
+
+
+// ==============================================================
+// Command
+// ==============================================================
+
+typedef struct PS PS;
+typedef struct PC PC;
+typedef struct CT CT;
+typedef struct CTC CTC;
+typedef struct CTR CTR;
+typedef struct TTC TTC;
+typedef struct TTS TTS;
+typedef struct TT_RESULT TT_RESULT;
+typedef struct TTS_SOCK TTS_SOCK;
+typedef struct TTC_SOCK TTC_SOCK;
+typedef struct PT PT;
+
+// ==============================================================
+// EtherLogger
+// ==============================================================
+
+typedef struct EL EL;
+typedef struct EL_DEVICE EL_DEVICE;
+typedef struct EL_LICENSE_STATUS EL_LICENSE_STATUS;
+typedef struct RPC_ADD_DEVICE RPC_ADD_DEVICE;
+typedef struct RPC_DELETE_DEVICE RPC_DELETE_DEVICE;
+typedef struct RPC_ENUM_DEVICE_ITEM RPC_ENUM_DEVICE_ITEM;
+typedef struct RPC_ENUM_DEVICE RPC_ENUM_DEVICE;
+typedef struct RPC_EL_LICENSE_STATUS RPC_EL_LICENSE_STATUS;
+
+
+// ==============================================================
+// Database
+// ==============================================================
+
+typedef struct LICENSE_PRODUCT LICENSE_PRODUCT;
+typedef struct LICENSE_SYSTEM LICENSE_SYSTEM;
+typedef struct LICENSE_DATA LICENSE_DATA;
+typedef struct LICENSE LICENSE;
+typedef struct LICENSE_STATUS LICENSE_STATUS;
+typedef struct SECURE_PACK_FOLDER SECURE_PACK_FOLDER;
+typedef struct WIDE_MACHINE_ID WIDE_MACHINE_ID;
+typedef struct TRIAL_INFO TRIAL_INFO;
+
+
+// ==============================================================
+// IPsec
+// ==============================================================
+
+typedef struct IPSEC_SERVER IPSEC_SERVER;
+typedef struct IPSEC_SERVICES IPSEC_SERVICES;
+typedef struct ETHERIP_ID ETHERIP_ID;
+
+
+// ==============================================================
+// L2TP
+// ==============================================================
+
+typedef struct L2TP_SERVER L2TP_SERVER;
+typedef struct L2TP_TUNNEL L2TP_TUNNEL;
+typedef struct L2TP_SESSION L2TP_SESSION;
+typedef struct L2TP_PACKET L2TP_PACKET;
+typedef struct L2TP_AVP L2TP_AVP;
+typedef struct L2TP_QUEUE L2TP_QUEUE;
+
+
+// ==============================================================
+// PPP
+// ==============================================================
+
+typedef struct PPP_SESSION PPP_SESSION;
+typedef struct PPP_OPTION PPP_OPTION;
+typedef struct PPP_LCP PPP_LCP;
+typedef struct PPP_PACKET PPP_PACKET;
+typedef struct PPP_IPOPTION PPP_IPOPTION;
+
+
+// ==============================================================
+// EtherIP
+// ==============================================================
+
+typedef struct ETHERIP_SERVER ETHERIP_SERVER;
+
+
+// ==============================================================
+// IKE
+// ==============================================================
+
+typedef struct IKE_SERVER IKE_SERVER;
+typedef struct IKE_SA IKE_SA;
+typedef struct IKE_SA_TRANSFORM_SETTING IKE_SA_TRANSFORM_SETTING;
+typedef struct IKE_CLIENT IKE_CLIENT;
+typedef struct IPSECSA IPSECSA;
+typedef struct IKE_CAPS IKE_CAPS;
+
+// ==============================================================
+// IPSec Packet
+// ==============================================================
+
+typedef struct IKE_COMMON_HEADER IKE_COMMON_HEADER;
+typedef struct IKE_SA_HEADER IKE_SA_HEADER;
+typedef struct IKE_PROPOSAL_HEADER IKE_PROPOSAL_HEADER;
+typedef struct IKE_TRANSFORM_HEADER IKE_TRANSFORM_HEADER;
+typedef struct IKE_TRANSFORM_VALUE IKE_TRANSFORM_VALUE;
+typedef struct IKE_ID_HEADER IKE_ID_HEADER;
+typedef struct IKE_CERT_HEADER IKE_CERT_HEADER;
+typedef struct IKE_CERT_REQUEST_HEADER IKE_CERT_REQUEST_HEADER;
+typedef struct IKE_NOTICE_HEADER IKE_NOTICE_HEADER;
+typedef struct IKE_DELETE_HEADER IKE_DELETE_HEADER;
+typedef struct IKE_NAT_OA_HEADER IKE_NAT_OA_HEADER;
+typedef struct IPSEC_SA_TRANSFORM_SETTING IPSEC_SA_TRANSFORM_SETTING;
+
+typedef struct IKE_PACKET_SA_PAYLOAD IKE_PACKET_SA_PAYLOAD;
+typedef struct IKE_PACKET_PROPOSAL_PAYLOAD IKE_PACKET_PROPOSAL_PAYLOAD;
+typedef struct IKE_PACKET_TRANSFORM_PAYLOAD IKE_PACKET_TRANSFORM_PAYLOAD;
+typedef struct IKE_PACKET_TRANSFORM_VALUE IKE_PACKET_TRANSFORM_VALUE;
+typedef struct IKE_PACKET_DATA_PAYLOAD IKE_PACKET_DATA_PAYLOAD;
+typedef struct IKE_PACKET_ID_PAYLOAD IKE_PACKET_ID_PAYLOAD;
+typedef struct IKE_PACKET_CERT_PAYLOAD IKE_PACKET_CERT_PAYLOAD;
+typedef struct IKE_PACKET_CERT_REQUEST_PAYLOAD IKE_PACKET_CERT_REQUEST_PAYLOAD;
+typedef struct IKE_PACKET_NOTICE_PAYLOAD IKE_PACKET_NOTICE_PAYLOAD;
+typedef struct IKE_PACKET_DELETE_PAYLOAD IKE_PACKET_DELETE_PAYLOAD;
+typedef struct IKE_PACKET_NAT_OA_PAYLOAD IKE_PACKET_NAT_OA_PAYLOAD;
+
+typedef struct IKE_PACKET_PAYLOAD IKE_PACKET_PAYLOAD;
+typedef struct IKE_PACKET IKE_PACKET;
+
+typedef struct IKE_P1_KEYSET IKE_P1_KEYSET;
+
+typedef struct IKE_CRYPTO IKE_CRYPTO;
+typedef struct IKE_HASH IKE_HASH;
+typedef struct IKE_DH IKE_DH;
+typedef struct IKE_ENGINE IKE_ENGINE;
+typedef struct IKE_CRYPTO_KEY IKE_CRYPTO_KEY;
+typedef struct IKE_CRYPTO_PARAM IKE_CRYPTO_PARAM;
+
+
+// ==============================================================
+// IPSec for Windows 7 / Vista / 2008 / 2008 R2
+// ==============================================================
+
+typedef struct IPSEC_WIN7 IPSEC_WIN7;
+
+
+// ==============================================================
+// In-Process VPN Client
+// ==============================================================
+
+typedef struct IPC IPC;
+typedef struct IPC_ARP IPC_ARP;
+typedef struct IPC_ASYNC IPC_ASYNC;
+typedef struct IPC_PARAM IPC_PARAM;
+typedef struct IPC_DHCP_RELESAE_QUEUE IPC_DHCP_RELESAE_QUEUE;
+typedef struct IPC_MSCHAP_V2_AUTHINFO IPC_MSCHAP_V2_AUTHINFO;
+
+
+// ==============================================================
+// UDP Acceleration
+// ==============================================================
+
+typedef struct UDP_ACCEL UDP_ACCEL;
+
+
+// ==============================================================
+// SSTP (Microsoft Secure Socket Tunneling Protocol) Stack
+// ==============================================================
+
+typedef struct SSTP_SERVER SSTP_SERVER;
+typedef struct SSTP_PACKET SSTP_PACKET;
+typedef struct SSTP_ATTRIBUTE SSTP_ATTRIBUTE;
+
+
+// ==============================================================
+// OpenVPN Protocol Stack
+// ==============================================================
+
+typedef struct OPENVPN_SERVER OPENVPN_SERVER;
+typedef struct OPENVPN_SERVER_UDP OPENVPN_SERVER_UDP;
+typedef struct OPENVPN_SESSION OPENVPN_SESSION;
+typedef struct OPENVPN_CHANNEL OPENVPN_CHANNEL;
+typedef struct OPENVPN_PACKET OPENVPN_PACKET;
+typedef struct OPENVPN_CONTROL_PACKET OPENVPN_CONTROL_PACKET;
+typedef struct OPENVPN_KEY_METHOD_2 OPENVPN_KEY_METHOD_2;
+
+
+// ==============================================================
+// Dynamic DNS Client
+// ==============================================================
+
+typedef struct DDNS_CLIENT DDNS_CLIENT;
+typedef struct DDNS_REGISTER_PARAM DDNS_REGISTER_PARAM;
+typedef struct DDNS_CLIENT_STATUS DDNS_CLIENT_STATUS;
+
+
+// ==============================================================
+// VPN Azure Client
+// ==============================================================
+typedef struct AZURE_CLIENT AZURE_CLIENT;
+typedef struct AZURE_PARAM AZURE_PARAM;
+
+
+// ==============================================================
+// VPN Gate Service
+// ==============================================================
+
+typedef struct VGS VGS;
+typedef struct VGS_CONFIG VGS_CONFIG;
+typedef struct VGC VGC;
+typedef struct VGHOST VGHOST;
+typedef struct VGHOSTLIST VGHOSTLIST;
+typedef struct VGHOSTDAT VGHOSTDAT;
+typedef struct VGCPOLLTASK VGCPOLLTASK;
+typedef struct VGS_LOG VGS_LOG;
+typedef struct VGC_UDPHOST VGC_UDPHOST;
+typedef struct MIRROR_SERVER MIRROR_SERVER;
+
+
+// ==============================================================
+// Native Stack
+// ==============================================================
+
+typedef struct NATIVE_STACK NATIVE_STACK;
+
+
+// ==============================================================
+// SeLow User-mode
+// ==============================================================
+
+typedef struct SU SU;
+typedef struct SU_ADAPTER SU_ADAPTER;
+typedef struct SU_ADAPTER_LIST SU_ADAPTER_LIST;
+
+
+
+#endif // CEDARTYPE_H
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Client.c b/src/Cedar/Client.c
new file mode 100644
index 00000000..16062e7f
--- /dev/null
+++ b/src/Cedar/Client.c
@@ -0,0 +1,11005 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Client.c
+// Client Manager
+
+#include "CedarPch.h"
+
+static CLIENT *client = NULL;
+static LISTENER *cn_listener = NULL;
+static LOCK *cn_listener_lock = NULL;
+static UINT64 cn_next_allow = 0;
+static LOCK *ci_active_sessions_lock = NULL;
+static UINT ci_num_active_sessions = 0;
+
+
+// In Windows 8 or later, change unreasonable setting of WCM to ensure normal VPN communication
+void CiDisableWcmNetworkMinimize(CLIENT *c)
+{
+#ifdef OS_WIN32
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ if (c->Config.NoChangeWcmNetworkSettingOnWindows8)
+ {
+ return;
+ }
+
+ MsDisableWcmNetworkMinimize();
+#endif // OS_WIN32
+}
+
+// Compare RPC_CLIENT_ENUM_ACCOUNT_ITEM items by last connected date (Reverse)
+int CiCompareClientAccountEnumItemByLastConnectDateTime(void *p1, void *p2)
+{
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *a1, *a2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ a1 = *(RPC_CLIENT_ENUM_ACCOUNT_ITEM **)p1;
+ a2 = *(RPC_CLIENT_ENUM_ACCOUNT_ITEM **)p2;
+ if (a1 == NULL || a2 == NULL)
+ {
+ return 0;
+ }
+ if (a1->LastConnectDateTime > a2->LastConnectDateTime)
+ {
+ return -1;
+ }
+ else if (a1->LastConnectDateTime < a2->LastConnectDateTime)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
+// If machine changed, reshuffle MAC address for all virtual NIC
+void CiChangeAllVLanMacAddressIfMachineChanged(CLIENT *c)
+{
+ UCHAR current_hash_new[SHA1_SIZE];
+ UCHAR current_hash[SHA1_SIZE];
+ UCHAR current_hash_old[SHA1_SIZE];
+ UCHAR saved_hash[SHA1_SIZE];
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ if (MsIsAdmin() == false)
+ {
+ return;
+ }
+#endif
+
+ CiGetCurrentMachineHashNew(current_hash_new);
+ CiGetCurrentMachineHash(current_hash);
+ CiGetCurrentMachineHashOld(current_hash_old);
+
+ if (CiReadLastMachineHash(saved_hash) == false)
+ {
+ CiWriteLastMachineHash(current_hash_new);
+ return;
+ }
+
+ if (Cmp(saved_hash, current_hash_old, SHA1_SIZE) == 0)
+ {
+ CiWriteLastMachineHash(current_hash_new);
+ return;
+ }
+
+ if (Cmp(saved_hash, current_hash, SHA1_SIZE) == 0)
+ {
+ CiWriteLastMachineHash(current_hash_new);
+ return;
+ }
+
+ if (Cmp(saved_hash, current_hash_new, SHA1_SIZE) == 0)
+ {
+ return;
+ }
+
+ if (CiWriteLastMachineHash(current_hash_new) == false)
+ {
+ return;
+ }
+
+ CiChangeAllVLanMacAddress(c);
+}
+
+// Get current machine hash (Old)
+void CiGetCurrentMachineHashOld(void *data)
+{
+ char name[MAX_PATH];
+ char *product_id = NULL;
+ // Validate arguments
+ if (data == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ // Priduct ID
+ product_id = MsRegReadStr(REG_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "ProductId");
+ if (product_id == NULL)
+ {
+ product_id = MsRegReadStr(REG_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion", "ProductId");
+ }
+
+ StrCpy(name, sizeof(name), product_id);
+
+ Free(product_id);
+
+#else // OS_WIN32
+ GetMachineName(name, sizeof(name));
+#endif // OS_WIN32
+
+ Trim(name);
+ StrUpper(name);
+
+ Hash(data, name, StrLen(name), true);
+}
+
+// Get current machine hash
+void CiGetCurrentMachineHash(void *data)
+{
+ char name[MAX_PATH];
+ char *product_id = NULL;
+ // Validate arguments
+ if (data == NULL)
+ {
+ return;
+ }
+
+ GetMachineName(name, sizeof(name));
+
+ Trim(name);
+ StrUpper(name);
+
+ Hash(data, name, StrLen(name), true);
+}
+
+// Get current machine hash (without using domain name)
+void CiGetCurrentMachineHashNew(void *data)
+{
+ char name[MAX_PATH];
+ char *p;
+
+ // Validate arguments
+ if (data == NULL)
+ {
+ return;
+ }
+
+ GetMachineName(name, sizeof(name));
+
+ // Ignore after first period(.)
+ for(p=name; *p; p++)
+ if(*p == '.')
+ *p = 0;
+
+ Trim(name);
+ StrUpper(name);
+
+ Hash(data, name, StrLen(name), true);
+}
+
+
+// Write machine hash
+bool CiWriteLastMachineHash(void *data)
+{
+ // Validate arguments
+ if (data == NULL)
+ {
+ return false;
+ }
+
+#ifdef OS_WIN32
+ if (MsRegWriteBinEx(REG_LOCAL_MACHINE, MS_REG_TCP_SETTING_KEY, "LastMachineHash", data, SHA1_SIZE, true) == false)
+ {
+ return false;
+ }
+
+ return true;
+#else // OS_WIN32
+ return false;
+#endif // OS_WIN32
+}
+
+// Get previous machine hash
+bool CiReadLastMachineHash(void *data)
+{
+ BUF *b = NULL;
+ // Validate arguments
+ if (data == NULL)
+ {
+ return false;
+ }
+
+#ifdef OS_WIN32
+ b = MsRegReadBinEx(REG_LOCAL_MACHINE, MS_REG_TCP_SETTING_KEY, "LastMachineHash", true);
+ if (b == NULL)
+ {
+ return false;
+ }
+ if (b->Size == SHA1_SIZE)
+ {
+ Copy(data, b->Buf, b->Size);
+ FreeBuf(b);
+
+ return true;
+ }
+
+ FreeBuf(b);
+ return false;
+#else // OS_WIN32
+ return false;
+#endif // OS_WIN32
+}
+
+// If the MAC address of each virtual LAN card has been eliminated, set it to random numbers
+// (measures for Windows 8 -> 8.1 upgrade problem)
+void CiChangeAllVLanMacAddressIfCleared(CLIENT *c)
+{
+#ifdef OS_WIN32
+ RPC_CLIENT_ENUM_VLAN t;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ if (MsIsInfCatalogRequired() == false)
+ {
+ // Not required for other than Windows 8
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ if (CtEnumVLan(c, &t))
+ {
+ UINT i;
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_VLAN_ITEM *e = t.Items[i];
+ UCHAR mac[6];
+
+ if (StrToMac(mac, e->MacAddress))
+ {
+ if (mac[0] == 0x00 &&
+ mac[1] == 0x00 &&
+ mac[2] == 0x01 &&
+ mac[3] == 0x00 &&
+ mac[4] == 0x00 &&
+ mac[5] == 0x01)
+ {
+ char *name = e->DeviceName;
+ RPC_CLIENT_SET_VLAN s;
+ UCHAR mac[6];
+
+ GenMacAddress(mac);
+
+ Zero(&s, sizeof(s));
+ StrCpy(s.DeviceName, sizeof(s.DeviceName), name);
+
+ MacToStr(s.MacAddress, sizeof(s.MacAddress), mac);
+
+ CtSetVLan(c, &s);
+ }
+ }
+ }
+
+ CiFreeClientEnumVLan(&t);
+ }
+#endif // OS_WIN32
+}
+
+// Set the MAC address of all virtual LAN cards to random number
+void CiChangeAllVLanMacAddress(CLIENT *c)
+{
+ RPC_CLIENT_ENUM_VLAN t;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ if (CtEnumVLan(c, &t))
+ {
+ UINT i;
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_VLAN_ITEM *e = t.Items[i];
+ UCHAR mac[6];
+
+ if (StrToMac(mac, e->MacAddress) && mac[1] == 0xAC)
+ {
+ char *name = e->DeviceName;
+ RPC_CLIENT_SET_VLAN s;
+ UCHAR mac[6];
+
+ GenMacAddress(mac);
+
+ Zero(&s, sizeof(s));
+ StrCpy(s.DeviceName, sizeof(s.DeviceName), name);
+
+ MacToStr(s.MacAddress, sizeof(s.MacAddress), mac);
+
+ CtSetVLan(c, &s);
+ }
+ }
+
+ CiFreeClientEnumVLan(&t);
+ }
+}
+
+// Wait for preparation of notification service to complete
+void CnWaitForCnServiceReady()
+{
+ UINT64 start_time = Tick64();
+
+ while ((start_time + (UINT64)CLIENT_WAIT_CN_READY_TIMEOUT) >= Tick64())
+ {
+ if (CnIsCnServiceReady())
+ {
+ break;
+ }
+
+ SleepThread(100);
+ }
+}
+
+// Check whether preparation of notification service completed
+bool CnIsCnServiceReady()
+{
+ SOCK *s;
+ // Confirm running the notification service
+ if (CnCheckAlreadyExists(false) == false)
+ {
+ // Not running
+ return false;
+ }
+
+ // Try to connect to the TCP port
+ s = ConnectEx("localhost", CLIENT_NOTIFY_PORT, 500);
+ if (s == NULL)
+ {
+ // The TCP port is not opened
+ return false;
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+
+ // Running
+ return true;
+}
+
+// Check whether the notification service is already running
+bool CnCheckAlreadyExists(bool lock)
+{
+ bool ret = false;
+
+#ifdef OS_WIN32
+ ret = Win32CnCheckAlreadyExists(lock);
+#endif
+
+ return ret;
+}
+
+typedef struct CNC_STATUS_PRINTER_WINDOW_PARAM
+{
+ THREAD *Thread;
+ SESSION *Session;
+ SOCK *Sock;
+} CNC_STATUS_PRINTER_WINDOW_PARAM;
+
+typedef struct CNC_CONNECT_ERROR_DLG_THREAD_PARAM
+{
+ SESSION *Session;
+ SOCK *Sock;
+ bool HaltThread;
+ EVENT *Event;
+} CNC_CONNECT_ERROR_DLG_THREAD_PARAM;
+
+
+// Get the file name of vpnclient.exe in Win32
+char *CiGetVpnClientExeFileName()
+{
+ if (Is64() == false)
+ {
+ return CLIENT_WIN32_EXE_FILENAME;
+ }
+ else
+ {
+ if (IsX64())
+ {
+ return CLIENT_WIN32_EXE_FILENAME_X64;
+ }
+ else
+ {
+ return CLIENT_WIN32_EXE_FILENAME_IA64;
+ }
+ }
+}
+
+// Thread to stop forcibly the Certificate check dialog client
+void CncCheckCertHaltThread(THREAD *thread, void *param)
+{
+ CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp = (CNC_CONNECT_ERROR_DLG_THREAD_PARAM *)param;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ if (dp->Session->Halt || dp->HaltThread)
+ {
+ break;
+ }
+
+ Wait(dp->Event, 100);
+ }
+
+ Disconnect(dp->Sock);
+}
+
+// Show the certification check dialog
+void CncCheckCert(SESSION *session, UI_CHECKCERT *dlg)
+{
+ SOCK *s;
+ PACK *p;
+ CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp;
+ THREAD *t;
+ // Validate arguments
+ if (dlg == NULL || session == NULL)
+ {
+ return;
+ }
+
+ s = CncConnect();
+ if (s == NULL)
+ {
+ return;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "check_cert");
+ PackAddUniStr(p, "AccountName", dlg->AccountName);
+ PackAddStr(p, "ServerName", dlg->ServerName);
+ PackAddX(p, "x", dlg->x);
+ PackAddX(p, "parent_x", dlg->parent_x);
+ PackAddX(p, "old_x", dlg->old_x);
+ PackAddBool(p, "DiffWarning", dlg->DiffWarning);
+ PackAddBool(p, "Ok", dlg->Ok);
+ PackAddBool(p, "SaveServerCert", dlg->SaveServerCert);
+
+ SendPack(s, p);
+ FreePack(p);
+
+ dp = ZeroMalloc(sizeof(CNC_CONNECT_ERROR_DLG_THREAD_PARAM));
+ dp->Sock = s;
+ dp->Event = NewEvent();
+ dp->Session = session;
+
+ t = NewThread(CncCheckCertHaltThread, dp);
+
+ p = RecvPack(s);
+ if (p != NULL)
+ {
+ dlg->Ok = PackGetBool(p, "Ok");
+ dlg->DiffWarning = PackGetBool(p, "DiffWarning");
+ dlg->SaveServerCert = PackGetBool(p, "SaveServerCert");
+
+ FreePack(p);
+ }
+
+ dp->HaltThread = true;
+ Set(dp->Event);
+
+ WaitThread(t, INFINITE);
+
+ ReleaseEvent(dp->Event);
+ Free(dp);
+ ReleaseThread(t);
+
+ Disconnect(s);
+ ReleaseSock(s);
+}
+
+// Smart card signature dialog
+bool CncSecureSignDlg(SECURE_SIGN *sign)
+{
+ SOCK *s;
+ PACK *p;
+ bool ret = false;
+ // Validate arguments
+ if (sign == NULL)
+ {
+ return false;
+ }
+
+ s = CncConnect();
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "secure_sign");
+ OutRpcSecureSign(p, sign);
+
+ SendPack(s, p);
+ FreePack(p);
+
+ p = RecvPack(s);
+ if (p != NULL)
+ {
+ ret = PackGetBool(p, "ret");
+
+ if (ret)
+ {
+ FreeRpcSecureSign(sign);
+
+ Zero(sign, sizeof(SECURE_SIGN));
+ InRpcSecureSign(sign, p);
+ }
+
+ FreePack(p);
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+
+ return ret;
+}
+
+// Show the NIC information dialog
+SOCK *CncNicInfo(UI_NICINFO *info)
+{
+ SOCK *s;
+ PACK *p;
+ bool ret = false;
+ // Validate arguments
+ if (info == NULL)
+ {
+ return NULL;
+ }
+
+ s = CncConnectEx(200);
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "nicinfo");
+ PackAddStr(p, "NicName", info->NicName);
+ PackAddUniStr(p, "AccountName", info->AccountName);
+
+ SendPack(s, p);
+ FreePack(p);
+
+ return s;
+}
+
+// Close the NIC information dialog
+void CncNicInfoFree(SOCK *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+}
+
+// Show the message dialog
+SOCK *CncMsgDlg(UI_MSG_DLG *dlg)
+{
+ SOCK *s;
+ PACK *p;
+ bool ret = false;
+ char *utf;
+ // Validate arguments
+ if (dlg == NULL)
+ {
+ return NULL;
+ }
+
+ s = CncConnectEx(200);
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "msg_dialog");
+ PackAddStr(p, "ServerName", dlg->ServerName);
+ PackAddStr(p, "HubName", dlg->HubName);
+ utf = CopyUniToUtf(dlg->Msg);
+ PackAddData(p, "Msg", utf, StrLen(utf));
+ Free(utf);
+
+ SendPack(s, p);
+ FreePack(p);
+
+ return s;
+}
+
+// Close the message dialog
+void CndMsgDlgFree(SOCK *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+}
+
+// The thread to stop the password input dialog client forcibly
+void CncPasswordDlgHaltThread(THREAD *thread, void *param)
+{
+ CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp = (CNC_CONNECT_ERROR_DLG_THREAD_PARAM *)param;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ if (dp->Session->Halt || dp->HaltThread)
+ {
+ break;
+ }
+
+ Wait(dp->Event, 100);
+ }
+
+ Disconnect(dp->Sock);
+}
+
+// Show the password input dialog
+bool CncPasswordDlg(SESSION *session, UI_PASSWORD_DLG *dlg)
+{
+ SOCK *s;
+ PACK *p;
+ CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp;
+ THREAD *t;
+ bool ret = false;
+ // Validate arguments
+ if (dlg == NULL || session == NULL)
+ {
+ return false;
+ }
+
+ s = CncConnect();
+ if (s == NULL)
+ {
+ Wait(session->HaltEvent, session->RetryInterval);
+ return true;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "password_dialog");
+ PackAddInt(p, "Type", dlg->Type);
+ PackAddStr(p, "Username", dlg->Username);
+ PackAddStr(p, "Password", dlg->Password);
+ PackAddStr(p, "ServerName", dlg->ServerName);
+ PackAddInt(p, "RetryIntervalSec", dlg->RetryIntervalSec);
+ PackAddBool(p, "ProxyServer", dlg->ProxyServer);
+ PackAddBool(p, "AdminMode", dlg->AdminMode);
+ PackAddBool(p, "ShowNoSavePassword", dlg->ShowNoSavePassword);
+ PackAddBool(p, "NoSavePassword", dlg->NoSavePassword);
+
+ SendPack(s, p);
+ FreePack(p);
+
+ dp = ZeroMalloc(sizeof(CNC_CONNECT_ERROR_DLG_THREAD_PARAM));
+ dp->Session = session;
+ dp->Sock = s;
+ dp->Event = NewEvent();
+
+ t = NewThread(CncConnectErrorDlgHaltThread, dp);
+
+ p = RecvPack(s);
+ if (p != NULL)
+ {
+ ret = PackGetBool(p, "ok");
+ dlg->NoSavePassword = PackGetBool(p, "NoSavePassword");
+ dlg->ProxyServer = PackGetBool(p, "ProxyServer");
+ dlg->Type = PackGetInt(p, "Type");
+ PackGetStr(p, "Username", dlg->Username, sizeof(dlg->Username));
+ PackGetStr(p, "Password", dlg->Password, sizeof(dlg->Password));
+
+ FreePack(p);
+ }
+
+ dp->HaltThread = true;
+ Set(dp->Event);
+
+ WaitThread(t, INFINITE);
+
+ ReleaseEvent(dp->Event);
+ Free(dp);
+ ReleaseThread(t);
+
+ Disconnect(s);
+ ReleaseSock(s);
+
+ return ret;
+}
+
+// Thread to stop the connection error dialog client forcibly
+void CncConnectErrorDlgHaltThread(THREAD *thread, void *param)
+{
+ CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp = (CNC_CONNECT_ERROR_DLG_THREAD_PARAM *)param;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ if (dp->Session->Halt || dp->HaltThread)
+ {
+ break;
+ }
+
+ Wait(dp->Event, 100);
+ }
+
+ Disconnect(dp->Sock);
+}
+
+// Show the connection error dialog
+bool CncConnectErrorDlg(SESSION *session, UI_CONNECTERROR_DLG *dlg)
+{
+ SOCK *s;
+ PACK *p;
+ CNC_CONNECT_ERROR_DLG_THREAD_PARAM *dp;
+ THREAD *t;
+ bool ret = false;
+ // Validate arguments
+ if (dlg == NULL || session == NULL)
+ {
+ return false;
+ }
+
+ s = CncConnect();
+ if (s == NULL)
+ {
+ Wait(session->HaltEvent, session->RetryInterval);
+ return true;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "connecterror_dialog");
+ PackAddUniStr(p, "AccountName", dlg->AccountName);
+ PackAddStr(p, "ServerName", dlg->ServerName);
+ PackAddInt(p, "Err", dlg->Err);
+ PackAddInt(p, "CurrentRetryCount", dlg->CurrentRetryCount);
+ PackAddInt(p, "RetryLimit", dlg->RetryLimit);
+ PackAddInt(p, "RetryIntervalSec", dlg->RetryIntervalSec);
+ PackAddBool(p, "HideWindow", dlg->HideWindow);
+
+ SendPack(s, p);
+ FreePack(p);
+
+ dp = ZeroMalloc(sizeof(CNC_CONNECT_ERROR_DLG_THREAD_PARAM));
+ dp->Session = session;
+ dp->Sock = s;
+ dp->Event = NewEvent();
+
+ t = NewThread(CncConnectErrorDlgHaltThread, dp);
+
+ p = RecvPack(s);
+ if (p != NULL)
+ {
+ ret = PackGetBool(p, "ok");
+ dlg->HideWindow = PackGetBool(p, "HideWindow");
+
+ FreePack(p);
+ }
+
+ dp->HaltThread = true;
+ Set(dp->Event);
+
+ WaitThread(t, INFINITE);
+
+ ReleaseEvent(dp->Event);
+ Free(dp);
+ ReleaseThread(t);
+
+ Disconnect(s);
+ ReleaseSock(s);
+
+ return ret;
+}
+
+// Thread for the status indicator client
+void CncStatusPrinterWindowThreadProc(THREAD *thread, void *param)
+{
+ CNC_STATUS_PRINTER_WINDOW_PARAM *pp;
+ SOCK *sock;
+ PACK *p;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ pp = (CNC_STATUS_PRINTER_WINDOW_PARAM *)param;
+ sock = pp->Sock;
+ pp->Thread = thread;
+ AddRef(pp->Thread->ref);
+
+ NoticeThreadInit(thread);
+
+ p = RecvPack(sock);
+ if (p != NULL)
+ {
+ // Stop the session
+ StopSessionEx(pp->Session, true);
+
+ FreePack(p);
+ }
+}
+
+// Create a status indicator client
+SOCK *CncStatusPrinterWindowStart(SESSION *s)
+{
+ SOCK *sock;
+ PACK *p;
+ THREAD *t;
+ CNC_STATUS_PRINTER_WINDOW_PARAM *param;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ sock = CncConnect();
+
+ if (sock == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "status_printer");
+ PackAddUniStr(p, "account_name", s->Account->ClientOption->AccountName);
+
+ if (SendPack(sock, p) == false)
+ {
+ FreePack(p);
+ ReleaseSock(sock);
+
+ return NULL;
+ }
+
+ FreePack(p);
+
+ param = ZeroMalloc(sizeof(CNC_STATUS_PRINTER_WINDOW_PARAM));
+ param->Sock = sock;
+ param->Session = s;
+
+ sock->Param = param;
+
+ t = NewThread(CncStatusPrinterWindowThreadProc, param);
+ WaitThreadInit(t);
+
+ ReleaseThread(t);
+
+ return sock;
+}
+
+// Send a string to the status indicator
+void CncStatusPrinterWindowPrint(SOCK *s, wchar_t *str)
+{
+ CNC_STATUS_PRINTER_WINDOW_PARAM *param;
+ PACK *p;
+ // Validate arguments
+ if (s == NULL || str == NULL)
+ {
+ return;
+ }
+
+ param = (CNC_STATUS_PRINTER_WINDOW_PARAM *)s->Param;
+
+ p = NewPack();
+ PackAddUniStr(p, "string", str);
+ SendPack(s, p);
+ FreePack(p);
+}
+
+// Stop the status indicator client
+void CncStatusPrinterWindowStop(SOCK *s)
+{
+ CNC_STATUS_PRINTER_WINDOW_PARAM *param;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ param = (CNC_STATUS_PRINTER_WINDOW_PARAM *)s->Param;
+
+ // Disconnect the client socket
+ Disconnect(s);
+
+ // Terminate the thread
+ WaitThread(param->Thread, INFINITE);
+ ReleaseThread(param->Thread);
+
+ Free(param);
+ ReleaseSock(s);
+}
+
+// Start the driver installer for Windows Vista
+bool CncExecDriverInstaller(char *arg)
+{
+ SOCK *s = CncConnect();
+ PACK *p;
+ bool ret;
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "exec_driver_installer");
+ PackAddStr(p, "arg", arg);
+
+ SendPack(s, p);
+ FreePack(p);
+
+ p = RecvPack(s);
+ if (p == NULL)
+ {
+ Disconnect(s);
+ ReleaseSock(s);
+ return false;
+ }
+
+ ret = PackGetBool(p, "ret");
+
+ FreePack(p);
+
+ Disconnect(s);
+ ReleaseSock(s);
+
+ return ret;
+}
+
+// Let the current running client notification services releasing the socket
+void CncReleaseSocket()
+{
+ SOCK *s = CncConnect();
+ PACK *p;
+ if (s == NULL)
+ {
+ return;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "release_socket");
+
+#ifdef OS_WIN32
+ PackAddInt(p, "pid", MsGetProcessId());
+#endif // OS_WIN32
+
+ SendPack(s, p);
+ FreePack(p);
+
+ Disconnect(s);
+ ReleaseSock(s);
+}
+
+// Get the Session ID of the client notification service
+UINT CncGetSessionId()
+{
+ SOCK *s = CncConnect();
+ PACK *p;
+ UINT ret;
+ if (s == NULL)
+ {
+ return INFINITE;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "function", "get_session_id");
+
+ SendPack(s, p);
+ FreePack(p);
+
+ p = RecvPack(s);
+ if (p == NULL)
+ {
+ Disconnect(s);
+ ReleaseSock(s);
+ return INFINITE;
+ }
+
+ ret = PackGetInt(p, "session_id");
+
+ FreePack(p);
+
+ Disconnect(s);
+ ReleaseSock(s);
+
+ return ret;
+}
+
+// Terminate the process of the client notification service
+void CncExit()
+{
+ SOCK *s = CncConnectEx(256);
+ PACK *p;
+ if (s != NULL)
+ {
+ p = NewPack();
+ PackAddStr(p, "function", "exit");
+
+ SendPack(s, p);
+
+ FreePack(p);
+
+ FreePack(RecvPack(s));
+
+ Disconnect(s);
+ ReleaseSock(s);
+ }
+
+#ifdef OS_WIN32
+ MsKillOtherInstanceEx("vpnclient");
+#endif // OS_WIN32
+}
+
+// Connect to the client notification service
+SOCK *CncConnect()
+{
+ return CncConnectEx(0);
+}
+SOCK *CncConnectEx(UINT timeout)
+{
+ SOCK *s = ConnectEx("localhost", CLIENT_NOTIFY_PORT, timeout);
+
+ return s;
+}
+
+#ifdef OS_WIN32
+
+// Thread for the certificate check dialog
+void Win32CnCheckCertThreadProc(THREAD *thread, void *param)
+{
+ UI_CHECKCERT *dlg;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ dlg = (UI_CHECKCERT *)param;
+
+ CheckCertDlg(dlg);
+ {
+ PACK *p = NewPack();
+
+ PackAddBool(p, "Ok", dlg->Ok);
+ PackAddBool(p, "SaveServerCert", dlg->SaveServerCert);
+
+ SendPack(dlg->Sock, p);
+ FreePack(p);
+
+ FreePack(RecvPack(dlg->Sock));
+ }
+
+ Disconnect(dlg->Sock);
+}
+
+// Certificate check dialog
+void Win32CnCheckCert(SOCK *s, PACK *p)
+{
+ UI_CHECKCERT dlg;
+ THREAD *t;
+ Zero(&dlg, sizeof(dlg));
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackGetUniStr(p, "AccountName", dlg.AccountName, sizeof(dlg.AccountName));
+ PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName));
+ dlg.x = PackGetX(p, "x");
+ dlg.parent_x = PackGetX(p, "parent_x");
+ dlg.old_x = PackGetX(p, "old_x");
+ dlg.DiffWarning = PackGetBool(p, "DiffWarning");
+ dlg.Ok = PackGetBool(p, "Ok");
+ dlg.SaveServerCert = PackGetBool(p, "SaveServerCert");
+ dlg.Sock = s;
+
+ t = NewThread(Win32CnCheckCertThreadProc, &dlg);
+
+ FreePack(RecvPack(s));
+
+ dlg.Halt = true;
+
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+
+ FreeX(dlg.parent_x);
+ FreeX(dlg.old_x);
+ FreeX(dlg.x);
+}
+
+// Message display dialog thread procedure
+void Win32CnMsgDlgThreadProc(THREAD *thread, void *param)
+{
+ UI_MSG_DLG *dlg = (UI_MSG_DLG *)param;
+ wchar_t tmp[MAX_SIZE];
+ char url[MAX_SIZE];
+ // Validate arguments
+ if (thread == NULL || dlg == NULL)
+ {
+ return;
+ }
+
+ UniFormat(tmp, sizeof(tmp), _UU("CM_MSG_TITLE"),
+ dlg->ServerName, dlg->HubName);
+
+ if (IsURLMsg(dlg->Msg, url, sizeof(url)) == false)
+ {
+ OnceMsgEx(NULL, tmp, dlg->Msg, true, 167, &dlg->Halt);
+ }
+ else
+ {
+ if (MsExecute(url, NULL) == false)
+ {
+ OnceMsgEx(NULL, tmp, dlg->Msg, true, 167, &dlg->Halt);
+ }
+ }
+
+ Disconnect(dlg->Sock);
+}
+
+// NIC information dialog thread procedure
+void Win32CnNicInfoThreadProc(THREAD *thread, void *param)
+{
+ UI_NICINFO *info = (UI_NICINFO *)param;
+ // Validate arguments
+ if (thread == NULL || info == NULL)
+ {
+ return;
+ }
+
+ if (MsIsNt())
+ {
+ // Do not show a dialog on Windows 9x system
+ NicInfo(info);
+ }
+
+ Disconnect(info->Sock);
+}
+
+// NIC information dialog
+void Win32CnNicInfo(SOCK *s, PACK *p)
+{
+ UI_NICINFO info;
+ THREAD *t;
+ Zero(&info, sizeof(info));
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackGetStr(p, "NicName", info.NicName, sizeof(info.NicName));
+ PackGetUniStr(p, "AccountName", info.AccountName, sizeof(info.AccountName));
+
+ info.Sock = s;
+
+ t = NewThread(Win32CnNicInfoThreadProc, &info);
+
+ FreePack(RecvPack(s));
+
+ info.Halt = true;
+
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+}
+
+// Message display dialog
+void Win32CnMsgDlg(SOCK *s, PACK *p)
+{
+ UI_MSG_DLG dlg;
+ THREAD *t;
+ UINT utf_size;
+ char *utf;
+ wchar_t *msg;
+ Zero(&dlg, sizeof(dlg));
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName));
+ PackGetStr(p, "HubName", dlg.HubName, sizeof(dlg.HubName));
+
+ utf_size = PackGetDataSize(p, "Msg");
+ utf = ZeroMalloc(utf_size + 8);
+
+ PackGetData(p, "Msg", utf);
+
+ msg = CopyUtfToUni(utf);
+ Free(utf);
+
+ dlg.Sock = s;
+ dlg.Msg = msg;
+
+ t = NewThread(Win32CnMsgDlgThreadProc, &dlg);
+
+ FreePack(RecvPack(s));
+
+ dlg.Halt = true;
+
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+
+ Free(msg);
+}
+
+// Thread for Password input dialog
+void Win32CnPasswordDlgThreadProc(THREAD *thread, void *param)
+{
+ UI_PASSWORD_DLG *dlg;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ dlg = (UI_PASSWORD_DLG *)param;
+
+ if (PasswordDlg(NULL, dlg))
+ {
+ PACK *p = NewPack();
+
+ PackAddBool(p, "ok", true);
+ PackAddStr(p, "Username", dlg->Username);
+ PackAddStr(p, "Password", dlg->Password);
+ PackAddInt(p, "Type", dlg->Type);
+ PackAddBool(p, "ProxyServer", dlg->ProxyServer);
+ PackAddBool(p, "NoSavePassword", dlg->NoSavePassword);
+
+ SendPack(dlg->Sock, p);
+ FreePack(p);
+
+ FreePack(RecvPack(dlg->Sock));
+ }
+
+ Disconnect(dlg->Sock);
+}
+
+// Password input dialog
+void Win32CnPasswordDlg(SOCK *s, PACK *p)
+{
+ UI_PASSWORD_DLG dlg;
+ THREAD *t = NULL;
+ Zero(&dlg, sizeof(dlg));
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ dlg.Type = PackGetInt(p, "Type");
+ PackGetStr(p, "Username", dlg.Username, sizeof(dlg.Username));
+ PackGetStr(p, "Password", dlg.Password, sizeof(dlg.Password));
+ PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName));
+ dlg.RetryIntervalSec = PackGetInt(p, "RetryIntervalSec");
+ dlg.ProxyServer = PackGetBool(p, "ProxyServer");
+ dlg.AdminMode = PackGetBool(p, "AdminMode");
+ dlg.ShowNoSavePassword = PackGetBool(p, "ShowNoSavePassword");
+ dlg.NoSavePassword = PackGetBool(p, "NoSavePassword");
+ dlg.CancelEvent = NewEvent();
+ dlg.Sock = s;
+
+ t = NewThread(Win32CnPasswordDlgThreadProc, &dlg);
+
+ FreePack(RecvPack(s));
+
+ Set(dlg.CancelEvent);
+
+ WaitThread(t, INFINITE);
+ ReleaseEvent(dlg.CancelEvent);
+ ReleaseThread(t);
+}
+
+// Thread for the connection error dialog
+void Win32CnConnectErrorDlgThreadProc(THREAD *thread, void *param)
+{
+ UI_CONNECTERROR_DLG *dlg;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ dlg = (UI_CONNECTERROR_DLG *)param;
+
+ if (ConnectErrorDlg(dlg))
+ {
+ PACK *p = NewPack();
+
+ PackAddBool(p, "ok", true);
+ PackAddBool(p, "HideWindow", dlg->HideWindow);
+
+ SendPack(dlg->Sock, p);
+ FreePack(p);
+
+ FreePack(RecvPack(dlg->Sock));
+ }
+
+ Disconnect(dlg->Sock);
+}
+
+// Connection Error dialog (Win32)
+void Win32CnConnectErrorDlg(SOCK *s, PACK *p)
+{
+ UI_CONNECTERROR_DLG dlg;
+ THREAD *t;
+ Zero(&dlg, sizeof(dlg));
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackGetUniStr(p, "AccountName", dlg.AccountName, sizeof(dlg.AccountName));
+ PackGetStr(p, "ServerName", dlg.ServerName, sizeof(dlg.ServerName));
+ dlg.Err = PackGetInt(p, "Err");
+ dlg.CurrentRetryCount = PackGetInt(p, "CurrentRetryCount");
+ dlg.RetryLimit = PackGetInt(p, "RetryLimit");
+ dlg.RetryIntervalSec = PackGetInt(p, "RetryIntervalSec");
+ dlg.HideWindow = PackGetBool(p, "HideWindow");
+ dlg.CancelEvent = NewEvent();
+ dlg.Sock = s;
+
+ t = NewThread(Win32CnConnectErrorDlgThreadProc, &dlg);
+
+ FreePack(RecvPack(s));
+
+ Set(dlg.CancelEvent);
+
+ WaitThread(t, INFINITE);
+ ReleaseEvent(dlg.CancelEvent);
+ ReleaseThread(t);
+}
+
+// Status indicator (Win32)
+void Win32CnStatusPrinter(SOCK *s, PACK *p)
+{
+ STATUS_WINDOW *w;
+ wchar_t account_name[MAX_ACCOUNT_NAME_LEN + 1];
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackGetUniStr(p, "account_name", account_name, sizeof(account_name));
+
+ w = StatusPrinterWindowStart(s, account_name);
+
+ while (true)
+ {
+ PACK *p = RecvPack(s);
+
+ if (p == NULL)
+ {
+ // Exit the dialog because it is disconnected
+ break;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ // Rewrite the string
+ PackGetUniStr(p, "string", tmp, sizeof(tmp));
+
+ StatusPrinterWindowPrint(w, tmp);
+
+ FreePack(p);
+ }
+ }
+
+ StatusPrinterWindowStop(w);
+}
+
+// Start the driver installer (for Windows Vista)
+void Win32CnExecDriverInstaller(SOCK *s, PACK *p)
+{
+ char arg[MAX_SIZE];
+ bool ret;
+ void *helper = NULL;
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (PackGetStr(p, "arg", arg, sizeof(arg)) == false)
+ {
+ return;
+ }
+
+ if (MsIsVista())
+ {
+ helper = CmStartUacHelper();
+ }
+
+ ret = MsExecDriverInstaller(arg);
+
+ CmStopUacHelper(helper);
+
+ p = NewPack();
+ PackAddBool(p, "ret", ret);
+ SendPack(s, p);
+
+ FreePack(p);
+}
+
+#endif // OS_WIN32
+
+// Start the driver installer
+void CnExecDriverInstaller(SOCK *s, PACK *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ Win32CnExecDriverInstaller(s, p);
+#endif // OS_WIN32
+}
+
+// Certificate confirmation dialog
+void CnCheckCert(SOCK *s, PACK *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ Win32CnCheckCert(s, p);
+#endif // OS_WIN32
+}
+
+// NIC information dialog
+void CnNicInfo(SOCK *s, PACK *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ Win32CnNicInfo(s, p);
+#endif // OS_WIN32
+}
+
+// Message display dialog
+void CnMsgDlg(SOCK *s, PACK *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ Win32CnMsgDlg(s, p);
+#endif // OS_WIN32
+}
+
+// Password input dialog
+void CnPasswordDlg(SOCK *s, PACK *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ Win32CnPasswordDlg(s, p);
+#endif // OS_WIN32
+}
+
+// Connection Error dialog
+void CnConnectErrorDlg(SOCK *s, PACK *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ Win32CnConnectErrorDlg(s, p);
+#endif // OS_WIN32
+}
+
+// Status indicator
+void CnStatusPrinter(SOCK *s, PACK *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ Win32CnStatusPrinter(s, p);
+#endif // OS_WIN32
+}
+// Client notification service listener thread
+void CnListenerProc(THREAD *thread, void *param)
+{
+ TCP_ACCEPTED_PARAM *data = (TCP_ACCEPTED_PARAM *)param;
+ SOCK *s;
+ PACK *p;
+ // Validate arguments
+ if (data == NULL || thread == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ //Set Application ID
+ JL_SetCurrentProcessExplicitAppUserModelID(APPID_CM);
+#endif // OS_WIN32
+
+ s = data->s;
+ AddRef(s->ref);
+ NoticeThreadInit(thread);
+
+ if (s->LocalIP.addr[0] == 127)
+ {
+ p = RecvPack(s);
+
+ if (p != NULL)
+ {
+ char function[MAX_SIZE];
+
+ if (PackGetStr(p, "function", function, sizeof(function)))
+ {
+ if (StrCmpi(function, "status_printer") == 0)
+ {
+ CnStatusPrinter(s, p);
+ }
+ else if (StrCmpi(function, "connecterror_dialog") == 0)
+ {
+ CnConnectErrorDlg(s, p);
+ }
+ else if (StrCmpi(function, "msg_dialog") == 0)
+ {
+ CnMsgDlg(s, p);
+ }
+ else if (StrCmpi(function, "nicinfo") == 0)
+ {
+ CnNicInfo(s, p);
+ }
+ else if (StrCmpi(function, "password_dialog") == 0)
+ {
+ CnPasswordDlg(s, p);
+ }
+ else if (StrCmpi(function, "secure_sign") == 0)
+ {
+ CnSecureSign(s, p);
+ }
+ else if (StrCmpi(function, "check_cert") == 0)
+ {
+ CnCheckCert(s, p);
+ }
+ else if (StrCmpi(function, "exit") == 0)
+ {
+#ifdef OS_WIN32
+ MsTerminateProcess();
+#else // OS_WIN32
+ _exit(0);
+#endif // OS_WIN32
+ }
+ else if (StrCmpi(function, "get_session_id") == 0)
+ {
+ PACK *p = NewPack();
+#ifdef OS_WIN32
+ PackAddInt(p, "session_id", MsGetCurrentTerminalSessionId());
+#endif // OS_WIN32
+ SendPack(s, p);
+ FreePack(p);
+ }
+ else if (StrCmpi(function, "exec_driver_installer") == 0)
+ {
+ CnExecDriverInstaller(s, p);
+ }
+ else if (StrCmpi(function, "release_socket") == 0)
+ {
+ // Stop the listener
+ CnReleaseSocket(s, p);
+ }
+ }
+
+ FreePack(p);
+ }
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+}
+
+// Do the Secure Sign
+void CnSecureSign(SOCK *s, PACK *p)
+{
+ SECURE_SIGN sign;
+ bool ret = false;
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(&sign, sizeof(sign));
+ InRpcSecureSign(&sign, p);
+
+#ifdef OS_WIN32
+ // Win32: Show dialog
+ ret = Win32CiSecureSign(&sign);
+#else // OS_WIN32
+ // UNIX: not implemented
+ ret = false;
+#endif // OS_WIN32
+
+ p = NewPack();
+
+ OutRpcSecureSign(p, &sign);
+ FreeRpcSecureSign(&sign);
+
+ PackAddBool(p, "ret", ret);
+
+ SendPack(s, p);
+ FreePack(p);
+}
+
+// Stop the listener
+void CnReleaseSocket(SOCK *s, PACK *p)
+{
+ UINT pid = 0;
+ UINT current_pid = 0;
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ pid = PackGetInt(p, "pid");
+
+#ifdef OS_WIN32
+ current_pid = MsGetProcessId();
+#endif // OS_WIN32
+
+ if (current_pid == pid)
+ {
+ return;
+ }
+
+ Lock(cn_listener_lock);
+ {
+ if (cn_listener != NULL)
+ {
+ if (cn_listener->Halt == false)
+ {
+ StopListener(cn_listener);
+
+ cn_next_allow = Tick64() + (6 * 1000);
+ }
+ }
+ }
+ Unlock(cn_listener_lock);
+}
+
+// Start the client notification service
+void CnStart()
+{
+ CEDAR *cedar;
+ LISTENER *o;
+ UINT last_cursor_hash = 0;
+ bool last_session_active = false;
+
+ cn_next_allow = 0;
+ cn_listener_lock = NewLock();
+
+#ifdef OS_WIN32
+ MsSetShutdownParameters(0xff, 0x00000001);
+ InitWinUi(_UU("CN_TITLE"), _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+#endif // OS_WIN32
+
+ cedar = NewCedar(NULL, NULL);
+
+ if (CnCheckAlreadyExists(true))
+ {
+ // Already started
+ ReleaseCedar(cedar);
+#ifdef OS_WIN32
+ FreeWinUi();
+#endif // OS_WIN32
+ return;
+ }
+
+#ifdef OS_WIN32
+ MsRegWriteInt(REG_CURRENT_USER, CM_REG_KEY,
+ "NotifyServerProcessId", MsGetProcessId());
+#endif // OS_WIN32
+
+ DisableDosProtect();
+
+BEGIN_LISTENER:
+ Lock(cn_listener_lock);
+ cn_listener = o = NewListenerEx(cedar, LISTENER_TCP, CLIENT_NOTIFY_PORT, CnListenerProc, NULL);
+ Unlock(cn_listener_lock);
+
+ while (true)
+ {
+ UINT current_cursor_hash = 0;
+ bool cursor_changed = false;
+
+#ifdef OS_WIN32
+ // Get the current cursor position
+ current_cursor_hash = MsGetCursorPosHash();
+#endif // OS_WIN32
+
+ if (last_cursor_hash != current_cursor_hash)
+ {
+ // Check the cursor position
+ cursor_changed = true;
+ last_cursor_hash = current_cursor_hash;
+ }
+
+ Lock(cn_listener_lock);
+
+ // Check the status periodically after that the listener has started
+ if (cn_listener->Status == LISTENER_STATUS_TRYING || cn_listener->Halt)
+ {
+ bool session_active = false;
+#ifdef OS_WIN32
+ session_active = MsIsCurrentTerminalSessionActive();
+ if (cursor_changed)
+ {
+ // If the cursor position is changed but the terminal session is
+ // not active, the cursor position is regarded as not changed.
+ if (session_active == false)
+ {
+ cursor_changed = false;
+ }
+ }
+ if (last_session_active != session_active)
+ {
+ //If the cursor position doesn't changed but the terminal session
+ // became active than previous, the cursor position is regarded as changed.
+ last_session_active = session_active;
+
+ if (session_active)
+ {
+ cursor_changed = true;
+ }
+ }
+#endif // OS_WIN32
+
+ // If the port cannot be opened
+ if (cn_next_allow <= Tick64())
+ {
+ if (cursor_changed || cn_listener->Halt)
+ {
+ if (cursor_changed)
+ {
+ // It can be judged to have the rights to open the port
+ // since the mouse cursor is moving.
+ // So, take over the port which is owned by other process forcibly
+ CncReleaseSocket();
+ }
+
+ if (cn_listener->Halt)
+ {
+ ReleaseListener(cn_listener);
+ cn_listener = NULL;
+
+ Unlock(cn_listener_lock);
+ goto BEGIN_LISTENER;
+ }
+ }
+ }
+ }
+
+ Unlock(cn_listener_lock);
+
+ SleepThread(1000);
+ }
+}
+
+// Confirm whether the account file is parsed successfully
+bool CiTryToParseAccount(BUF *b)
+{
+ RPC_CLIENT_CREATE_ACCOUNT *a;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return false;
+ }
+
+ a = CiCfgToAccount(b);
+ if (a != NULL)
+ {
+ CiFreeClientCreateAccount(a);
+ Free(a);
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+bool CiTryToParseAccountFile(wchar_t *name)
+{
+ bool ret;
+ BUF *b;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return false;
+ }
+
+ b = ReadDumpW(name);
+ if (b == NULL)
+ {
+ return false;
+ }
+
+ ret = CiTryToParseAccount(b);
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Confirm whether the account information includes sensitive information
+bool CiHasAccountSensitiveInformation(BUF *b)
+{
+ RPC_CLIENT_CREATE_ACCOUNT *a;
+ bool ret = false;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return false;
+ }
+
+ a = CiCfgToAccount(b);
+ if (a == NULL)
+ {
+ return false;
+ }
+
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_PASSWORD)
+ {
+ ret = true;
+ }
+ else if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_PLAIN_PASSWORD)
+ {
+ ret = true;
+ }
+
+ CiFreeClientCreateAccount(a);
+ Free(a);
+
+ return ret;
+}
+bool CiHasAccountSensitiveInformationFile(wchar_t *name)
+{
+ bool ret = false;
+ BUF *b;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return false;
+ }
+
+ b = ReadDumpW(name);
+ if (b == NULL)
+ {
+ return false;
+ }
+
+ ret = CiHasAccountSensitiveInformation(b);
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Delete the sensitive information in the account information
+bool CiEraseSensitiveInAccount(BUF *b)
+{
+ RPC_CLIENT_CREATE_ACCOUNT *a;
+ BUF *b2;
+ bool ret = false;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return false;
+ }
+
+ a = CiCfgToAccount(b);
+ if (a == NULL)
+ {
+ return false;
+ }
+
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_PASSWORD)
+ {
+ Zero(a->ClientAuth->HashedPassword, sizeof(a->ClientAuth->HashedPassword));
+ ClearStr(a->ClientAuth->Username, sizeof(a->ClientAuth->Username));
+ }
+ else if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_PLAIN_PASSWORD)
+ {
+ ClearStr(a->ClientAuth->PlainPassword, sizeof(a->ClientAuth->PlainPassword));
+ ClearStr(a->ClientAuth->Username, sizeof(a->ClientAuth->Username));
+ }
+
+ b2 = CiAccountToCfg(a);
+ if (b2 != NULL)
+ {
+ ret = true;
+
+ ClearBuf(b);
+
+ WriteBuf(b, b2->Buf, b2->Size);
+ SeekBuf(b, 0, 0);
+
+ FreeBuf(b2);
+ }
+
+ CiFreeClientCreateAccount(a);
+ Free(a);
+
+ return ret;
+}
+
+// Read the account information from the buffer
+RPC_CLIENT_CREATE_ACCOUNT *CiCfgToAccount(BUF *b)
+{
+ RPC_CLIENT_CREATE_ACCOUNT *t;
+ FOLDER *f;
+ ACCOUNT *a;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return NULL;
+ }
+
+ f = CfgBufTextToFolder(b);
+ if (f == NULL)
+ {
+ return NULL;
+ }
+
+ a = CiLoadClientAccount(f);
+
+ CfgDeleteFolder(f);
+
+ if (a == NULL)
+ {
+ return NULL;
+ }
+
+ DeleteLock(a->lock);
+
+ t = ZeroMalloc(sizeof(RPC_CLIENT_CREATE_ACCOUNT));
+ t->ClientOption = a->ClientOption;
+ t->ClientAuth = a->ClientAuth;
+ t->StartupAccount = a->StartupAccount;
+ t->CheckServerCert = a->CheckServerCert;
+ t->ServerCert = a->ServerCert;
+ Free(a);
+
+ return t;
+}
+
+// Write the account information to a buffer
+BUF *CiAccountToCfg(RPC_CLIENT_CREATE_ACCOUNT *t)
+{
+ BUF *b;
+ FOLDER *root;
+ ACCOUNT a;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ root = CfgCreateFolder(NULL, TAG_ROOT);
+ Zero(&a, sizeof(a));
+ a.ClientOption = t->ClientOption;
+ a.ClientAuth = t->ClientAuth;
+ a.CheckServerCert = t->CheckServerCert;
+ a.ServerCert = t->ServerCert;
+ a.StartupAccount = t->StartupAccount;
+
+ CiWriteAccountData(root, &a);
+
+ b = CfgFolderToBufEx(root, true, true);
+ CfgDeleteFolder(root);
+
+ return b;
+}
+
+// RPC dispatch routine
+PACK *CiRpcDispatch(RPC *rpc, char *name, PACK *p)
+{
+ CLIENT *c = rpc->Param;
+ PACK *ret;
+ // Validate arguments
+ if (rpc == NULL || name == NULL || p == NULL)
+ {
+ return NULL;
+ }
+
+ ret = NewPack();
+
+ if (StrCmpi(name, "GetClientVersion") == 0)
+ {
+ RPC_CLIENT_VERSION a;
+ if (CtGetClientVersion(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientVersion(ret, &a);
+ }
+ }
+ else if (StrCmpi(name, "GetCmSetting") == 0)
+ {
+ CM_SETTING a;
+ if (CtGetCmSetting(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcCmSetting(ret, &a);
+ }
+ }
+ else if (StrCmpi(name, "SetCmSetting") == 0)
+ {
+ CM_SETTING a;
+ Zero(&a, sizeof(a));
+ InRpcCmSetting(&a, p);
+ if (CtSetCmSetting(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "SetPassword") == 0)
+ {
+ RPC_CLIENT_PASSWORD a;
+ InRpcClientPassword(&a, p);
+ if (CtSetPassword(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "GetPasswordSetting") == 0)
+ {
+ RPC_CLIENT_PASSWORD_SETTING a;
+ if (CtGetPasswordSetting(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientPasswordSetting(ret, &a);
+ }
+ }
+ else if (StrCmpi(name, "EnumCa") == 0)
+ {
+ RPC_CLIENT_ENUM_CA a;
+ if (CtEnumCa(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientEnumCa(ret, &a);
+ CiFreeClientEnumCa(&a);
+ }
+ }
+ else if (StrCmpi(name, "AddCa") == 0)
+ {
+ RPC_CERT a;
+ InRpcCert(&a, p);
+ if (CtAddCa(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ FreeX(a.x);
+ }
+ else if (StrCmpi(name, "DeleteCa") == 0)
+ {
+ RPC_CLIENT_DELETE_CA a;
+ InRpcClientDeleteCa(&a, p);
+ if (CtDeleteCa(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "GetCa") == 0)
+ {
+ RPC_GET_CA a;
+ InRpcGetCa(&a, p);
+ if (CtGetCa(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcGetCa(ret, &a);
+ }
+ CiFreeGetCa(&a);
+ }
+ else if (StrCmpi(name, "EnumSecure") == 0)
+ {
+ RPC_CLIENT_ENUM_SECURE a;
+ if (CtEnumSecure(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientEnumSecure(ret, &a);
+ CiFreeClientEnumSecure(&a);
+ }
+ }
+ else if (StrCmpi(name, "UseSecure") == 0)
+ {
+ RPC_USE_SECURE a;
+ InRpcUseSecure(&a, p);
+ if (CtUseSecure(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "GetUseSecure") == 0)
+ {
+ RPC_USE_SECURE a;
+ Zero(&a, sizeof(a));
+ if (CtGetUseSecure(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcUseSecure(ret, &a);
+ }
+ }
+ else if (StrCmpi(name, "EnumObjectInSecure") == 0)
+ {
+ RPC_ENUM_OBJECT_IN_SECURE a;
+ if (CtEnumObjectInSecure(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcEnumObjectInSecure(ret, &a);
+ CiFreeEnumObjectInSecure(&a);
+ }
+ }
+ else if (StrCmpi(name, "CreateVLan") == 0)
+ {
+ RPC_CLIENT_CREATE_VLAN a;
+ InRpcCreateVLan(&a, p);
+ if (CtCreateVLan(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "UpgradeVLan") == 0)
+ {
+ RPC_CLIENT_CREATE_VLAN a;
+ InRpcCreateVLan(&a, p);
+ if (CtUpgradeVLan(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "GetVLan") == 0)
+ {
+ RPC_CLIENT_GET_VLAN a;
+ InRpcClientGetVLan(&a, p);
+ if (CtGetVLan(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientGetVLan(ret, &a);
+ }
+ }
+ else if (StrCmpi(name, "SetVLan") == 0)
+ {
+ RPC_CLIENT_SET_VLAN a;
+ InRpcClientSetVLan(&a, p);
+ if (CtSetVLan(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "EnumVLan") == 0)
+ {
+ RPC_CLIENT_ENUM_VLAN a;
+ if (CtEnumVLan(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientEnumVLan(ret, &a);
+ CiFreeClientEnumVLan(&a);
+ }
+ }
+ else if (StrCmpi(name, "DeleteVLan") == 0)
+ {
+ RPC_CLIENT_CREATE_VLAN a;
+ InRpcCreateVLan(&a, p);
+ if (CtDeleteVLan(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "EnableVLan") == 0)
+ {
+ RPC_CLIENT_CREATE_VLAN a;
+ InRpcCreateVLan(&a, p);
+ if (CtEnableVLan(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "DisableVLan") == 0)
+ {
+ RPC_CLIENT_CREATE_VLAN a;
+ InRpcCreateVLan(&a, p);
+ if (CtDisableVLan(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "CreateAccount") == 0)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT a;
+ InRpcClientCreateAccount(&a, p);
+ if (CtCreateAccount(c, &a, false) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ CiFreeClientCreateAccount(&a);
+ }
+ else if (StrCmpi(name, "EnumAccount") == 0)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT a;
+ if (CtEnumAccount(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientEnumAccount(ret, &a);
+ CiFreeClientEnumAccount(&a);
+ }
+ }
+ else if (StrCmpi(name, "DeleteAccount") == 0)
+ {
+ RPC_CLIENT_DELETE_ACCOUNT a;
+ InRpcClientDeleteAccount(&a, p);
+ if (CtDeleteAccount(c, &a, false) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "SetStartupAccount") == 0)
+ {
+ RPC_CLIENT_DELETE_ACCOUNT a;
+ InRpcClientDeleteAccount(&a, p);
+ if (CtSetStartupAccount(c, &a, false) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "RemoveStartupAccount") == 0)
+ {
+ RPC_CLIENT_DELETE_ACCOUNT a;
+ InRpcClientDeleteAccount(&a, p);
+ if (CtRemoveStartupAccount(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "GetIssuer") == 0)
+ {
+ RPC_GET_ISSUER a;
+ InRpcGetIssuer(&a, p);
+ if (CtGetIssuer(c, &a))
+ {
+ OutRpcGetIssuer(ret, &a);
+ }
+ else
+ {
+ RpcError(ret, c->Err);
+ }
+ CiFreeGetIssuer(&a);
+ }
+ else if (StrCmpi(name, "GetCommonProxySetting") == 0)
+ {
+ INTERNET_SETTING t;
+ InRpcInternetSetting(&t, p);
+ if (CtGetCommonProxySetting(c, &t))
+ {
+ OutRpcInternetSetting(ret, &t);
+ }
+ else
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "SetCommonProxySetting") == 0)
+ {
+ INTERNET_SETTING t;
+ InRpcInternetSetting(&t, p);
+ if (CtSetCommonProxySetting(c, &t))
+ {
+ OutRpcInternetSetting(ret, &t);
+ }
+ else
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "SetAccount") == 0)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT a;
+ InRpcClientCreateAccount(&a, p);
+ if (CtSetAccount(c, &a, false) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ CiFreeClientCreateAccount(&a);
+ }
+ else if (StrCmpi(name, "GetAccount") == 0)
+ {
+ RPC_CLIENT_GET_ACCOUNT a;
+ InRpcClientGetAccount(&a, p);
+ if (CtGetAccount(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientGetAccount(ret, &a);
+ }
+ CiFreeClientGetAccount(&a);
+ }
+ else if (StrCmpi(name, "RenameAccount") == 0)
+ {
+ RPC_RENAME_ACCOUNT a;
+ InRpcRenameAccount(&a, p);
+ if (CtRenameAccount(c, &a, false) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "SetClientConfig") == 0)
+ {
+ CLIENT_CONFIG a;
+ InRpcClientConfig(&a, p);
+ if (CtSetClientConfig(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "GetClientConfig") == 0)
+ {
+ CLIENT_CONFIG a;
+ if (CtGetClientConfig(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientConfig(ret, &a);
+ }
+ }
+ else if (StrCmpi(name, "Connect") == 0)
+ {
+ RPC_CLIENT_CONNECT a;
+ InRpcClientConnect(&a, p);
+ if (CtConnect(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "Disconnect") == 0)
+ {
+ RPC_CLIENT_CONNECT a;
+ InRpcClientConnect(&a, p);
+ if (CtDisconnect(c, &a, false) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ }
+ else if (StrCmpi(name, "GetAccountStatus") == 0)
+ {
+ RPC_CLIENT_GET_CONNECTION_STATUS a;
+ InRpcClientGetConnectionStatus(&a, p);
+ if (CtGetAccountStatus(c, &a) == false)
+ {
+ RpcError(ret, c->Err);
+ }
+ else
+ {
+ OutRpcClientGetConnectionStatus(ret, &a);
+ }
+ CiFreeClientGetConnectionStatus(&a);
+ }
+ else
+ {
+ FreePack(ret);
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+// Set the CM_SETTING
+UINT CcSetCmSetting(REMOTE_CLIENT *r, CM_SETTING *a)
+{
+ PACK *ret, *p;
+ UINT err;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcCmSetting(p, a);
+
+ ret = RpcCall(r->Rpc, "SetCmSetting", p);
+
+ if (RpcIsOk(ret))
+ {
+ FreePack(ret);
+ return 0;
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ FreePack(ret);
+ return err;
+ }
+}
+
+// Get the CM_SETTING
+UINT CcGetCmSetting(REMOTE_CLIENT *r, CM_SETTING *a)
+{
+ PACK *ret;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = RpcCall(r->Rpc, "GetCmSetting", NULL);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcCmSetting(a, ret);
+ FreePack(ret);
+ return 0;
+ }
+ else
+ {
+ UINT err = RpcGetError(ret);
+ FreePack(ret);
+ return err;
+ }
+}
+
+// Get the client version
+UINT CcGetClientVersion(REMOTE_CLIENT *r, RPC_CLIENT_VERSION *a)
+{
+ PACK *ret;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = RpcCall(r->Rpc, "GetClientVersion", NULL);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcClientVersion(a, ret);
+ FreePack(ret);
+ return 0;
+ }
+ else
+ {
+ UINT err = RpcGetError(ret);
+ FreePack(ret);
+ return err;
+ }
+}
+
+// Set the password
+UINT CcSetPassword(REMOTE_CLIENT *r, RPC_CLIENT_PASSWORD *pass)
+{
+ PACK *ret, *p;
+ // Validate arguments
+ if (r == NULL || pass == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+
+ OutRpcClientPassword(p, pass);
+
+ ret = RpcCall(r->Rpc, "SetPassword", p);
+
+ if (RpcIsOk(ret))
+ {
+ FreePack(ret);
+ return 0;
+ }
+ else
+ {
+ UINT err = RpcGetError(ret);
+ FreePack(ret);
+ return err;
+ }
+}
+
+// Get the password setting
+UINT CcGetPasswordSetting(REMOTE_CLIENT *r, RPC_CLIENT_PASSWORD_SETTING *a)
+{
+ PACK *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = RpcCall(r->Rpc, "GetPasswordSetting", NULL);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcClientPasswordSetting(a, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+ return err;
+}
+
+// Enumerate the CA
+UINT CcEnumCa(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_CA *e)
+{
+ PACK *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || e == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = RpcCall(r->Rpc, "EnumCa", NULL);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcClientEnumCa(e, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Add the CA
+UINT CcAddCa(REMOTE_CLIENT *r, RPC_CERT *cert)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || cert == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcCert(p, cert);
+
+ ret = RpcCall(r->Rpc, "AddCa", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Delete the CA
+UINT CcDeleteCa(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_CA *c)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || c == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientDeleteCa(p, c);
+
+ ret = RpcCall(r->Rpc, "DeleteCa", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+
+// Get the proxy setting
+UINT CcGetCommonProxySetting(REMOTE_CLIENT *r, INTERNET_SETTING *a)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcInternetSetting(p, a);
+
+ ret = RpcCall(r->Rpc, "GetCommonProxySetting", p);
+
+ if (RpcIsOk(ret))
+ {
+ Zero(a, sizeof(INTERNET_SETTING));
+ InRpcInternetSetting(a, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Set the proxy setting
+UINT CcSetCommonProxySetting(REMOTE_CLIENT *r, INTERNET_SETTING *a)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcInternetSetting(p, a);
+
+ ret = RpcCall(r->Rpc, "SetCommonProxySetting", p);
+
+ if (RpcIsOk(ret))
+ {
+ Zero(a, sizeof(INTERNET_SETTING));
+ InRpcInternetSetting(a, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Get the issuer
+UINT CcGetIssuer(REMOTE_CLIENT *r, RPC_GET_ISSUER *a)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcGetIssuer(p, a);
+
+ ret = RpcCall(r->Rpc, "GetIssuer", p);
+
+ if (RpcIsOk(ret))
+ {
+ if (a->x != NULL)
+ {
+ FreeX(a->x);
+ a->x = NULL;
+ }
+ InRpcGetIssuer(a, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Get the CA
+UINT CcGetCa(REMOTE_CLIENT *r, RPC_GET_CA *get)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || get == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcGetCa(p, get);
+
+ ret = RpcCall(r->Rpc, "GetCa", p);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcGetCa(get, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Enumeration of the secure devices
+UINT CcEnumSecure(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_SECURE *e)
+{
+ PACK *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || e == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = RpcCall(r->Rpc, "EnumSecure", NULL);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcClientEnumSecure(e, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Get the secure device that the user is using
+UINT CcGetUseSecure(REMOTE_CLIENT *r, RPC_USE_SECURE *sec)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || sec == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+
+ ret = RpcCall(r->Rpc, "GetUseSecure", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+ else
+ {
+ InRpcUseSecure(sec, ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Use the secure device
+UINT CcUseSecure(REMOTE_CLIENT *r, RPC_USE_SECURE *sec)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || sec == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcUseSecure(p, sec);
+
+ ret = RpcCall(r->Rpc, "UseSecure", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Enumerate objects in the secure device
+UINT CcEnumObjectInSecure(REMOTE_CLIENT *r, RPC_ENUM_OBJECT_IN_SECURE *e)
+{
+ PACK *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || e == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = RpcCall(r->Rpc, "EnumObjectInSecure", NULL);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcEnumObjectInSecure(e, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Get a next recommended virtual LAN card name
+bool CiGetNextRecommendedVLanName(REMOTE_CLIENT *r, char *name, UINT size)
+{
+ RPC_CLIENT_ENUM_VLAN t;
+ UINT i;
+ bool b;
+ UINT j;
+ bool ok = false;
+ // Validate arguments
+ if (r == NULL || name == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+
+ if (CcEnumVLan(r, &t) != ERR_NO_ERROR)
+ {
+ return false;
+ }
+
+ for (i = 1;i < 128;i++)
+ {
+ char tmp[MAX_SIZE];
+
+ CiGenerateVLanRegulatedName(tmp, sizeof(tmp), i);
+
+ b = false;
+
+ for (j = 0;j < t.NumItem;j++)
+ {
+ if (StrCmpi(t.Items[j]->DeviceName, tmp) == 0)
+ {
+ b = true;
+ break;
+ }
+ }
+
+ if (b == false)
+ {
+ ok = true;
+
+ StrCpy(name, size, tmp);
+ break;
+ }
+ }
+
+ if (ok)
+ {
+ CiFreeClientEnumVLan(&t);
+ }
+
+ return true;
+}
+
+// Generate a virtual LAN card name automatically
+void CiGenerateVLanRegulatedName(char *name, UINT size, UINT i)
+{
+ // Validate arguments
+ if (name == NULL)
+ {
+ return;
+ }
+
+ if (i == 1)
+ {
+ StrCpy(name, size, "VPN");
+ }
+ else
+ {
+ Format(name, size, "VPN%u", i);
+ }
+}
+
+// Examine whether the specified name is valid as a virtual LAN card name of Windows 8 and later?
+bool CiIsValidVLanRegulatedName(char *name)
+{
+ UINT i;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return false;
+ }
+
+ for (i = 1;i < 128;i++)
+ {
+ char tmp[MAX_SIZE];
+
+ CiGenerateVLanRegulatedName(tmp, sizeof(tmp), i);
+
+ if (StrCmpi(name, tmp) == 0)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Create a VLAN
+UINT CcCreateVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *create)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ char *s = NULL;
+ // Validate arguments
+ if (r == NULL || create == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcCreateVLan(p, create);
+
+#ifdef OS_WIN32
+ s = MsNoWarningSoundInit();
+#endif // OS_WIN32
+
+ ret = RpcCall(r->Rpc, "CreateVLan", p);
+
+#ifdef OS_WIN32
+ MsNoWarningSoundFree(s);
+#endif // OS_WIN32
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Upgrade the VLAN
+UINT CcUpgradeVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *create)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ char *s = NULL;
+ // Validate arguments
+ if (r == NULL || create == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcCreateVLan(p, create);
+
+#ifdef OS_WIN32
+ s = MsNoWarningSoundInit();
+#endif // OS_WIN32
+
+ ret = RpcCall(r->Rpc, "UpgradeVLan", p);
+
+#ifdef OS_WIN32
+ MsNoWarningSoundFree(s);
+#endif // OS_WIN32
+
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Get the VLAN
+UINT CcGetVLan(REMOTE_CLIENT *r, RPC_CLIENT_GET_VLAN *get)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || get == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientGetVLan(p, get);
+
+ ret = RpcCall(r->Rpc, "GetVLan", p);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcClientGetVLan(get, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// VLAN configuration
+UINT CcSetVLan(REMOTE_CLIENT *r, RPC_CLIENT_SET_VLAN *set)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || set == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientSetVLan(p, set);
+
+ ret = RpcCall(r->Rpc, "SetVLan", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Enumeration of VLAN
+UINT CcEnumVLan(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_VLAN *e)
+{
+ PACK *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || e == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = RpcCall(r->Rpc, "EnumVLan", NULL);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcClientEnumVLan(e, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Delete the VLAN
+UINT CcDeleteVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *d)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || d == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcCreateVLan(p, d);
+
+ ret = RpcCall(r->Rpc, "DeleteVLan", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Enable the VLAN
+UINT CcEnableVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *vlan)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || vlan == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcCreateVLan(p, vlan);
+
+ ret = RpcCall(r->Rpc, "EnableVLan", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Disable the VLAN
+UINT CcDisableVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *vlan)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || vlan == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcCreateVLan(p, vlan);
+
+ ret = RpcCall(r->Rpc, "DisableVLan", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Create an Account
+UINT CcCreateAccount(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_ACCOUNT *a)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientCreateAccount(p, a);
+
+ ret = RpcCall(r->Rpc, "CreateAccount", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Enumeration of accounts
+UINT CcEnumAccount(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_ACCOUNT *e)
+{
+ PACK *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || e == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = RpcCall(r->Rpc, "EnumAccount", NULL);
+
+ if (RpcIsOk(ret))
+ {
+ UINT i;
+ InRpcClientEnumAccount(e, ret);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *t = e->Items[i];
+
+ if (IsEmptyStr(t->HubName) && t->Port == 0)
+ {
+ UINT err2;
+ RPC_CLIENT_GET_ACCOUNT a;
+
+ // Because the Client Manager can not get the port number and HUB name
+ // when enumerating in the VPN Client of the old version, get these separately.
+ Zero(&a, sizeof(a));
+ UniStrCpy(a.AccountName, sizeof(a.AccountName), t->AccountName);
+ err2 = CcGetAccount(r, &a);
+ if (err2 == ERR_NO_ERROR)
+ {
+ StrCpy(t->HubName, sizeof(t->HubName), a.ClientOption->HubName);
+ t->Port = a.ClientOption->Port;
+
+ CiFreeClientGetAccount(&a);
+ }
+ }
+ }
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Unset the startup flag of the accout
+UINT CcRemoveStartupAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientDeleteAccount(p, a);
+
+ ret = RpcCall(r->Rpc, "RemoveStartupAccount", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Set to start-up flag of the account
+UINT CcSetStartupAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientDeleteAccount(p, a);
+
+ ret = RpcCall(r->Rpc, "SetStartupAccount", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Delete the account
+UINT CcDeleteAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientDeleteAccount(p, a);
+
+ ret = RpcCall(r->Rpc, "DeleteAccount", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Account setting
+UINT CcSetAccount(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_ACCOUNT *a)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientCreateAccount(p, a);
+
+ ret = RpcCall(r->Rpc, "SetAccount", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Get the account
+UINT CcGetAccount(REMOTE_CLIENT *r, RPC_CLIENT_GET_ACCOUNT *a)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || a == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientGetAccount(p, a);
+
+ ret = RpcCall(r->Rpc, "GetAccount", p);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcClientGetAccount(a, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Change the account name
+UINT CcRenameAccount(REMOTE_CLIENT *r, RPC_RENAME_ACCOUNT *rename)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || rename == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcRenameAccount(p, rename);
+
+ ret = RpcCall(r->Rpc, "RenameAccount", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Set the Client configuration
+UINT CcSetClientConfig(REMOTE_CLIENT *r, CLIENT_CONFIG *o)
+{
+ PACK *p, *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || o == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientConfig(p, o);
+
+ ret = RpcCall(r->Rpc, "SetClientConfig", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Get the client configuration
+UINT CcGetClientConfig(REMOTE_CLIENT *r, CLIENT_CONFIG *o)
+{
+ PACK *ret;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || o == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = RpcCall(r->Rpc, "GetClientConfig", NULL);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcClientConfig(o, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Set the service to foreground process
+void CcSetServiceToForegroundProcess(REMOTE_CLIENT *r)
+{
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+ // Abolition
+/*
+ if (r->Rpc != NULL && r->Rpc->Sock != NULL && r->Rpc->Sock->RemoteIP.addr[0] == 127)
+ {
+ if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) &&
+ GET_KETA(GetOsInfo()->OsType, 100) >= 2)
+ {
+ // Only on a Windows 2000 or later
+ RPC_CLIENT_VERSION v;
+ Zero(&v, sizeof(v));
+
+ if (r->ClientBuildInt == 0)
+ {
+ CcGetClientVersion(r, &v);
+ r->ClientBuildInt = v.ClientBuildInt;
+ r->ProcessId = v.ProcessId;
+ }
+ if (r->ProcessId != 0 && r->ClientBuildInt <= 5080)
+ {
+#ifdef OS_WIN32
+ // Set the service process as a foreground window
+ AllowFGWindow(v.ProcessId);
+#endif // OS_WIN32
+ }
+ }
+ }*/
+}
+
+// Connect
+UINT CcConnect(REMOTE_CLIENT *r, RPC_CLIENT_CONNECT *connect)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || connect == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ CcSetServiceToForegroundProcess(r);
+
+ p = NewPack();
+ OutRpcClientConnect(p, connect);
+
+ ret = RpcCall(r->Rpc, "Connect", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Disconnect
+UINT CcDisconnect(REMOTE_CLIENT *r, RPC_CLIENT_CONNECT *connect)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || connect == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ CcSetServiceToForegroundProcess(r);
+
+ p = NewPack();
+ OutRpcClientConnect(p, connect);
+
+ ret = RpcCall(r->Rpc, "Disconnect", p);
+
+ if (RpcIsOk(ret) == false)
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+// Get the account status
+UINT CcGetAccountStatus(REMOTE_CLIENT *r, RPC_CLIENT_GET_CONNECTION_STATUS *st)
+{
+ PACK *ret, *p;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || st == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ p = NewPack();
+ OutRpcClientGetConnectionStatus(p, st);
+
+ ret = RpcCall(r->Rpc, "GetAccountStatus", p);
+
+ if (RpcIsOk(ret))
+ {
+ InRpcClientGetConnectionStatus(st, ret);
+ }
+ else
+ {
+ err = RpcGetError(ret);
+ }
+
+ FreePack(ret);
+
+ return err;
+}
+
+
+// Client service sends a notification to the connection manager
+void CiNotify(CLIENT *c)
+{
+ CiNotifyInternal(c);
+}
+void CiNotifyInternal(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Set all the notification event
+ LockList(c->NotifyCancelList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(c->NotifyCancelList);i++)
+ {
+ CANCEL *cancel = LIST_DATA(c->NotifyCancelList, i);
+ Cancel(cancel);
+ }
+ }
+ UnlockList(c->NotifyCancelList);
+}
+
+// Release the RPC_CLIENT_ENUM_ACCOUNT
+void CiFreeClientEnumAccount(RPC_CLIENT_ENUM_ACCOUNT *a)
+{
+ UINT i;
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < a->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *e = a->Items[i];
+ Free(e);
+ }
+ Free(a->Items);
+}
+
+
+// Thread to save the configuration file periodically
+void CiSaverThread(THREAD *t, void *param)
+{
+ CLIENT *c = (CLIENT *)param;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ NoticeThreadInit(t);
+
+ // Wait for a certain period of time
+ while (c->Halt == false)
+ {
+ Wait(c->SaverHalter, CLIENT_SAVER_INTERVAL);
+
+ // Save
+ CiSaveConfigurationFile(c);
+ }
+}
+
+// Initialize the Saver
+void CiInitSaver(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->SaverHalter = NewEvent();
+
+ c->SaverThread = NewThread(CiSaverThread, c);
+ WaitThreadInit(c->SaverThread);
+}
+
+// Release the Saver
+void CiFreeSaver(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->Halt = true;
+ Set(c->SaverHalter);
+ WaitThread(c->SaverThread, INFINITE);
+ ReleaseThread(c->SaverThread);
+
+ ReleaseEvent(c->SaverHalter);
+}
+
+// CM_SETTING
+void InRpcCmSetting(CM_SETTING *c, PACK *p)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(CM_SETTING));
+ c->EasyMode = PackGetBool(p, "EasyMode");
+ c->LockMode = PackGetBool(p, "LockMode");
+ PackGetData2(p, "HashedPassword", c->HashedPassword, sizeof(c->HashedPassword));
+}
+void OutRpcCmSetting(PACK *p, CM_SETTING *c)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "EasyMode", c->EasyMode);
+ PackAddBool(p, "LockMode", c->LockMode);
+ PackAddData(p, "HashedPassword", c->HashedPassword, sizeof(c->HashedPassword));
+}
+
+// CLIENT_CONFIG
+void InRpcClientConfig(CLIENT_CONFIG *c, PACK *p)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(CLIENT_CONFIG));
+ c->UseKeepConnect = PackGetInt(p, "UseKeepConnect") == 0 ? false : true;
+ c->KeepConnectPort = PackGetInt(p, "KeepConnectPort");
+ c->KeepConnectProtocol = PackGetInt(p, "KeepConnectProtocol");
+ c->KeepConnectInterval = PackGetInt(p, "KeepConnectInterval");
+ c->AllowRemoteConfig = PackGetInt(p, "AllowRemoteConfig") == 0 ? false : true;
+ PackGetStr(p, "KeepConnectHost", c->KeepConnectHost, sizeof(c->KeepConnectHost));
+}
+void OutRpcClientConfig(PACK *p, CLIENT_CONFIG *c)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "UseKeepConnect", c->UseKeepConnect);
+ PackAddInt(p, "KeepConnectPort", c->KeepConnectPort);
+ PackAddInt(p, "KeepConnectProtocol", c->KeepConnectProtocol);
+ PackAddInt(p, "KeepConnectInterval", c->KeepConnectInterval);
+ PackAddInt(p, "AllowRemoteConfig", c->AllowRemoteConfig);
+ PackAddStr(p, "KeepConnectHost", c->KeepConnectHost);
+}
+
+// RPC_CLIENT_VERSION
+void InRpcClientVersion(RPC_CLIENT_VERSION *ver, PACK *p)
+{
+ // Validate arguments
+ if (ver == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(ver, sizeof(RPC_CLIENT_VERSION));
+ PackGetStr(p, "ClientProductName", ver->ClientProductName, sizeof(ver->ClientProductName));
+ PackGetStr(p, "ClientVersionString", ver->ClientVersionString, sizeof(ver->ClientVersionString));
+ PackGetStr(p, "ClientBuildInfoString", ver->ClientBuildInfoString, sizeof(ver->ClientBuildInfoString));
+ ver->ClientVerInt = PackGetInt(p, "ClientVerInt");
+ ver->ClientBuildInt = PackGetInt(p, "ClientBuildInt");
+ ver->ProcessId = PackGetInt(p, "ProcessId");
+ ver->OsType = PackGetInt(p, "OsType");
+ ver->IsVLanNameRegulated = PackGetBool(p, "IsVLanNameRegulated");
+ ver->IsVgcSupported = PackGetBool(p, "IsVgcSupported");
+ ver->ShowVgcLink = PackGetBool(p, "ShowVgcLink");
+ PackGetStr(p, "ClientId", ver->ClientId, sizeof(ver->ClientId));
+}
+void OutRpcClientVersion(PACK *p, RPC_CLIENT_VERSION *ver)
+{
+ // Validate arguments
+ if (ver == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "ClientProductName", ver->ClientProductName);
+ PackAddStr(p, "ClientVersionString", ver->ClientVersionString);
+ PackAddStr(p, "ClientBuildInfoString", ver->ClientBuildInfoString);
+ PackAddInt(p, "ClientVerInt", ver->ClientVerInt);
+ PackAddInt(p, "ClientBuildInt", ver->ClientBuildInt);
+ PackAddInt(p, "ProcessId", ver->ProcessId);
+ PackAddInt(p, "OsType", ver->OsType);
+ PackAddBool(p, "IsVLanNameRegulated", ver->IsVLanNameRegulated);
+ PackAddBool(p, "IsVgcSupported", ver->IsVgcSupported);
+ PackAddBool(p, "ShowVgcLink", ver->ShowVgcLink);
+ PackAddStr(p, "ClientId", ver->ClientId);
+}
+
+// RPC_CLIENT_PASSWORD
+void InRpcClientPassword(RPC_CLIENT_PASSWORD *pw, PACK *p)
+{
+ // Validate arguments
+ if (pw == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(pw, sizeof(RPC_CLIENT_PASSWORD));
+ PackGetStr(p, "Password", pw->Password, sizeof(pw->Password));
+ pw->PasswordRemoteOnly = PackGetInt(p, "PasswordRemoteOnly");
+}
+void OutRpcClientPassword(PACK *p, RPC_CLIENT_PASSWORD *pw)
+{
+ // Validate arguments
+ if (pw == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "Password", pw->Password);
+ PackAddInt(p, "PasswordRemoteOnly", pw->PasswordRemoteOnly);
+}
+
+// RPC_CLIENT_PASSWORD_SETTING
+void InRpcClientPasswordSetting(RPC_CLIENT_PASSWORD_SETTING *a, PACK *p)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(a, sizeof(RPC_CLIENT_PASSWORD_SETTING));
+
+ a->IsPasswordPresented = PackGetInt(p, "IsPasswordPresented") == 0 ? false : true;
+ a->PasswordRemoteOnly = PackGetInt(p, "PasswordRemoteOnly") == 0 ? false : true;
+}
+void OutRpcClientPasswordSetting(PACK *p, RPC_CLIENT_PASSWORD_SETTING *a)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "IsPasswordPresented", a->IsPasswordPresented);
+ PackAddInt(p, "PasswordRemoteOnly", a->PasswordRemoteOnly);
+}
+
+// RPC_CLIENT_ENUM_CA
+void InRpcClientEnumCa(RPC_CLIENT_ENUM_CA *e, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(e, sizeof(RPC_CLIENT_ENUM_CA));
+ e->NumItem = PackGetNum(p, "NumItem");
+
+ e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM *) * e->NumItem);
+ for (i = 0;i < e->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_CA_ITEM *item = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM));
+ e->Items[i] = item;
+
+ item->Key = PackGetIntEx(p, "Key", i);
+ PackGetUniStrEx(p, "SubjectName", item->SubjectName, sizeof(item->SubjectName), i);
+ PackGetUniStrEx(p, "IssuerName", item->IssuerName, sizeof(item->IssuerName), i);
+ item->Expires = PackGetInt64Ex(p, "Expires", i);
+ }
+}
+void OutRpcClientEnumCa(PACK *p, RPC_CLIENT_ENUM_CA *e)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddNum(p, "NumItem", e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_CA_ITEM *item = e->Items[i];
+ PackAddIntEx(p, "Key", item->Key, i, e->NumItem);
+ PackAddUniStrEx(p, "SubjectName", item->SubjectName, i, e->NumItem);
+ PackAddUniStrEx(p, "IssuerName", item->IssuerName, i, e->NumItem);
+ PackAddInt64Ex(p, "Expires", item->Expires, i, e->NumItem);
+ }
+}
+
+// RPC_GET_ISSUER
+void InRpcGetIssuer(RPC_GET_ISSUER *c, PACK *p)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(RPC_GET_ISSUER));
+ b = PackGetBuf(p, "x");
+ if (b != NULL)
+ {
+ if (c->x != NULL)
+ {
+ FreeX(c->x);
+ }
+ c->x = BufToX(b, false);
+ FreeBuf(b);
+ }
+
+ b = PackGetBuf(p, "issuer_x");
+ if (b != NULL)
+ {
+ c->issuer_x = BufToX(b, false);
+ FreeBuf(b);
+ }
+}
+void OutRpcGetIssuer(PACK *p, RPC_GET_ISSUER *c)
+{
+ BUF *b;
+ // Validate arguments
+ if (p == NULL || c == NULL)
+ {
+ return;
+ }
+
+ if (c->x != NULL)
+ {
+ b = XToBuf(c->x, false);
+
+ PackAddBuf(p, "x", b);
+ FreeBuf(b);
+ }
+
+ if (c->issuer_x != NULL)
+ {
+ b = XToBuf(c->issuer_x, false);
+
+ PackAddBuf(p, "issuer_x", b);
+ FreeBuf(b);
+ }
+}
+
+// TRAFFIC_EX
+void InRpcTrafficEx(TRAFFIC *t, PACK *p, UINT i)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(TRAFFIC));
+ t->Recv.BroadcastBytes = PackGetInt64Ex(p, "Ex.Recv.BroadcastBytes", i);
+ t->Recv.BroadcastCount = PackGetInt64Ex(p, "Ex.Recv.BroadcastCount", i);
+ t->Recv.UnicastBytes = PackGetInt64Ex(p, "Ex.Recv.UnicastBytes", i);
+ t->Recv.UnicastCount = PackGetInt64Ex(p, "Ex.Recv.UnicastCount", i);
+ t->Send.BroadcastBytes = PackGetInt64Ex(p, "Ex.Send.BroadcastBytes", i);
+ t->Send.BroadcastCount = PackGetInt64Ex(p, "Ex.Send.BroadcastCount", i);
+ t->Send.UnicastBytes = PackGetInt64Ex(p, "Ex.Send.UnicastBytes", i);
+ t->Send.UnicastCount = PackGetInt64Ex(p, "Ex.Send.UnicastCount", i);
+}
+void OutRpcTrafficEx(TRAFFIC *t, PACK *p, UINT i, UINT num)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt64Ex(p, "Ex.Recv.BroadcastBytes", t->Recv.BroadcastBytes, i, num);
+ PackAddInt64Ex(p, "Ex.Recv.BroadcastCount", t->Recv.BroadcastCount, i, num);
+ PackAddInt64Ex(p, "Ex.Recv.UnicastBytes", t->Recv.UnicastBytes, i, num);
+ PackAddInt64Ex(p, "Ex.Recv.UnicastCount", t->Recv.UnicastCount, i, num);
+ PackAddInt64Ex(p, "Ex.Send.BroadcastBytes", t->Send.BroadcastBytes, i, num);
+ PackAddInt64Ex(p, "Ex.Send.BroadcastCount", t->Send.BroadcastCount, i, num);
+ PackAddInt64Ex(p, "Ex.Send.UnicastBytes", t->Send.UnicastBytes, i, num);
+ PackAddInt64Ex(p, "Ex.Send.UnicastCount", t->Send.UnicastCount, i, num);
+}
+
+// TRAFFIC
+void InRpcTraffic(TRAFFIC *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(TRAFFIC));
+ t->Recv.BroadcastBytes = PackGetInt64(p, "Recv.BroadcastBytes");
+ t->Recv.BroadcastCount = PackGetInt64(p, "Recv.BroadcastCount");
+ t->Recv.UnicastBytes = PackGetInt64(p, "Recv.UnicastBytes");
+ t->Recv.UnicastCount = PackGetInt64(p, "Recv.UnicastCount");
+ t->Send.BroadcastBytes = PackGetInt64(p, "Send.BroadcastBytes");
+ t->Send.BroadcastCount = PackGetInt64(p, "Send.BroadcastCount");
+ t->Send.UnicastBytes = PackGetInt64(p, "Send.UnicastBytes");
+ t->Send.UnicastCount = PackGetInt64(p, "Send.UnicastCount");
+}
+void OutRpcTraffic(PACK *p, TRAFFIC *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt64(p, "Recv.BroadcastBytes", t->Recv.BroadcastBytes);
+ PackAddInt64(p, "Recv.BroadcastCount", t->Recv.BroadcastCount);
+ PackAddInt64(p, "Recv.UnicastBytes", t->Recv.UnicastBytes);
+ PackAddInt64(p, "Recv.UnicastCount", t->Recv.UnicastCount);
+ PackAddInt64(p, "Send.BroadcastBytes", t->Send.BroadcastBytes);
+ PackAddInt64(p, "Send.BroadcastCount", t->Send.BroadcastCount);
+ PackAddInt64(p, "Send.UnicastBytes", t->Send.UnicastBytes);
+ PackAddInt64(p, "Send.UnicastCount", t->Send.UnicastCount);
+}
+
+// RPC_CERT
+void InRpcCert(RPC_CERT *c, PACK *p)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(RPC_CERT));
+ b = PackGetBuf(p, "x");
+ if (b == NULL)
+ {
+ return;
+ }
+
+ c->x = BufToX(b, false);
+ FreeBuf(b);
+}
+void OutRpcCert(PACK *p, RPC_CERT *c)
+{
+ BUF *b;
+ // Validate arguments
+ if (p == NULL || c == NULL)
+ {
+ return;
+ }
+
+ if (c->x != NULL)
+ {
+ b = XToBuf(c->x, false);
+
+ PackAddBuf(p, "x", b);
+
+ FreeBuf(b);
+ }
+}
+
+// RPC_CLIENT_DELETE_CA
+void InRpcClientDeleteCa(RPC_CLIENT_DELETE_CA *c, PACK *p)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(RPC_CLIENT_DELETE_CA));
+ c->Key = PackGetInt(p, "Key");
+}
+void OutRpcClientDeleteCa(PACK *p, RPC_CLIENT_DELETE_CA *c)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "Key", c->Key);
+}
+
+// RPC_GET_CA
+void InRpcGetCa(RPC_GET_CA *c, PACK *p)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(RPC_GET_CA));
+
+ c->Key = PackGetInt(p, "Key");
+
+ b = PackGetBuf(p, "x");
+ if (b != NULL)
+ {
+ c->x = BufToX(b, false);
+
+ FreeBuf(b);
+ }
+}
+void OutRpcGetCa(PACK *p, RPC_GET_CA *c)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "Key", c->Key);
+
+ if (c->x != NULL)
+ {
+ BUF *b = XToBuf(c->x, false);
+
+ PackAddBuf(p, "x", b);
+
+ FreeBuf(b);
+ }
+}
+
+// RPC_CLIENT_ENUM_SECURE
+void InRpcClientEnumSecure(RPC_CLIENT_ENUM_SECURE *e, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(e, sizeof(RPC_CLIENT_ENUM_SECURE));
+
+ e->NumItem = PackGetNum(p, "NumItem");
+ e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM *) * e->NumItem);
+ for (i = 0;i < e->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_SECURE_ITEM *item = e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM));
+
+ item->DeviceId = PackGetIntEx(p, "DeviceId", i);
+ item->Type = PackGetIntEx(p, "Type", i);
+ PackGetStrEx(p, "DeviceName", item->DeviceName, sizeof(item->DeviceName), i);
+ PackGetStrEx(p, "Manufacturer", item->Manufacturer, sizeof(item->Manufacturer), i);
+ }
+}
+void OutRpcClientEnumSecure(PACK *p, RPC_CLIENT_ENUM_SECURE *e)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddNum(p, "NumItem", e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_SECURE_ITEM *item = e->Items[i];
+
+ PackAddIntEx(p, "DeviceId", item->DeviceId, i, e->NumItem);
+ PackAddIntEx(p, "Type", item->Type, i, e->NumItem);
+ PackAddStrEx(p, "DeviceName", item->DeviceName, i, e->NumItem);
+ PackAddStrEx(p, "Manufacturer", item->Manufacturer, i, e->NumItem);
+ }
+}
+
+// RPC_USE_SECURE
+void InRpcUseSecure(RPC_USE_SECURE *u, PACK *p)
+{
+ // Validate arguments
+ if (u == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(u, sizeof(RPC_USE_SECURE));
+ u->DeviceId = PackGetInt(p, "DeviceId");
+}
+void OutRpcUseSecure(PACK *p, RPC_USE_SECURE *u)
+{
+ // Validate arguments
+ if (u == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "DeviceId", u->DeviceId);
+}
+
+// Release the RPC_ENUM_OBJECT_IN_SECURE
+void CiFreeEnumObjectInSecure(RPC_ENUM_OBJECT_IN_SECURE *a)
+{
+ UINT i;
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < a->NumItem;i++)
+ {
+ Free(a->ItemName[i]);
+ }
+ Free(a->ItemName);
+ Free(a->ItemType);
+}
+
+// RPC_ENUM_OBJECT_IN_SECURE
+void InRpcEnumObjectInSecure(RPC_ENUM_OBJECT_IN_SECURE *e, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(e, sizeof(RPC_ENUM_OBJECT_IN_SECURE));
+
+ e->NumItem = PackGetNum(p, "NumItem");
+ e->hWnd = PackGetInt(p, "hWnd");
+ e->ItemName = ZeroMalloc(sizeof(char *) * e->NumItem);
+ e->ItemType = ZeroMalloc(sizeof(bool) * e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ char name[MAX_SIZE];
+
+ Zero(name, sizeof(name));
+ PackGetStrEx(p, "ItemName", name, sizeof(name), i);
+ e->ItemName[i] = CopyStr(name);
+
+ e->ItemType[i] = PackGetIntEx(p, "ItemType", i) ? true : false;
+ }
+}
+void OutRpcEnumObjectInSecure(PACK *p, RPC_ENUM_OBJECT_IN_SECURE *e)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddNum(p, "NumItem", e->NumItem);
+ PackAddInt(p, "hWnd", e->hWnd);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ PackAddStrEx(p, "ItemName", e->ItemName[i], i, e->NumItem);
+ PackAddIntEx(p, "ItemType", e->ItemType[i], i, e->NumItem);
+ }
+}
+
+// RPC_CLIENT_CREATE_VLAN
+void InRpcCreateVLan(RPC_CLIENT_CREATE_VLAN *v, PACK *p)
+{
+ // Validate arguments
+ if (v == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(v, sizeof(RPC_CLIENT_CREATE_VLAN));
+ PackGetStr(p, "DeviceName", v->DeviceName, sizeof(v->DeviceName));
+}
+void OutRpcCreateVLan(PACK *p, RPC_CLIENT_CREATE_VLAN *v)
+{
+ // Validate arguments
+ if (v == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "DeviceName", v->DeviceName);
+}
+
+// RPC_CLIENT_GET_VLAN
+void InRpcClientGetVLan(RPC_CLIENT_GET_VLAN *v, PACK *p)
+{
+ // Validate arguments
+ if (v == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(v, sizeof(RPC_CLIENT_GET_VLAN));
+ PackGetStr(p, "DeviceName", v->DeviceName, sizeof(v->DeviceName));
+ v->Enabled = PackGetInt(p, "Enabled") ? true : false;
+ PackGetStr(p, "MacAddress", v->MacAddress, sizeof(v->MacAddress));
+ PackGetStr(p, "Version", v->Version, sizeof(v->Version));
+ PackGetStr(p, "FileName", v->FileName, sizeof(v->FileName));
+ PackGetStr(p, "Guid", v->Guid, sizeof(v->Guid));
+}
+void OutRpcClientGetVLan(PACK *p, RPC_CLIENT_GET_VLAN *v)
+{
+ // Validate arguments
+ if (v == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "DeviceName", v->DeviceName);
+ PackAddInt(p, "Enabled", v->Enabled);
+ PackAddStr(p, "MacAddress", v->MacAddress);
+ PackAddStr(p, "Version", v->Version);
+ PackAddStr(p, "FileName", v->FileName);
+ PackAddStr(p, "Guid", v->Guid);
+}
+
+// RPC_CLIENT_SET_VLAN
+void InRpcClientSetVLan(RPC_CLIENT_SET_VLAN *v, PACK *p)
+{
+ // Validate arguments
+ if (v == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(v, sizeof(RPC_CLIENT_SET_VLAN));
+ PackGetStr(p, "DeviceName", v->DeviceName, sizeof(v->DeviceName));
+ PackGetStr(p, "MacAddress", v->MacAddress, sizeof(v->MacAddress));
+}
+void OutRpcClientSetVLan(PACK *p, RPC_CLIENT_SET_VLAN *v)
+{
+ // Validate arguments
+ if (v == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "DeviceName", v->DeviceName);
+ PackAddStr(p, "MacAddress", v->MacAddress);
+}
+
+// RPC_CLIENT_ENUM_VLAN
+void InRpcClientEnumVLan(RPC_CLIENT_ENUM_VLAN *v, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (v == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(v, sizeof(RPC_CLIENT_ENUM_VLAN));
+ v->NumItem = PackGetNum(p, "NumItem");
+ v->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM *) * v->NumItem);
+
+ for (i = 0;i < v->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_VLAN_ITEM *item = v->Items[i] =
+ ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM));
+
+ PackGetStrEx(p, "DeviceName", item->DeviceName, sizeof(item->DeviceName), i);
+ item->Enabled = PackGetIntEx(p, "Enabled", i) ? true : false;
+ PackGetStrEx(p, "MacAddress", item->MacAddress, sizeof(item->MacAddress), i);
+ PackGetStrEx(p, "Version", item->Version, sizeof(item->Version), i);
+ }
+}
+void OutRpcClientEnumVLan(PACK *p, RPC_CLIENT_ENUM_VLAN *v)
+{
+ UINT i;
+ // Validate arguments
+ if (v == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddNum(p, "NumItem", v->NumItem);
+
+ for (i = 0;i < v->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_VLAN_ITEM *item = v->Items[i];
+
+ PackAddStrEx(p, "DeviceName", item->DeviceName, i, v->NumItem);
+ PackAddIntEx(p, "Enabled", item->Enabled, i, v->NumItem);
+ PackAddStrEx(p, "MacAddress", item->MacAddress, i, v->NumItem);
+ PackAddStrEx(p, "Version", item->Version, i, v->NumItem);
+ }
+}
+
+// CLIENT_OPTION
+void InRpcClientOption(CLIENT_OPTION *c, PACK *p)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(CLIENT_OPTION));
+
+ PackGetUniStr(p, "AccountName", c->AccountName, sizeof(c->AccountName));
+ PackGetStr(p, "Hostname", c->Hostname, sizeof(c->Hostname));
+ c->Port = PackGetInt(p, "Port");
+ c->PortUDP = PackGetInt(p, "PortUDP");
+ c->ProxyType = PackGetInt(p, "ProxyType");
+ c->ProxyPort = PackGetInt(p, "ProxyPort");
+ c->NumRetry = PackGetInt(p, "NumRetry");
+ c->RetryInterval = PackGetInt(p, "RetryInterval");
+ c->MaxConnection = PackGetInt(p, "MaxConnection");
+ c->AdditionalConnectionInterval = PackGetInt(p, "AdditionalConnectionInterval");
+ c->ConnectionDisconnectSpan = PackGetInt(p, "ConnectionDisconnectSpan");
+ c->HideStatusWindow = PackGetBool(p, "HideStatusWindow");
+ c->HideNicInfoWindow = PackGetBool(p, "HideNicInfoWindow");
+ c->DisableQoS = PackGetBool(p, "DisableQoS");
+ PackGetStr(p, "ProxyName", c->ProxyName, sizeof(c->ProxyName));
+ PackGetStr(p, "ProxyUsername", c->ProxyUsername, sizeof(c->ProxyUsername));
+ PackGetStr(p, "ProxyPassword", c->ProxyPassword, sizeof(c->ProxyPassword));
+ PackGetStr(p, "HubName", c->HubName, sizeof(c->HubName));
+ PackGetStr(p, "DeviceName", c->DeviceName, sizeof(c->DeviceName));
+ c->UseEncrypt = PackGetInt(p, "UseEncrypt") ? true : false;
+ c->UseCompress = PackGetInt(p, "UseCompress") ? true : false;
+ c->HalfConnection = PackGetInt(p, "HalfConnection") ? true : false;
+ c->NoRoutingTracking = PackGetInt(p, "NoRoutingTracking") ? true : false;
+ c->RequireMonitorMode = PackGetBool(p, "RequireMonitorMode");
+ c->RequireBridgeRoutingMode = PackGetBool(p, "RequireBridgeRoutingMode");
+ c->FromAdminPack = PackGetBool(p, "FromAdminPack");
+ c->NoTls1 = PackGetBool(p, "NoTls1");
+ c->NoUdpAcceleration = PackGetBool(p, "NoUdpAcceleration");
+ PackGetData2(p, "HostUniqueKey", c->HostUniqueKey, SHA1_SIZE);
+}
+void OutRpcClientOption(PACK *p, CLIENT_OPTION *c)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddUniStr(p, "AccountName", c->AccountName);
+ PackAddStr(p, "Hostname", c->Hostname);
+ PackAddStr(p, "ProxyName", c->ProxyName);
+ PackAddStr(p, "ProxyUsername", c->ProxyUsername);
+ PackAddStr(p, "ProxyPassword", c->ProxyPassword);
+ PackAddStr(p, "HubName", c->HubName);
+ PackAddStr(p, "DeviceName", c->DeviceName);
+ PackAddInt(p, "Port", c->Port);
+ PackAddInt(p, "PortUDP", c->PortUDP);
+ PackAddInt(p, "ProxyType", c->ProxyType);
+ PackAddInt(p, "ProxyPort", c->ProxyPort);
+ PackAddInt(p, "NumRetry", c->NumRetry);
+ PackAddInt(p, "RetryInterval", c->RetryInterval);
+ PackAddInt(p, "MaxConnection", c->MaxConnection);
+ PackAddInt(p, "UseEncrypt", c->UseEncrypt);
+ PackAddInt(p, "UseCompress", c->UseCompress);
+ PackAddInt(p, "HalfConnection", c->HalfConnection);
+ PackAddInt(p, "NoRoutingTracking", c->NoRoutingTracking);
+ PackAddInt(p, "AdditionalConnectionInterval", c->AdditionalConnectionInterval);
+ PackAddInt(p, "ConnectionDisconnectSpan", c->ConnectionDisconnectSpan);
+ PackAddBool(p, "HideStatusWindow", c->HideStatusWindow);
+ PackAddBool(p, "HideNicInfoWindow", c->HideNicInfoWindow);
+ PackAddBool(p, "RequireMonitorMode", c->RequireMonitorMode);
+ PackAddBool(p, "RequireBridgeRoutingMode", c->RequireBridgeRoutingMode);
+ PackAddBool(p, "DisableQoS", c->DisableQoS);
+ PackAddBool(p, "FromAdminPack", c->FromAdminPack);
+ PackAddBool(p, "NoTls1", c->NoTls1);
+ PackAddBool(p, "NoUdpAcceleration", c->NoUdpAcceleration);
+ PackAddData(p, "HostUniqueKey", c->HostUniqueKey, SHA1_SIZE);
+}
+
+// CLIENT_AUTH
+void InRpcClientAuth(CLIENT_AUTH *c, PACK *p)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(CLIENT_AUTH));
+ c->AuthType = PackGetInt(p, "AuthType");
+ PackGetStr(p, "Username", c->Username, sizeof(c->Username));
+
+ switch (c->AuthType)
+ {
+ case CLIENT_AUTHTYPE_ANONYMOUS:
+ break;
+
+ case CLIENT_AUTHTYPE_PASSWORD:
+ if (PackGetDataSize(p, "HashedPassword") == SHA1_SIZE)
+ {
+ PackGetData(p, "HashedPassword", c->HashedPassword);
+ }
+ break;
+
+ case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+ PackGetStr(p, "PlainPassword", c->PlainPassword, sizeof(c->PlainPassword));
+ break;
+
+ case CLIENT_AUTHTYPE_CERT:
+ b = PackGetBuf(p, "ClientX");
+ if (b != NULL)
+ {
+ c->ClientX = BufToX(b, false);
+ FreeBuf(b);
+ }
+ b = PackGetBuf(p, "ClientK");
+ if (b != NULL)
+ {
+ c->ClientK = BufToK(b, true, false, NULL);
+ FreeBuf(b);
+ }
+ break;
+
+ case CLIENT_AUTHTYPE_SECURE:
+ PackGetStr(p, "SecurePublicCertName", c->SecurePublicCertName, sizeof(c->SecurePublicCertName));
+ PackGetStr(p, "SecurePrivateKeyName", c->SecurePrivateKeyName, sizeof(c->SecurePrivateKeyName));
+ break;
+ }
+}
+void OutRpcClientAuth(PACK *p, CLIENT_AUTH *c)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "AuthType", c->AuthType);
+ PackAddStr(p, "Username", c->Username);
+
+ switch (c->AuthType)
+ {
+ case CLIENT_AUTHTYPE_ANONYMOUS:
+ break;
+
+ case CLIENT_AUTHTYPE_PASSWORD:
+ PackAddData(p, "HashedPassword", c->HashedPassword, SHA1_SIZE);
+ break;
+
+ case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+ PackAddStr(p, "PlainPassword", c->PlainPassword);
+ break;
+
+ case CLIENT_AUTHTYPE_CERT:
+ b = XToBuf(c->ClientX, false);
+ if (b != NULL)
+ {
+ PackAddBuf(p, "ClientX", b);
+ FreeBuf(b);
+ }
+ b = KToBuf(c->ClientK, false, NULL);
+ if (b != NULL)
+ {
+ PackAddBuf(p, "ClientK", b);
+ FreeBuf(b);
+ }
+ break;
+
+ case CLIENT_AUTHTYPE_SECURE:
+ PackAddStr(p, "SecurePublicCertName", c->SecurePublicCertName);
+ PackAddStr(p, "SecurePrivateKeyName", c->SecurePrivateKeyName);
+ break;
+ }
+}
+
+// RPC_CLIENT_CREATE_ACCOUNT
+void InRpcClientCreateAccount(RPC_CLIENT_CREATE_ACCOUNT *c, PACK *p)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(RPC_CLIENT_CREATE_ACCOUNT));
+ c->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ c->ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+
+ InRpcClientOption(c->ClientOption, p);
+ InRpcClientAuth(c->ClientAuth, p);
+
+ c->StartupAccount = PackGetInt(p, "StartupAccount") ? true : false;
+ c->CheckServerCert = PackGetInt(p, "CheckServerCert") ? true : false;
+ b = PackGetBuf(p, "ServerCert");
+ if (b != NULL)
+ {
+ c->ServerCert = BufToX(b, false);
+ FreeBuf(b);
+ }
+ PackGetData2(p, "ShortcutKey", c->ShortcutKey, sizeof(c->ShortcutKey));
+}
+void OutRpcClientCreateAccount(PACK *p, RPC_CLIENT_CREATE_ACCOUNT *c)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ OutRpcClientOption(p, c->ClientOption);
+ OutRpcClientAuth(p, c->ClientAuth);
+
+ PackAddInt(p, "StartupAccount", c->StartupAccount);
+ PackAddInt(p, "CheckServerCert", c->CheckServerCert);
+ if (c->ServerCert != NULL)
+ {
+ b = XToBuf(c->ServerCert, false);
+ if (b != NULL)
+ {
+ PackAddBuf(p, "ServerCert", b);
+ FreeBuf(b);
+ }
+ }
+ PackAddData(p, "ShortcutKey", c->ShortcutKey, sizeof(c->ShortcutKey));
+}
+
+// RPC_CLIENT_ENUM_ACCOUNT
+void InRpcClientEnumAccount(RPC_CLIENT_ENUM_ACCOUNT *e, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(e, sizeof(RPC_CLIENT_ENUM_ACCOUNT));
+
+ e->NumItem = PackGetNum(p, "NumItem");
+ e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM *) * e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = e->Items[i] =
+ ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM));
+
+ PackGetUniStrEx(p, "AccountName", item->AccountName, sizeof(item->AccountName), i);
+ PackGetStrEx(p, "UserName", item->UserName, sizeof(item->UserName), i);
+ PackGetStrEx(p, "ServerName", item->ServerName, sizeof(item->ServerName), i);
+ PackGetStrEx(p, "ProxyName", item->ProxyName, sizeof(item->ProxyName), i);
+ PackGetStrEx(p, "DeviceName", item->DeviceName, sizeof(item->DeviceName), i);
+ item->ProxyType = PackGetIntEx(p, "ProxyType", i);
+ item->Active = PackGetIntEx(p, "Active", i) ? true : false;
+ item->StartupAccount = PackGetIntEx(p, "StartupAccount", i) ? true : false;
+ item->Connected = PackGetBoolEx(p, "Connected", i);
+ item->Port = PackGetIntEx(p, "Port", i);
+ PackGetStrEx(p, "HubName", item->HubName, sizeof(item->HubName), i);
+ item->CreateDateTime = PackGetInt64Ex(p, "CreateDateTime", i);
+ item->UpdateDateTime = PackGetInt64Ex(p, "UpdateDateTime", i);
+ item->LastConnectDateTime = PackGetInt64Ex(p, "LastConnectDateTime", i);
+ }
+}
+void OutRpcClientEnumAccount(PACK *p, RPC_CLIENT_ENUM_ACCOUNT *e)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddNum(p, "NumItem", e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = e->Items[i];
+
+ PackAddUniStrEx(p, "AccountName", item->AccountName, i, e->NumItem);
+ PackAddStrEx(p, "UserName", item->UserName, i, e->NumItem);
+ PackAddStrEx(p, "ServerName", item->ServerName, i, e->NumItem);
+ PackAddStrEx(p, "ProxyName", item->ProxyName, i, e->NumItem);
+ PackAddStrEx(p, "DeviceName", item->DeviceName, i, e->NumItem);
+ PackAddIntEx(p, "ProxyType", item->ProxyType, i, e->NumItem);
+ PackAddIntEx(p, "Active", item->Active, i, e->NumItem);
+ PackAddIntEx(p, "StartupAccount", item->StartupAccount, i, e->NumItem);
+ PackAddBoolEx(p, "Connected", item->Connected, i, e->NumItem);
+ PackAddIntEx(p, "Port", item->Port, i, e->NumItem);
+ PackAddStrEx(p, "HubName", item->HubName, i, e->NumItem);
+ PackAddInt64Ex(p, "CreateDateTime", item->CreateDateTime, i, e->NumItem);
+ PackAddInt64Ex(p, "UpdateDateTime", item->UpdateDateTime, i, e->NumItem);
+ PackAddInt64Ex(p, "LastConnectDateTime", item->LastConnectDateTime, i, e->NumItem);
+ }
+}
+
+// RPC_CLIENT_DELETE_ACCOUNT
+void InRpcClientDeleteAccount(RPC_CLIENT_DELETE_ACCOUNT *a, PACK *p)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(a, sizeof(RPC_CLIENT_DELETE_ACCOUNT));
+ PackGetUniStr(p, "AccountName", a->AccountName, sizeof(a->AccountName));
+}
+void OutRpcClientDeleteAccount(PACK *p, RPC_CLIENT_DELETE_ACCOUNT *a)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddUniStr(p, "AccountName", a->AccountName);
+}
+
+// RPC_RENAME_ACCOUNT
+void InRpcRenameAccount(RPC_RENAME_ACCOUNT *a, PACK *p)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(a, sizeof(RPC_RENAME_ACCOUNT));
+
+ PackGetUniStr(p, "OldName", a->OldName, sizeof(a->OldName));
+ PackGetUniStr(p, "NewName", a->NewName, sizeof(a->NewName));
+}
+void OutRpcRenameAccount(PACK *p, RPC_RENAME_ACCOUNT *a)
+{
+ // Validate arguments
+ if (a == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddUniStr(p, "OldName", a->OldName);
+ PackAddUniStr(p, "NewName", a->NewName);
+}
+
+// RPC_CLIENT_GET_ACCOUNT
+void InRpcClientGetAccount(RPC_CLIENT_GET_ACCOUNT *c, PACK *p)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(RPC_CLIENT_GET_ACCOUNT));
+
+ c->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ c->ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+
+ PackGetUniStr(p, "AccountName", c->AccountName, sizeof(c->AccountName));
+ c->StartupAccount = PackGetInt(p, "StartupAccount") ? true : false;
+ c->CheckServerCert = PackGetInt(p, "CheckServerCert") ? true : false;
+ b = PackGetBuf(p, "ServerCert");
+ if (b != NULL)
+ {
+ c->ServerCert = BufToX(b, false);
+ FreeBuf(b);
+ }
+
+ InRpcClientOption(c->ClientOption, p);
+ InRpcClientAuth(c->ClientAuth, p);
+
+ c->CreateDateTime = PackGetInt64(p, "CreateDateTime");
+ c->UpdateDateTime = PackGetInt64(p, "UpdateDateTime");
+ c->LastConnectDateTime = PackGetInt64(p, "LastConnectDateTime");
+
+ PackGetData2(p, "ShortcutKey", c->ShortcutKey, SHA1_SIZE);
+}
+void OutRpcClientGetAccount(PACK *p, RPC_CLIENT_GET_ACCOUNT *c)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddUniStr(p, "AccountName", c->AccountName);
+ PackAddInt(p, "StartupAccount", c->StartupAccount);
+ PackAddInt(p, "CheckServerCert", c->CheckServerCert);
+
+ if (c->ServerCert != NULL)
+ {
+ b = XToBuf(c->ServerCert, false);
+ if (b != NULL)
+ {
+ PackAddBuf(p, "ServerCert", b);
+ FreeBuf(b);
+ }
+ }
+
+ OutRpcClientOption(p, c->ClientOption);
+ OutRpcClientAuth(p, c->ClientAuth);
+
+ PackAddData(p, "ShortcutKey", c->ShortcutKey, SHA1_SIZE);
+
+ PackAddInt64(p, "CreateDateTime", c->CreateDateTime);
+ PackAddInt64(p, "UpdateDateTime", c->UpdateDateTime);
+ PackAddInt64(p, "LastConnectDateTime", c->LastConnectDateTime);
+}
+
+// RPC_CLIENT_CONNECT
+void InRpcClientConnect(RPC_CLIENT_CONNECT *c, PACK *p)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(RPC_CLIENT_CONNECT));
+
+ PackGetUniStr(p, "AccountName", c->AccountName, sizeof(c->AccountName));
+}
+void OutRpcClientConnect(PACK *p, RPC_CLIENT_CONNECT *c)
+{
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddUniStr(p, "AccountName", c->AccountName);
+}
+
+// POLICY
+void InRpcPolicy(POLICY *o, PACK *p)
+{
+ POLICY *pol;
+ // Validate arguments
+ if (o == NULL || p == NULL)
+ {
+ return;
+ }
+
+ pol = PackGetPolicy(p);
+ Copy(o, pol, sizeof(POLICY));
+ Free(pol);
+}
+void OutRpcPolicy(PACK *p, POLICY *o)
+{
+ // Validate arguments
+ if (o == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddPolicy(p, o);
+}
+
+// RPC_CLIENT_GET_CONNECTION_STATUS
+void InRpcClientGetConnectionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *s, PACK *p)
+{
+ BUF *b;
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(s, sizeof(RPC_CLIENT_GET_CONNECTION_STATUS));
+
+ PackGetUniStr(p, "AccountName", s->AccountName, sizeof(s->AccountName));
+
+ PackGetStr(p, "ServerName", s->ServerName, sizeof(s->ServerName));
+ PackGetStr(p, "ServerProductName", s->ServerProductName, sizeof(s->ServerProductName));
+ PackGetStr(p, "CipherName", s->CipherName, sizeof(s->CipherName));
+ PackGetStr(p, "SessionName", s->SessionName, sizeof(s->SessionName));
+ PackGetStr(p, "ConnectionName", s->ConnectionName, sizeof(s->ConnectionName));
+
+ if (PackGetDataSize(p, "SessionKey") == SHA1_SIZE)
+ {
+ PackGetData(p, "SessionKey", s->SessionKey);
+ }
+
+ s->SessionStatus = PackGetInt(p, "SessionStatus");
+ s->ServerPort = PackGetInt(p, "ServerPort");
+ s->ServerProductVer = PackGetInt(p, "ServerProductVer");
+ s->ServerProductBuild = PackGetInt(p, "ServerProductBuild");
+ s->NumConnectionsEatablished = PackGetInt(p, "NumConnectionsEatablished");
+ s->MaxTcpConnections = PackGetInt(p, "MaxTcpConnections");
+ s->NumTcpConnections = PackGetInt(p, "NumTcpConnections");
+ s->NumTcpConnectionsUpload = PackGetInt(p, "NumTcpConnectionsUpload");
+ s->NumTcpConnectionsDownload = PackGetInt(p, "NumTcpConnectionsDownload");
+
+ s->StartTime = PackGetInt64(p, "StartTime");
+ s->FirstConnectionEstablisiedTime = PackGetInt64(p, "FirstConnectionEstablisiedTime");
+ s->CurrentConnectionEstablishTime = PackGetInt64(p, "CurrentConnectionEstablishTime");
+ s->TotalSendSize = PackGetInt64(p, "TotalSendSize");
+ s->TotalRecvSize = PackGetInt64(p, "TotalRecvSize");
+ s->TotalSendSizeReal = PackGetInt64(p, "TotalSendSizeReal");
+ s->TotalRecvSizeReal = PackGetInt64(p, "TotalRecvSizeReal");
+
+ s->Active = PackGetInt(p, "Active") ? true : false;
+ s->Connected = PackGetInt(p, "Connected") ? true : false;
+ s->HalfConnection = PackGetInt(p, "HalfConnection") ? true : false;
+ s->QoS = PackGetInt(p, "QoS") ? true : false;
+ s->UseEncrypt = PackGetInt(p, "UseEncrypt") ? true : false;
+ s->UseCompress = PackGetInt(p, "UseCompress") ? true : false;
+ s->IsRUDPSession = PackGetInt(p, "IsRUDPSession") ? true : false;
+ PackGetStr(p, "UnderlayProtocol", s->UnderlayProtocol, sizeof(s->UnderlayProtocol));
+ s->IsUdpAccelerationEnabled = PackGetInt(p, "IsUdpAccelerationEnabled") ? true : false;
+ s->IsUsingUdpAcceleration = PackGetInt(p, "IsUsingUdpAcceleration") ? true : false;
+
+ s->IsBridgeMode = PackGetBool(p, "IsBridgeMode");
+ s->IsMonitorMode = PackGetBool(p, "IsMonitorMode");
+
+ s->VLanId = PackGetInt(p, "VLanId");
+
+ b = PackGetBuf(p, "ServerX");
+ if (b != NULL)
+ {
+ s->ServerX = BufToX(b, false);
+ FreeBuf(b);
+ }
+
+ b = PackGetBuf(p, "ClientX");
+ if (b != NULL)
+ {
+ s->ClientX = BufToX(b, false);
+ FreeBuf(b);
+ }
+
+ InRpcPolicy(&s->Policy, p);
+
+ InRpcTraffic(&s->Traffic, p);
+}
+void OutRpcClientGetConnectionStatus(PACK *p, RPC_CLIENT_GET_CONNECTION_STATUS *c)
+{
+ BUF *b;
+ // Validate arguments
+ if (p == NULL || c == NULL)
+ {
+ return;
+ }
+
+ PackAddUniStr(p, "AccountName", c->AccountName);
+
+ PackAddStr(p, "ServerName", c->ServerName);
+ PackAddStr(p, "ServerProductName", c->ServerProductName);
+ PackAddStr(p, "CipherName", c->CipherName);
+ PackAddStr(p, "SessionName", c->SessionName);
+ PackAddStr(p, "ConnectionName", c->ConnectionName);
+
+ PackAddData(p, "SessionKey", c->SessionKey, SHA1_SIZE);
+
+ PackAddInt(p, "Active", c->Active);
+ PackAddInt(p, "Connected", c->Connected);
+ PackAddInt(p, "SessionStatus", c->SessionStatus);
+ PackAddInt(p, "ServerPort", c->ServerPort);
+ PackAddInt(p, "ServerProductVer", c->ServerProductVer);
+ PackAddInt(p, "ServerProductBuild", c->ServerProductBuild);
+ PackAddInt(p, "NumConnectionsEatablished", c->NumConnectionsEatablished);
+ PackAddInt(p, "HalfConnection", c->HalfConnection);
+ PackAddInt(p, "QoS", c->QoS);
+ PackAddInt(p, "MaxTcpConnections", c->MaxTcpConnections);
+ PackAddInt(p, "NumTcpConnections", c->NumTcpConnections);
+ PackAddInt(p, "NumTcpConnectionsUpload", c->NumTcpConnectionsUpload);
+ PackAddInt(p, "NumTcpConnectionsDownload", c->NumTcpConnectionsDownload);
+ PackAddInt(p, "UseEncrypt", c->UseEncrypt);
+ PackAddInt(p, "UseCompress", c->UseCompress);
+ PackAddInt(p, "IsRUDPSession", c->IsRUDPSession);
+ PackAddStr(p, "UnderlayProtocol", c->UnderlayProtocol);
+ PackAddInt(p, "IsUdpAccelerationEnabled", c->IsUdpAccelerationEnabled);
+ PackAddInt(p, "IsUsingUdpAcceleration", c->IsUsingUdpAcceleration);
+
+ PackAddBool(p, "IsBridgeMode", c->IsBridgeMode);
+ PackAddBool(p, "IsMonitorMode", c->IsMonitorMode);
+
+ PackAddInt64(p, "StartTime", c->StartTime);
+ PackAddInt64(p, "FirstConnectionEstablisiedTime", c->FirstConnectionEstablisiedTime);
+ PackAddInt64(p, "CurrentConnectionEstablishTime", c->CurrentConnectionEstablishTime);
+ PackAddInt64(p, "TotalSendSize", c->TotalSendSize);
+ PackAddInt64(p, "TotalRecvSize", c->TotalRecvSize);
+ PackAddInt64(p, "TotalSendSizeReal", c->TotalSendSizeReal);
+ PackAddInt64(p, "TotalRecvSizeReal", c->TotalRecvSizeReal);
+
+ PackAddInt(p, "VLanId", c->VLanId);
+
+ OutRpcPolicy(p, &c->Policy);
+
+ OutRpcTraffic(p, &c->Traffic);
+
+ if (c->ServerX != NULL)
+ {
+ b = XToBuf(c->ServerX, false);
+ PackAddBuf(p, "ServerX", b);
+ FreeBuf(b);
+ }
+
+ if (c->ClientX != NULL)
+ {
+ b = XToBuf(c->ClientX, false);
+ PackAddBuf(p, "ClientX", b);
+ FreeBuf(b);
+ }
+}
+
+void InRpcClientNotify(RPC_CLIENT_NOTIFY *n, PACK *p)
+{
+ // Validate arguments
+ if (n == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(n, sizeof(RPC_CLIENT_NOTIFY));
+
+ n->NotifyCode = PackGetInt(p, "NotifyCode");
+}
+void OutRpcClientNotify(PACK *p, RPC_CLIENT_NOTIFY *n)
+{
+ // Validate arguments
+ if (n == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NotifyCode", n->NotifyCode);
+}
+
+// Notification main
+void CiNotifyMain(CLIENT *c, SOCK *s)
+{
+ CANCEL *cancel;
+ // Validate arguments
+ if (c == NULL || s == NULL)
+ {
+ return;
+ }
+
+ // Register a Cencel
+ cancel = NewCancel();
+ LockList(c->NotifyCancelList);
+ {
+ Add(c->NotifyCancelList, cancel);
+ }
+ UnlockList(c->NotifyCancelList);
+
+ // Wait
+ while (true)
+ {
+ char ch = '@';
+ SOCKSET set;
+ InitSockSet(&set);
+ AddSockSet(&set, s);
+ Select(&set, INFINITE, cancel, NULL);
+
+ if (c->Halt)
+ {
+ // Abort
+ break;
+ }
+
+ // 1 byte transmission
+ if (Send(s, &ch, 1, false) == 0)
+ {
+ // Disconnected
+ break;
+ }
+ }
+
+ // Disconnect
+ Disconnect(s);
+
+ // Unregister the Cancel
+ LockList(c->NotifyCancelList);
+ {
+ Delete(c->NotifyCancelList, cancel);
+ }
+ UnlockList(c->NotifyCancelList);
+
+ ReleaseCancel(cancel);
+}
+
+// RPC acceptance code
+void CiRpcAccepted(CLIENT *c, SOCK *s)
+{
+ UCHAR hashed_password[SHA1_SIZE];
+ UINT rpc_mode;
+ UINT retcode;
+ RPC *rpc;
+ // Validate arguments
+ if (c == NULL || s == NULL)
+ {
+ return;
+ }
+
+ // Receive the RPC mode
+ if (RecvAll(s, &rpc_mode, sizeof(UINT), false) == false)
+ {
+ return;
+ }
+
+ rpc_mode = Endian32(rpc_mode);
+
+ if (rpc_mode == CLIENT_RPC_MODE_NOTIFY)
+ {
+ // Notification mode
+ CiNotifyMain(c, s);
+ return;
+ }
+ else if (rpc_mode == CLIENT_RPC_MODE_SHORTCUT || rpc_mode == CLIENT_RPC_MODE_SHORTCUT_DISCONNECT)
+ {
+ // Shortcut key received
+ UCHAR key[SHA1_SIZE];
+ UINT err = ERR_NO_ERROR;
+ if (RecvAll(s, key, SHA1_SIZE, false))
+ {
+ UINT i;
+ wchar_t title[MAX_ACCOUNT_NAME_LEN + 1];
+ bool ok = false;
+ // Connect to the specified setting
+ LockList(c->AccountList);
+ {
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+ Lock(a->lock);
+ {
+ if (Cmp(a->ShortcutKey, key, SHA1_SIZE) == 0)
+ {
+ ok = true;
+ UniStrCpy(title, sizeof(title), a->ClientOption->AccountName);
+ }
+ }
+ Unlock(a->lock);
+ }
+ }
+ UnlockList(c->AccountList);
+
+ if (ok == false)
+ {
+ err = ERR_ACCOUNT_NOT_FOUND;
+ }
+ else
+ {
+ RPC_CLIENT_CONNECT t;
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), title);
+
+ if (rpc_mode == CLIENT_RPC_MODE_SHORTCUT)
+ {
+ // Connect
+ if (CtConnect(c, &t))
+ {
+ err = ERR_NO_ERROR;
+ }
+ else
+ {
+ err = c->Err;
+ }
+ }
+ else
+ {
+ // Connect
+ if (CtDisconnect(c, &t, false))
+ {
+ err = ERR_NO_ERROR;
+ }
+ else
+ {
+ err = c->Err;
+ }
+ }
+ }
+
+ err = Endian32(err);
+ SendAll(s, &err, sizeof(UINT), false);
+ RecvAll(s, &err, sizeof(UINT), false);
+ }
+ return;
+ }
+
+ // Password reception
+ if (RecvAll(s, hashed_password, SHA1_SIZE, false) == false)
+ {
+ return;
+ }
+
+ retcode = 0;
+
+ // Password comparison
+ if (Cmp(hashed_password, c->EncryptedPassword, SHA1_SIZE) != 0)
+ {
+ retcode = 1;
+ }
+
+ if (c->PasswordRemoteOnly && s->RemoteIP.addr[0] == 127)
+ {
+ // If in a mode that requires a password only remote,
+ // the password sent from localhost is considered to be always correct
+ retcode = 0;
+ }
+
+ Lock(c->lock);
+ {
+ if (c->Config.AllowRemoteConfig == false)
+ {
+ // If the remote control is prohibited,
+ // identify whether this connection is from remote
+ if (s->RemoteIP.addr[0] != 127)
+ {
+ retcode = 2;
+ }
+ }
+ }
+ Unlock(c->lock);
+
+ retcode = Endian32(retcode);
+ // Error code transmission
+ if (SendAll(s, &retcode, sizeof(UINT), false) == false)
+ {
+ return;
+ }
+
+
+
+ if (retcode != 0)
+ {
+ // Disconnect due to an error
+ return;
+ }
+
+ // Create a RPC server
+ rpc = StartRpcServer(s, CiRpcDispatch, c);
+
+ // RPC server operation
+ RpcServer(rpc);
+
+ // Release the RPC server
+ EndRpc(rpc);
+}
+
+// RPC acceptance thread
+void CiRpcAcceptThread(THREAD *thread, void *param)
+{
+ CLIENT_RPC_CONNECTION *conn;
+ CLIENT *c;
+ SOCK *s;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ conn = (CLIENT_RPC_CONNECTION *)param;
+ s = conn->Sock;
+ c = conn->Client;
+ AddRef(s->ref);
+
+ // Add to the RPC connection list
+ LockList(c->RpcConnectionList);
+ {
+ Add(c->RpcConnectionList, conn);
+ }
+ UnlockList(c->RpcConnectionList);
+
+ NoticeThreadInit(thread);
+
+ // Main process
+ CiRpcAccepted(c, s);
+
+ // Release from the connection list
+ LockList(c->RpcConnectionList);
+ {
+ Delete(c->RpcConnectionList, conn);
+ }
+ UnlockList(c->RpcConnectionList);
+
+ ReleaseSock(conn->Sock);
+ ReleaseThread(conn->Thread);
+ Free(conn);
+
+ Disconnect(s);
+ ReleaseSock(s);
+}
+
+// RPC server thread
+void CiRpcServerThread(THREAD *thread, void *param)
+{
+ CLIENT *c;
+ SOCK *listener;
+ UINT i;
+ LIST *thread_list;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ c = (CLIENT *)param;
+
+ // RPC connection list
+ c->RpcConnectionList = NewList(NULL);
+
+ // Open the port
+ listener = NULL;
+ for (i = CLIENT_CONFIG_PORT;i < (CLIENT_CONFIG_PORT + 5);i++)
+ {
+ listener = Listen(i);
+ if (listener != NULL)
+ {
+ break;
+ }
+ }
+
+ if (listener == NULL)
+ {
+ // Error
+ Alert(CEDAR_PRODUCT_STR " VPN Client RPC Port Open Failed.", CEDAR_CLIENT_STR);
+ return;
+ }
+
+ c->RpcListener = listener;
+ AddRef(listener->ref);
+
+ NoticeThreadInit(thread);
+
+ while (true)
+ {
+ // Wait for client connection
+ CLIENT_RPC_CONNECTION *conn;
+ SOCK *s = Accept(listener);
+ if (s == NULL)
+ {
+ // Stop
+ break;
+ }
+
+ // Create a client processing thread
+ conn = ZeroMalloc(sizeof(CLIENT_RPC_CONNECTION));
+ conn->Client = c;
+ conn->Sock = s;
+ AddRef(s->ref);
+
+ conn->Thread = NewThread(CiRpcAcceptThread, (void *)conn);
+ WaitThreadInit(conn->Thread);
+
+ ReleaseSock(s);
+ }
+
+ // Release the listener
+ ReleaseSock(listener);
+
+ thread_list = NewListFast(NULL);
+
+ // Set all the event notification
+ LockList(c->NotifyCancelList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(c->NotifyCancelList);i++)
+ {
+ CANCEL *cancel = LIST_DATA(c->NotifyCancelList, i);
+ Cancel(cancel);
+ }
+ }
+ UnlockList(c->NotifyCancelList);
+
+ // Disconnect all the connections of connected yet
+ LockList(c->RpcConnectionList);
+ {
+ for (i = 0;i < LIST_NUM(c->RpcConnectionList);i++)
+ {
+ CLIENT_RPC_CONNECTION *cc = LIST_DATA(c->RpcConnectionList, i);
+ AddRef(cc->Thread->ref);
+ Add(thread_list, cc->Thread);
+ Disconnect(cc->Sock);
+ }
+ }
+ UnlockList(c->RpcConnectionList);
+
+ for (i = 0;i < LIST_NUM(thread_list);i++)
+ {
+ THREAD *t = LIST_DATA(thread_list, i);
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+ }
+
+ ReleaseList(c->RpcConnectionList);
+ ReleaseList(thread_list);
+}
+
+// Start the Keep
+void CiInitKeep(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->Keep = StartKeep();
+
+ // Apply settings
+ if (c->Config.UseKeepConnect)
+ {
+ KEEP *k = c->Keep;
+ Lock(k->lock);
+ {
+ StrCpy(k->ServerName, sizeof(k->ServerName), c->Config.KeepConnectHost);
+ k->ServerPort = c->Config.KeepConnectPort;
+ k->Interval = c->Config.KeepConnectInterval * 1000;
+ k->UdpMode = (c->Config.KeepConnectProtocol == CONNECTION_UDP) ? true : false;
+ k->Enable = true;
+ }
+ Unlock(k->lock);
+ }
+}
+
+// Stop the Keep
+void CiFreeKeep(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ StopKeep(c->Keep);
+ c->Keep = NULL;
+}
+
+// Start the RPC
+void CiStartRpcServer(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->RpcThread = NewThread(CiRpcServerThread, (void *)c);
+ WaitThreadInit(c->RpcThread);
+}
+
+// Stop the RPC
+void CiStopRpcServer(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ Disconnect(c->RpcListener);
+ ReleaseSock(c->RpcListener);
+
+ WaitThread(c->RpcThread, INFINITE);
+ ReleaseThread(c->RpcThread);
+}
+
+// Wait for the next notification
+bool CcWaitNotify(NOTIFY_CLIENT *n)
+{
+ UCHAR c;
+ // Validate arguments
+ if (n == NULL)
+ {
+ return false;
+ }
+
+ // 1 character reception
+ if (RecvAll(n->Sock, &c, 1, false) == false)
+ {
+ // Disconnected
+ return false;
+ }
+
+ return true;
+}
+
+// Connect as a notification client
+NOTIFY_CLIENT *CcConnectNotify(REMOTE_CLIENT *rc)
+{
+ NOTIFY_CLIENT *n;
+ SOCK *s;
+ char tmp[MAX_SIZE];
+ bool rpc_mode = false;
+ UINT port;
+ // Validate arguments
+ if (rc == NULL || rc->Rpc == NULL || rc->Rpc->Sock == NULL)
+ {
+ return NULL;
+ }
+
+ // Connect
+ IPToStr(tmp, sizeof(tmp), &rc->Rpc->Sock->RemoteIP);
+ port = rc->Rpc->Sock->RemotePort;
+
+ s = Connect(tmp, port);
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ rpc_mode = Endian32(rpc_mode);
+ if (SendAll(s, &rpc_mode, sizeof(rpc_mode), false) == false)
+ {
+ ReleaseSock(s);
+ return NULL;
+ }
+
+ n = ZeroMalloc(sizeof(NOTIFY_CLIENT));
+ n->Sock = s;
+
+ return n;
+}
+
+// Stop the notification client
+void CcStopNotify(NOTIFY_CLIENT *n)
+{
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ Disconnect(n->Sock);
+}
+
+// Delete the notification client
+void CcDisconnectNotify(NOTIFY_CLIENT *n)
+{
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ // Disconnect
+ Disconnect(n->Sock);
+ ReleaseSock(n->Sock);
+
+ // Memory release
+ Free(n);
+}
+
+// Disconnect the remote connection
+void CcDisconnectRpc(REMOTE_CLIENT *rc)
+{
+ // Validate arguments
+ if (rc == NULL)
+ {
+ return;
+ }
+
+ RpcFree(rc->Rpc);
+ Free(rc);
+}
+
+// Connect to the client to start the shortcut connection setting
+UINT CcShortcut(UCHAR *key)
+{
+ UINT ret;
+ // Validate arguments
+ if (key == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ CcConnectRpcEx("localhost", NULL, NULL, NULL, key, &ret, false, 0);
+
+ return ret;
+}
+
+// Disconnect the connected shortcut connection
+UINT CcShortcutDisconnect(UCHAR *key)
+{
+ UINT ret;
+ // Validate arguments
+ if (key == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ CcConnectRpcEx("localhost", NULL, NULL, NULL, key, &ret, true, 0);
+
+ return ret;
+}
+
+// Connect to the remote client
+REMOTE_CLIENT *CcConnectRpc(char *server_name, char *password, bool *bad_pass, bool *no_remote, UINT wait_retry)
+{
+ return CcConnectRpcEx(server_name, password, bad_pass, no_remote, NULL, NULL, false, wait_retry);
+}
+REMOTE_CLIENT *CcConnectRpcEx(char *server_name, char *password, bool *bad_pass, bool *no_remote, UCHAR *key, UINT *key_error_code, bool shortcut_disconnect, UINT wait_retry)
+{
+ SOCK *s;
+ UINT i;
+ UINT retcode;
+ UINT rpc_mode = CLIENT_RPC_MODE_MANAGEMENT;
+ RPC *rpc;
+ REMOTE_CLIENT *ret;
+ UCHAR hash_password[SHA1_SIZE];
+ UINT port_start;
+ UINT64 try_started = 0;
+ bool ok;
+ // Validate arguments
+ if (server_name == NULL)
+ {
+ return NULL;
+ }
+ if (password == NULL)
+ {
+ password = "";
+ }
+
+ if (key_error_code != NULL)
+ {
+ *key_error_code = ERR_NO_ERROR;
+ }
+
+ if (bad_pass != NULL)
+ {
+ *bad_pass = false;
+ }
+
+ if (no_remote != NULL)
+ {
+ *no_remote = false;
+ }
+
+ port_start = CLIENT_CONFIG_PORT - 1;
+
+RETRY:
+ port_start++;
+
+ if (port_start >= (CLIENT_CONFIG_PORT + 5))
+ {
+ return NULL;
+ }
+
+ ok = false;
+
+ while (true)
+ {
+ for (i = port_start;i < (CLIENT_CONFIG_PORT + 5);i++)
+ {
+ if (CheckTCPPort(server_name, i))
+ {
+ ok = true;
+ break;
+ }
+ }
+
+ if (ok)
+ {
+ break;
+ }
+
+ if (wait_retry == 0)
+ {
+ break;
+ }
+
+ if (try_started == 0)
+ {
+ try_started = Tick64();
+ }
+
+ if ((try_started + (UINT64)wait_retry) <= Tick64())
+ {
+ break;
+ }
+ }
+
+ if (ok == false)
+ {
+ if (key_error_code)
+ {
+ *key_error_code = ERR_CONNECT_FAILED;
+ }
+ return NULL;
+ }
+
+ port_start = i;
+
+ s = Connect(server_name, i);
+ if (s == NULL)
+ {
+ if (key_error_code)
+ {
+ *key_error_code = ERR_CONNECT_FAILED;
+ }
+ goto RETRY;
+ }
+
+ Hash(hash_password, password, StrLen(password), true);
+
+ if (key != NULL)
+ {
+ if (shortcut_disconnect == false)
+ {
+ rpc_mode = CLIENT_RPC_MODE_SHORTCUT;
+ }
+ else
+ {
+ rpc_mode = CLIENT_RPC_MODE_SHORTCUT_DISCONNECT;
+ }
+ }
+
+ rpc_mode = Endian32(rpc_mode);
+ SendAdd(s, &rpc_mode, sizeof(UINT));
+
+ if (key != NULL)
+ {
+ SendAdd(s, key, SHA1_SIZE);
+ }
+ else
+ {
+ SendAdd(s, hash_password, SHA1_SIZE);
+ }
+
+ if (SendNow(s, false) == false)
+ {
+ ReleaseSock(s);
+ goto RETRY;
+ }
+
+ if (RecvAll(s, &retcode, sizeof(UINT), false) == false)
+ {
+ ReleaseSock(s);
+ goto RETRY;
+ }
+
+ retcode = Endian32(retcode);
+
+ if (retcode >= 1024)
+ {
+ goto RETRY;
+ }
+
+ if (key != NULL)
+ {
+ if (key_error_code)
+ {
+ *key_error_code = retcode;
+ }
+ SendAll(s, &retcode, sizeof(UINT), false);
+ ReleaseSock(s);
+ return NULL;
+ }
+
+ switch (retcode)
+ {
+ case 1:
+ if (bad_pass != NULL)
+ {
+ *bad_pass = true;
+ }
+ break;
+ case 2:
+ if (no_remote != NULL)
+ {
+ *no_remote = true;
+ }
+ break;
+ }
+
+ if (retcode != 0)
+ {
+ ReleaseSock(s);
+ return NULL;
+ }
+
+ rpc = StartRpcClient(s, NULL);
+
+ ReleaseSock(s);
+
+ ret = ZeroMalloc(sizeof(REMOTE_CLIENT));
+ ret->Rpc = rpc;
+ rpc->Param = ret;
+
+ if (ret != NULL)
+ {
+ RPC_CLIENT_VERSION t;
+ Zero(&t, sizeof(t));
+ CcGetClientVersion(ret, &t);
+ ret->OsType = t.OsType;
+ ret->Unix = OS_IS_UNIX(ret->OsType);
+ ret->Win9x = OS_IS_WINDOWS_9X(ret->OsType);
+ ret->IsVgcSupported = t.IsVgcSupported;
+ ret->ShowVgcLink = t.ShowVgcLink;
+ StrCpy(ret->ClientId, sizeof(ret->ClientId), t.ClientId);
+ }
+
+ return ret;
+}
+
+// Get a RPC_CLIENT_GET_CONNECTION_STATUS from the session
+void CiGetSessionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *st, SESSION *s)
+{
+ // Validate arguments
+ if (st == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Lock(s->lock);
+ {
+ // Operation flag
+ st->Active = true;
+
+ // Session status
+ st->SessionStatus = s->ClientStatus;
+
+ // Account name
+ UniStrCpy(st->AccountName, sizeof(st->AccountName), s->ClientOption->AccountName);
+
+ if (s->ClientStatus == CLIENT_STATUS_ESTABLISHED && s->Connection != NULL)
+ {
+ Lock(s->Connection->lock);
+ {
+ // Connected flag
+ st->Connected = true;
+ // Product name
+ StrCpy(st->ServerProductName, sizeof(st->ServerProductName), s->Connection->ServerStr);
+ // Version
+ st->ServerProductVer = s->Connection->ServerVer;
+ // Build Number
+ st->ServerProductBuild = s->Connection->ServerBuild;
+ // Server certificate
+ st->ServerX = CloneX(s->Connection->ServerX);
+ // Client certificate
+ st->ClientX = CloneX(s->Connection->ClientX);
+ // Connection completion time of this connection
+ st->CurrentConnectionEstablishTime = TickToTime(s->CurrentConnectionEstablishTime);
+ // Maximum number of the TCP connections
+ st->MaxTcpConnections = s->MaxConnection;
+ // Half-connection
+ st->HalfConnection = s->HalfConnection;
+ // VLAN
+ st->VLanId = s->VLanId;
+ // VoIP / QoS
+ st->QoS = s->QoS;
+ if (s->Connection->Protocol == CONNECTION_TCP)
+ {
+ UINT i;
+ // Number of current TCP connections
+ LockList(s->Connection->Tcp->TcpSockList);
+ {
+ st->NumTcpConnections = LIST_NUM(s->Connection->Tcp->TcpSockList);
+ if (st->HalfConnection)
+ {
+ for (i = 0;i < st->NumTcpConnections;i++)
+ {
+ TCPSOCK *ts = LIST_DATA(s->Connection->Tcp->TcpSockList, i);
+ if (ts->Direction & TCP_SERVER_TO_CLIENT)
+ {
+ st->NumTcpConnectionsDownload++;
+ }
+ else
+ {
+ st->NumTcpConnectionsUpload++;
+ }
+ }
+ }
+ }
+ UnlockList(s->Connection->Tcp->TcpSockList);
+ }
+ // Use of encryption
+ st->UseEncrypt = s->UseEncrypt;
+ if (st->UseEncrypt)
+ {
+ StrCpy(st->CipherName, sizeof(st->CipherName), s->Connection->CipherName);
+ }
+ // Use of compression
+ st->UseCompress = s->UseCompress;
+ // R-UDP
+ st->IsRUDPSession = s->IsRUDPSession;
+ // Physical communication protocol
+ StrCpy(st->UnderlayProtocol, sizeof(st->UnderlayProtocol), s->UnderlayProtocol);
+ // UDP acceleration function
+ st->IsUdpAccelerationEnabled = s->UseUdpAcceleration;
+ st->IsUsingUdpAcceleration = s->IsUsingUdpAcceleration;
+ // Session key
+ Copy(st->SessionKey, s->SessionKey, SHA1_SIZE);
+ // Policy
+ Copy(&st->Policy, s->Policy, sizeof(POLICY));
+ // Data size
+ if (s->ServerMode == false)
+ {
+ st->TotalSendSize = s->TotalSendSize;
+ st->TotalRecvSize = s->TotalRecvSize;
+ st->TotalRecvSizeReal = s->TotalRecvSizeReal;
+ st->TotalSendSizeReal = s->TotalSendSizeReal;
+ }
+ else
+ {
+ st->TotalSendSize = s->TotalRecvSize;
+ st->TotalRecvSize = s->TotalSendSize;
+ st->TotalRecvSizeReal = s->TotalSendSizeReal;
+ st->TotalSendSizeReal = s->TotalRecvSizeReal;
+ }
+ // Session name
+ StrCpy(st->SessionName, sizeof(st->SessionName), s->Name);
+ // Connection name
+ StrCpy(st->ConnectionName, sizeof(st->ConnectionName), s->Connection->Name);
+ // Server name
+ StrCpy(st->ServerName, sizeof(st->ServerName), s->Connection->ServerName);
+ // Port number
+ st->ServerPort = s->Connection->ServerPort;
+ // Traffic data
+ Lock(s->TrafficLock);
+ {
+ Copy(&st->Traffic, s->Traffic, sizeof(TRAFFIC));
+ }
+ Unlock(s->TrafficLock);
+
+ st->IsBridgeMode = s->IsBridgeMode;
+ st->IsMonitorMode = s->IsMonitorMode;
+ }
+ Unlock(s->Connection->lock);
+ }
+ // Connection start time
+ st->StartTime = TickToTime(s->CreatedTime);
+ // Connection completion time of the first connection
+ st->FirstConnectionEstablisiedTime = TickToTime(s->FirstConnectionEstablisiedTime);
+ // Number of connections have been established so far
+ st->NumConnectionsEatablished = s->NumConnectionsEatablished;
+ }
+ Unlock(s->lock);
+}
+
+// Get the connection status
+bool CtGetAccountStatus(CLIENT *c, RPC_CLIENT_GET_CONNECTION_STATUS *st)
+{
+ // Validate arguments
+ if (c == NULL || st == NULL)
+ {
+ return false;
+ }
+
+ LockList(c->AccountList);
+ {
+ ACCOUNT t, *r;
+
+ // Search for account
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), st->AccountName);
+
+ r = Search(c->AccountList, &t);
+ if (r == NULL)
+ {
+ // Specified account is not found
+ UnlockList(c->AccountList);
+
+ Free(t.ClientOption);
+ CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+ Lock(r->lock);
+ {
+ Zero(st, sizeof(RPC_CLIENT_GET_CONNECTION_STATUS));
+ if (r->ClientSession != NULL)
+ {
+ SESSION *s = r->ClientSession;
+ CiGetSessionStatus(st, s);
+ }
+ }
+ Unlock(r->lock);
+ }
+ UnlockList(c->AccountList);
+
+ return true;
+}
+
+// Release the connection status
+void CiFreeClientGetConnectionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *st)
+{
+ // Validate arguments
+ if (st == NULL)
+ {
+ return;
+ }
+
+ if (st->ServerX != NULL)
+ {
+ FreeX(st->ServerX);
+ }
+
+ if (st->ClientX != NULL)
+ {
+ FreeX(st->ClientX);
+ }
+}
+
+// Verification procedure of the server certificate
+bool CiCheckCertProc(SESSION *s, CONNECTION *c, X *server_x, bool *expired)
+{
+#ifdef OS_WIN32
+ ACCOUNT *a;
+ X *old_x = NULL;
+ UI_CHECKCERT dlg;
+ // Validate arguments
+ if (s == NULL || c == NULL || server_x == NULL)
+ {
+ return false;
+ }
+
+ if (expired != NULL)
+ {
+ *expired = false;
+ }
+
+ Zero(&dlg, sizeof(dlg));
+
+ a = s->Account;
+ if (a == NULL)
+ {
+ return false;
+ }
+
+ Lock(a->lock);
+ {
+ if (a->CheckServerCert == false)
+ {
+ // Not to validate the server certificate
+ Unlock(a->lock);
+ return true;
+ }
+
+ if (a->ServerCert != NULL)
+ {
+ old_x = CloneX(a->ServerCert);
+ }
+ }
+ Unlock(a->lock);
+
+ if (CheckXDateNow(server_x) == false)
+ {
+ // Expired
+ if (old_x != NULL)
+ {
+ FreeX(old_x);
+ }
+
+ if (expired != NULL)
+ {
+ *expired = true;
+ }
+
+ return false;
+ }
+
+ if (old_x != NULL)
+ {
+ if (CompareX(old_x, server_x))
+ {
+ // Matched exactly to the certificate that is already registered
+ if (old_x != NULL)
+ {
+ FreeX(old_x);
+ }
+ return true;
+ }
+ else
+ {
+ dlg.DiffWarning = true;
+ }
+ }
+
+ // Because this certificate can not be trusted, confirm to be trusted by showing a dialog box
+ UniStrCpy(dlg.AccountName, sizeof(dlg.AccountName), a->ClientOption->AccountName);
+ StrCpy(dlg.ServerName, sizeof(dlg.ServerName), a->ClientOption->Hostname);
+ dlg.x = server_x;
+ dlg.old_x = old_x;
+
+ dlg.Session = s;
+ AddRef(s->ref);
+
+ CncCheckCert(s, &dlg);
+
+ ReleaseSession(s);
+
+ if (old_x != NULL)
+ {
+ FreeX(old_x);
+ }
+
+ if (dlg.Ok && dlg.SaveServerCert)
+ {
+ // Save the server certificate and trust it from the next time
+ Lock(a->lock);
+ {
+ if (a->ServerCert != NULL)
+ {
+ FreeX(a->ServerCert);
+ }
+
+ a->ServerCert = CloneX(server_x);
+ }
+ Unlock(a->lock);
+ CiSaveConfigurationFile(s->Cedar->Client);
+ }
+
+ return dlg.Ok;
+#else // OS_WIN32
+ ACCOUNT *a;
+ X *old_x = NULL;
+ // Validate arguments
+ if (s == NULL || c == NULL || server_x == NULL)
+ {
+ return false;
+ }
+
+ if (expired != NULL)
+ {
+ *expired = false;
+ }
+
+ a = s->Account;
+ if (a == NULL)
+ {
+ return false;
+ }
+
+ Lock(a->lock);
+ {
+ if (a->CheckServerCert == false)
+ {
+ // Not to validate the server certificate
+ Unlock(a->lock);
+ return true;
+ }
+
+ if (a->ServerCert != NULL)
+ {
+ old_x = CloneX(a->ServerCert);
+ }
+ }
+ Unlock(a->lock);
+
+ if (CheckXDateNow(server_x) == false)
+ {
+ // Expired
+ if (old_x != NULL)
+ {
+ FreeX(old_x);
+ }
+
+ if (expired != NULL)
+ {
+ *expired = true;
+ }
+
+ return false;
+ }
+
+ if (old_x != NULL)
+ {
+ if (CompareX(old_x, server_x))
+ {
+ // Exactly matched to the certificate that is already registered
+ if (old_x != NULL)
+ {
+ FreeX(old_x);
+ }
+ return true;
+ }
+ else
+ {
+ // Mismatch
+ if (old_x != NULL)
+ {
+ FreeX(old_x);
+ }
+ return false;
+ }
+ }
+
+ if (old_x != NULL)
+ {
+ FreeX(old_x);
+ }
+
+ return false;
+#endif // OS_WIN32
+}
+
+// Signature procedure with a secure device
+bool CiSecureSignProc(SESSION *s, CONNECTION *c, SECURE_SIGN *sign)
+{
+ // The UI is available in Win32
+ return CncSecureSignDlg(sign);
+}
+
+#ifdef OS_WIN32
+// Signing procedure (for Win32)
+bool Win32CiSecureSign(SECURE_SIGN *sign)
+{
+ bool ret = false;
+ BUF *random;
+ // Validate arguments
+ if (sign == NULL)
+ {
+ return false;
+ }
+
+ random = NewBuf();
+ WriteBuf(random, sign->Random, SHA1_SIZE);
+
+ // Batch processing
+ {
+ WINUI_SECURE_BATCH batch[] =
+ {
+ {WINUI_SECURE_READ_CERT, sign->SecurePublicCertName, true, NULL, NULL, NULL, NULL, NULL, NULL},
+ {WINUI_SECURE_SIGN_WITH_KEY, sign->SecurePrivateKeyName, true, random, NULL, NULL, NULL, NULL, NULL}
+ };
+
+ if (SecureDeviceWindow(NULL, batch, sizeof(batch) / sizeof(batch[0]),
+ sign->UseSecureDeviceId, sign->BitmapId) == false)
+ {
+ // Failure
+ if (batch[0].OutputX != 0)
+ {
+ FreeX(batch[0].OutputX);
+ }
+ ret = false;
+ }
+ else
+ {
+ // Success
+ ret = true;
+ sign->ClientCert = batch[0].OutputX;
+ Copy(sign->Signature, batch[1].OutputSign, 128);
+ }
+ }
+
+ FreeBuf(random);
+
+ return ret;
+}
+#endif // OS_WIN32
+
+// Disconnect
+bool CtDisconnect(CLIENT *c, RPC_CLIENT_CONNECT *connect, bool inner)
+{
+ bool ret = false;
+ ACCOUNT t, *r;
+ SESSION *s = NULL;
+ // Validate arguments
+ if (c == NULL || connect == NULL)
+ {
+ return false;
+ }
+
+ LockList(c->AccountList);
+ {
+ // Search for account
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), connect->AccountName);
+
+ r = Search(c->AccountList, &t);
+ if (r == NULL)
+ {
+ // Specified account isn't found
+ UnlockList(c->AccountList);
+
+ Free(t.ClientOption);
+ CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+ Lock(r->lock);
+ {
+ if (r->ClientSession == NULL)
+ {
+ // Not connected
+ CiSetError(c, ERR_ACCOUNT_INACTIVE);
+ }
+ else
+ {
+ s = r->ClientSession;
+ AddRef(s->ref);
+ // Disconnect complete
+ r->ClientSession = NULL;
+ ret = true;
+ }
+ }
+ Unlock(r->lock);
+ }
+ UnlockList(c->AccountList);
+
+ if (s != NULL)
+ {
+ // Disconnect the connection (Wait until the disconnection is complete)
+ CLog(c, "LC_DISCONNECT", connect->AccountName);
+ StopSession(s);
+ ReleaseSession(s);
+ }
+
+
+ if (ret != false)
+ {
+ CiNotify(c);
+ }
+
+ return ret;
+}
+
+// Connect
+bool CtConnect(CLIENT *c, RPC_CLIENT_CONNECT *connect)
+{
+ bool ret = false;
+ RPC_CLIENT_ENUM_VLAN t;
+ // Validate arguments
+ if (c == NULL || connect == NULL)
+ {
+ return false;
+ }
+
+ Lock(c->lockForConnect);
+ {
+ Zero(&t, sizeof(t));
+ if (CtEnumVLan(c, &t))
+ {
+ if (t.NumItem == 0)
+ {
+ // There are no virtual LAN cards in the system
+ if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) || OS_IS_UNIX(GetOsInfo()->OsType))
+ {
+ // Only in Linux system or Windows NT system,
+ // create a new virtual LAN card which named as "VPN" automatically
+ RPC_CLIENT_CREATE_VLAN t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), "VPN");
+ CtCreateVLan(c, &t);
+ }
+ }
+
+ CiFreeClientEnumVLan(&t);
+ }
+ }
+ Unlock(c->lockForConnect);
+
+ CiNormalizeAccountVLan(c);
+
+ // Ensure successfully VPN communication by changing the irrational WCM settings in the case of Windows 8 or later
+ CiDisableWcmNetworkMinimize(c);
+
+ LockList(c->AccountList);
+ {
+ ACCOUNT t, *r;
+ bool unix_disabled = false;
+
+ // Search for account
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), connect->AccountName);
+
+ r = Search(c->AccountList, &t);
+ if (r == NULL)
+ {
+ // Specified account isn't found
+ UnlockList(c->AccountList);
+
+ Free(t.ClientOption);
+ CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+#ifndef OS_WIN32
+ // Search for the virtual LAN card
+ LockList(c->UnixVLanList);
+ {
+ UNIX_VLAN *v, t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), r->ClientOption->DeviceName);
+
+ v = Search(c->UnixVLanList, &t);
+ if (v == NULL)
+ {
+ UnlockList(c->UnixVLanList);
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ return false;
+ }
+
+ unix_disabled = v->Enabled ? false : true;
+ }
+ UnlockList(c->UnixVLanList);
+#endif // OS_WIN32
+
+ Lock(r->lock);
+ {
+ bool already_used = false;
+ UINT i;
+
+ if (r->ClientSession != NULL)
+ {
+ // Already in connecting
+ CiSetError(c, ERR_ACCOUNT_ACTIVE);
+ }
+ else if (r->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE &&
+ client->UseSecureDeviceId == 0)
+ {
+ // Secure device is not specified
+ CiSetError(c, ERR_NO_SECURE_DEVICE_SPECIFIED);
+ }
+#ifdef OS_WIN32
+ else if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, r->ClientOption->DeviceName) == false &&
+ MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, r->ClientOption->DeviceName) == false)
+ {
+ // Virtual LAN card can not be found
+ CiSetError(c, ERR_VLAN_FOR_ACCOUNT_NOT_FOUND);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ }
+ else if (MsIsVLanEnabled(r->ClientOption->DeviceName) == false)
+ {
+ // The virtual LAN card is disabled
+ CiSetError(c, ERR_VLAN_FOR_ACCOUNT_DISABLED);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ }
+#else // OS_WIN32
+ else if (unix_disabled)
+ {
+ // The virtual LAN card is disabled
+ CiSetError(c, ERR_VLAN_FOR_ACCOUNT_DISABLED);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ }
+#endif // OS_WIN32
+ else
+ {
+ // Check whether the virtual LAN card is being used by a different account already
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+ if (a != r)
+ {
+ if (StrCmpi(a->ClientOption->DeviceName,
+ r->ClientOption->DeviceName) == 0)
+ {
+ if (a->ClientSession != NULL)
+ {
+ already_used = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (already_used)
+ {
+ CiSetError(c, ERR_VLAN_FOR_ACCOUNT_USED);
+ }
+ else
+ {
+ // Start the connection
+ PACKET_ADAPTER *pa = VLanGetPacketAdapter();
+
+ if (r->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE)
+ {
+ // Register a procedure for secure device authentication
+ r->ClientAuth->SecureSignProc = CiSecureSignProc;
+ }
+ else
+ {
+ r->ClientAuth->SecureSignProc = NULL;
+ }
+
+ if (r->CheckServerCert)
+ {
+ // Register a procedure to validate the server certificate
+ r->ClientAuth->CheckCertProc = CiCheckCertProc;
+ }
+ else
+ {
+ r->ClientAuth->CheckCertProc = NULL;
+ }
+
+ r->StatusPrinter = CiClientStatusPrinter;
+ r->LastConnectDateTime = SystemTime64();
+
+ CLog(c, "LC_CONNECT", connect->AccountName);
+
+ r->ClientSession = NewClientSessionEx(c->Cedar, r->ClientOption, r->ClientAuth, pa, r);
+ Notify(r->ClientSession, CLIENT_NOTIFY_ACCOUNT_CHANGED);
+
+ ret = true;
+ }
+ }
+ }
+ Unlock(r->lock);
+
+ }
+ UnlockList(c->AccountList);
+
+ CiSaveConfigurationFile(c);
+
+ return ret;
+}
+
+// Get the account information
+bool CtGetAccount(CLIENT *c, RPC_CLIENT_GET_ACCOUNT *a)
+{
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+ LockList(c->AccountList);
+ {
+ ACCOUNT t, *r;
+
+ // Search for account
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName);
+
+ r = Search(c->AccountList, &t);
+ if (r == NULL)
+ {
+ // Specified account can not be found
+ UnlockList(c->AccountList);
+
+ Free(t.ClientOption);
+ CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+ Lock(r->lock);
+ {
+ // Copy the client option
+ if (a->ClientOption != NULL)
+ {
+ Free(a->ClientOption);
+ }
+ a->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(a->ClientOption, r->ClientOption, sizeof(CLIENT_OPTION));
+
+ // Copy the authentication data
+ if (a->ClientAuth != NULL)
+ {
+ CiFreeClientAuth(a->ClientAuth);
+ }
+ a->ClientAuth = CopyClientAuth(r->ClientAuth);
+
+ a->StartupAccount = r->StartupAccount;
+
+ a->CheckServerCert = r->CheckServerCert;
+ a->ServerCert = NULL;
+ if (r->ServerCert != NULL)
+ {
+ a->ServerCert = CloneX(r->ServerCert);
+ }
+
+ // Shortcut Key
+ Copy(a->ShortcutKey, r->ShortcutKey, SHA1_SIZE);
+
+ a->CreateDateTime = r->CreateDateTime;
+ a->LastConnectDateTime = r->LastConnectDateTime;
+ a->UpdateDateTime = r->UpdateDateTime;
+ }
+ Unlock(r->lock);
+
+ }
+ UnlockList(c->AccountList);
+
+ return true;
+}
+
+// Change the account name
+bool CtRenameAccount(CLIENT *c, RPC_RENAME_ACCOUNT *rename, bool inner)
+{
+ bool ret;
+ // Validate arguments
+ if (c == NULL || rename == NULL)
+ {
+ return false;
+ }
+
+
+ ret = false;
+
+ if (UniStrCmp(rename->NewName, rename->OldName) == 0)
+ {
+ // The name has not been changed
+ return true;
+ }
+
+ LockList(c->AccountList);
+ {
+ ACCOUNT t, *r, *r2;
+
+ if (UniStrLen(rename->NewName) == 0)
+ {
+ // Name is invalid
+ CiSetError(c, ERR_INVALID_VALUE);
+ UnlockList(c->AccountList);
+ return false;
+ }
+
+ // Search for old account name
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), rename->OldName);
+
+ r = Search(c->AccountList, &t);
+ if (r == NULL)
+ {
+ // Specified account can not be found
+ UnlockList(c->AccountList);
+
+ Free(t.ClientOption);
+ CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+ // Search for a new account name
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), rename->NewName);
+
+ r2 = Search(c->AccountList, &t);
+ if (r2 != NULL)
+ {
+ // Account with the specified name already exists
+ UnlockList(c->AccountList);
+
+ Free(t.ClientOption);
+ CiSetError(c, ERR_ACCOUNT_ALREADY_EXISTS);
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+ Lock(r->lock);
+ {
+ // Check the operating state of the account
+ if (r->ClientSession != NULL)
+ {
+ // The Account is working
+ Unlock(r->lock);
+ UnlockList(c->AccountList);
+ CiSetError(c, ERR_ACCOUNT_ACTIVE);
+
+ return false;
+ }
+
+ // Update the account name
+ UniStrCpy(r->ClientOption->AccountName, sizeof(r->ClientOption->AccountName),
+ rename->NewName);
+
+ CLog(c, "LC_RENAME_ACCOUNT", rename->OldName, rename->NewName);
+
+ ret = true;
+ }
+ Unlock(r->lock);
+
+ Sort(c->AccountList);
+
+ }
+ UnlockList(c->AccountList);
+
+ CiSaveConfigurationFile(c);
+
+ CiNotify(c);
+
+ return ret;
+}
+
+// Set the client configuration
+bool CtSetClientConfig(CLIENT *c, CLIENT_CONFIG *o)
+{
+ KEEP *k;
+ // Validate arguments
+ if (c == NULL || o == NULL)
+ {
+ return false;
+ }
+
+ if (o->UseKeepConnect)
+ {
+ if (IsEmptyStr(o->KeepConnectHost) ||
+ o->KeepConnectPort == 0 ||
+ o->KeepConnectPort >= 65536)
+ {
+ CiSetError(c, ERR_INVALID_PARAMETER);
+ return false;
+ }
+ }
+
+ Lock(c->lock);
+ {
+ Copy(&c->Config, o, sizeof(CLIENT_CONFIG));
+ }
+ Unlock(c->lock);
+
+ // Save the settings
+ CiSaveConfigurationFile(c);
+
+ // Apply the Keep Connect
+ k = c->Keep;
+ Lock(k->lock);
+ {
+ if (o->UseKeepConnect)
+ {
+ StrCpy(k->ServerName, sizeof(k->ServerName), c->Config.KeepConnectHost);
+ k->ServerPort = c->Config.KeepConnectPort;
+ k->Interval = c->Config.KeepConnectInterval * 1000;
+ k->UdpMode = (c->Config.KeepConnectProtocol == CONNECTION_UDP) ? true : false;
+ k->Enable = true;
+ }
+ else
+ {
+ k->Enable = false;
+ }
+ }
+ Unlock(k->lock);
+
+ return true;
+}
+
+// Get the network client configuration
+bool CtGetClientConfig(CLIENT *c, CLIENT_CONFIG *o)
+{
+ // Validate arguments
+ if (c == NULL || o == NULL)
+ {
+ return false;
+ }
+
+ Lock(c->lock);
+ {
+ Copy(o, &c->Config, sizeof(CLIENT_CONFIG));
+ }
+ Unlock(c->lock);
+
+ return true;
+}
+
+// Unset the startup attribute of the account
+bool CtRemoveStartupAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a)
+{
+ bool ret;
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+ ret = false;
+
+ LockList(c->AccountList);
+ {
+ ACCOUNT t, *r;
+ // Search for an Account
+
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName);
+
+ r = Search(c->AccountList, &t);
+ if (r == NULL)
+ {
+ // Specified account can not be found
+ UnlockList(c->AccountList);
+
+ Free(t.ClientOption);
+ CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+ Lock(r->lock);
+ {
+ // Unset the startup account
+ ret = true;
+ r->StartupAccount = false;
+ }
+ Unlock(r->lock);
+ }
+ UnlockList(c->AccountList);
+
+ if (ret)
+ {
+ CiSaveConfigurationFile(c);
+ CiNotify(c);
+ }
+
+ return ret;
+}
+
+// Set the account as a start-up account
+bool CtSetStartupAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a, bool inner)
+{
+ bool ret;
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+
+ ret = false;
+
+ LockList(c->AccountList);
+ {
+ ACCOUNT t, *r;
+ // Search for an account
+
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName);
+
+ r = Search(c->AccountList, &t);
+ if (r == NULL)
+ {
+ // Specified account can not be found
+ UnlockList(c->AccountList);
+
+ Free(t.ClientOption);
+ CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+ Lock(r->lock);
+ {
+ // Set to a start-up account
+ ret = true;
+ r->StartupAccount = true;
+ }
+ Unlock(r->lock);
+ }
+ UnlockList(c->AccountList);
+
+ if (ret)
+ {
+ CiSaveConfigurationFile(c);
+ CiNotify(c);
+ }
+
+ return ret;
+}
+
+// Delete the account
+bool CtDeleteAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a, bool inner)
+{
+ bool ret;
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+ ret = false;
+
+ if (c->Halt)
+ {
+ // Don't allow the removal of the account in the process of stopping
+ CiSetError(c, ERR_INTERNAL_ERROR);
+ return false;
+ }
+
+ LockList(c->AccountList);
+ {
+ ACCOUNT t, *r;
+ // Search for an Account
+
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), a->AccountName);
+
+ r = Search(c->AccountList, &t);
+ if (r == NULL)
+ {
+ // Specified account can not be found
+ UnlockList(c->AccountList);
+
+ Free(t.ClientOption);
+ CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+ Lock(r->lock);
+ {
+ // Check the operating state of the account
+ if (r->ClientSession != NULL)
+ {
+ // The account is active
+ Unlock(r->lock);
+ UnlockList(c->AccountList);
+ CiSetError(c, ERR_ACCOUNT_ACTIVE);
+
+ return false;
+ }
+
+ // Remove this account from the list
+ Delete(c->AccountList, r);
+ }
+ Unlock(r->lock);
+
+ // Free the memory of this account
+ CiFreeAccount(r);
+
+ CLog(c, "LC_DELETE_ACCOUNT", a->AccountName);
+ ret = true;
+
+ }
+ UnlockList(c->AccountList);
+
+ if (ret)
+ {
+ CiSaveConfigurationFile(c);
+ CiNotify(c);
+ }
+
+ return ret;
+}
+
+// Enumeration of accounts
+bool CtEnumAccount(CLIENT *c, RPC_CLIENT_ENUM_ACCOUNT *e)
+{
+ // Validate arguments
+ if (c == NULL || e == NULL)
+ {
+ return false;
+ }
+
+ LockList(c->AccountList);
+ {
+ UINT i;
+ // Number of accounts
+ e->NumItem = LIST_NUM(c->AccountList);
+ e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM *) * e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *item = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_ACCOUNT_ITEM));
+ e->Items[i] = item;
+
+ // Account name
+ UniStrCpy(item->AccountName, sizeof(item->AccountName), a->ClientOption->AccountName);
+
+ // User name
+ StrCpy(item->UserName, sizeof(item->UserName), a->ClientAuth->Username);
+
+ // Server name
+ StrCpy(item->ServerName, sizeof(item->ServerName), a->ClientOption->Hostname);
+
+ // Proxy type
+ item->ProxyType = a->ClientOption->ProxyType;
+
+ // Device name
+ StrCpy(item->DeviceName, sizeof(item->DeviceName), a->ClientOption->DeviceName);
+
+ // Proxy information
+ if (item->ProxyType != PROXY_DIRECT)
+ {
+ StrCpy(item->ProxyName, sizeof(item->ProxyName), a->ClientOption->ProxyName);
+ }
+
+ // Startup
+ item->StartupAccount = a->StartupAccount;
+
+ // Active flag
+ item->Active = (a->ClientSession == NULL ? false : true);
+
+ // Connection flag
+ item->Connected = (item->Active == false) ? false : a->ClientSession->ConnectSucceed;
+
+ // Port number
+ item->Port = a->ClientOption->Port;
+
+ // Virtual HUB name
+ StrCpy(item->HubName, sizeof(item->HubName), a->ClientOption->HubName);
+
+ item->CreateDateTime = a->CreateDateTime;
+ item->LastConnectDateTime = a->LastConnectDateTime;
+ item->UpdateDateTime = a->UpdateDateTime;
+ }
+ }
+ UnlockList(c->AccountList);
+
+ return true;
+}
+
+// Configure the account
+bool CtSetAccount(CLIENT *c, RPC_CLIENT_CREATE_ACCOUNT *a, bool inner)
+{
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+
+ // Check whether an account already exists
+ LockList(c->AccountList);
+ {
+ ACCOUNT t, *ret;
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName),
+ a->ClientOption->AccountName);
+
+ ret = Search(c->AccountList, &t);
+ if (ret == NULL)
+ {
+ // Not exist
+ UnlockList(c->AccountList);
+ Free(t.ClientOption);
+
+ CiSetError(c, ERR_ACCOUNT_NOT_FOUND);
+
+ return false;
+ }
+ Free(t.ClientOption);
+
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)
+ {
+ if (a->ClientAuth->ClientX == NULL ||
+ a->ClientAuth->ClientX->is_compatible_bit == false ||
+ a->ClientAuth->ClientK == NULL)
+ {
+ // Client certificate is invalid
+ UnlockList(c->AccountList);
+ CiSetError(c, ERR_NOT_RSA_1024);
+ return false;
+ }
+ }
+
+ if (a->ServerCert != NULL && a->ServerCert->is_compatible_bit == false)
+ {
+ // Server certificate is invalid
+ UnlockList(c->AccountList);
+ CiSetError(c, ERR_NOT_RSA_1024);
+ return false;
+ }
+
+ Lock(ret->lock);
+ {
+
+#if 0
+ // Rewriting of the configuration is done even account running in the current version
+ // (New setting isn't applied until connecting next time)
+ if (ret->ClientSession != NULL)
+ {
+ // The account is operating
+ Unlock(ret->lock);
+ UnlockList(c->AccountList);
+
+ CiSetError(c, ERR_ACCOUNT_ACTIVE);
+
+ return false;
+ }
+#endif
+
+ // Delete the client authentication data
+ CiFreeClientAuth(ret->ClientAuth);
+
+ // Copy the client authentication data
+ ret->ClientAuth = CopyClientAuth(a->ClientAuth);
+
+ // Delete the client option
+ Free(ret->ClientOption);
+
+ // Copy the client option
+ ret->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(ret->ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));
+
+ ret->StartupAccount = a->StartupAccount;
+
+ ret->CheckServerCert = a->CheckServerCert;
+
+ if (a->ServerCert != NULL)
+ {
+ if (ret->ServerCert != NULL)
+ {
+ FreeX(ret->ServerCert);
+ }
+ ret->ServerCert = CloneX(a->ServerCert);
+ }
+ else
+ {
+ if (ret->ServerCert != NULL)
+ {
+ FreeX(ret->ServerCert);
+ }
+ ret->ServerCert = false;
+ }
+
+ ret->UpdateDateTime = SystemTime64();
+ }
+ Unlock(ret->lock);
+ }
+ UnlockList(c->AccountList);
+
+ CiSaveConfigurationFile(c);
+
+ CiNotify(c);
+
+ return true;
+}
+
+// Create an account
+bool CtCreateAccount(CLIENT *c, RPC_CLIENT_CREATE_ACCOUNT *a, bool inner)
+{
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+
+ // Check whether an account already exists
+ LockList(c->AccountList);
+ {
+ ACCOUNT t, *ret, *new_account;
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName),
+ a->ClientOption->AccountName);
+
+ ret = Search(c->AccountList, &t);
+ if (ret != NULL)
+ {
+ // Already exist
+ UnlockList(c->AccountList);
+ Free(t.ClientOption);
+
+ CiSetError(c, ERR_ACCOUNT_ALREADY_EXISTS);
+
+ return false;
+ }
+
+ Free(t.ClientOption);
+
+ if (UniStrLen(a->ClientOption->AccountName) == 0)
+ {
+ // The name is invalid
+ UnlockList(c->AccountList);
+ CiSetError(c, ERR_INVALID_VALUE);
+ return false;
+ }
+
+ if (a->ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)
+ {
+ if (a->ClientAuth->ClientX == NULL ||
+ a->ClientAuth->ClientX->is_compatible_bit == false ||
+ a->ClientAuth->ClientK == NULL)
+ {
+ // The client certificate is invalid
+ UnlockList(c->AccountList);
+ CiSetError(c, ERR_NOT_RSA_1024);
+ return false;
+ }
+ }
+
+ if (a->ServerCert != NULL && a->ServerCert->is_compatible_bit == false)
+ {
+ // The server certificate is invalid
+ UnlockList(c->AccountList);
+ CiSetError(c, ERR_NOT_RSA_1024);
+ return false;
+ }
+
+ // Add a new account
+ new_account = ZeroMalloc(sizeof(ACCOUNT));
+ new_account->lock = NewLock();
+
+ // Copy the client authentication data
+ new_account->ClientAuth = CopyClientAuth(a->ClientAuth);
+
+ // Copy the client option
+ new_account->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(new_account->ClientOption, a->ClientOption, sizeof(CLIENT_OPTION));
+
+ new_account->StartupAccount = a->StartupAccount;
+
+ new_account->CheckServerCert = a->CheckServerCert;
+ if (a->ServerCert != NULL)
+ {
+ new_account->ServerCert = CloneX(a->ServerCert);
+ }
+
+ // Shortcut Key
+ if (IsZero(a->ShortcutKey, SHA1_SIZE))
+ {
+ Rand(new_account->ShortcutKey, SHA1_SIZE);
+ }
+ else
+ {
+ Copy(new_account->ShortcutKey, a->ShortcutKey, SHA1_SIZE);
+ }
+
+ new_account->CreateDateTime = new_account->UpdateDateTime = SystemTime64();
+
+ // Insert into the list
+ Insert(c->AccountList, new_account);
+
+ CLog(c, "LC_NEW_ACCOUNT", a->ClientOption->AccountName);
+ }
+ UnlockList(c->AccountList);
+
+ CiNormalizeAccountVLan(c);
+
+ CiSaveConfigurationFile(c);
+
+ CiNotify(c);
+
+ return true;
+}
+
+// Release the account acquisition structure
+void CiFreeClientGetAccount(RPC_CLIENT_GET_ACCOUNT *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ // Release the account information
+ if (a->ServerCert != NULL)
+ {
+ FreeX(a->ServerCert);
+ }
+ CiFreeClientAuth(a->ClientAuth);
+ Free(a->ClientOption);
+}
+
+// Release the account creation structure
+void CiFreeClientCreateAccount(RPC_CLIENT_CREATE_ACCOUNT *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ // Release the account information
+ if (a->ServerCert != NULL)
+ {
+ FreeX(a->ServerCert);
+ }
+ CiFreeClientAuth(a->ClientAuth);
+ Free(a->ClientOption);
+}
+
+// Stop the virtual LAN card
+bool CtDisableVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *vlan)
+{
+ UINT i;
+ bool used;
+ // Validate arguments
+ if (c == NULL || vlan == NULL)
+ {
+ return false;
+ }
+
+#ifndef OS_WIN32
+
+ if (GetOsInfo()->OsType == OSTYPE_MACOS_X)
+ {
+ // Can not be added or removed the virtual LAN card in MacOS X
+ CiSetError(c, ERR_NOT_SUPPORTED);
+ return false;
+ }
+
+ // Check whether the virtual LAN card with the specified name is not
+ // being used by one or more accounts
+ used = false;
+ LockList(c->AccountList);
+ {
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+ if (StrCmpi(a->ClientOption->DeviceName, vlan->DeviceName) == 0)
+ {
+ Lock(a->lock);
+ {
+ if (a->ClientSession != NULL)
+ {
+ used = true;
+ }
+ }
+ Unlock(a->lock);
+ }
+ }
+ }
+ UnlockList(c->AccountList);
+
+ // Search for the virtual LAN card
+ LockList(c->UnixVLanList);
+ {
+ UNIX_VLAN *v, t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), vlan->DeviceName);
+
+ v = Search(c->UnixVLanList, &t);
+ if (v == NULL)
+ {
+ UnlockList(c->UnixVLanList);
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ return false;
+ }
+
+ // Stop
+ v->Enabled = false;
+ }
+ UnlockList(c->UnixVLanList);
+
+ CiSaveConfigurationFile(c);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ return true;
+
+#else // OS_WIN32
+
+ // Check whether the virtual LAN card with the specified name is not
+ // being used by one or more accounts
+ used = false;
+ LockList(c->AccountList);
+ {
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+ if (StrCmpi(a->ClientOption->DeviceName, vlan->DeviceName) == 0)
+ {
+ Lock(a->lock);
+ {
+ if (a->ClientSession != NULL)
+ {
+ used = true;
+ }
+ }
+ Unlock(a->lock);
+ }
+ }
+ }
+ UnlockList(c->AccountList);
+
+#if 0
+ if (used)
+ {
+ // In using
+ CiSetError(c, ERR_VLAN_IS_USED);
+ return false;
+ }
+#endif
+
+
+ // Check whether the virtual LAN card are present
+ if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, vlan->DeviceName) == false &&
+ MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, vlan->DeviceName) == false)
+ {
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+
+
+ if (MsIs64BitWindows() && Is32() && MsIsAdmin())
+ {
+ // Execute the driver_installer to process since this Windows is 64 bit
+ // but this code is 32 bit
+ char tmp[MAX_SIZE];
+
+ Format(tmp, sizeof(tmp), "disablevlan %s", vlan->DeviceName);
+
+ if (MsExecDriverInstaller(tmp) == false)
+ {
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+ }
+ else
+ {
+ // Stop the virtual LAN card
+ if (MsDisableVLan(vlan->DeviceName) == false)
+ {
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+ }
+
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ return true;
+
+#endif // OS_WIN32
+
+}
+
+// Start the virtual LAN card
+bool CtEnableVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *vlan)
+{
+ // Validate arguments
+ if (c == NULL || vlan == NULL)
+ {
+ return false;
+ }
+
+#ifndef OS_WIN32
+
+ if (GetOsInfo()->OsType == OSTYPE_MACOS_X)
+ {
+ // Can not be added or removed the virtual LAN card in MacOS X
+ CiSetError(c, ERR_NOT_SUPPORTED);
+ return false;
+ }
+
+ // Search the virtual LAN card
+ LockList(c->UnixVLanList);
+ {
+ UNIX_VLAN *v, t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), vlan->DeviceName);
+
+ v = Search(c->UnixVLanList, &t);
+ if (v == NULL)
+ {
+ UnlockList(c->UnixVLanList);
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ return false;
+ }
+
+ // Enable
+ v->Enabled = true;
+ }
+ UnlockList(c->UnixVLanList);
+
+ CiSaveConfigurationFile(c);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ return true;
+
+#else // OS_WIN32
+
+ // Check whether the virtual LAN card are present
+ if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, vlan->DeviceName) == false &&
+ MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, vlan->DeviceName) == false)
+ {
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+
+ if (MsIs64BitWindows() && Is32() && MsIsAdmin())
+ {
+ // Execute the driver_installer to process since this Windows is 64 bit
+ // but this code is 32 bit
+ char tmp[MAX_SIZE];
+
+ Format(tmp, sizeof(tmp), "enablevlan %s", vlan->DeviceName);
+
+ if (MsExecDriverInstaller(tmp) == false)
+ {
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+ }
+ else
+ {
+ // Start the virtual LAN card
+ if (MsEnableVLan(vlan->DeviceName) == false)
+ {
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+ }
+
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ return true;
+
+#endif // OS_WIN32
+
+}
+
+// Delete the virtual LAN card
+bool CtDeleteVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *d)
+{
+ UINT i;
+ bool used;
+ // Validate arguments
+ if (c == NULL || d == NULL)
+ {
+ return false;
+ }
+
+#ifndef OS_WIN32
+
+ if (GetOsInfo()->OsType == OSTYPE_MACOS_X)
+ {
+ // Can not be added or removed the virtual LAN card in MacOS X
+ CiSetError(c, ERR_NOT_SUPPORTED);
+ return false;
+ }
+
+ // Check whether the virtual LAN card with the specified name is not
+ // being used by one or more accounts
+ used = false;
+ LockList(c->AccountList);
+ {
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+ if (StrCmpi(a->ClientOption->DeviceName, d->DeviceName) == 0)
+ {
+ used = true;
+ }
+ }
+ }
+ UnlockList(c->AccountList);
+
+#if 0
+ if (used)
+ {
+ // In using
+ CiSetError(c, ERR_VLAN_IS_USED);
+ return false;
+ }
+#endif
+
+ // Search for the virtual LAN card
+ LockList(c->UnixVLanList);
+ {
+ UNIX_VLAN *v, t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), d->DeviceName);
+
+ v = Search(c->UnixVLanList, &t);
+ if (v == NULL)
+ {
+ UnlockList(c->UnixVLanList);
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ return false;
+ }
+
+ // Remove
+ if (Delete(c->UnixVLanList, v))
+ {
+ Free(v);
+ }
+
+ CLog(c, "LC_DELETE_VLAN", d->DeviceName);
+
+ UnixVLanDelete(d->DeviceName);
+ }
+ UnlockList(c->UnixVLanList);
+
+ CiNormalizeAccountVLan(c);
+
+ CiSaveConfigurationFile(c);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ return true;
+
+#else // OS_WIN32
+
+ if (MsIsNt() == false)
+ {
+ // Not available in Win9x
+ CiSetError(c, ERR_NOT_SUPPORTED);
+ return false;
+ }
+
+ // Check whether the virtual LAN card are present
+ if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, d->DeviceName) == false &&
+ MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, d->DeviceName) == false)
+ {
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ return false;
+ }
+
+ // Check whether the virtual LAN card with the specified name is not
+ // being used by one or more accounts
+ used = false;
+ LockList(c->AccountList);
+ {
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+ if (StrCmpi(a->ClientOption->DeviceName, d->DeviceName) == 0)
+ {
+ used = true;
+ }
+ }
+ }
+ UnlockList(c->AccountList);
+
+#if 0
+ if (used)
+ {
+ // In using
+ CiSetError(c, ERR_VLAN_IS_USED);
+ return false;
+ }
+#endif
+
+ if (MsIs64BitWindows() && Is32() && MsIsAdmin())
+ {
+ // Execute the driver_installer to process since this Windows is 64 bit
+ // but this code is 32 bit
+ char tmp[MAX_SIZE];
+
+ Format(tmp, sizeof(tmp), "uninstvlan %s", d->DeviceName);
+
+ if (MsExecDriverInstaller(tmp) == false)
+ {
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ return false;
+ }
+ }
+ else
+ {
+ // Delete the virtual LAN card directly
+ if (MsUninstallVLan(d->DeviceName) == false)
+ {
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+ }
+
+ CLog(c, "LC_DELETE_VLAN", d->DeviceName);
+
+ CiNormalizeAccountVLan(c);
+
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ return true;
+
+#endif // OS_WIN32
+
+}
+
+// Get the name of the first VLAN
+char *CiGetFirstVLan(CLIENT *c)
+{
+ char *ret = NULL;
+ RPC_CLIENT_ENUM_VLAN t;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&t, sizeof(t));
+ if (CtEnumVLan(c, &t) == false)
+ {
+ return NULL;
+ }
+
+ if (t.NumItem >= 1)
+ {
+ UINT i;
+ char *tmp = t.Items[0]->DeviceName;
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ if (t.Items[i]->Enabled)
+ {
+ tmp = t.Items[i]->DeviceName;
+ }
+ }
+
+ ret = CopyStr(tmp);
+ }
+
+ CiFreeClientEnumVLan(&t);
+
+ return ret;
+}
+
+// Enumerate virtual LAN cards
+bool CtEnumVLan(CLIENT *c, RPC_CLIENT_ENUM_VLAN *e)
+{
+ UINT i;
+ TOKEN_LIST *t;
+ // Validate arguments
+ if (c == NULL || e == NULL)
+ {
+ return false;
+ }
+
+#ifndef OS_WIN32
+
+ LockList(c->UnixVLanList);
+ {
+ e->NumItem = LIST_NUM(c->UnixVLanList);
+ e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM *) * e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_VLAN_ITEM *item;
+ UNIX_VLAN *v;
+
+ v = LIST_DATA(c->UnixVLanList, i);
+ e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM));
+ item = e->Items[i];
+
+ item->Enabled = v->Enabled;
+ BinToStr(item->MacAddress, sizeof(item->MacAddress), v->MacAddress, 6);
+ StrCpy(item->DeviceName, sizeof(item->DeviceName), v->Name);
+ StrCpy(item->Version, sizeof(item->Version), c->Cedar->VerString);
+ }
+ }
+ UnlockList(c->UnixVLanList);
+
+ return true;
+
+#else // OS_WIN32
+
+ // Enumeration
+ t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, VLAN_ADAPTER_NAME_OLD);
+ if (t == NULL)
+ {
+ // Enumeration failure
+ e->NumItem = 0;
+ e->Items = ZeroMalloc(0);
+ }
+ else
+ {
+ // Enumeration success
+ e->NumItem = t->NumTokens;
+ e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM *) * e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ char *tmp;
+ RPC_CLIENT_ENUM_VLAN_ITEM *item;
+ e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_VLAN_ITEM));
+ item = e->Items[i];
+
+ StrCpy(item->DeviceName, sizeof(item->DeviceName), t->Token[i]);
+ item->Enabled = MsIsVLanEnabled(item->DeviceName);
+
+ tmp = MsGetMacAddress(VLAN_ADAPTER_NAME_TAG, item->DeviceName);
+ if (tmp == NULL)
+ {
+ tmp = MsGetMacAddress(VLAN_ADAPTER_NAME_TAG_OLD, item->DeviceName);
+ }
+
+ StrCpy(item->MacAddress, sizeof(item->MacAddress), tmp);
+ Free(tmp);
+
+ tmp = MsGetDriverVersion(VLAN_ADAPTER_NAME_TAG, item->DeviceName);
+ if (tmp == NULL)
+ {
+ tmp = MsGetDriverVersion(VLAN_ADAPTER_NAME_TAG_OLD, item->DeviceName);
+ }
+
+ StrCpy(item->Version, sizeof(item->Version), tmp);
+ Free(tmp);
+ }
+
+ FreeToken(t);
+ }
+
+ return true;
+
+#endif // OS_WIN32
+}
+
+// Release the virtual LAN card enumeration
+void CiFreeClientEnumVLan(RPC_CLIENT_ENUM_VLAN *e)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ Free(e->Items[i]);
+ }
+ Free(e->Items);
+}
+
+// Set the information about the virtual LAN card
+bool CtSetVLan(CLIENT *c, RPC_CLIENT_SET_VLAN *set)
+{
+ // Validate arguments
+ if (c == NULL || set == NULL)
+ {
+ return false;
+ }
+
+#ifndef OS_WIN32
+
+ LockList(c->UnixVLanList);
+ {
+ UNIX_VLAN t, *r;
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), set->DeviceName);
+
+ r = Search(c->UnixVLanList, &t);
+ if (r == NULL)
+ {
+ // Not exist
+ CiSetError(c, ERR_VLAN_ALREADY_EXISTS);
+ UnlockList(c->UnixVLanList);
+ return false;
+ }
+
+ StrToMac(r->MacAddress, set->MacAddress);
+ }
+ UnlockList(c->UnixVLanList);
+
+ CiSaveConfigurationFile(c);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ return true;
+
+#else // OS_WIN32
+
+ // Check whether the virtual LAN card with the specified name already exists
+ if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, set->DeviceName) == false &&
+ MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, set->DeviceName) == false)
+ {
+ // Not exist
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ return false;
+ }
+
+ // Configuring MAC address
+ MsSetMacAddress(VLAN_ADAPTER_NAME_TAG, set->DeviceName, set->MacAddress);
+ MsSetMacAddress(VLAN_ADAPTER_NAME_TAG_OLD, set->DeviceName, set->MacAddress);
+
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ return true;
+
+#endif // OS_WIN32
+}
+
+// Get the information about the virtual LAN card
+bool CtGetVLan(CLIENT *c, RPC_CLIENT_GET_VLAN *get)
+{
+ char *tmp;
+ // Validate arguments
+ if (c == NULL || get == NULL)
+ {
+ return false;
+ }
+
+#ifndef OS_WIN32
+
+ // Unsupported
+ CiSetError(c, ERR_NOT_SUPPORTED);
+ return false;
+
+#else // OS_WIN32
+
+ // Check whether the virtual LAN card with the specified name already exists
+ if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, get->DeviceName) == false &&
+ MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, get->DeviceName) == false)
+ {
+ // Not exist
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ return false;
+ }
+
+ // Activity
+ get->Enabled = MsIsVLanEnabled(get->DeviceName);
+
+ // MAC address
+ tmp = MsGetMacAddress(VLAN_ADAPTER_NAME_TAG, get->DeviceName);
+ if (tmp == NULL)
+ {
+ tmp = MsGetMacAddress(VLAN_ADAPTER_NAME_TAG_OLD, get->DeviceName);
+ }
+ StrCpy(get->MacAddress, sizeof(get->MacAddress), tmp);
+ Free(tmp);
+
+ // Version
+ tmp = MsGetDriverVersion(VLAN_ADAPTER_NAME_TAG, get->DeviceName);
+ if (tmp == NULL)
+ {
+ tmp = MsGetDriverVersion(VLAN_ADAPTER_NAME_TAG_OLD, get->DeviceName);
+ }
+ StrCpy(get->Version, sizeof(get->Version), tmp);
+ Free(tmp);
+
+ // File name
+ tmp = MsGetDriverFileName(VLAN_ADAPTER_NAME_TAG, get->DeviceName);
+ if (tmp == NULL)
+ {
+ tmp = MsGetDriverFileName(VLAN_ADAPTER_NAME_TAG_OLD, get->DeviceName);
+ }
+ StrCpy(get->FileName, sizeof(get->FileName), tmp);
+ Free(tmp);
+
+ // GUID
+ tmp = MsGetNetworkAdapterGuid(VLAN_ADAPTER_NAME_TAG, get->DeviceName);
+ if (tmp == NULL)
+ {
+ tmp = MsGetNetworkAdapterGuid(VLAN_ADAPTER_NAME_TAG_OLD, get->DeviceName);
+ }
+ StrCpy(get->Guid, sizeof(get->Guid), tmp);
+ Free(tmp);
+
+ return true;
+
+#endif // OS_WIN32
+}
+
+#ifdef OS_WIN32
+// Initialize the driver version information structure
+void CiInitDriverVerStruct(MS_DRIVER_VER *ver)
+{
+ UINT cedar_ver = CEDAR_VER;
+ // Validate arguments
+ if (ver == NULL)
+ {
+ return;
+ }
+
+ Zero(ver, sizeof(MS_DRIVER_VER));
+
+ ver->Year = BUILD_DATE_Y;
+ ver->Month = BUILD_DATE_M;
+ ver->Day = BUILD_DATE_D;
+ ver->Major = cedar_ver / 100;
+ ver->Minor = cedar_ver % 100;
+ ver->Build = CEDAR_BUILD;
+}
+#endif // OS_WIN32
+
+// Upgrade the virtual LAN card
+bool CtUpgradeVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *create)
+{
+ bool use_old_name = false;
+
+#ifdef OS_WIN32
+ KAKUSHI *k = NULL;
+ MS_DRIVER_VER ver;
+#endif // OS_WIN32
+
+ // Validate arguments
+ if (c == NULL || create == NULL)
+ {
+ return false;
+ }
+
+
+#ifndef OS_WIN32
+
+ // Always succeed
+ return true;
+
+#else // OS_WIN32
+
+ CiInitDriverVerStruct(&ver);
+
+ if (MsIsNt() == false)
+ {
+ // Not available in Win9x
+ CiSetError(c, ERR_NOT_SUPPORTED);
+ return false;
+ }
+
+ // Check whether the LAN card with the specified name already exists
+ if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, create->DeviceName) == false &&
+ MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, create->DeviceName) == false)
+ {
+ // Not exist
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+
+ if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, create->DeviceName))
+ {
+ use_old_name = true;
+ }
+
+ if (MsIsVista() == false)
+ {
+ k = InitKakushi();
+ }
+
+
+ if (MsIsVista() == false)
+ {
+ // Perform the installation (other than Windows Vista)
+ if (MsUpgradeVLan(use_old_name ? VLAN_ADAPTER_NAME_TAG_OLD : VLAN_ADAPTER_NAME_TAG,
+ use_old_name ? VLAN_CONNECTION_NAME_OLD : VLAN_CONNECTION_NAME,
+ create->DeviceName, &ver) == false)
+ {
+ // Installation Failed
+ FreeKakushi(k);
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+ }
+ else
+ {
+ // Perform the installation (Windows Vista)
+ char tmp[MAX_SIZE];
+
+ Format(tmp, sizeof(tmp), "upgradevlan %s", create->DeviceName);
+
+ if (CncExecDriverInstaller(tmp) == false)
+ {
+ // Installation Failed
+ FreeKakushi(k);
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+ }
+
+ FreeKakushi(k);
+
+ CLog(c, "LC_UPDATE_VLAN", create->DeviceName);
+
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ return true;
+
+#endif // OS_WIN32
+}
+
+// Create a virtual LAN card
+bool CtCreateVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *create)
+{
+ TOKEN_LIST *t;
+ UINT max_len;
+
+#ifdef OS_WIN32
+ KAKUSHI *k = NULL;
+#endif // OS_WIN32
+
+ // Validate arguments
+ if (c == NULL || create == NULL)
+ {
+ return false;
+ }
+
+ if (SearchStrEx(create->DeviceName, " ", 0, false) != INFINITE)
+ {
+ // Spaces in the name is not allowed
+ CiSetError(c, ERR_INVALID_PARAMETER);
+ return false;
+ }
+
+#ifndef OS_WIN32
+
+ // Non-Win32
+ if (GetOsInfo()->OsType == OSTYPE_MACOS_X)
+ {
+ // A virtual LAN card can not be added or removed in MacOS X
+ CiSetError(c, ERR_NOT_SUPPORTED);
+ return false;
+ }
+
+ // Check whether the specified name is valid or not
+ if (IsSafeStr(create->DeviceName) == false)
+ {
+ // Name is invalid
+ CiSetError(c, ERR_VLAN_INVALID_NAME);
+ return false;
+ }
+
+ // Check whether the LAN card of the specified name already exists
+ LockList(c->UnixVLanList);
+ {
+ UNIX_VLAN t, *r;
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), create->DeviceName);
+
+ r = Search(c->UnixVLanList, &t);
+ if (r != NULL)
+ {
+ // Already exist
+ CiSetError(c, ERR_VLAN_ALREADY_EXISTS);
+ UnlockList(c->UnixVLanList);
+ return false;
+ }
+
+ // Register
+ r = ZeroMalloc(sizeof(UNIX_VLAN));
+ r->Enabled = true;
+ GenMacAddress(r->MacAddress);
+ StrCpy(r->Name, sizeof(r->Name), create->DeviceName);
+
+ // Create a Tap
+ if (UnixVLanCreate(r->Name, r->MacAddress) == false)
+ {
+ // Failure
+ Free(r);
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ UnlockList(c->UnixVLanList);
+ return false;
+ }
+
+ CLog(c, "LC_CREATE_VLAN", create->DeviceName);
+
+ Add(c->UnixVLanList, r);
+ }
+ UnlockList(c->UnixVLanList);
+
+ CiNormalizeAccountVLan(c);
+
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ CiSaveConfigurationFile(c);
+
+ return true;
+
+#else // OS_WIN32
+
+ if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType))
+ {
+ // Only one LAN card is available in the Win9x
+ TOKEN_LIST *t;
+
+ t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, VLAN_ADAPTER_NAME_OLD);
+ if (t != NULL)
+ {
+ if (t->NumTokens >= 1)
+ {
+ FreeToken(t);
+ CiSetError(c, ERR_NOT_SUPPORTED);
+ return false;
+ }
+ FreeToken(t);
+ }
+ }
+
+ // Check whether the specified name is valid or not
+ if (IsSafeStr(create->DeviceName) == false)
+ {
+ // Name is invalid
+ CiSetError(c, ERR_VLAN_INVALID_NAME);
+ return false;
+ }
+
+ max_len = MsIsNt() ? MAX_DEVICE_NAME_LEN : MAX_DEVICE_NAME_LEN_9X;
+ if (StrLen(create->DeviceName) > max_len)
+ {
+ // Name is too long
+ CiSetError(c, ERR_VLAN_INVALID_NAME);
+ return false;
+ }
+
+ // Regulation in Windows 8
+ if (MsIsInfCatalogRequired())
+ {
+ if (CiIsValidVLanRegulatedName(create->DeviceName) == false)
+ {
+ // Name is invalid
+ CiSetError(c, ERR_VLAN_INVALID_NAME);
+ return false;
+ }
+ }
+
+ // Check whether the LAN card with the specified name already exists
+ if (MsIsVLanExists(VLAN_ADAPTER_NAME_TAG, create->DeviceName) ||
+ MsIsVLanExists(VLAN_ADAPTER_NAME_TAG_OLD, create->DeviceName))
+ {
+ // Already exist
+ CiSetError(c, ERR_VLAN_ALREADY_EXISTS);
+ return false;
+ }
+
+ if (MsIsNt())
+ {
+ if (MsIsVista() == false)
+ {
+ k = InitKakushi();
+ }
+ }
+
+ if (MsIsVista() == false)
+ {
+ MS_DRIVER_VER ver;
+
+ CiInitDriverVerStruct(&ver);
+
+ // Perform the installation (other than Windows Vista)
+ if (MsInstallVLan(VLAN_ADAPTER_NAME_TAG, VLAN_CONNECTION_NAME, create->DeviceName, &ver) == false)
+ {
+ // Installation Failed
+ FreeKakushi(k);
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+ }
+ else
+ {
+ // Perform the installation (Windows Vista)
+ char tmp[MAX_SIZE];
+
+ Format(tmp, sizeof(tmp), "instvlan %s", create->DeviceName);
+
+ if (CncExecDriverInstaller(tmp) == false)
+ {
+ // Installation Failed
+ FreeKakushi(k);
+ CiSetError(c, ERR_VLAN_INSTALL_ERROR);
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ return false;
+ }
+ }
+
+ FreeKakushi(k);
+
+ t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, VLAN_ADAPTER_NAME_OLD);
+ if (t->NumTokens == 1)
+ {
+ UINT i;
+ // If the result of the installation, virtual LAN card is only one,
+ // set virtual LAN card setting of all existing accounts to this virtual LAN card
+ LockList(c->AccountList);
+ {
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+ Lock(a->lock);
+ {
+ if (a->ClientOption != NULL)
+ {
+ StrCpy(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName), create->DeviceName);
+ }
+ }
+ Unlock(a->lock);
+ }
+ }
+ UnlockList(c->AccountList);
+ }
+ FreeToken(t);
+
+ CLog(c, "LC_CREATE_VLAN", create->DeviceName);
+
+ CiNormalizeAccountVLan(c);
+
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+
+ CiSaveConfigurationFile(c);
+
+ if (MsIsNt() == false)
+ {
+ if (GetOsInfo()->OsType == OSTYPE_WINDOWS_ME)
+ {
+ // Show the warning in the case of Windows Me
+ MsgBox(NULL, 0x00000040L, _UU("CM_9X_VLAN_ME_MESSAGE"));
+ }
+
+ ReleaseThread(NewThread(Win9xRebootThread, NULL));
+ }
+
+ return true;
+
+#endif // OS_WIN32
+}
+
+// Enumerate objects in the secure device
+bool CtEnumObjectInSecure(CLIENT *c, RPC_ENUM_OBJECT_IN_SECURE *e)
+{
+ UINT i;
+ // Validate arguments
+ if (c == NULL || e == NULL)
+ {
+ return false;
+ }
+
+ e->NumItem = 5;
+ e->ItemName = ZeroMalloc(sizeof(char *) * e->NumItem);
+ e->ItemType = ZeroMalloc(sizeof(bool) * e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ char tmp[MAX_SIZE];
+ Format(tmp, sizeof(tmp), "Test Object %u", i);
+ e->ItemName[i] = CopyStr(tmp);
+ e->ItemType[i] = (i % 2 == 0) ? false : true;
+ }
+
+ return true;
+}
+
+// Get the secure device to be used
+bool CtGetUseSecure(CLIENT *c, RPC_USE_SECURE *sec)
+{
+ // Validate arguments
+ if (c == NULL || sec == NULL)
+ {
+ return false;
+ }
+
+ sec->DeviceId = c->UseSecureDeviceId;
+
+ return true;
+}
+
+// Specifying a secure device to be used
+bool CtUseSecure(CLIENT *c, RPC_USE_SECURE *sec)
+{
+ // Validate arguments
+ if (c == NULL || sec == NULL)
+ {
+ return false;
+ }
+
+// Do not check whether there is the specified device on the client manager
+/* if (CheckSecureDeviceId(sec->DeviceId))
+ {
+ c->UseSecureDeviceId = sec->DeviceId;
+ }
+ else
+ {
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ return false;
+ }
+*/
+ c->UseSecureDeviceId = sec->DeviceId;
+
+ CiSaveConfigurationFile(c);
+
+ return true;
+}
+
+// Enumeration of secure devices
+bool CtEnumSecure(CLIENT *c, RPC_CLIENT_ENUM_SECURE *e)
+{
+ LIST *o;
+ UINT i;
+ // Validate arguments
+ if (c == NULL || e == NULL)
+ {
+ return false;
+ }
+
+ o = GetSecureDeviceList();
+
+ e->NumItem = LIST_NUM(o);
+ e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM *) * e->NumItem);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ RPC_CLIENT_ENUM_SECURE_ITEM *item = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_SECURE_ITEM));
+ SECURE_DEVICE *s = LIST_DATA(o, i);
+
+ item->DeviceId = s->Id;
+ StrCpy(item->DeviceName, sizeof(item->DeviceName), s->DeviceName);
+ StrCpy(item->Manufacturer, sizeof(item->Manufacturer), s->Manufacturer);
+ item->Type = s->Type;
+
+ e->Items[i] = item;
+ }
+
+ return true;
+}
+
+// Release the secure device enumeration
+void CiFreeClientEnumSecure(RPC_CLIENT_ENUM_SECURE *e)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ Free(e->Items[i]);
+ }
+ Free(e->Items);
+}
+
+// Release the RPC_GET_ISSUER
+void CiFreeGetIssuer(RPC_GET_ISSUER *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ if (a->issuer_x != NULL)
+ {
+ FreeX(a->issuer_x);
+ }
+ if (a->x != NULL)
+ {
+ FreeX(a->x);
+ }
+}
+
+// Get the common proxy settings
+bool CtGetCommonProxySetting(CLIENT *c, INTERNET_SETTING *a)
+{
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+ Copy(a, &c->CommonProxySetting, sizeof(INTERNET_SETTING));
+
+ return true;
+}
+
+// Set the common proxy settings
+bool CtSetCommonProxySetting(CLIENT *c, INTERNET_SETTING *a)
+{
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+ Copy(&c->CommonProxySetting, a, sizeof(INTERNET_SETTING));
+
+
+ CiSaveConfigurationFile(c);
+
+ return true;
+}
+
+// Get the issuer
+bool CtGetIssuer(CLIENT *c, RPC_GET_ISSUER *a)
+{
+ X *x;
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+ x = FindCaSignedX(c->Cedar->CaList, a->x);
+ if (x == NULL)
+ {
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);;
+ return false;
+ }
+ else
+ {
+ a->issuer_x = x;
+ if (a->x != NULL)
+ {
+ FreeX(a->x);
+ a->x = NULL;
+ }
+ return true;
+ }
+}
+
+// Get the CA certificate
+bool CtGetCa(CLIENT *c, RPC_GET_CA *get)
+{
+ bool ret = true;
+ X *cert = NULL;
+ // Validate arguments
+ if (c == NULL || get == NULL)
+ {
+ return false;
+ }
+
+ LockList(c->Cedar->CaList);
+ {
+ UINT i;
+
+ for (i = 0;i < LIST_NUM(c->Cedar->CaList);i++)
+ {
+ X *x = LIST_DATA(c->Cedar->CaList, i);
+
+ if (POINTER_TO_KEY(x) == get->Key)
+ {
+ cert = CloneX(x);
+ break;
+ }
+ }
+ }
+ UnlockList(c->Cedar->CaList);
+
+ if (cert == NULL)
+ {
+ // Certificate does not exist
+ ret = false;
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ }
+ else
+ {
+ ret = true;
+ get->x = cert;
+ }
+
+ return ret;
+}
+
+// Delete the CA certificate
+bool CtDeleteCa(CLIENT *c, RPC_CLIENT_DELETE_CA *p)
+{
+ bool ret;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return false;
+ }
+
+ ret = DeleteCa(c->Cedar, p->Key);
+
+ if (ret == false)
+ {
+ CiSetError(c, ERR_OBJECT_NOT_FOUND);
+ }
+
+ CiSaveConfigurationFile(c);
+
+ return ret;
+}
+
+// Add a CA certificate
+bool CtAddCa(CLIENT *c, RPC_CERT *cert)
+{
+ // Validate arguments
+ if (c == NULL || cert == NULL)
+ {
+ return false;
+ }
+
+ if (cert->x->is_compatible_bit == false)
+ {
+ CiSetError(c, ERR_NOT_RSA_1024);
+ return false;
+ }
+
+ AddCa(c->Cedar, cert->x);
+
+ CiSaveConfigurationFile(c);
+
+ return true;
+}
+
+// Enumerate the trusted CA
+bool CtEnumCa(CLIENT *c, RPC_CLIENT_ENUM_CA *e)
+{
+ // Validate arguments
+ if (c == NULL || e == NULL)
+ {
+ return false;
+ }
+
+ Zero(e, sizeof(RPC_CLIENT_ENUM_CA));
+
+ LockList(c->Cedar->CaList);
+ {
+ UINT i;
+ e->NumItem = LIST_NUM(c->Cedar->CaList);
+ e->Items = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM *) * e->NumItem);
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ X *x = LIST_DATA(c->Cedar->CaList, i);
+ e->Items[i] = ZeroMalloc(sizeof(RPC_CLIENT_ENUM_CA_ITEM));
+ GetAllNameFromNameEx(e->Items[i]->SubjectName, sizeof(e->Items[i]->SubjectName), x->subject_name);
+ GetAllNameFromNameEx(e->Items[i]->IssuerName, sizeof(e->Items[i]->IssuerName), x->issuer_name);
+ e->Items[i]->Expires = x->notAfter;
+ e->Items[i]->Key = POINTER_TO_KEY(x);
+ }
+ }
+ UnlockList(c->Cedar->CaList);
+
+ return true;
+}
+
+// Release the CA enumeration
+void CiFreeClientEnumCa(RPC_CLIENT_ENUM_CA *e)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < e->NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_CA_ITEM *ca = e->Items[i];
+ Free(ca);
+ }
+ Free(e->Items);
+}
+
+// Get the password setting
+bool CtGetPasswordSetting(CLIENT *c, RPC_CLIENT_PASSWORD_SETTING *a)
+{
+ UCHAR hash[SHA1_SIZE];
+ // Validate arguments
+ if (c == NULL || a == NULL)
+ {
+ return false;
+ }
+
+ Hash(hash, "", 0, true);
+ if (Cmp(hash, c->EncryptedPassword, SHA1_SIZE) == 0)
+ {
+ a->IsPasswordPresented = false;
+ }
+ else
+ {
+ a->IsPasswordPresented = true;
+ }
+
+ a->PasswordRemoteOnly = c->PasswordRemoteOnly;
+
+ return true;
+}
+
+// Set the password
+bool CtSetPassword(CLIENT *c, RPC_CLIENT_PASSWORD *pass)
+{
+ char *str;
+ if (c == NULL)
+ {
+ return false;
+ }
+ if (pass->Password == NULL)
+ {
+ str = "";
+ }
+ else
+ {
+ str = pass->Password;
+ }
+
+ if (StrCmp(str, "********") != 0)
+ {
+ // Hash the password
+ Hash(c->EncryptedPassword, str, StrLen(str), true);
+ }
+
+ c->PasswordRemoteOnly = pass->PasswordRemoteOnly;
+
+ CLog(c, "LC_SET_PASSWORD");
+
+ CiSaveConfigurationFile(c);
+
+ return true;
+}
+
+void CiFreeIni(LIST *o)
+{
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ FreeIni(o);
+}
+
+// Read the custom.ini file
+LIST *CiLoadIni()
+{
+ BUF *b = ReadDump(CLIENT_CUSTOM_INI_FILENAME);
+ LIST *ini;
+ if (b == NULL)
+ {
+ return NULL;
+ }
+
+ ini = ReadIni(b);
+
+ FreeBuf(b);
+
+ return ini;
+
+}
+
+// Reflect the settings of the custom.ini
+void CiLoadIniSettings(CLIENT *c)
+{
+ LIST *o;
+ //char *log;
+ //char *config;
+
+ if (c == NULL)
+ {
+ return;
+ }
+
+ o = CiLoadIni();
+
+ if (o == NULL)
+ {
+ return;
+ }
+
+ /*log = IniStrValue(o, "NoSaveLog");
+ config = IniStrValue(o, "NoSaveConfig");
+
+ if(StrCmpi(log, "true") == 0)
+ {
+ c->NoSaveLog = true;
+ }
+ if(StrCmpi(config, "true") == 0)
+ {
+ c->NoSaveConfig = true;
+ }*/
+
+ c->NoSaveLog = ToBool(IniStrValue(o, "NoSaveLog"));
+ c->NoSaveConfig = ToBool(IniStrValue(o, "NoSaveConfig"));
+
+ CiFreeIni(o);
+
+}
+
+bool CiLoadConfigFilePathFromIni(char *path, UINT size)
+{
+ char *tmp;
+ LIST *o;
+ bool ret = false;
+
+ // Validate arguments
+ if (path == NULL)
+ {
+ return false;
+ }
+
+ o = CiLoadIni();
+
+ if (o == NULL)
+ {
+ return false;
+ }
+
+ StrCpy(path, size, "");
+
+ tmp = IniStrValue(o, "ConfigPath");
+ NormalizePath(path, size, tmp);
+
+ if (IsEmptyStr(path) == false)
+ {
+ ret = true;
+ }
+ else
+ {
+ ret = false;
+ }
+
+ CiFreeIni(o);
+
+ return ret;
+}
+
+// Set the client error code
+void CiSetError(CLIENT *c, UINT err)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->Err = err;
+}
+
+// UNIX virtual LAN card comparison function
+int CiCompareUnixVLan(void *p1, void *p2)
+{
+ UNIX_VLAN *v1, *v2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ v1 = *(UNIX_VLAN **)p1;
+ v2 = *(UNIX_VLAN **)p2;
+ if (v1 == NULL || v2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(v1->Name, v2->Name);
+}
+
+// Modify the account settings that an incorrect VLAN name is specified
+void CiNormalizeAccountVLan(CLIENT *c)
+{
+ bool b = false;
+ char *name;
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ name = CiGetFirstVLan(c);
+
+ if (name != NULL)
+ {
+ LockList(c->AccountList);
+ {
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+
+ Lock(a->lock);
+ {
+ if (a->ClientOption != NULL)
+ {
+ if (CiIsVLan(c, a->ClientOption->DeviceName) == false)
+ {
+ StrCpy(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName),
+ name);
+ b = true;
+ }
+ }
+ }
+ Unlock(a->lock);
+ }
+ }
+ UnlockList(c->AccountList);
+
+ Free(name);
+ }
+
+ if (b)
+ {
+ CiNotify(c);
+ CiSendGlobalPulse(c);
+ CiSaveConfigurationFile(c);
+ }
+}
+
+// Check whether a virtual LAN card of the specified name exists
+bool CiIsVLan(CLIENT *c, char *name)
+{
+ // Validate arguments
+ if (c == NULL || name == NULL)
+ {
+ return false;
+ }
+
+#ifdef OS_WIN32
+ {
+ TOKEN_LIST *t;
+ UINT i;
+
+ t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, VLAN_ADAPTER_NAME_OLD);
+ if (t == NULL)
+ {
+ return false;
+ }
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ if (StrCmpi(t->Token[i], name) == 0)
+ {
+ FreeToken(t);
+ return true;
+ }
+ }
+
+ FreeToken(t);
+
+ return false;
+ }
+#else // OS_WIN32
+ {
+ UNIX_VLAN *v;
+ UINT i;
+ bool ret = false;
+
+ LockList(c->UnixVLanList);
+ {
+ for (i = 0;i < LIST_NUM(c->UnixVLanList);i++)
+ {
+ v = (UNIX_VLAN *)LIST_DATA(c->UnixVLanList, i);
+ if (StrCmpi(v->Name, name) == 0)
+ {
+ ret = true;
+ }
+ }
+ }
+ UnlockList(c->UnixVLanList);
+
+ return ret;
+ }
+#endif // OS_WIN32
+}
+
+// If a non-existent virtual LAN card is specified in any Account, and only
+// one virtual LAN card is installed, set the virtual LAN card to the account
+void CiSetVLanToDefault(CLIENT *c)
+{
+ char device_name[MAX_SIZE];
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ {
+ TOKEN_LIST *t;
+
+ t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, VLAN_ADAPTER_NAME_OLD);
+ if (t == NULL)
+ {
+ return;
+ }
+ if (t->NumTokens != 1)
+ {
+ FreeToken(t);
+ return;
+ }
+ StrCpy(device_name, sizeof(device_name), t->Token[0]);
+ FreeToken(t);
+ }
+#else // OS_WIN32
+ {
+ UINT i;
+ UNIX_VLAN *v;
+
+ LockList(c->UnixVLanList);
+
+ if (LIST_NUM(c->UnixVLanList) != 1)
+ {
+ UnlockList(c->UnixVLanList);
+ return;
+ }
+ v = LIST_DATA(c->UnixVLanList, 0);
+ StrCpy(device_name, sizeof(device_name), v->Name);
+
+ UnlockList(c->UnixVLanList);
+ }
+#endif // OS_WIN32
+
+ {
+ UINT i;
+ LockList(c->AccountList);
+ {
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+
+ Lock(a->lock);
+ {
+ if (CiIsVLan(c, a->ClientOption->DeviceName) == false)
+ {
+ StrCpy(a->ClientOption->DeviceName, sizeof(a->ClientOption->DeviceName),
+ device_name);
+ }
+ }
+ Unlock(a->lock);
+ }
+ }
+ UnlockList(c->AccountList);
+ }
+}
+
+// Initialize the settings
+void CiInitConfiguration(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_UNIX
+ // Initialize the VLAN
+ UnixVLanInit();
+#endif // OS_UNIX
+
+ // Account list
+ c->AccountList = NewList(CiCompareAccount);
+
+ // Unix version VLAN list
+ if (OS_IS_UNIX(GetOsInfo()->OsType))
+ {
+ c->UnixVLanList = NewList(CiCompareUnixVLan);
+ }
+
+ // Read the configuration file
+ CLog(c, "LC_LOAD_CONFIG_1");
+ if (CiLoadConfigurationFile(c) == false)
+ {
+ CLog(c, "LC_LOAD_CONFIG_3");
+ // Do the initial setup because the configuration file does not exist
+ // Clear the password
+ Hash(c->EncryptedPassword, "", 0, true);
+ // Initialize the client configuration
+ if (OS_IS_WINDOWS(GetOsInfo()->OsType))
+ {
+ // Disable remote management in Windows
+ c->Config.AllowRemoteConfig = false;
+ }
+ else
+ {
+ // Disable the remote management also in case of UNIX
+ c->Config.AllowRemoteConfig = false;
+ }
+ StrCpy(c->Config.KeepConnectHost, sizeof(c->Config.KeepConnectHost), CLIENT_DEFAULT_KEEPALIVE_HOST);
+ c->Config.KeepConnectPort = CLIENT_DEFAULT_KEEPALIVE_PORT;
+ c->Config.KeepConnectProtocol = CONNECTION_UDP;
+ c->Config.KeepConnectInterval = CLIENT_DEFAULT_KEEPALIVE_INTERVAL;
+ c->Config.UseKeepConnect = false; // Don't use the connection maintenance function by default in the Client
+ // Eraser
+ c->Eraser = NewEraser(c->Logger, 0);
+ }
+ else
+ {
+ CLog(c, "LC_LOAD_CONFIG_2");
+ }
+
+ // Appropriate setting for virtual LAN card
+ CiSetVLanToDefault(c);
+}
+
+// Release the settings
+void CiFreeConfiguration(CLIENT *c)
+{
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Write to the configuration file
+ CiSaveConfigurationFile(c);
+
+ // Release the configuration file
+ FreeCfgRw(c->CfgRw);
+
+ // Release the account list
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+
+ CiFreeAccount(a);
+ }
+ ReleaseList(c->AccountList);
+
+ if (c->UnixVLanList != NULL)
+ {
+ // Release of UNIX version VLAN list
+ for (i = 0;i < LIST_NUM(c->UnixVLanList);i++)
+ {
+ UNIX_VLAN *v = LIST_DATA(c->UnixVLanList, i);
+ Free(v);
+ }
+ ReleaseList(c->UnixVLanList);
+ }
+ c->UnixVLanList = NULL;
+
+#ifdef OS_UNIX
+ // Release the VLAN
+ UnixVLanFree();
+#endif // OS_UNIX
+}
+
+// Release the certificate data acquisition
+void CiFreeGetCa(RPC_GET_CA *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ FreeX(a->x);
+}
+
+// Release the client authentication data
+void CiFreeClientAuth(CLIENT_AUTH *auth)
+{
+ // Validate arguments
+ if (auth == NULL)
+ {
+ return;
+ }
+
+ if (auth->ClientX != NULL)
+ {
+ FreeX(auth->ClientX);
+ }
+ if (auth->ClientK != NULL)
+ {
+ FreeK(auth->ClientK);
+ }
+
+ Free(auth);
+}
+
+// Release the account
+void CiFreeAccount(ACCOUNT *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ // Release the lock
+ DeleteLock(a->lock);
+
+ // Release the client option
+ Free(a->ClientOption);
+
+ // Release the client authentication data
+ CiFreeClientAuth(a->ClientAuth);
+
+ if (a->ServerCert != NULL)
+ {
+ FreeX(a->ServerCert);
+ }
+
+ Free(a);
+}
+
+// Sort accounts
+int CiCompareAccount(void *p1, void *p2)
+{
+ ACCOUNT *a1, *a2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ a1 = *(ACCOUNT **)p1;
+ a2 = *(ACCOUNT **)p2;
+ if (a1 == NULL || a2 == NULL)
+ {
+ return 0;
+ }
+
+ return UniStrCmpi(a1->ClientOption->AccountName, a2->ClientOption->AccountName);
+}
+
+// Read the client configuration
+void CiLoadClientConfig(CLIENT_CONFIG *c, FOLDER *f)
+{
+ // Validate arguments
+ if (c == NULL || f == NULL)
+ {
+ return;
+ }
+
+ c->UseKeepConnect = CfgGetBool(f, "UseKeepConnect");
+ CfgGetStr(f, "KeepConnectHost", c->KeepConnectHost, sizeof(c->KeepConnectHost));
+ c->KeepConnectPort = CfgGetInt(f, "KeepConnectPort");
+ c->KeepConnectProtocol = CfgGetInt(f, "KeepConnectProtocol");
+ c->AllowRemoteConfig = CfgGetBool(f, "AllowRemoteConfig");
+ c->KeepConnectInterval = MAKESURE(CfgGetInt(f, "KeepConnectInterval"), KEEP_INTERVAL_MIN, KEEP_INTERVAL_MAX);
+ c->NoChangeWcmNetworkSettingOnWindows8 = CfgGetBool(f, "NoChangeWcmNetworkSettingOnWindows8");
+}
+
+// Read the client authentication data
+CLIENT_AUTH *CiLoadClientAuth(FOLDER *f)
+{
+ CLIENT_AUTH *a;
+ char *s;
+ BUF *b;
+ // Validate arguments
+ if (f == NULL)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(CLIENT_AUTH));
+
+ a->AuthType = CfgGetInt(f, "AuthType");
+ CfgGetStr(f, "Username", a->Username, sizeof(a->Username));
+
+ switch (a->AuthType)
+ {
+ case CLIENT_AUTHTYPE_ANONYMOUS:
+ break;
+
+ case CLIENT_AUTHTYPE_PASSWORD:
+ CfgGetByte(f, "HashedPassword", a->HashedPassword, SHA1_SIZE);
+ break;
+
+ case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+ b = CfgGetBuf(f, "EncryptedPassword");
+ if (b != NULL)
+ {
+ s = DecryptPassword(b);
+ StrCpy(a->PlainPassword, sizeof(a->PlainPassword), s);
+ Free(s);
+ FreeBuf(b);
+ }
+ break;
+
+ case CLIENT_AUTHTYPE_CERT:
+ b = CfgGetBuf(f, "ClientCert");
+ if (b != NULL)
+ {
+ a->ClientX = BufToX(b, false);
+ }
+ FreeBuf(b);
+ b = CfgGetBuf(f, "ClientKey");
+ if (b != NULL)
+ {
+ a->ClientK = BufToK(b, true, false, NULL);
+ }
+ FreeBuf(b);
+ break;
+
+ case CLIENT_AUTHTYPE_SECURE:
+ CfgGetStr(f, "SecurePublicCertName", a->SecurePublicCertName, sizeof(a->SecurePublicCertName));
+ CfgGetStr(f, "SecurePrivateKeyName", a->SecurePrivateKeyName, sizeof(a->SecurePrivateKeyName));
+ break;
+ }
+
+ return a;
+}
+
+// Read the client option
+CLIENT_OPTION *CiLoadClientOption(FOLDER *f)
+{
+ CLIENT_OPTION *o;
+ char *s;
+ BUF *b;
+ // Validate arguments
+ if (f == NULL)
+ {
+ return NULL;
+ }
+
+ o = ZeroMalloc(sizeof(CLIENT_OPTION));
+
+ CfgGetUniStr(f, "AccountName", o->AccountName, sizeof(o->AccountName));
+ CfgGetStr(f, "Hostname", o->Hostname, sizeof(o->Hostname));
+ o->Port = CfgGetInt(f, "Port");
+ o->PortUDP = CfgGetInt(f, "PortUDP");
+ o->ProxyType = CfgGetInt(f, "ProxyType");
+ CfgGetStr(f, "ProxyName", o->ProxyName, sizeof(o->ProxyName));
+ o->ProxyPort = CfgGetInt(f, "ProxyPort");
+ CfgGetStr(f, "ProxyUsername", o->ProxyUsername, sizeof(o->ProxyUsername));
+ b = CfgGetBuf(f, "ProxyPassword");
+ s = DecryptPassword(b);
+ StrCpy(o->ProxyPassword, sizeof(o->ProxyPassword), s);
+ Free(s);
+ FreeBuf(b);
+ o->NumRetry = CfgGetInt(f, "NumRetry");
+ o->RetryInterval = CfgGetInt(f, "RetryInterval");
+ CfgGetStr(f, "HubName", o->HubName, sizeof(o->HubName));
+ o->MaxConnection = CfgGetInt(f, "MaxConnection");
+ o->UseEncrypt = CfgGetBool(f, "UseEncrypt");
+ o->UseCompress = CfgGetBool(f, "UseCompress");
+ o->HalfConnection = CfgGetBool(f, "HalfConnection");
+ o->NoRoutingTracking = CfgGetBool(f, "NoRoutingTracking");
+ CfgGetStr(f, "DeviceName", o->DeviceName, sizeof(o->DeviceName));
+ o->AdditionalConnectionInterval = CfgGetInt(f, "AdditionalConnectionInterval");
+ o->HideStatusWindow = CfgGetBool(f, "HideStatusWindow");
+ o->HideNicInfoWindow = CfgGetBool(f, "HideNicInfoWindow");
+ o->ConnectionDisconnectSpan = CfgGetInt(f, "ConnectionDisconnectSpan");
+ o->RequireMonitorMode = CfgGetBool(f, "RequireMonitorMode");
+ o->RequireBridgeRoutingMode = CfgGetBool(f, "RequireBridgeRoutingMode");
+ o->DisableQoS = CfgGetBool(f, "DisableQoS");
+ o->FromAdminPack = CfgGetBool(f, "FromAdminPack");
+ o->NoTls1 = CfgGetBool(f, "NoTls1");
+ o->NoUdpAcceleration = CfgGetBool(f, "NoUdpAcceleration");
+
+ b = CfgGetBuf(f, "HostUniqueKey");
+ if (b != NULL)
+ {
+ if (b->Size == SHA1_SIZE)
+ {
+ Copy(o->HostUniqueKey, b->Buf, SHA1_SIZE);
+ }
+
+ FreeBuf(b);
+ }
+
+ return o;
+}
+
+// Read the account data
+ACCOUNT *CiLoadClientAccount(FOLDER *f)
+{
+ ACCOUNT *a;
+ FOLDER *client_option_folder, *client_auth_folder;
+ BUF *b;
+ char tmp[64];
+ // Validate arguments
+ if (f == NULL)
+ {
+ return NULL;
+ }
+
+ client_option_folder = CfgGetFolder(f, "ClientOption");
+
+ if (client_option_folder != NULL)
+ {
+ // Compare whether it matches to the account name that is already registered
+ }
+
+ client_auth_folder = CfgGetFolder(f, "ClientAuth");
+
+ if (client_option_folder == NULL || client_auth_folder == NULL)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(ACCOUNT));
+ a->lock = NewLock();
+
+ a->ClientOption = CiLoadClientOption(client_option_folder);
+ a->ClientAuth = CiLoadClientAuth(client_auth_folder);
+
+ a->StartupAccount = CfgGetBool(f, "StartupAccount");
+ a->CheckServerCert = CfgGetBool(f, "CheckServerCert");
+ a->CreateDateTime = CfgGetInt64(f, "CreateDateTime");
+ a->UpdateDateTime = CfgGetInt64(f, "UpdateDateTime");
+ a->LastConnectDateTime = CfgGetInt64(f, "LastConnectDateTime");
+
+ b = CfgGetBuf(f, "ServerCert");
+ if (b != NULL)
+ {
+ a->ServerCert = BufToX(b, false);
+ FreeBuf(b);
+ }
+
+ if (CfgGetStr(f, "ShortcutKey", tmp, sizeof(tmp)))
+ {
+ BUF *b = StrToBin(tmp);
+ if (b->Size == SHA1_SIZE)
+ {
+ Copy(a->ShortcutKey, b->Buf, SHA1_SIZE);
+ }
+ FreeBuf(b);
+ }
+
+ if (IsZero(a->ShortcutKey, SHA1_SIZE))
+ {
+ Rand(a->ShortcutKey, SHA1_SIZE);
+ }
+
+ return a;
+}
+
+// Read the account database
+void CiLoadAccountDatabase(CLIENT *c, FOLDER *f)
+{
+ TOKEN_LIST *t;
+ UINT i;
+ // Validate arguments
+ if (c == NULL || f == NULL)
+ {
+ return;
+ }
+
+ t = CfgEnumFolderToTokenList(f);
+ if (t == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ FOLDER *ff = CfgGetFolder(f, t->Token[i]);
+
+ if (ff != NULL)
+ {
+ ACCOUNT *a = CiLoadClientAccount(ff);
+ if (a != NULL)
+ {
+ {
+ Add(c->AccountList, a);
+ }
+ }
+ }
+ }
+
+ Sort(c->AccountList);
+
+ FreeToken(t);
+}
+
+// Read the root CA certificate
+void CiLoadCACert(CLIENT *c, FOLDER *f)
+{
+ BUF *b;
+ X *x;
+ // Validate arguments
+ if (c == NULL || f == NULL)
+ {
+ return;
+ }
+
+ b = CfgGetBuf(f, "X509");
+ if (b == NULL)
+ {
+ return;
+ }
+
+ x = BufToX(b, false);
+
+ AddCa(c->Cedar, x);
+
+ FreeX(x);
+
+ FreeBuf(b);
+}
+
+// Read the root CA list
+void CiLoadCAList(CLIENT *c, FOLDER *f)
+{
+ CEDAR *cedar;
+ TOKEN_LIST *t;
+ // Validate arguments
+ if (c == NULL || f == NULL)
+ {
+ return;
+ }
+
+ t = CfgEnumFolderToTokenList(f);
+
+ cedar = c->Cedar;
+
+ LockList(cedar->CaList);
+ {
+ UINT i;
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ FOLDER *folder = CfgGetFolder(f, t->Token[i]);
+ CiLoadCACert(c, folder);
+ }
+ }
+ UnlockList(cedar->CaList);
+
+ FreeToken(t);
+}
+
+// Read a VLAN
+void CiLoadVLan(CLIENT *c, FOLDER *f)
+{
+ char tmp[MAX_SIZE];
+ UCHAR addr[6];
+ BUF *b;
+ UNIX_VLAN *v;
+ // Validate arguments
+ if (c == NULL || f == NULL)
+ {
+ return;
+ }
+
+ if (CfgGetStr(f, "MacAddress", tmp, sizeof(tmp)) == false)
+ {
+ return;
+ }
+
+ b = StrToBin(tmp);
+ if (b == NULL)
+ {
+ return;
+ }
+
+ if (b->Size != 6)
+ {
+ FreeBuf(b);
+ return;
+ }
+
+ Copy(addr, b->Buf, 6);
+
+ FreeBuf(b);
+
+ if (IsZero(addr, 6))
+ {
+ return;
+ }
+
+ v = ZeroMalloc(sizeof(UNIX_VLAN));
+ Copy(v->MacAddress, addr, 6);
+ StrCpy(v->Name, sizeof(v->Name), f->Name);
+ v->Enabled = CfgGetBool(f, "Enabled");
+
+ Add(c->UnixVLanList, v);
+
+#ifdef OS_UNIX
+ UnixVLanCreate(v->Name, v->MacAddress);
+#endif // OS_UNIX
+}
+
+// Read a VLAN list
+void CiLoadVLanList(CLIENT *c, FOLDER *f)
+{
+ TOKEN_LIST *t;
+ // Validate arguments
+ if (c == NULL || f == NULL)
+ {
+ return;
+ }
+
+ t = CfgEnumFolderToTokenList(f);
+
+ LockList(c->UnixVLanList);
+ {
+ UINT i;
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ FOLDER *folder = CfgGetFolder(f, t->Token[i]);
+ CiLoadVLan(c, folder);
+ }
+ }
+ UnlockList(c->UnixVLanList);
+
+ FreeToken(t);
+}
+
+// Read the configuration from the configuration file
+bool CiReadSettingFromCfg(CLIENT *c, FOLDER *root)
+{
+ FOLDER *config;
+ FOLDER *cert;
+ FOLDER *db;
+ FOLDER *vlan;
+ FOLDER *cmsetting;
+ FOLDER *proxy;
+ char user_agent[MAX_SIZE];
+ // Validate arguments
+ if (c == NULL || root == NULL)
+ {
+ return false;
+ }
+
+ // Initialize the setting if there isn't either of AccountDatabase and Config
+ config = CfgGetFolder(root, "Config");
+ if (config == NULL)
+ {
+ return false;
+ }
+
+ db = CfgGetFolder(root, "AccountDatabase");
+ if (db == NULL)
+ {
+ return false;
+ }
+
+ cmsetting = CfgGetFolder(root, "ClientManagerSetting");
+
+ CiLoadClientConfig(&c->Config, config);
+
+
+ proxy = CfgGetFolder(root, "CommonProxySetting");
+
+ if (proxy != NULL)
+ {
+ INTERNET_SETTING t;
+ BUF *pw;
+
+ // Proxy Setting
+ Zero(&t, sizeof(t));
+ t.ProxyType = CfgGetInt(proxy, "ProxyType");
+ CfgGetStr(proxy, "ProxyHostName", t.ProxyHostName, sizeof(t.ProxyHostName));
+ t.ProxyPort = CfgGetInt(proxy, "ProxyPort");
+ CfgGetStr(proxy, "ProxyUsername", t.ProxyUsername, sizeof(t.ProxyUsername));
+ pw = CfgGetBuf(proxy, "ProxyPassword");
+ if (pw != NULL)
+ {
+ char *pw_str = DecryptPassword(pw);
+ StrCpy(t.ProxyPassword, sizeof(t.ProxyPassword), pw_str);
+
+ Free(pw_str);
+ FreeBuf(pw);
+ }
+
+ Copy(&c->CommonProxySetting, &t, sizeof(INTERNET_SETTING));
+ }
+
+ // Eraser
+ c->Eraser = NewEraser(c->Logger, CfgGetInt64(config, "AutoDeleteCheckDiskFreeSpaceMin"));
+
+ if (OS_IS_UNIX(GetOsInfo()->OsType) && GetOsInfo()->OsType != OSTYPE_MACOS_X)
+ {
+ // Read the UNIX version virtual LAN card list (except MacOS)
+ vlan = CfgGetFolder(root, "UnixVLan");
+ if (vlan != NULL)
+ {
+ CiLoadVLanList(c, vlan);
+ }
+ }
+
+ if (GetOsInfo()->OsType == OSTYPE_MACOS_X)
+ {
+#ifdef OS_UNIX
+ UNIX_VLAN *uv;
+
+ // Create a Tap for MacOS X
+ if (UnixVLanCreate(CLIENT_MACOS_TAP_NAME, NULL) == false)
+ {
+ // Fail (abort)
+ CLog(c, "LC_TAP_NOT_FOUND");
+ Alert("tun/tap driver not found.", NULL);
+ exit(0);
+ }
+
+ uv = ZeroMalloc(sizeof(UNIX_VLAN));
+ uv->Enabled = true;
+ StrCpy(uv->Name, sizeof(uv->Name), CLIENT_MACOS_TAP_NAME);
+ Add(c->UnixVLanList, uv);
+#endif // OS_UNIX
+ }
+
+ CiLoadAccountDatabase(c, db);
+
+ if (CfgGetByte(root, "EncryptedPassword", c->EncryptedPassword, SHA1_SIZE) == false)
+ {
+ Hash(c->EncryptedPassword, "", 0, true);
+ }
+
+ c->PasswordRemoteOnly = CfgGetBool(root, "PasswordRemoteOnly");
+ c->UseSecureDeviceId = CfgGetInt(root, "UseSecureDeviceId");
+
+ if (CfgGetStr(root, "UserAgent", user_agent, sizeof(user_agent)))
+ {
+ if (IsEmptyStr(user_agent) == false)
+ {
+ Free(c->Cedar->HttpUserAgent);
+ c->Cedar->HttpUserAgent = CopyStr(user_agent);
+ }
+ }
+
+ cert = CfgGetFolder(root, "RootCA");
+ if (cert != NULL)
+ {
+ CiLoadCAList(c, cert);
+ }
+
+ c->DontSavePassword = CfgGetBool(root, "DontSavePassword");
+
+ if (cmsetting != NULL)
+ {
+ UINT ostype = GetOsInfo()->OsType;
+ // CM_SETTING
+ CM_SETTING *s = c->CmSetting;
+
+ if (OS_IS_UNIX(ostype) || OS_IS_WINDOWS_NT(ostype))
+ {
+ s->EasyMode = CfgGetBool(cmsetting, "EasyMode");
+ }
+
+ s->LockMode = CfgGetBool(cmsetting, "LockMode");
+ CfgGetByte(cmsetting, "HashedPassword", s->HashedPassword, sizeof(s->HashedPassword));
+ }
+
+ return true;
+}
+
+// Read the configuration file
+bool CiLoadConfigurationFile(CLIENT *c)
+{
+ bool ret;
+ FOLDER *root;
+ char path[MAX_SIZE];
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ // Read the configuration file
+ if (CiLoadConfigFilePathFromIni(path, sizeof(path)))
+ {
+ c->CfgRw = NewCfgRw(&root, path);
+ }
+ else
+ {
+ c->CfgRw = NewCfgRw(&root, CLIENT_CONFIG_FILE_NAME);
+ }
+
+ if (root == NULL)
+ {
+ return false;
+ }
+
+ ret = CiReadSettingFromCfg(c, root);
+
+ CfgDeleteFolder(root);
+
+ return ret;
+}
+
+// Write the CLIENT_CONFIG
+void CiWriteClientConfig(FOLDER *cc, CLIENT_CONFIG *config)
+{
+ // Validate arguments
+ if (cc == NULL || config == NULL)
+ {
+ return;
+ }
+
+ CfgAddBool(cc, "UseKeepConnect", config->UseKeepConnect);
+ CfgAddStr(cc, "KeepConnectHost", config->KeepConnectHost);
+ CfgAddInt(cc, "KeepConnectPort", config->KeepConnectPort);
+ CfgAddInt(cc, "KeepConnectProtocol", config->KeepConnectProtocol);
+ CfgAddBool(cc, "AllowRemoteConfig", config->AllowRemoteConfig);
+ CfgAddInt(cc, "KeepConnectInterval", config->KeepConnectInterval);
+ CfgAddBool(cc, "NoChangeWcmNetworkSettingOnWindows8", config->NoChangeWcmNetworkSettingOnWindows8);
+}
+
+// Write the client authentication data
+void CiWriteClientAuth(FOLDER *f, CLIENT_AUTH *a)
+{
+ BUF *b;
+ // Validate arguments
+ if (f == NULL || a == NULL)
+ {
+ return;
+ }
+
+ CfgAddInt(f, "AuthType", a->AuthType);
+ CfgAddStr(f, "Username", a->Username);
+
+ switch (a->AuthType)
+ {
+ case CLIENT_AUTHTYPE_ANONYMOUS:
+ break;
+
+ case CLIENT_AUTHTYPE_PASSWORD:
+ CfgAddByte(f, "HashedPassword", a->HashedPassword, SHA1_SIZE);
+ break;
+
+ case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+ b = EncryptPassword(a->PlainPassword);
+ CfgAddByte(f, "EncryptedPassword", b->Buf, b->Size);
+ FreeBuf(b);
+ break;
+
+ case CLIENT_AUTHTYPE_CERT:
+ if (a->ClientK != NULL && a->ClientX != NULL)
+ {
+ b = XToBuf(a->ClientX, false);
+ CfgAddByte(f, "ClientCert", b->Buf, b->Size);
+ FreeBuf(b);
+
+ b = KToBuf(a->ClientK, false, NULL);
+ CfgAddByte(f, "ClientKey", b->Buf, b->Size);
+ FreeBuf(b);
+ }
+ break;
+
+ case CLIENT_AUTHTYPE_SECURE:
+ CfgAddStr(f, "SecurePublicCertName", a->SecurePublicCertName);
+ CfgAddStr(f, "SecurePrivateKeyName", a->SecurePrivateKeyName);
+ break;
+ }
+}
+
+// Write the client option
+void CiWriteClientOption(FOLDER *f, CLIENT_OPTION *o)
+{
+ BUF *b;
+ // Validate arguments
+ if (f == NULL || o == NULL)
+ {
+ return;
+ }
+
+ CfgAddUniStr(f, "AccountName", o->AccountName);
+ CfgAddStr(f, "Hostname", o->Hostname);
+ CfgAddInt(f, "Port", o->Port);
+ CfgAddInt(f, "PortUDP", o->PortUDP);
+ CfgAddInt(f, "ProxyType", o->ProxyType);
+ CfgAddStr(f, "ProxyName", o->ProxyName);
+ CfgAddInt(f, "ProxyPort", o->ProxyPort);
+ CfgAddStr(f, "ProxyUsername", o->ProxyUsername);
+ b = EncryptPassword(o->ProxyPassword);
+ CfgAddByte(f, "ProxyPassword", b->Buf, b->Size);
+ FreeBuf(b);
+ CfgAddInt(f, "NumRetry", o->NumRetry);
+ CfgAddInt(f, "RetryInterval", o->RetryInterval);
+ CfgAddStr(f, "HubName", o->HubName);
+ CfgAddInt(f, "MaxConnection", o->MaxConnection);
+ CfgAddBool(f, "UseEncrypt", o->UseEncrypt);
+ CfgAddBool(f, "UseCompress", o->UseCompress);
+ CfgAddBool(f, "HalfConnection", o->HalfConnection);
+ CfgAddBool(f, "NoRoutingTracking", o->NoRoutingTracking);
+ CfgAddStr(f, "DeviceName", o->DeviceName);
+ CfgAddInt(f, "AdditionalConnectionInterval", o->AdditionalConnectionInterval);
+ CfgAddBool(f, "HideStatusWindow", o->HideStatusWindow);
+ CfgAddBool(f, "HideNicInfoWindow", o->HideNicInfoWindow);
+ CfgAddInt(f, "ConnectionDisconnectSpan", o->ConnectionDisconnectSpan);
+ CfgAddBool(f, "RequireMonitorMode", o->RequireMonitorMode);
+ CfgAddBool(f, "RequireBridgeRoutingMode", o->RequireBridgeRoutingMode);
+ CfgAddBool(f, "DisableQoS", o->DisableQoS);
+ CfgAddBool(f, "NoTls1", o->NoTls1);
+ CfgAddBool(f, "NoUdpAcceleration", o->NoUdpAcceleration);
+
+ if (o->FromAdminPack)
+ {
+ CfgAddBool(f, "FromAdminPack", o->FromAdminPack);
+ }
+
+ if (IsZero(o->HostUniqueKey, SHA1_SIZE) == false)
+ {
+ BUF *b = MemToBuf(o->HostUniqueKey, SHA1_SIZE);
+ CfgAddBuf(f, "HostUniqueKey", b);
+ FreeBuf(b);
+ }
+}
+
+// Decrypt the password
+char *DecryptPassword(BUF *b)
+{
+ char *str;
+ char *key = "EncryptPassword";
+ CRYPT *c;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return CopyStr("");
+ }
+
+ str = ZeroMalloc(b->Size + 1);
+ c = NewCrypt(key, sizeof(key));
+ Encrypt(c, str, b->Buf, b->Size);
+ FreeCrypt(c);
+
+ str[b->Size] = 0;
+
+ return str;
+}
+char *DecryptPassword2(BUF *b)
+{
+ char *str;
+ char *key = "EncryptPassword2";
+ CRYPT *c;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return CopyStr("");
+ }
+
+ str = ZeroMalloc(b->Size + 1);
+ c = NewCrypt(key, StrLen(key));
+ Encrypt(c, str, b->Buf, b->Size);
+ FreeCrypt(c);
+
+ str[b->Size] = 0;
+
+ return str;
+}
+
+// Encrypt the password
+BUF *EncryptPassword(char *password)
+{
+ UCHAR *tmp;
+ UINT size;
+ char *key = "EncryptPassword";
+ CRYPT *c;
+ BUF *b;
+ // Validate arguments
+ if (password == NULL)
+ {
+ password = "";
+ }
+
+ size = StrLen(password) + 1;
+ tmp = ZeroMalloc(size);
+
+ c = NewCrypt(key, sizeof(key));
+ Encrypt(c, tmp, password, size - 1);
+ FreeCrypt(c);
+
+ b = NewBuf();
+ WriteBuf(b, tmp, size - 1);
+ SeekBuf(b, 0, 0);
+ Free(tmp);
+
+ return b;
+}
+BUF *EncryptPassword2(char *password)
+{
+ UCHAR *tmp;
+ UINT size;
+ char *key = "EncryptPassword2";
+ CRYPT *c;
+ BUF *b;
+ // Validate arguments
+ if (password == NULL)
+ {
+ password = "";
+ }
+
+ size = StrLen(password) + 1;
+ tmp = ZeroMalloc(size);
+
+ c = NewCrypt(key, StrLen(key));
+ Encrypt(c, tmp, password, size - 1);
+ FreeCrypt(c);
+
+ b = NewBuf();
+ WriteBuf(b, tmp, size - 1);
+ SeekBuf(b, 0, 0);
+ Free(tmp);
+
+ return b;
+}
+
+// Write the account data
+void CiWriteAccountData(FOLDER *f, ACCOUNT *a)
+{
+ // Validate arguments
+ if (f == NULL || a == NULL)
+ {
+ return;
+ }
+
+ // Client Option
+ CiWriteClientOption(CfgCreateFolder(f, "ClientOption"), a->ClientOption);
+
+ // Client authentication data
+ CiWriteClientAuth(CfgCreateFolder(f, "ClientAuth"), a->ClientAuth);
+
+ // Startup account
+ CfgAddBool(f, "StartupAccount", a->StartupAccount);
+
+ // Server certificate check flag
+ CfgAddBool(f, "CheckServerCert", a->CheckServerCert);
+
+ // Date and time
+ CfgAddInt64(f, "CreateDateTime", a->CreateDateTime);
+ CfgAddInt64(f, "UpdateDateTime", a->UpdateDateTime);
+ CfgAddInt64(f, "LastConnectDateTime", a->LastConnectDateTime);
+
+ // Server certificate body
+ if (a->ServerCert != NULL)
+ {
+ BUF *b = XToBuf(a->ServerCert, false);
+ if (b != NULL)
+ {
+ CfgAddBuf(f, "ServerCert", b);
+ FreeBuf(b);
+ }
+ }
+
+ // Shortcut Key
+ if (IsZero(a->ShortcutKey, SHA1_SIZE) == false)
+ {
+ char tmp[64];
+ BinToStr(tmp, sizeof(tmp), a->ShortcutKey, SHA1_SIZE);
+ CfgAddStr(f, "ShortcutKey", tmp);
+ }
+}
+
+// Write the account database
+void CiWriteAccountDatabase(CLIENT *c, FOLDER *f)
+{
+ char name[MAX_SIZE];
+ // Validate arguments
+ if (c == NULL || f == NULL)
+ {
+ return;
+ }
+
+ LockList(c->AccountList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(c->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(c->AccountList, i);
+
+ {
+ Format(name, sizeof(name), "Account%u", i);
+ Lock(a->lock);
+ {
+ CiWriteAccountData(CfgCreateFolder(f, name), a);
+ }
+ Unlock(a->lock);
+ }
+ }
+ }
+ UnlockList(c->AccountList);
+}
+
+// Write the CA certificate
+void CiWriteCACert(CLIENT *c, FOLDER *f, X *x)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || f == NULL || x == NULL)
+ {
+ return;
+ }
+
+ b = XToBuf(x, false);
+ CfgAddBuf(f, "X509", b);
+ FreeBuf(b);
+}
+
+// Write a VLAN
+void CiWriteVLan(CLIENT *c, FOLDER *f, UNIX_VLAN *v)
+{
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (c == NULL || f == NULL || v == NULL)
+ {
+ return;
+ }
+
+ MacToStr(tmp, sizeof(tmp), v->MacAddress);
+ CfgAddStr(f, "MacAddress", tmp);
+ CfgAddBool(f, "Enabled", v->Enabled);
+}
+
+// Write a VLAN list
+void CiWriteVLanList(CLIENT *c, FOLDER *f)
+{
+ // Validate arguments
+ if (c == NULL || f == NULL)
+ {
+ return;
+ }
+
+ LockList(c->UnixVLanList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(c->UnixVLanList);i++)
+ {
+ UNIX_VLAN *v = LIST_DATA(c->UnixVLanList, i);
+ CiWriteVLan(c, CfgCreateFolder(f, v->Name), v);
+ }
+ }
+ UnlockList(c->UnixVLanList);
+}
+
+// Write the CA list
+void CiWriteCAList(CLIENT *c, FOLDER *f)
+{
+ CEDAR *cedar;
+ // Validate arguments
+ if (c == NULL || f == NULL)
+ {
+ return;
+ }
+
+ cedar = c->Cedar;
+
+ LockList(cedar->CaList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(cedar->CaList);i++)
+ {
+ char tmp[MAX_SIZE];
+ X *x = LIST_DATA(cedar->CaList, i);
+ Format(tmp, sizeof(tmp), "Certificate%u", i);
+ CiWriteCACert(c, CfgCreateFolder(f, tmp), x);
+ }
+ }
+ UnlockList(cedar->CaList);
+}
+
+// Write the current settings to ROOT
+void CiWriteSettingToCfg(CLIENT *c, FOLDER *root)
+{
+ FOLDER *cc;
+ FOLDER *account_database;
+ FOLDER *ca;
+ FOLDER *vlan;
+ FOLDER *cmsetting;
+ FOLDER *proxy;
+ // Validate arguments
+ if (c == NULL || root == NULL)
+ {
+ return;
+ }
+
+ cmsetting = CfgCreateFolder(root, "ClientManagerSetting");
+
+ // CLIENT_CONFIG
+ cc = CfgCreateFolder(root, "Config");
+ CiWriteClientConfig(cc, &c->Config);
+
+
+ // Eraser
+ CfgAddInt64(cc, "AutoDeleteCheckDiskFreeSpaceMin", c->Eraser->MinFreeSpace);
+
+ // Account Database
+ account_database = CfgCreateFolder(root, "AccountDatabase");
+ CiWriteAccountDatabase(c, account_database);
+
+ // Proxy
+ proxy = CfgCreateFolder(root, "CommonProxySetting");
+ if (proxy != NULL)
+ {
+ INTERNET_SETTING *t = &c->CommonProxySetting;
+ BUF *pw;
+
+ CfgAddInt(proxy, "ProxyType", t->ProxyType);
+ CfgAddStr(proxy, "ProxyHostName", t->ProxyHostName);
+ CfgAddInt(proxy, "ProxyPort", t->ProxyPort);
+ CfgAddStr(proxy, "ProxyUsername", t->ProxyUsername);
+
+ if (IsEmptyStr(t->ProxyPassword) == false)
+ {
+ pw = EncryptPassword(t->ProxyPassword);
+
+ CfgAddBuf(proxy, "ProxyPassword", pw);
+
+ FreeBuf(pw);
+ }
+ }
+
+ // CA
+ ca = CfgCreateFolder(root, "RootCA");
+ CiWriteCAList(c, ca);
+
+ // VLAN
+ if (OS_IS_UNIX(GetOsInfo()->OsType) && GetOsInfo()->OsType != OSTYPE_MACOS_X)
+ {
+ vlan = CfgCreateFolder(root, "UnixVLan");
+ CiWriteVLanList(c, vlan);
+ }
+
+ // Password
+ CfgAddByte(root, "EncryptedPassword", c->EncryptedPassword, SHA1_SIZE);
+ CfgAddBool(root, "PasswordRemoteOnly", c->PasswordRemoteOnly);
+
+ // UseSecureDeviceId
+ CfgAddInt(root, "UseSecureDeviceId", c->UseSecureDeviceId);
+
+ // DontSavePassword
+ CfgAddBool(root, "DontSavePassword", c->DontSavePassword);
+
+ // UserAgent
+ if (c->Cedar != NULL)
+ {
+ CfgAddStr(root, "UserAgent", c->Cedar->HttpUserAgent);
+ }
+
+ if (cmsetting != NULL)
+ {
+ CM_SETTING *s = c->CmSetting;
+
+ CfgAddBool(cmsetting, "EasyMode", s->EasyMode);
+ CfgAddBool(cmsetting, "LockMode", s->LockMode);
+
+ if (IsZero(s->HashedPassword, sizeof(s->HashedPassword)) == false)
+ {
+ CfgAddByte(cmsetting, "HashedPassword", s->HashedPassword, sizeof(s->HashedPassword));
+ }
+ }
+}
+
+// Create the inner VPN Server
+SERVER *CiNewInnerVPNServer(CLIENT *c)
+{
+ SERVER *s = NULL;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ SetNatTLowPriority();
+
+ s = SiNewServerEx(false, true);
+
+ return s;
+}
+
+// Stop the inner VPN Server
+void CiFreeInnerVPNServer(CLIENT *c, SERVER *s)
+{
+ // Validate arguments
+ if (c == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SiReleaseServer(s);
+}
+
+// Apply settings of Inner VPN Server
+void CiApplyInnerVPNServerConfig(CLIENT *c)
+{
+}
+
+// Write to the configuration file
+void CiSaveConfigurationFile(CLIENT *c)
+{
+ FOLDER *root;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Do not save the configuration file
+ if(c->NoSaveConfig)
+ {
+ return;
+ }
+
+ root = CfgCreateFolder(NULL, TAG_ROOT);
+ CiWriteSettingToCfg(c, root);
+
+ SaveCfgRw(c->CfgRw, root);
+
+ CfgDeleteFolder(root);
+}
+
+// Set the CM_SETTING
+bool CtSetCmSetting(CLIENT *c, CM_SETTING *s)
+{
+ // Validate arguments
+ if (c == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ Copy(c->CmSetting, s, sizeof(CM_SETTING));
+
+ CiSaveConfigurationFile(c);
+
+ return true;
+}
+
+// Get the CM_SETTING
+bool CtGetCmSetting(CLIENT *c, CM_SETTING *s)
+{
+ // Validate arguments
+ if (c == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ Copy(s, c->CmSetting, sizeof(CM_SETTING));
+
+ return true;
+}
+
+// Get the client version
+bool CtGetClientVersion(CLIENT *c, RPC_CLIENT_VERSION *ver)
+{
+ // Validate arguments
+ if (ver == NULL)
+ {
+ return false;
+ }
+
+ Zero(ver, sizeof(RPC_CLIENT_VERSION));
+ StrCpy(ver->ClientProductName, sizeof(ver->ClientProductName), CEDAR_CLIENT_STR);
+ StrCpy(ver->ClientVersionString, sizeof(ver->ClientVersionString), c->Cedar->VerString);
+ StrCpy(ver->ClientBuildInfoString, sizeof(ver->ClientBuildInfoString), c->Cedar->BuildInfo);
+ ver->ClientVerInt = c->Cedar->Version;
+ ver->ClientBuildInt = c->Cedar->Build;
+
+
+#ifdef OS_WIN32
+ ver->ProcessId = MsGetProcessId();
+ ver->IsVLanNameRegulated = MsIsInfCatalogRequired();
+
+#endif // OS_WIN32
+
+ ver->OsType = GetOsInfo()->OsType;
+
+ return true;
+}
+
+// Creating a Client object
+CLIENT *CiNewClient()
+{
+ CLIENT *c = ZeroMalloc(sizeof(CLIENT));
+
+// StartCedarLog();
+
+ if (ci_active_sessions_lock == NULL)
+ {
+ ci_active_sessions_lock = NewLock();
+ ci_num_active_sessions = 0;
+ }
+
+
+ c->CmSetting = ZeroMalloc(sizeof(CM_SETTING));
+
+ c->SockList = NewSockList();
+
+ c->lock = NewLock();
+ c->lockForConnect = NewLock();
+ c->ref = NewRef();
+
+ c->Cedar = NewCedar(NULL, NULL);
+
+ c->Cedar->Client = c;
+
+ c->NotifyCancelList = NewList(NULL);
+
+ Hash(c->EncryptedPassword, "", 0, true);
+
+#ifdef OS_WIN32
+ c->GlobalPulse = MsOpenOrCreateGlobalPulse(CLIENT_GLOBAL_PULSE_NAME);
+#endif // OS_WIN32
+
+ if (c->GlobalPulse != NULL)
+ {
+ c->PulseRecvThread = NewThread(CiPulseRecvThread, c);
+ }
+
+ CiLoadIniSettings(c);
+
+ // Log Settings
+ if(c->NoSaveLog == false)
+ {
+ MakeDir(CLIENT_LOG_DIR_NAME);
+ c->Logger = NewLog(CLIENT_LOG_DIR_NAME, CLIENT_LOG_PREFIX, LOG_SWITCH_DAY);
+ }
+
+ CLog(c, "L_LINE");
+ CLog(c, "LC_START_2", CEDAR_CLIENT_STR, c->Cedar->VerString);
+ CLog(c, "LC_START_3", c->Cedar->BuildInfo);
+ CLog(c, "LC_START_1");
+
+#ifdef OS_WIN32
+ {
+ // Initialize the Win32 UI
+ wchar_t tmp[MAX_SIZE];
+ StrToUni(tmp, sizeof(tmp), CEDAR_CLIENT_STR);
+
+ InitWinUi(tmp, _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+ }
+#endif // OS_WIN32
+
+ // Initialize the settings
+ CiInitConfiguration(c);
+
+ // Raise the priority
+ OSSetHighPriority();
+
+
+
+#ifdef OS_WIN32
+ // For Win9x, release the DHCP address of all the virtual LAN card
+ if (MsIsNt() == false)
+ {
+ Win32ReleaseAllDhcp9x(true);
+ }
+#endif // OS_WIN32
+
+ CiChangeAllVLanMacAddressIfMachineChanged(c);
+
+ CiChangeAllVLanMacAddressIfCleared(c);
+
+ // Initialize the internal VPN server
+ CiApplyInnerVPNServerConfig(c);
+
+ return c;
+}
+
+// Examine whether two proxy server settings equal
+bool CompareInternetSetting(INTERNET_SETTING *s1, INTERNET_SETTING *s2)
+{
+ // Validate arguments
+ if (s1 == NULL || s2 == NULL)
+ {
+ return false;
+ }
+
+ if (s1->ProxyType != s2->ProxyType)
+ {
+ return false;
+ }
+
+ if (s1->ProxyType == PROXY_DIRECT)
+ {
+ return true;
+ }
+
+ if (s1->ProxyPort != s2->ProxyPort)
+ {
+ return false;
+ }
+
+ if (StrCmp(s1->ProxyHostName, s2->ProxyHostName) != 0)
+ {
+ return false;
+ }
+
+ if (StrCmp(s1->ProxyUsername, s2->ProxyUsername) != 0)
+ {
+ return false;
+ }
+
+ if (StrCmp(s1->ProxyPassword, s2->ProxyPassword) != 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Send a global pulse
+void CiSendGlobalPulse(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+#ifdef OS_WIN32
+ MsSendGlobalPulse(c->GlobalPulse);
+#endif // OS_WIN32
+}
+
+// Pulse reception thread
+void CiPulseRecvThread(THREAD *thread, void *param)
+{
+#ifdef OS_WIN32
+ CLIENT *c = (CLIENT *)param;
+
+ if (c == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ if (c->HaltPulseThread)
+ {
+ break;
+ }
+
+ MsWaitForGlobalPulse(c->GlobalPulse, INFINITE);
+
+ if (c->HaltPulseThread)
+ {
+ break;
+ }
+
+ CiNotifyInternal(c);
+ }
+#endif // OS_WIN32
+}
+
+// Clean-up the client
+void CiCleanupClient(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+
+ // Release the settings
+ CiFreeConfiguration(c);
+
+#ifdef OS_WIN32
+ // Release the Win32 UI
+ FreeWinUi();
+#endif // OS_WIN32
+
+ CLog(c, "LC_END");
+ CLog(c, "L_LINE");
+ FreeEraser(c->Eraser);
+ FreeLog(c->Logger);
+ c->Logger = NULL;
+
+
+ ReleaseCedar(c->Cedar);
+
+ DeleteLock(c->lockForConnect);
+ DeleteLock(c->lock);
+
+ c->HaltPulseThread = true;
+
+ if (c->GlobalPulse != NULL)
+ {
+#ifdef OS_WIN32
+ MsSendGlobalPulse(c->GlobalPulse);
+#endif // OS_WIN32
+ }
+
+ if (c->PulseRecvThread != NULL)
+ {
+ WaitThread(c->PulseRecvThread, INFINITE);
+ ReleaseThread(c->PulseRecvThread);
+ }
+
+ if (c->GlobalPulse != NULL)
+ {
+#ifdef OS_WIN32
+ MsCloseGlobalPulse(c->GlobalPulse);
+#endif // OS_WIN32
+ }
+
+ ReleaseList(c->NotifyCancelList);
+
+ FreeSockList(c->SockList);
+
+ Free(c->CmSetting);
+
+
+ Free(c);
+
+#ifdef OS_WIN32
+ // For Win9x, release the DHCP address of all the virtual LAN card
+ if (MsIsNt() == false)
+ {
+ Win32ReleaseAllDhcp9x(true);
+ }
+#endif // OS_WIN32
+
+ StopCedarLog();
+
+ if (ci_active_sessions_lock != NULL)
+ {
+ DeleteLock(ci_active_sessions_lock);
+ ci_active_sessions_lock = NULL;
+
+ ci_num_active_sessions = 0;
+ }
+}
+
+// Increment of the number of active sessions
+void CiIncrementNumActiveSessions()
+{
+ Lock(ci_active_sessions_lock);
+ {
+ ci_num_active_sessions++;
+ }
+ Unlock(ci_active_sessions_lock);
+}
+
+// Decrement of the number of active sessions
+void CiDecrementNumActiveSessions()
+{
+ Lock(ci_active_sessions_lock);
+ {
+ if (ci_num_active_sessions >= 1)
+ {
+ ci_num_active_sessions--;
+ }
+ }
+ Unlock(ci_active_sessions_lock);
+}
+
+// Get the number of active sessions
+UINT CiGetNumActiveSessions()
+{
+ UINT ret;
+
+ Lock(ci_active_sessions_lock);
+ {
+ ret = ci_num_active_sessions;
+ }
+ Unlock(ci_active_sessions_lock);
+
+ return ret;
+}
+
+// Release the client
+void CtReleaseClient(CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ if (Release(c->ref) == 0)
+ {
+ CiCleanupClient(c);
+ }
+}
+
+// Start the operation of the client program
+void CtStartClient()
+{
+ UINT i;
+ LIST *o;
+ if (client != NULL)
+ {
+ // It is already in running
+ return;
+ }
+
+ // OS check
+ CiCheckOs();
+
+#ifdef OS_WIN32
+ RegistWindowsFirewallAll();
+#endif
+
+ // Creating a client
+ client = CiNewClient();
+
+ // Start the Keep
+ CiInitKeep(client);
+
+ // Start the RPC server
+ CiStartRpcServer(client);
+
+ // Start the Saver
+ CiInitSaver(client);
+
+ // Start the startup connection
+ o = NewListFast(NULL);
+ LockList(client->AccountList);
+ {
+ for (i = 0;i < LIST_NUM(client->AccountList);i++)
+ {
+ ACCOUNT *a = LIST_DATA(client->AccountList, i);
+ Lock(a->lock);
+ {
+ if (a->StartupAccount)
+ {
+ Add(o, CopyUniStr(a->ClientOption->AccountName));
+ }
+ }
+ Unlock(a->lock);
+ }
+ }
+ UnlockList(client->AccountList);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ wchar_t *s = LIST_DATA(o, i);
+ RPC_CLIENT_CONNECT c;
+ Zero(&c, sizeof(c));
+ UniStrCpy(c.AccountName, sizeof(c.AccountName), s);
+ CtConnect(client, &c);
+ Free(s);
+ }
+ ReleaseList(o);
+}
+
+// Stop the operation of the client program
+void CtStopClient()
+{
+ UINT i, num;
+ ACCOUNT **account_list;
+ if (client == NULL)
+ {
+ // It is not running yet
+ return;
+ }
+
+ // Halting flag
+ client->Halt = true;
+
+ // Disconnect all the RPC
+ CiStopRpcServer(client);
+
+ // Exit the client notification service
+ CncExit();
+
+ // Exit the Keep
+ CiFreeKeep(client);
+
+ // Disconnect all accounts connected
+ LockList(client->AccountList);
+ {
+ num = LIST_NUM(client->AccountList);
+ account_list = ToArray(client->AccountList);
+ }
+ UnlockList(client->AccountList);
+
+ for (i = 0;i < num;i++)
+ {
+ ACCOUNT *a = account_list[i];
+ SESSION *s = NULL;
+
+ Lock(a->lock);
+ {
+ if (a->ClientSession != NULL)
+ {
+ s = a->ClientSession;
+ AddRef(s->ref);
+ }
+ }
+ Unlock(a->lock);
+
+ if (s != NULL)
+ {
+ StopSession(s);
+ ReleaseSession(s);
+ Lock(a->lock);
+ {
+ if (a->ClientSession != NULL)
+ {
+ ReleaseSession(a->ClientSession);
+ a->ClientSession = NULL;
+ }
+ }
+ Unlock(a->lock);
+ }
+ }
+
+ Free(account_list);
+
+ // Stop the Saver
+ CiFreeSaver(client);
+
+ // Release the client
+ CtReleaseClient(client);
+ client = NULL;
+}
+
+// OS check
+void CiCheckOs()
+{
+ // Get the OS type
+ OS_INFO *info = GetOsInfo();
+
+ if (OS_IS_WINDOWS(info->OsType))
+ {
+ bool ok = IS_CLIENT_SUPPORTED_OS(info->OsType);
+
+ if (ok == false)
+ {
+ Alert(
+ CEDAR_PRODUCT_STR " VPN Client doesn't support this Windows Operating System.\n"
+ CEDAR_PRODUCT_STR " VPN Client requires Windows 98, Windows Me, Windows 2000, Windows XP, Windows Server 2003 or Greater.\n\n"
+ "Please contact your system administrator.", CEDAR_PRODUCT_STR " VPN Client");
+ exit(0);
+ }
+ }
+}
+
+// Get the client object
+CLIENT *CtGetClient()
+{
+ if (client == NULL)
+ {
+ return NULL;
+ }
+
+ AddRef(client->ref);
+
+ return client;
+}
+
+// Client status indicator
+void CiClientStatusPrinter(SESSION *s, wchar_t *status)
+{
+#ifdef OS_WIN32
+ ACCOUNT *a;
+ // Validate arguments
+ if (s == NULL || status == NULL)
+ {
+ return;
+ }
+
+ a = s->Account;
+ if (a == NULL)
+ {
+ return;
+ }
+
+ if (UniStrCmpi(status, L"init") == 0)
+ {
+ if (a->StatusWindow == NULL && s->Win32HideConnectWindow == false)
+ {
+ a->StatusWindow = CncStatusPrinterWindowStart(s);
+ }
+ }
+ else if (UniStrCmpi(status, L"free") == 0)
+ {
+ if (a->StatusWindow != NULL)
+ {
+ CncStatusPrinterWindowStop(a->StatusWindow);
+ a->StatusWindow = NULL;
+ }
+ }
+ else
+ {
+ if (a->StatusWindow != NULL)
+ {
+ CncStatusPrinterWindowPrint(a->StatusWindow, status);
+ }
+ }
+#else // OS_WIN32
+ UniPrint(L"Status: %s\n", status);
+#endif // OS_WIN32
+}
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Client.h b/src/Cedar/Client.h
new file mode 100644
index 00000000..345f8e76
--- /dev/null
+++ b/src/Cedar/Client.h
@@ -0,0 +1,849 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Client.h
+// Header of Client.c
+
+#ifndef CLIENT_H
+#define CLIENT_H
+
+#define CLIENT_CONFIG_PORT GC_CLIENT_CONFIG_PORT // Client port number
+#define CLIENT_NOTIFY_PORT GC_CLIENT_NOTIFY_PORT // Client notification port number
+#define CLIENT_WAIT_CN_READY_TIMEOUT (10 * 1000) // Standby time to start the client notification service
+
+
+// Check whether the client can run on the specified OS_TYPE
+#define IS_CLIENT_SUPPORTED_OS(t) \
+ ((OS_IS_WINDOWS_NT(t) && GET_KETA(t, 100) >= 2) || (OS_IS_WINDOWS_9X(t)))
+
+
+// Constants
+#define CLIENT_CONFIG_FILE_NAME "@vpn_client.config"
+#define CLIENT_DEFAULT_KEEPALIVE_HOST "keepalive.softether.org"
+#define CLIENT_DEFAULT_KEEPALIVE_PORT 80
+#define CLIENT_DEFAULT_KEEPALIVE_INTERVAL KEEP_INTERVAL_DEFAULT
+
+#define CLIENT_RPC_MODE_NOTIFY 0
+#define CLIENT_RPC_MODE_MANAGEMENT 1
+#define CLIENT_RPC_MODE_SHORTCUT 2
+#define CLIENT_RPC_MODE_SHORTCUT_DISCONNECT 3
+
+#define CLIENT_MACOS_TAP_NAME "tap0"
+
+#define CLIENT_SAVER_INTERVAL (30 * 1000)
+
+#define CLIENT_NOTIFY_SERVICE_INSTANCENAME GC_SW_SOFTETHER_PREFIX "vpnclient_uihelper"
+
+#define CLIENT_WIN32_EXE_FILENAME "vpnclient.exe"
+#define CLIENT_WIN32_EXE_FILENAME_X64 "vpnclient_x64.exe"
+#define CLIENT_WIN32_EXE_FILENAME_IA64 "vpnclient_ia64.exe"
+
+#define CLIENT_CUSTOM_INI_FILENAME "@custom.ini"
+
+#define CLIENT_GLOBAL_PULSE_NAME "clientglobalpulse"
+
+
+// List of virtual LAN cards in UNIX
+struct UNIX_VLAN
+{
+ bool Enabled; // Enable flag
+ char Name[MAX_SIZE]; // Name
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2];
+};
+
+// Account
+struct ACCOUNT
+{
+ // Static data
+ CLIENT_OPTION *ClientOption; // Client Option
+ CLIENT_AUTH *ClientAuth; // Client authentication data
+ bool CheckServerCert; // Check the server certificate
+ X *ServerCert; // Server certificate
+ bool StartupAccount; // Start-up account
+ UCHAR ShortcutKey[SHA1_SIZE]; // Key
+ UINT64 CreateDateTime; // Creation date and time
+ UINT64 UpdateDateTime; // Updating date
+ UINT64 LastConnectDateTime; // Last connection date and time
+
+ // Dynamic data
+ LOCK *lock; // Lock
+ SESSION *ClientSession; // Client session
+ CLIENT_STATUS_PRINTER *StatusPrinter; // Status indicator
+
+ SOCK *StatusWindow; // Status window
+};
+
+// Client Settings
+struct CLIENT_CONFIG
+{
+ bool AllowRemoteConfig; // Allow the remote configuration
+ bool UseKeepConnect; // Keep connected to the Internet
+ char KeepConnectHost[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT KeepConnectPort; // Port number
+ UINT KeepConnectProtocol; // Protocol
+ UINT KeepConnectInterval; // Interval
+ bool NoChangeWcmNetworkSettingOnWindows8; // Don't change the WCM network settings on Windows 8
+};
+
+// Version acquisition
+struct RPC_CLIENT_VERSION
+{
+ char ClientProductName[128]; // Client product name
+ char ClientVersionString[128]; // Client version string
+ char ClientBuildInfoString[128]; // Build client information string
+ UINT ClientVerInt; // Client version integer value
+ UINT ClientBuildInt; // Client build number integer value
+ UINT ProcessId; // Process ID
+ UINT OsType; // OS type
+ bool IsVLanNameRegulated; // Whether a virtual LAN card name must be "VLAN" + number
+ bool IsVgcSupported; // Whether the VPN Gate Client is supported
+ bool ShowVgcLink; // Display a VPN Gate Client link
+ char ClientId[128]; // Client OD
+};
+
+// Password Setting
+struct RPC_CLIENT_PASSWORD
+{
+ char Password[MAX_PASSWORD_LEN + 1]; // Password
+ bool PasswordRemoteOnly; // The password is required only remote access
+};
+
+// Get the password setting
+struct RPC_CLIENT_PASSWORD_SETTING
+{
+ bool IsPasswordPresented; // Password exists
+ bool PasswordRemoteOnly; // The password is required only remote access
+};
+
+// Certificate enumeration item
+struct RPC_CLIENT_ENUM_CA_ITEM
+{
+ UINT Key; // Certificate key
+ wchar_t SubjectName[MAX_SIZE]; // Issued to
+ wchar_t IssuerName[MAX_SIZE]; // Issuer
+ UINT64 Expires; // Expiration date
+};
+
+// Certificate enumeration
+struct RPC_CLIENT_ENUM_CA
+{
+ UINT NumItem; // Number of items
+ RPC_CLIENT_ENUM_CA_ITEM **Items; // Item
+};
+
+// Certificate item
+struct RPC_CERT
+{
+ X *x; // Certificate
+};
+
+// Delete the certificate
+struct RPC_CLIENT_DELETE_CA
+{
+ UINT Key; // Certificate key
+};
+
+// Get the certificate
+struct RPC_GET_CA
+{
+ UINT Key; // Certificate key
+ X *x; // Certificate
+};
+
+// Get the issuer
+struct RPC_GET_ISSUER
+{
+ X *x; // Certificate
+ X *issuer_x; // Issuer
+};
+
+// Secure device enumeration item
+struct RPC_CLIENT_ENUM_SECURE_ITEM
+{
+ UINT DeviceId; // Device ID
+ UINT Type; // Type
+ char DeviceName[MAX_SIZE]; // Device name
+ char Manufacturer[MAX_SIZE]; // Manufacturer
+};
+
+// Enumeration of secure devices
+struct RPC_CLIENT_ENUM_SECURE
+{
+ UINT NumItem; // Number of items
+ RPC_CLIENT_ENUM_SECURE_ITEM **Items; // Item
+};
+
+// Specify a secure device
+struct RPC_USE_SECURE
+{
+ UINT DeviceId; // Device ID
+};
+
+// Enumerate objects in the secure device
+struct RPC_ENUM_OBJECT_IN_SECURE
+{
+ UINT hWnd; // Window handle
+ UINT NumItem; // Number of items
+ char **ItemName; // Item name
+ bool *ItemType; // Type (true = secret key, false = public key)
+};
+
+// Create a virtual LAN
+struct RPC_CLIENT_CREATE_VLAN
+{
+ char DeviceName[MAX_SIZE]; // Device name
+};
+
+// Get a Virtual LAN information
+struct RPC_CLIENT_GET_VLAN
+{
+ char DeviceName[MAX_SIZE]; // Device name
+ bool Enabled; // Flag of whether it works or not
+ char MacAddress[MAX_SIZE]; // MAC address
+ char Version[MAX_SIZE]; // Version
+ char FileName[MAX_SIZE]; // Driver file name
+ char Guid[MAX_SIZE]; // GUID
+};
+
+// Set the virtual LAN information
+struct RPC_CLIENT_SET_VLAN
+{
+ char DeviceName[MAX_SIZE]; // Device name
+ char MacAddress[MAX_SIZE]; // MAC address
+};
+
+// Virtual LAN enumeration item
+struct RPC_CLIENT_ENUM_VLAN_ITEM
+{
+ char DeviceName[MAX_SIZE]; // Device name
+ bool Enabled; // Operation flag
+ char MacAddress[MAX_SIZE]; // MAC address
+ char Version[MAX_SIZE]; // Version
+};
+
+// Enumerate the virtual LANs
+struct RPC_CLIENT_ENUM_VLAN
+{
+ UINT NumItem; // Item count
+ RPC_CLIENT_ENUM_VLAN_ITEM **Items; // Item
+};
+
+// Create an account
+struct RPC_CLIENT_CREATE_ACCOUNT
+{
+ CLIENT_OPTION *ClientOption; // Client Option
+ CLIENT_AUTH *ClientAuth; // Client authentication data
+ bool StartupAccount; // Startup account
+ bool CheckServerCert; // Checking of the server certificate
+ X *ServerCert; // Server certificate
+ UCHAR ShortcutKey[SHA1_SIZE]; // Shortcut Key
+};
+
+// Enumeration item of account
+struct RPC_CLIENT_ENUM_ACCOUNT_ITEM
+{
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+ char UserName[MAX_USERNAME_LEN + 1]; // User name
+ char ServerName[MAX_HOST_NAME_LEN + 1]; // Server name
+ char DeviceName[MAX_DEVICE_NAME_LEN + 1]; // Device name
+ UINT ProxyType; // Type of proxy connection
+ char ProxyName[MAX_HOST_NAME_LEN + 1]; // Host name
+ bool Active; // Operation flag
+ bool Connected; // Connection completion flag
+ bool StartupAccount; // Startup account
+ UINT Port; // Port number (Ver 3.0 or later)
+ char HubName[MAX_HUBNAME_LEN + 1]; // Virtual HUB name (Ver 3.0 or later)
+ UINT64 CreateDateTime; // Creation date and time (Ver 3.0 or later)
+ UINT64 UpdateDateTime; // Modified date (Ver 3.0 or later)
+ UINT64 LastConnectDateTime; // Last connection date and time (Ver 3.0 or later)
+ UINT tmp1; // Temporary data
+};
+
+// Enumeration of accounts
+struct RPC_CLIENT_ENUM_ACCOUNT
+{
+ UINT NumItem; // Item count
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM **Items; // Items
+};
+
+// Delete the Account
+struct RPC_CLIENT_DELETE_ACCOUNT
+{
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+};
+
+// Change the account name
+struct RPC_RENAME_ACCOUNT
+{
+ wchar_t OldName[MAX_ACCOUNT_NAME_LEN + 1]; // Old name
+ wchar_t NewName[MAX_ACCOUNT_NAME_LEN + 1]; // New Name
+};
+
+// Get the account
+struct RPC_CLIENT_GET_ACCOUNT
+{
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+ CLIENT_OPTION *ClientOption; // Client Option
+ CLIENT_AUTH *ClientAuth; // Client authentication data
+ bool StartupAccount; // Startup account
+ bool CheckServerCert; // Check the server certificate
+ X *ServerCert; // Server certificate
+ UCHAR ShortcutKey[SHA1_SIZE]; // Shortcut Key
+ UINT64 CreateDateTime; // Creation date and time (Ver 3.0 or later)
+ UINT64 UpdateDateTime; // Modified date (Ver 3.0 or later)
+ UINT64 LastConnectDateTime; // Last connection date and time (Ver 3.0 or later)
+};
+
+// Connection
+struct RPC_CLIENT_CONNECT
+{
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+};
+
+// Get the Connection status
+struct RPC_CLIENT_GET_CONNECTION_STATUS
+{
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+ bool Active; // Operation flag
+ bool Connected; // Connected flag
+ UINT SessionStatus; // Session status
+ char ServerName[MAX_HOST_NAME_LEN + 1]; // Server name
+ UINT ServerPort; // Port number of the server
+ char ServerProductName[MAX_SIZE]; // Server product name
+ UINT ServerProductVer; // Server product version
+ UINT ServerProductBuild; // Server product build number
+ X *ServerX; // Server certificate
+ X *ClientX; // Client certificate
+ UINT64 StartTime; // Connection start time
+ UINT64 FirstConnectionEstablisiedTime; // Connection completion time of the first connection
+ UINT64 CurrentConnectionEstablishTime; // Connection completion time of this connection
+ UINT NumConnectionsEatablished; // Number of connections have been established so far
+ bool HalfConnection; // Half-connection
+ bool QoS; // VoIP / QoS
+ UINT MaxTcpConnections; // Maximum number of the TCP connections
+ UINT NumTcpConnections; // Number of current TCP connections
+ UINT NumTcpConnectionsUpload; // Number of inbound connections
+ UINT NumTcpConnectionsDownload; // Number of outbound connections
+ bool UseEncrypt; // Use of encryption
+ char CipherName[32]; // Cipher algorithm name
+ char ProtocolName[64]; // Protocol name
+ bool UseCompress; // Use of compression
+ bool IsRUDPSession; // R-UDP session
+ char UnderlayProtocol[64]; // Physical communication protocol
+ bool IsUdpAccelerationEnabled; // The UDP acceleration is enabled
+ bool IsUsingUdpAcceleration; // Using the UDP acceleration function
+ char SessionName[MAX_SESSION_NAME_LEN + 1]; // Session name
+ char ConnectionName[MAX_CONNECTION_NAME_LEN + 1]; // Connection name
+ UCHAR SessionKey[SHA1_SIZE]; // Session key
+ POLICY Policy; // Policy
+ UINT64 TotalSendSize; // Total transmitted data size
+ UINT64 TotalRecvSize; // Total received data size
+ UINT64 TotalSendSizeReal; // Total transmitted data size (no compression)
+ UINT64 TotalRecvSizeReal; // Total received data size (no compression)
+ TRAFFIC Traffic; // Traffic data
+ bool IsBridgeMode; // Bridge Mode
+ bool IsMonitorMode; // Monitor mode
+ UINT VLanId; // VLAN ID
+};
+
+
+// RPC connection
+struct CLIENT_RPC_CONNECTION
+{
+ struct CLIENT *Client; // Client
+ bool RpcMode; // True: RPC mode, false: notification mode
+ THREAD *Thread; // Processing thread
+ SOCK *Sock; // Socket
+};
+
+// Client object
+struct CLIENT
+{
+ LOCK *lock; // Lock
+ LOCK *lockForConnect; // Lock to be used in the CtConnect
+ REF *ref; // Reference counter
+ CEDAR *Cedar; // Cedar
+ volatile bool Halt; // Halting flag
+ UINT Err; // Error code
+ CFG_RW *CfgRw; // Configuration file R/W
+ LIST *AccountList; // Account list
+ UCHAR EncryptedPassword[SHA1_SIZE]; // Password
+ bool PasswordRemoteOnly; // Password is required only remote access
+ UINT UseSecureDeviceId; // Secure device ID to be used
+ CLIENT_CONFIG Config; // Client Settings
+ LIST *RpcConnectionList; // RPC connection list
+ SOCK *RpcListener; // RPC listener
+ THREAD *RpcThread; // RPC thread
+ LOCK *HelperLock; // Auxiliary lock
+ THREAD *SaverThread; // Saver thread
+ EVENT *SaverHalter; // The event to stop the Saver thread
+ LIST *NotifyCancelList; // Notification event list
+ KEEP *Keep; // Keep Connection
+ LIST *UnixVLanList; // List of virtual LAN cards in UNIX
+ LOG *Logger; // Logger
+ bool DontSavePassword; // Flag for not to save the password
+ ERASER *Eraser; // Eraser
+ SOCKLIST *SockList; // Socket list
+ CM_SETTING *CmSetting; // CM configuration
+ void *GlobalPulse; // Global pulse
+ THREAD *PulseRecvThread; // Pulse reception thread
+ volatile bool HaltPulseThread; // Stop flag for the pulse reception thread
+ bool NoSaveLog; // Do not save the log
+ bool NoSaveConfig; // Do not save the settings
+ INTERNET_SETTING CommonProxySetting; // Common proxy settings
+
+};
+
+// Notification to the remote client
+struct RPC_CLIENT_NOTIFY
+{
+ UINT NotifyCode; // Code
+};
+
+// Type of notification
+#define CLIENT_NOTIFY_ACCOUNT_CHANGED 1 // Account change notification
+#define CLIENT_NOTIFY_VLAN_CHANGED 2 // Virtual LAN card change notification
+
+// Remote client
+struct REMOTE_CLIENT
+{
+ RPC *Rpc;
+ UINT OsType;
+ bool Unix;
+ bool Win9x;
+ UINT ProcessId;
+ UINT ClientBuildInt;
+ bool IsVgcSupported;
+ bool ShowVgcLink;
+ char ClientId[128];
+};
+
+// Notification client
+struct NOTIFY_CLIENT
+{
+ SOCK *Sock;
+};
+
+// CM configuration
+struct CM_SETTING
+{
+ bool EasyMode; // Simple mode
+ bool LockMode; // Setting lock mode
+ UCHAR HashedPassword[SHA1_SIZE]; // Password
+};
+
+
+
+
+// Function prototype
+REMOTE_CLIENT *CcConnectRpc(char *server_name, char *password, bool *bad_pass, bool *no_remote, UINT wait_retry);
+REMOTE_CLIENT *CcConnectRpcEx(char *server_name, char *password, bool *bad_pass, bool *no_remote, UCHAR *key, UINT *key_error_code, bool shortcut_disconnect, UINT wait_retry);
+UINT CcShortcut(UCHAR *key);
+UINT CcShortcutDisconnect(UCHAR *key);
+void CcDisconnectRpc(REMOTE_CLIENT *rc);
+NOTIFY_CLIENT *CcConnectNotify(REMOTE_CLIENT *rc);
+void CcDisconnectNotify(NOTIFY_CLIENT *n);
+void CcStopNotify(NOTIFY_CLIENT *n);
+bool CcWaitNotify(NOTIFY_CLIENT *n);
+UINT CcGetClientVersion(REMOTE_CLIENT *r, RPC_CLIENT_VERSION *a);
+UINT CcSetCmSetting(REMOTE_CLIENT *r, CM_SETTING *a);
+UINT CcGetCmSetting(REMOTE_CLIENT *r, CM_SETTING *a);
+UINT CcSetPassword(REMOTE_CLIENT *r, RPC_CLIENT_PASSWORD *pass);
+UINT CcGetPasswordSetting(REMOTE_CLIENT *r, RPC_CLIENT_PASSWORD_SETTING *a);
+UINT CcEnumCa(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_CA *e);
+UINT CcAddCa(REMOTE_CLIENT *r, RPC_CERT *cert);
+UINT CcDeleteCa(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_CA *p);
+UINT CcGetCa(REMOTE_CLIENT *r, RPC_GET_CA *get);
+UINT CcEnumSecure(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_SECURE *e);
+UINT CcUseSecure(REMOTE_CLIENT *r, RPC_USE_SECURE *sec);
+UINT CcGetUseSecure(REMOTE_CLIENT *r, RPC_USE_SECURE *sec);
+UINT CcEnumObjectInSecure(REMOTE_CLIENT *r, RPC_ENUM_OBJECT_IN_SECURE *e);
+UINT CcCreateVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *create);
+UINT CcUpgradeVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *create);
+UINT CcGetVLan(REMOTE_CLIENT *r, RPC_CLIENT_GET_VLAN *get);
+UINT CcSetVLan(REMOTE_CLIENT *r, RPC_CLIENT_SET_VLAN *set);
+UINT CcEnumVLan(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_VLAN *e);
+UINT CcDeleteVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *d);
+UINT CcEnableVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *vlan);
+UINT CcDisableVLan(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_VLAN *vlan);
+UINT CcCreateAccount(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_ACCOUNT *a);
+UINT CcEnumAccount(REMOTE_CLIENT *r, RPC_CLIENT_ENUM_ACCOUNT *e);
+UINT CcDeleteAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a);
+UINT CcSetAccount(REMOTE_CLIENT *r, RPC_CLIENT_CREATE_ACCOUNT *a);
+UINT CcGetAccount(REMOTE_CLIENT *r, RPC_CLIENT_GET_ACCOUNT *a);
+UINT CcRenameAccount(REMOTE_CLIENT *r, RPC_RENAME_ACCOUNT *rename);
+UINT CcSetClientConfig(REMOTE_CLIENT *r, CLIENT_CONFIG *o);
+UINT CcGetClientConfig(REMOTE_CLIENT *r, CLIENT_CONFIG *o);
+UINT CcConnect(REMOTE_CLIENT *r, RPC_CLIENT_CONNECT *connect);
+UINT CcDisconnect(REMOTE_CLIENT *r, RPC_CLIENT_CONNECT *connect);
+UINT CcGetAccountStatus(REMOTE_CLIENT *r, RPC_CLIENT_GET_CONNECTION_STATUS *st);
+UINT CcSetStartupAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a);
+UINT CcRemoveStartupAccount(REMOTE_CLIENT *r, RPC_CLIENT_DELETE_ACCOUNT *a);
+UINT CcGetIssuer(REMOTE_CLIENT *r, RPC_GET_ISSUER *a);
+UINT CcGetCommonProxySetting(REMOTE_CLIENT *r, INTERNET_SETTING *a);
+UINT CcSetCommonProxySetting(REMOTE_CLIENT *r, INTERNET_SETTING *a);
+
+
+void CcSetServiceToForegroundProcess(REMOTE_CLIENT *r);
+char *CiGetFirstVLan(CLIENT *c);
+void CiNormalizeAccountVLan(CLIENT *c);
+
+bool CompareInternetSetting(INTERNET_SETTING *s1, INTERNET_SETTING *s2);
+
+
+void CnStart();
+void CnListenerProc(THREAD *thread, void *param);
+
+void CnReleaseSocket(SOCK *s, PACK *p);
+
+void CnStatusPrinter(SOCK *s, PACK *p);
+void Win32CnStatusPrinter(SOCK *s, PACK *p);
+
+void CnConnectErrorDlg(SOCK *s, PACK *p);
+void Win32CnConnectErrorDlg(SOCK *s, PACK *p);
+void Win32CnConnectErrorDlgThreadProc(THREAD *thread, void *param);
+
+void CnPasswordDlg(SOCK *s, PACK *p);
+void Win32CnPasswordDlg(SOCK *s, PACK *p);
+void Win32CnPasswordDlgThreadProc(THREAD *thread, void *param);
+
+void CnMsgDlg(SOCK *s, PACK *p);
+void Win32CnMsgDlg(SOCK *s, PACK *p);
+void Win32CnMsgDlgThreadProc(THREAD *thread, void *param);
+
+void CnNicInfo(SOCK *s, PACK *p);
+void Win32CnNicInfo(SOCK *s, PACK *p);
+void Win32CnNicInfoThreadProc(THREAD *thread, void *param);
+
+void CnCheckCert(SOCK *s, PACK *p);
+void Win32CnCheckCert(SOCK *s, PACK *p);
+void Win32CnCheckCertThreadProc(THREAD *thread, void *param);
+
+void CnExecDriverInstaller(SOCK *s, PACK *p);
+void Win32CnExecDriverInstaller(SOCK *s, PACK *p);
+
+bool CnCheckAlreadyExists(bool lock);
+bool CnIsCnServiceReady();
+void CnWaitForCnServiceReady();
+
+void CnSecureSign(SOCK *s, PACK *p);
+
+SOCK *CncConnect();
+SOCK *CncConnectEx(UINT timeout);
+void CncReleaseSocket();
+void CncExit();
+UINT CncGetSessionId();
+bool CncExecDriverInstaller(char *arg);
+SOCK *CncStatusPrinterWindowStart(SESSION *s);
+void CncStatusPrinterWindowPrint(SOCK *s, wchar_t *str);
+void CncStatusPrinterWindowStop(SOCK *s);
+void CncStatusPrinterWindowThreadProc(THREAD *thread, void *param);
+bool CncConnectErrorDlg(SESSION *session, UI_CONNECTERROR_DLG *dlg);
+void CncConnectErrorDlgHaltThread(THREAD *thread, void *param);
+bool CncPasswordDlg(SESSION *session, UI_PASSWORD_DLG *dlg);
+void CncPasswordDlgHaltThread(THREAD *thread, void *param);
+void CncCheckCert(SESSION *session, UI_CHECKCERT *dlg);
+void CncCheckCertHaltThread(THREAD *thread, void *param);
+bool CncSecureSignDlg(SECURE_SIGN *sign);
+SOCK *CncMsgDlg(UI_MSG_DLG *dlg);
+void CndMsgDlgFree(SOCK *s);
+SOCK *CncNicInfo(UI_NICINFO *info);
+void CncNicInfoFree(SOCK *s);
+
+void CtStartClient();
+void CtStopClient();
+CLIENT *CtGetClient();
+void CtReleaseClient(CLIENT *c);
+bool CtGetClientVersion(CLIENT *c, RPC_CLIENT_VERSION *ver);
+bool CtGetCmSetting(CLIENT *c, CM_SETTING *s);
+bool CtSetCmSetting(CLIENT *c, CM_SETTING *s);
+bool CtSetPassword(CLIENT *c, RPC_CLIENT_PASSWORD *pass);
+bool CtGetPasswordSetting(CLIENT *c, RPC_CLIENT_PASSWORD_SETTING *a);
+bool CtEnumCa(CLIENT *c, RPC_CLIENT_ENUM_CA *e);
+bool CtAddCa(CLIENT *c, RPC_CERT *cert);
+bool CtDeleteCa(CLIENT *c, RPC_CLIENT_DELETE_CA *p);
+bool CtGetCa(CLIENT *c, RPC_GET_CA *get);
+bool CtEnumSecure(CLIENT *c, RPC_CLIENT_ENUM_SECURE *e);
+bool CtUseSecure(CLIENT *c, RPC_USE_SECURE *sec);
+bool CtGetUseSecure(CLIENT *c, RPC_USE_SECURE *sec);
+bool CtEnumObjectInSecure(CLIENT *c, RPC_ENUM_OBJECT_IN_SECURE *e);
+bool CtCreateVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *create);
+bool CtUpgradeVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *create);
+bool CtGetVLan(CLIENT *c, RPC_CLIENT_GET_VLAN *get);
+bool CtSetVLan(CLIENT *c, RPC_CLIENT_SET_VLAN *set);
+bool CtEnumVLan(CLIENT *c, RPC_CLIENT_ENUM_VLAN *e);
+bool CtDeleteVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *d);
+bool CtEnableVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *vlan);
+bool CtDisableVLan(CLIENT *c, RPC_CLIENT_CREATE_VLAN *vlan);
+bool CtCreateAccount(CLIENT *c, RPC_CLIENT_CREATE_ACCOUNT *a, bool inner);
+bool CtEnumAccount(CLIENT *c, RPC_CLIENT_ENUM_ACCOUNT *e);
+bool CtDeleteAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a, bool inner);
+bool CtSetAccount(CLIENT *c, RPC_CLIENT_CREATE_ACCOUNT *a, bool inner);
+bool CtGetAccount(CLIENT *c, RPC_CLIENT_GET_ACCOUNT *a);
+bool CtRenameAccount(CLIENT *c, RPC_RENAME_ACCOUNT *rename, bool inner);
+bool CtSetClientConfig(CLIENT *c, CLIENT_CONFIG *o);
+bool CtGetClientConfig(CLIENT *c, CLIENT_CONFIG *o);
+bool CtConnect(CLIENT *c, RPC_CLIENT_CONNECT *connect);
+bool CtDisconnect(CLIENT *c, RPC_CLIENT_CONNECT *connect, bool inner);
+bool CtGetAccountStatus(CLIENT *c, RPC_CLIENT_GET_CONNECTION_STATUS *st);
+bool CtSetStartupAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a, bool inner);
+bool CtRemoveStartupAccount(CLIENT *c, RPC_CLIENT_DELETE_ACCOUNT *a);
+bool CtGetIssuer(CLIENT *c, RPC_GET_ISSUER *a);
+bool CtGetCommonProxySetting(CLIENT *c, INTERNET_SETTING *a);
+bool CtSetCommonProxySetting(CLIENT *c, INTERNET_SETTING *a);
+
+
+// Internal function prototype
+void CiSendGlobalPulse(CLIENT *c);
+void CiPulseRecvThread(THREAD *thread, void *param);
+char *CiGetVpnClientExeFileName();
+void CiServerThread(THREAD *t, void *param);
+void CiInitSaver(CLIENT *c);
+void CiFreeSaver(CLIENT *c);
+void CiGetSessionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *st, SESSION *s);
+PACK *CiRpcDispatch(RPC *rpc, char *name, PACK *p);
+void CiRpcAccepted(CLIENT *c, SOCK *s);
+void CiNotifyMain(CLIENT *c, SOCK *s);
+void CiRpcAcceptThread(THREAD *thread, void *param);
+void CiRpcServerThread(THREAD *thread, void *param);
+void CiStartRpcServer(CLIENT *c);
+void CiStopRpcServer(CLIENT *c);
+CLIENT_OPTION *CiLoadClientOption(FOLDER *f);
+CLIENT_AUTH *CiLoadClientAuth(FOLDER *f);
+ACCOUNT *CiLoadClientAccount(FOLDER *f);
+void CiLoadClientConfig(CLIENT_CONFIG *c, FOLDER *f);
+void CiLoadAccountDatabase(CLIENT *c, FOLDER *f);
+void CiLoadCAList(CLIENT *c, FOLDER *f);
+void CiLoadCACert(CLIENT *c, FOLDER *f);
+void CiLoadVLanList(CLIENT *c, FOLDER *f);
+void CiLoadVLan(CLIENT *c, FOLDER *f);
+bool CiReadSettingFromCfg(CLIENT *c, FOLDER *root);
+void CiWriteAccountDatabase(CLIENT *c, FOLDER *f);
+void CiWriteAccountData(FOLDER *f, ACCOUNT *a);
+void CiWriteClientOption(FOLDER *f, CLIENT_OPTION *o);
+void CiWriteClientAuth(FOLDER *f, CLIENT_AUTH *a);
+void CiWriteClientConfig(FOLDER *cc, CLIENT_CONFIG *config);
+void CiWriteSettingToCfg(CLIENT *c, FOLDER *root);
+void CiWriteCAList(CLIENT *c, FOLDER *f);
+void CiWriteCACert(CLIENT *c, FOLDER *f, X *x);
+void CiWriteVLanList(CLIENT *c, FOLDER *f);
+void CiWriteVLan(CLIENT *c, FOLDER *f, UNIX_VLAN *v);
+void CiFreeClientGetConnectionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *st);
+bool CiCheckCertProc(SESSION *s, CONNECTION *c, X *server_x, bool *expired);
+bool CiSecureSignProc(SESSION *s, CONNECTION *c, SECURE_SIGN *sign);
+bool Win32CiSecureSign(SECURE_SIGN *sign);
+void CiFreeClientAuth(CLIENT_AUTH *auth);
+void CiFreeClientCreateAccount(RPC_CLIENT_CREATE_ACCOUNT *a);
+void CiFreeClientGetAccount(RPC_CLIENT_GET_ACCOUNT *a);
+void CiFreeClientEnumVLan(RPC_CLIENT_ENUM_VLAN *e);
+void CiFreeClientEnumSecure(RPC_CLIENT_ENUM_SECURE *e);
+void CiFreeClientEnumCa(RPC_CLIENT_ENUM_CA *e);
+void CiFreeEnumObjectInSecure(RPC_ENUM_OBJECT_IN_SECURE *a);
+void CiFreeGetCa(RPC_GET_CA *a);
+void CiFreeGetIssuer(RPC_GET_ISSUER *a);
+void CiFreeClientEnumAccount(RPC_CLIENT_ENUM_ACCOUNT *a);
+void CiSetError(CLIENT *c, UINT err);
+void CiCheckOs();
+CLIENT *CiNewClient();
+void CiCleanupClient(CLIENT *c);
+bool CiLoadConfigurationFile(CLIENT *c);
+void CiSaveConfigurationFile(CLIENT *c);
+void CiInitConfiguration(CLIENT *c);
+void CiSetVLanToDefault(CLIENT *c);
+bool CiIsVLan(CLIENT *c, char *name);
+void CiFreeConfiguration(CLIENT *c);
+int CiCompareAccount(void *p1, void *p2);
+void CiFreeAccount(ACCOUNT *a);
+void CiNotify(CLIENT *c);
+void CiNotifyInternal(CLIENT *c);
+void CiClientStatusPrinter(SESSION *s, wchar_t *status);
+void CiInitKeep(CLIENT *c);
+void CiFreeKeep(CLIENT *c);
+int CiCompareUnixVLan(void *p1, void *p2);
+BUF *CiAccountToCfg(RPC_CLIENT_CREATE_ACCOUNT *t);
+RPC_CLIENT_CREATE_ACCOUNT *CiCfgToAccount(BUF *b);
+void CiChangeAllVLanMacAddressIfCleared(CLIENT *c);
+void CiChangeAllVLanMacAddress(CLIENT *c);
+void CiChangeAllVLanMacAddressIfMachineChanged(CLIENT *c);
+bool CiReadLastMachineHash(void *data);
+bool CiWriteLastMachineHash(void *data);
+void CiGetCurrentMachineHash(void *data);
+void CiGetCurrentMachineHashOld(void *data);
+void CiGetCurrentMachineHashNew(void *data);
+LIST *CiLoadIni();
+void CiFreeIni(LIST *o);
+void CiLoadIniSettings(CLIENT *c);
+bool CiLoadConfigFilePathFromIni(char *path, UINT size);
+int CiCompareClientAccountEnumItemByLastConnectDateTime(void *p1, void *p2);
+bool CiIsValidVLanRegulatedName(char *name);
+void CiGenerateVLanRegulatedName(char *name, UINT size, UINT i);
+bool CiGetNextRecommendedVLanName(REMOTE_CLIENT *r, char *name, UINT size);
+void CiDisableWcmNetworkMinimize(CLIENT *c);
+bool CiTryToParseAccount(BUF *b);
+bool CiTryToParseAccountFile(wchar_t *name);
+bool CiEraseSensitiveInAccount(BUF *b);
+bool CiHasAccountSensitiveInformation(BUF *b);
+bool CiHasAccountSensitiveInformationFile(wchar_t *name);
+void CiApplyInnerVPNServerConfig(CLIENT *c);
+SERVER *CiNewInnerVPNServer(CLIENT *c);
+void CiFreeInnerVPNServer(CLIENT *c, SERVER *s);
+void CiIncrementNumActiveSessions();
+void CiDecrementNumActiveSessions();
+UINT CiGetNumActiveSessions();
+
+BUF *EncryptPassword(char *password);
+BUF *EncryptPassword2(char *password);
+char *DecryptPassword(BUF *b);
+char *DecryptPassword2(BUF *b);
+
+void InRpcGetIssuer(RPC_GET_ISSUER *c, PACK *p);
+void OutRpcGetIssuer(PACK *p, RPC_GET_ISSUER *c);
+void InRpcClientVersion(RPC_CLIENT_VERSION *ver, PACK *p);
+void OutRpcClientVersion(PACK *p, RPC_CLIENT_VERSION *ver);
+void InRpcClientPassword(RPC_CLIENT_PASSWORD *pw, PACK *p);
+void OutRpcClientPassword(PACK *p, RPC_CLIENT_PASSWORD *pw);
+void InRpcClientEnumCa(RPC_CLIENT_ENUM_CA *e, PACK *p);
+void OutRpcClientEnumCa(PACK *p, RPC_CLIENT_ENUM_CA *e);
+void InRpcCert(RPC_CERT *c, PACK *p);
+void OutRpcCert(PACK *p, RPC_CERT *c);
+void InRpcClientDeleteCa(RPC_CLIENT_DELETE_CA *c, PACK *p);
+void OutRpcClientDeleteCa(PACK *p, RPC_CLIENT_DELETE_CA *c);
+void InRpcGetCa(RPC_GET_CA *c, PACK *p);
+void OutRpcGetCa(PACK *p, RPC_GET_CA *c);
+void InRpcClientEnumSecure(RPC_CLIENT_ENUM_SECURE *e, PACK *p);
+void OutRpcClientEnumSecure(PACK *p, RPC_CLIENT_ENUM_SECURE *e);
+void InRpcUseSecure(RPC_USE_SECURE *u, PACK *p);
+void OutRpcUseSecure(PACK *p, RPC_USE_SECURE *u);
+void InRpcEnumObjectInSecure(RPC_ENUM_OBJECT_IN_SECURE *e, PACK *p);
+void OutRpcEnumObjectInSecure(PACK *p, RPC_ENUM_OBJECT_IN_SECURE *e);
+void InRpcCreateVLan(RPC_CLIENT_CREATE_VLAN *v, PACK *p);
+void OutRpcCreateVLan(PACK *p, RPC_CLIENT_CREATE_VLAN *v);
+void InRpcClientGetVLan(RPC_CLIENT_GET_VLAN *v, PACK *p);
+void OutRpcClientGetVLan(PACK *p, RPC_CLIENT_GET_VLAN *v);
+void InRpcClientSetVLan(RPC_CLIENT_SET_VLAN *v, PACK *p);
+void OutRpcClientSetVLan(PACK *p, RPC_CLIENT_SET_VLAN *v);
+void InRpcClientEnumVLan(RPC_CLIENT_ENUM_VLAN *v, PACK *p);
+void OutRpcClientEnumVLan(PACK *p, RPC_CLIENT_ENUM_VLAN *v);
+void InRpcClientOption(CLIENT_OPTION *c, PACK *p);
+void OutRpcClientOption(PACK *p, CLIENT_OPTION *c);
+void InRpcClientAuth(CLIENT_AUTH *c, PACK *p);
+void OutRpcClientAuth(PACK *p, CLIENT_AUTH *c);
+void InRpcClientCreateAccount(RPC_CLIENT_CREATE_ACCOUNT *c, PACK *p);
+void OutRpcClientCreateAccount(PACK *p, RPC_CLIENT_CREATE_ACCOUNT *c);
+void InRpcClientEnumAccount(RPC_CLIENT_ENUM_ACCOUNT *e, PACK *p);
+void OutRpcClientEnumAccount(PACK *p, RPC_CLIENT_ENUM_ACCOUNT *e);
+void InRpcClientDeleteAccount(RPC_CLIENT_DELETE_ACCOUNT *a, PACK *p);
+void OutRpcClientDeleteAccount(PACK *p, RPC_CLIENT_DELETE_ACCOUNT *a);
+void InRpcRenameAccount(RPC_RENAME_ACCOUNT *a, PACK *p);
+void OutRpcRenameAccount(PACK *p, RPC_RENAME_ACCOUNT *a);
+void InRpcClientGetAccount(RPC_CLIENT_GET_ACCOUNT *c, PACK *p);
+void OutRpcClientGetAccount(PACK *p, RPC_CLIENT_GET_ACCOUNT *c);
+void InRpcClientConnect(RPC_CLIENT_CONNECT *c, PACK *p);
+void OutRpcClientConnect(PACK *p, RPC_CLIENT_CONNECT *c);
+void InRpcPolicy(POLICY *o, PACK *p);
+void OutRpcPolicy(PACK *p, POLICY *o);
+void InRpcClientGetConnectionStatus(RPC_CLIENT_GET_CONNECTION_STATUS *s, PACK *p);
+void OutRpcClientGetConnectionStatus(PACK *p, RPC_CLIENT_GET_CONNECTION_STATUS *c);
+void InRpcClientNotify(RPC_CLIENT_NOTIFY *n, PACK *p);
+void OutRpcClientNotify(PACK *p, RPC_CLIENT_NOTIFY *n);
+void InRpcClientConfig(CLIENT_CONFIG *c, PACK *p);
+void OutRpcClientConfig(PACK *p, CLIENT_CONFIG *c);
+void InRpcClientPasswordSetting(RPC_CLIENT_PASSWORD_SETTING *a, PACK *p);
+void OutRpcClientPasswordSetting(PACK *p, RPC_CLIENT_PASSWORD_SETTING *a);
+void InRpcTraffic(TRAFFIC *t, PACK *p);
+void OutRpcTraffic(PACK *p, TRAFFIC *t);
+void InRpcTrafficEx(TRAFFIC *t, PACK *p, UINT i);
+void OutRpcTrafficEx(TRAFFIC *t, PACK *p, UINT i, UINT num);
+void OutRpcCmSetting(PACK *p, CM_SETTING *c);
+void InRpcCmSetting(CM_SETTING *c, PACK *p);
+
+
+#ifdef OS_WIN32
+void CiInitDriverVerStruct(MS_DRIVER_VER *ver);
+#endif // OS_EIN32
+
+#endif // CLIENT_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Command.c b/src/Cedar/Command.c
new file mode 100644
index 00000000..1d762b45
--- /dev/null
+++ b/src/Cedar/Command.c
@@ -0,0 +1,23538 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Command.c
+// vpncmd Command Line Management Utility
+
+#include "CedarPch.h"
+
+// System checker definition
+typedef bool (CHECKER_PROC_DEF)();
+typedef struct CHECKER_PROC
+{
+ char *Title;
+ CHECKER_PROC_DEF *Proc;
+} CHECKER_PROC;
+
+static CHECKER_PROC checker_procs[] =
+{
+ {"CHECK_PROC_KERNEL", CheckKernel},
+ {"CHECK_PROC_MEMORY", CheckMemory},
+ {"CHECK_PROC_STRINGS", CheckStrings},
+ {"CHECK_PROC_FILESYSTEM", CheckFileSystem},
+ {"CHECK_PROC_THREAD", CheckThread},
+ {"CHECK_PROC_NETWORK", CheckNetwork},
+};
+
+typedef struct CHECK_NETWORK_1
+{
+ SOCK *ListenSocket;
+} CHECK_NETWORK_1;
+
+typedef struct CHECK_NETWORK_2
+{
+ SOCK *s;
+ X *x;
+ K *k;
+} CHECK_NETWORK_2;
+
+
+// Convert the TT_RESULT to RPC
+void OutRpcTtResult(PACK *p, TT_RESULT *t)
+{
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "Raw", t->Raw);
+ PackAddBool(p, "Double", t->Double);
+ PackAddInt64(p, "NumBytesUpload", t->NumBytesUpload);
+ PackAddInt64(p, "NumBytesDownload", t->NumBytesDownload);
+ PackAddInt64(p, "NumBytesTotal", t->NumBytesTotal);
+ PackAddInt64(p, "Span", t->Span);
+ PackAddInt64(p, "BpsUpload", t->BpsUpload);
+ PackAddInt64(p, "BpsDownload", t->BpsDownload);
+ PackAddInt64(p, "BpsTotal", t->BpsTotal);
+}
+
+// Convert an RPC to a TT_RESULT
+void InRpcTtResult(PACK *p, TT_RESULT *t)
+{
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(TT_RESULT));
+
+ t->Raw = PackGetBool(p, "Raw");
+ t->Double = PackGetBool(p, "Double");
+ t->NumBytesUpload = PackGetInt64(p, "NumBytesUpload");
+ t->NumBytesDownload = PackGetInt64(p, "NumBytesDownload");
+ t->NumBytesTotal = PackGetInt64(p, "NumBytesTotal");
+ t->Span = PackGetInt64(p, "Span");
+ t->BpsUpload = PackGetInt64(p, "BpsUpload");
+ t->BpsDownload = PackGetInt64(p, "BpsDownload");
+ t->BpsTotal = PackGetInt64(p, "BpsTotal");
+}
+
+// Accept thread
+void CheckNetworkAcceptThread(THREAD *thread, void *param)
+{
+ CHECK_NETWORK_2 *c = (CHECK_NETWORK_2 *)param;
+ SOCK *s = c->s;
+ UINT i = 0;
+
+ if (StartSSL(s, c->x, c->k))
+ {
+ while (true)
+ {
+ i++;
+ if (Send(s, &i, sizeof(UINT), true) == 0)
+ {
+ break;
+ }
+ }
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+}
+
+
+// Listen thread
+void CheckNetworkListenThread(THREAD *thread, void *param)
+{
+ CHECK_NETWORK_1 *c = (CHECK_NETWORK_1 *)param;
+ SOCK *s;
+ UINT i;
+ K *pub, *pri;
+ X *x;
+ LIST *o = NewList(NULL);
+ NAME *name = NewName(L"Test", L"Test", L"Test", L"JP", L"Ibaraki", L"Tsukuba");
+
+ RsaGen(&pri, &pub, 1024);
+ x = NewRootX(pub, pri, name, 1000, NULL);
+
+ FreeName(name);
+
+ for (i = 1025;;i++)
+ {
+ s = Listen(i);
+ if (s != NULL)
+ {
+ break;
+ }
+ }
+
+ c->ListenSocket = s;
+ AddRef(s->ref);
+
+ NoticeThreadInit(thread);
+
+ while (true)
+ {
+ SOCK *new_sock = Accept(s);
+
+ if (new_sock == NULL)
+ {
+ break;
+ }
+ else
+ {
+ CHECK_NETWORK_2 c;
+ THREAD *t;
+
+ Zero(&c, sizeof(c));
+ c.s = new_sock;
+ c.k = pri;
+ c.x = x;
+
+ t = NewThread(CheckNetworkAcceptThread, &c);
+ Insert(o, t);
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ THREAD *t = LIST_DATA(o, i);
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+ }
+
+ FreeK(pri);
+ FreeK(pub);
+
+ FreeX(x);
+
+ ReleaseSock(s);
+ ReleaseList(o);
+}
+
+// Network function check
+bool CheckNetwork()
+{
+ CHECK_NETWORK_1 c;
+ THREAD *t;
+ SOCK *listen_socket;
+ UINT port;
+ UINT i, num;
+ bool ok = true;
+ SOCK **socks;
+ SOCK_EVENT *se = NewSockEvent();
+
+ Zero(&c, sizeof(c));
+ t = NewThread(CheckNetworkListenThread, &c);
+ WaitThreadInit(t);
+
+ listen_socket = c.ListenSocket;
+
+ port = listen_socket->LocalPort;
+
+ num = 8;
+ socks = ZeroMalloc(sizeof(SOCK *) * num);
+ for (i = 0;i < num;i++)
+ {
+ socks[i] = Connect("localhost", port);
+ if (socks[i] == NULL)
+ {
+ Print("Connect Failed. (%u)\n", i);
+ ok = false;
+ num = i;
+ break;
+ }
+ if (StartSSL(socks[i], NULL, NULL) == false)
+ {
+ ReleaseSock(socks[i]);
+ Print("Connect Failed. (%u)\n", i);
+ ok = false;
+ num = i;
+ break;
+ }
+
+ JoinSockToSockEvent(socks[i], se);
+ }
+
+ if (ok)
+ {
+ while (true)
+ {
+ UINT i;
+ bool end = false;
+ bool all_blocked = true;
+
+ for (i = 0;i < num;i++)
+ {
+ UINT n;
+ UINT ret;
+
+ n = 0;
+ ret = Recv(socks[i], &n, sizeof(UINT), true);
+ if (ret == 0)
+ {
+ Print("Recv Failed (Disconnected).\n", ret);
+ end = true;
+ ok = false;
+ }
+ if (ret != SOCK_LATER)
+ {
+ all_blocked = false;
+ }
+
+ if (n >= 128)
+ {
+ end = true;
+ }
+ }
+
+ if (end)
+ {
+ break;
+ }
+
+ if (all_blocked)
+ {
+ WaitSockEvent(se, INFINITE);
+ }
+ }
+ }
+
+ for (i = 0;i < num;i++)
+ {
+ Disconnect(socks[i]);
+ ReleaseSock(socks[i]);
+ }
+ Free(socks);
+
+ Disconnect(listen_socket);
+
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+
+ ReleaseSock(listen_socket);
+
+ ReleaseSockEvent(se);
+
+ return ok;
+}
+
+typedef struct CHECK_THREAD_1
+{
+ UINT num;
+ LOCK *lock;
+ THREAD *wait_thread;
+} CHECK_THREAD_1;
+
+static UINT check_thread_global_1 = 0;
+
+#define CHECK_THREAD_INCREMENT_COUNT 32
+
+// Test thread 1
+void CheckThread1(THREAD *thread, void *param)
+{
+ CHECK_THREAD_1 *ct1 = (CHECK_THREAD_1 *)param;
+ UINT i;
+ UINT num = CHECK_THREAD_INCREMENT_COUNT;
+
+ WaitThread(ct1->wait_thread, INFINITE);
+
+ for (i = 0;i < num;i++)
+ {
+ Lock(ct1->lock);
+ check_thread_global_1 = ct1->num;
+ InputToNull((void *)check_thread_global_1);
+ check_thread_global_1 = check_thread_global_1 + 1 + RetZero();
+ ct1->num = check_thread_global_1;
+ Unlock(ct1->lock);
+ }
+}
+
+// Test thread 2
+void CheckThread2(THREAD *thread, void *param)
+{
+ EVENT *e = (EVENT *)param;
+ Wait(e, INFINITE);
+}
+
+typedef struct CHECK_THREAD_3
+{
+ UINT num, a;
+} CHECK_THREAD_3;
+
+// Test thread 3
+void CheckThread3(THREAD *thread, void *param)
+{
+ CHECK_THREAD_3 *c = (CHECK_THREAD_3 *)param;
+ THREAD *t;
+
+ if (c->num == 0)
+ {
+ return;
+ }
+ c->num--;
+ c->a++;
+
+ t = NewThread(CheckThread3, c);
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+}
+
+// Thread check
+bool CheckThread()
+{
+ bool ok = true;
+ CHECK_THREAD_1 ct1;
+ UINT num = 32;
+ UINT i;
+ THREAD **threads;
+ EVENT *e;
+ THREAD *t2;
+ THREAD *t;
+ CHECK_THREAD_3 c;
+
+ e = NewEvent();
+
+ Zero(&ct1, sizeof(ct1));
+ ct1.lock = NewLock();
+
+ t2 = NewThread(CheckThread2, e);
+ ct1.wait_thread = t2;
+
+ threads = ZeroMalloc(sizeof(THREAD *) * num);
+ for (i = 0;i < num;i++)
+ {
+ threads[i] = NewThread(CheckThread1, &ct1);
+ if (threads[i] == NULL)
+ {
+ Print("Thread %u Create Failed.\n", i);
+ ok = false;
+ }
+ }
+
+ Set(e);
+
+ for (i = 0;i < num;i++)
+ {
+ WaitThread(threads[i], INFINITE);
+ ReleaseThread(threads[i]);
+ }
+
+ Free(threads);
+
+ if (ct1.num != (num * CHECK_THREAD_INCREMENT_COUNT))
+ {
+ Print("Threading: %u != %u\n", ct1.num, num * CHECK_THREAD_INCREMENT_COUNT);
+ ok = false;
+ }
+
+ DeleteLock(ct1.lock);
+
+ WaitThread(t2, INFINITE);
+ ReleaseThread(t2);
+
+ ReleaseEvent(e);
+
+ num = 32;
+
+ Zero(&c, sizeof(c));
+ c.num = num;
+ t = NewThread(CheckThread3, &c);
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+
+ if (c.a != num)
+ {
+ Print("Threading: %u != %u\n", c.a, num);
+ ok = false;
+ }
+
+ return ok;
+}
+
+// File system check
+bool CheckFileSystem()
+{
+ bool ok = true;
+ char exe[MAX_PATH];
+ char exe_dir[MAX_PATH];
+ DIRLIST *dirs;
+ UINT i;
+
+ GetExeName(exe, sizeof(exe));
+ GetExeDir(exe_dir, sizeof(exe_dir));
+
+ ok = false;
+ dirs = EnumDir(exe_dir);
+ for (i = 0;i < dirs->NumFiles;i++)
+ {
+ if (EndWith(exe, dirs->File[i]->FileName))
+ {
+ ok = true;
+ break;
+ }
+ }
+ FreeDir(dirs);
+
+ if (ok == false)
+ {
+ Print("EnumDir Failed.\n");
+ return false;
+ }
+ else
+ {
+ UINT size = 1234567;
+ UCHAR *buf;
+ IO *io;
+#ifndef OS_WIN32
+ wchar_t *filename = L"/tmp/vpn_checker_tmp";
+#else // OS_WIN32
+ wchar_t filename[MAX_PATH];
+ CombinePathW(filename, sizeof(filename), MsGetMyTempDirW(), L"vpn_checker_tmp");
+#endif // OS_WIN32
+
+ buf = Malloc(size);
+ for (i = 0;i < size;i++)
+ {
+ buf[i] = i % 256;
+ }
+
+ io = FileCreateW(filename);
+ if (io == NULL)
+ {
+ Print("FileCreate Failed.\n");
+ Free(buf);
+ return false;
+ }
+ else
+ {
+ FileWrite(io, buf, size);
+ Free(buf);
+ FileClose(io);
+
+ io = FileOpenW(filename, false);
+ if (FileSize(io) != 1234567)
+ {
+ Print("FileSize Failed.\n");
+ FileClose(io);
+ return false;
+ }
+ else
+ {
+ BUF *b;
+
+ FileClose(io);
+ b = ReadDumpW(filename);
+
+ for (i = 0;i < b->Size;i++)
+ {
+ UCHAR c = ((UCHAR *)b->Buf)[i];
+
+ if (c != (i % 256))
+ {
+ Print("FileToBuf Failed.\n");
+ FreeBuf(b);
+ return false;
+ }
+ }
+
+ FreeBuf(b);
+ }
+ }
+
+ FileDeleteW(filename);
+ }
+
+ return ok;
+}
+
+// String check
+bool CheckStrings()
+{
+ wchar_t *numstr = _UU("CHECK_TEST_123456789");
+ char tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ UINT i;
+ UINT sum, sum2;
+ UNI_TOKEN_LIST *t;
+
+ UniStrCpy(tmp2, sizeof(tmp2), L"");
+
+ sum2 = 0;
+ for (i = 0;i < 64;i++)
+ {
+ sum2 += i;
+ UniFormat(tmp2, sizeof(tmp2), L"%s,%u", tmp2, i);
+ }
+
+ t = UniParseToken(tmp2, L",");
+
+ sum = 0;
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ wchar_t *s = t->Token[i];
+ UINT n = UniToInt(s);
+
+ sum += n;
+ }
+
+ UniFreeToken(t);
+
+ if (sum != sum2)
+ {
+ Print("UniParseToken Failed.\n");
+ return false;
+ }
+
+ if (UniToInt(numstr) != 123456789)
+ {
+ Print("UniToInt Failed.\n");
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), numstr);
+ if (ToInt(tmp) != 123456789)
+ {
+ Print("UniToStr Failed.\n");
+ return false;
+ }
+
+ return true;
+}
+
+// Memory check
+bool CheckMemory()
+{
+ UINT i, num, size, j;
+ void **pp;
+ bool ok = true;
+ UINT old_size;
+
+ num = 2000;
+ size = 1000;
+ pp = ZeroMalloc(sizeof(void *) * num);
+ for (i = 0;i < num;i++)
+ {
+ pp[i] = ZeroMalloc(size);
+ InputToNull(pp[i]);
+ for (j = 0;j < size;j++)
+ {
+ ((UCHAR *)pp[i])[j] = j % 256;
+ }
+ }
+ old_size = size;
+ size = size * 3;
+ for (i = 0;i < num;i++)
+ {
+ pp[i] = ReAlloc(pp[i], size);
+ for (j = old_size;j < size;j++)
+ {
+ InputToNull((void *)(UINT)(((UCHAR *)pp[i])[j] = j % 256));
+ }
+ }
+ for (i = 0;i < num;i++)
+ {
+ for (j = 0;j < size;j++)
+ {
+ if (((UCHAR *)pp[i])[j] != (j % 256))
+ {
+ ok = false;
+ }
+ }
+ Free(pp[i]);
+ }
+ Free(pp);
+
+ return ok;
+}
+
+// Function that do not do anything
+void InputToNull(void *p)
+{
+ if (RetZero() == 1)
+ {
+ UCHAR *c = (UCHAR *)p;
+ c[0] = 0x32;
+ }
+}
+
+// Function that returns 0
+UINT RetZero()
+{
+ if (g_debug == 0x123455)
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+// Kernel check
+bool CheckKernel()
+{
+ UINT num = 10, i;
+ UINT64 s = Tick64();
+ UINT64 t = Tick64();
+
+ for (i = 0;i < num;i++)
+ {
+ UINT64 q = Tick64();
+ if (t > q)
+ {
+ Print("Tick64 #1 Failed.\n");
+ return false;
+ }
+
+ t = q;
+
+ SleepThread(100);
+ }
+
+ t = (Tick64() - s);
+ if (t <= 500 || t >= 2000)
+ {
+ Print("Tick64 #2 Failed.\n");
+ return false;
+ }
+ else if (false)
+ {
+ UINT64 tick1 = Tick64();
+ UINT64 time1;
+ UINT64 tick2, time2;
+
+ SleepThread(1000);
+
+ tick2 = Tick64();
+ time2 = LocalTime64();
+ time1 = SystemToLocal64(TickToTime(tick1));
+
+ if (time2 > time1)
+ {
+ s = time2 - time1;
+ }
+ else
+ {
+ s = time1 - time2;
+ }
+
+ if (s <= 500 || s >= 2000)
+ {
+ Print("TickToTime Failed.\n");
+ return false;
+ }
+ }
+
+#ifdef OS_UNIX
+ {
+ // Test of child process
+ UINT pid;
+ char exe[MAX_SIZE];
+
+ GetExeName(exe, sizeof(exe));
+
+ pid = fork();
+
+ if (pid == -1)
+ {
+ Print("fork Failed.\n");
+ return false;
+ }
+
+ if (pid == 0)
+ {
+ char *param = UNIX_ARG_EXIT;
+ char **args;
+
+ args = ZeroMalloc(sizeof(char *) * 3);
+ args[0] = exe;
+ args[1] = param;
+ args[2] = NULL;
+
+ setsid();
+
+ // Close the standard I/O
+ UnixCloseIO();
+
+ // Stop unwanted signals
+ signal(SIGHUP, SIG_IGN);
+
+ execvp(exe, args);
+ AbortExit();
+ }
+ else
+ {
+ int status = 0, ret;
+
+ // Wait for the termination of the child process
+ ret = waitpid(pid, &status, 0);
+
+ if (WIFEXITED(status) == 0)
+ {
+ // Aborted
+ Print("waitpid Failed: 0x%x\n", ret);
+ return false;
+ }
+ }
+ }
+#endif // OS_UNIX
+
+ return true;
+}
+
+// System checker
+bool SystemCheck()
+{
+ UINT i;
+ bool ng = false;
+
+ UniPrint(_UU("CHECK_TITLE"));
+ UniPrint(_UU("CHECK_NOTE"));
+ for (i = 0;i < sizeof(checker_procs) / sizeof(checker_procs[0]);i++)
+ {
+ wchar_t *title;
+ bool ret = false;
+ CHECKER_PROC *p = &checker_procs[i];
+
+ title = _UU(p->Title);
+
+ UniPrint(_UU("CHECK_EXEC_TAG"), title);
+
+ ret = p->Proc();
+
+ if (ret == false)
+ {
+ ng = true;
+ }
+
+ UniPrint(L" %s\n", ret ? _UU("CHECK_PASS") : _UU("CHECK_FAIL"));
+ }
+
+ UniPrint(L"\n");
+ if (ng == false)
+ {
+ UniPrint(L"%s\n\n", _UU("CHECK_RESULT_1"));
+ }
+ else
+ {
+ UniPrint(L"%s\n\n", _UU("CHECK_RESULT_2"));
+ }
+
+ return true;
+}
+
+
+// Behavior checker
+UINT PtCheck(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ UINT ret = ERR_NO_ERROR;
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (SystemCheck() == false)
+ {
+ ret = ERR_INTERNAL_ERROR;
+ }
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// VPN Tools main function
+void PtMain(PT *pt)
+{
+ char prompt[MAX_SIZE];
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (pt == NULL)
+ {
+ return;
+ }
+
+ // Display a message that start-up is complete
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_VPNCMD_TOOLS_CONNECTED"));
+ pt->Console->Write(pt->Console, tmp);
+ pt->Console->Write(pt->Console, L"");
+
+ while (true)
+ {
+ // Definition of command
+ CMD cmd[] =
+ {
+ {"About", PsAbout},
+ {"MakeCert", PtMakeCert},
+ {"TrafficClient", PtTrafficClient},
+ {"TrafficServer", PtTrafficServer},
+ {"Check", PtCheck},
+ };
+
+ // Generate a prompt
+ StrCpy(prompt, sizeof(prompt), "VPN Tools>");
+
+ if (DispatchNextCmdEx(pt->Console, pt->CmdLine, prompt, cmd, sizeof(cmd) / sizeof(cmd[0]), pt) == false)
+ {
+ break;
+ }
+ pt->LastError = pt->Console->RetCode;
+
+ if (pt->LastError == ERR_NO_ERROR && pt->Console->ConsoleType != CONSOLE_CSV)
+ {
+ pt->Console->Write(pt->Console, _UU("CMD_MSG_OK"));
+ pt->Console->Write(pt->Console, L"");
+ }
+
+ if (pt->CmdLine != NULL)
+ {
+ break;
+ }
+ }
+}
+
+// Create a VPN Tools context
+PT *NewPt(CONSOLE *c, wchar_t *cmdline)
+{
+ PT *pt;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ if (UniIsEmptyStr(cmdline))
+ {
+ cmdline = NULL;
+ }
+
+ pt = ZeroMalloc(sizeof(PT));
+ pt->Console = c;
+ pt->CmdLine = CopyUniStr(cmdline);
+
+ return pt;
+}
+
+// Release the VPN Tools context
+void FreePt(PT *pt)
+{
+ // Validate arguments
+ if (pt == NULL)
+ {
+ return;
+ }
+
+ Free(pt->CmdLine);
+ Free(pt);
+}
+
+// Start VPN Tools
+UINT PtConnect(CONSOLE *c, wchar_t *cmdline)
+{
+ PT *pt;
+ UINT ret = 0;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ pt = NewPt(c, cmdline);
+
+ PtMain(pt);
+
+ ret = pt->LastError;
+
+ FreePt(pt);
+
+ return ret;
+}
+
+// Initialize the execution path information of vpncmd command
+void VpnCmdInitBootPath()
+{
+#ifdef OS_WIN32
+ char exe_path[MAX_PATH];
+ char tmp[MAX_PATH];
+ GetExeName(exe_path, sizeof(exe_path));
+
+ if (SearchStrEx(exe_path, "ham.exe", 0, false) != INFINITE || SearchStrEx(exe_path, "ham_x64.exe", 0, false) != INFINITE || SearchStrEx(exe_path, "ham_ia64.exe", 0, false) != INFINITE)
+ {
+ return;
+ }
+
+ if (MsIsAdmin())
+ {
+ UINT current_ver;
+
+ // Get the version of vpncmd that is currently installed
+ current_ver = MsRegReadInt(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_VER);
+
+ if ((CEDAR_BUILD >= current_ver) ||
+ MsRegIsValue(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH) == false)
+ {
+ char *src_filename;
+ bool b = false;
+ // Copy the vpncmdsys.exe to system32
+ if (MsIsNt())
+ {
+ Format(tmp, sizeof(tmp), "%s\\vpncmd.exe", MsGetSystem32Dir());
+ }
+ else
+ {
+ Format(tmp, sizeof(tmp), "%s\\vpncmd.exe", MsGetWindowsDir());
+ }
+
+ src_filename = VPNCMD_BOOTSTRAP_FILENAME;
+
+ if (IsX64())
+ {
+ src_filename = VPNCMD_BOOTSTRAP_FILENAME_X64;
+ }
+
+ if (IsIA64())
+ {
+ src_filename = VPNCMD_BOOTSTRAP_FILENAME_IA64;
+ }
+
+ b = true;
+
+ if (MsIs64BitWindows() == false || Is64())
+ {
+ if (IsFile(tmp) == false || (CEDAR_BUILD > current_ver) || MsRegIsValue(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH) == false)
+ {
+ b = FileCopy(src_filename, tmp);
+ }
+ }
+ else
+ {
+ void *wow;
+
+ wow = MsDisableWow64FileSystemRedirection();
+
+ if (true)
+ {
+ if (IsFile(tmp) == false || (CEDAR_BUILD > current_ver) || MsRegIsValue(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH) == false)
+ {
+ b = FileCopy(src_filename, tmp);
+ }
+ }
+
+ MsRestoreWow64FileSystemRedirection(wow);
+
+ if (true)
+ {
+ if (IsFile(tmp) == false || (CEDAR_BUILD > current_ver) || MsRegIsValue(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH) == false)
+ {
+ b = FileCopy(src_filename, tmp);
+ }
+ }
+ }
+
+ // Because the currently running prompt is newer version, overwrite the registry
+ if (MsIs64BitWindows() == false)
+ {
+ MsRegWriteStr(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH, exe_path);
+ MsRegWriteInt(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_VER, CEDAR_BUILD);
+ }
+ else
+ {
+ MsRegWriteStrEx2(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH, exe_path, true, false);
+ MsRegWriteIntEx2(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_VER, CEDAR_BUILD, true, false);
+
+ MsRegWriteStrEx2(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH, exe_path, false, true);
+ MsRegWriteIntEx2(REG_LOCAL_MACHINE, VPNCMD_BOOTSTRAP_REG_KEYNAME, VPNCMD_BOOTSTRAP_REG_VALUENAME_VER, CEDAR_BUILD, false, true);
+ }
+ }
+ }
+#endif // OS_WIN32
+}
+
+// Show the string
+void TtPrint(void *param, TT_PRINT_PROC *print_proc, wchar_t *str)
+{
+ // Validate arguments
+ if (print_proc == NULL || str == NULL)
+ {
+ return;
+ }
+
+ print_proc(param, str);
+}
+
+// Generate new random data
+void TtGenerateRandomData(UCHAR **buf, UINT *size)
+{
+ UCHAR *tmp;
+ UINT sz;
+ UINT i;
+ // Validate arguments
+ if (buf == NULL || size == NULL)
+ {
+ return;
+ }
+
+ sz = TRAFFIC_BUF_SIZE;
+ tmp = Malloc(sz);
+ for (i = 0;i < sz;i++)
+ {
+ tmp[i] = rand() % 256;
+
+ if (tmp[i] == '!')
+ {
+ tmp[i] = '_';
+ }
+ }
+
+ *buf = tmp;
+ *size = sz;
+}
+
+// Communication throughput measurement server worker thread
+void TtsWorkerThread(THREAD *thread, void *param)
+{
+ TTS *tts;
+ UINT buf_size;
+ UCHAR *send_buf_data, *recv_buf_data;
+ bool all_sockets_blocked = false;
+ UINT64 tmp64;
+ LIST *o;
+ UINT i;
+ wchar_t tmp[MAX_SIZE];
+ bool dont_block_next_time = false;
+ char *ver_str = TRAFFIC_VER_STR;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Allocate the data area
+ TtGenerateRandomData(&send_buf_data, &buf_size);
+ TtGenerateRandomData(&recv_buf_data, &buf_size);
+
+ tts = (TTS *)param;
+
+ // Preparation of socket events
+ tts->SockEvent = NewSockEvent();
+ AddRef(tts->SockEvent->ref);
+
+ // Preparing the Server socket list
+ tts->TtsSockList = NewList(NULL);
+
+ // Notify completion of preparation to parent thread
+ NoticeThreadInit(thread);
+
+ o = NewList(NULL);
+
+ while (tts->Halt == false)
+ {
+ UINT64 now = Tick64();
+
+ // Wait for all sockets
+ if (dont_block_next_time == false)
+ {
+ WaitSockEvent(tts->SockEvent, 50);
+ }
+ dont_block_next_time = false;
+
+ // Process for sockets that are currently registered
+ LockList(tts->TtsSockList);
+ {
+ UINT i;
+
+ all_sockets_blocked = false;
+
+ // Continue to send and receive data
+ // until all sockets become block state
+ while (all_sockets_blocked == false)
+ {
+ all_sockets_blocked = true;
+
+ for (i = 0;i < LIST_NUM(tts->TtsSockList);i++)
+ {
+ UINT ret = SOCK_LATER;
+ UCHAR *send_data = NULL, *recv_data = NULL;
+ UINT send_size = 0, recv_size = 0;
+ TTS_SOCK *ts = LIST_DATA(tts->TtsSockList, i);
+ bool blocked_for_this_socket = false;
+
+ if (ts->SockJoined == false)
+ {
+ JoinSockToSockEvent(ts->Sock, tts->SockEvent);
+ ts->SockJoined = true;
+ }
+
+ switch (ts->State)
+ {
+ case 0:
+ // Return the version string
+ ret = Send(ts->Sock, ver_str, TRAFFIC_VER_STR_SIZE, false);
+ if (ret != 0 && ret != SOCK_LATER)
+ {
+ ts->State = 5;
+ }
+ break;
+
+ case 5:
+ // Receive the direction from the client
+ ret = Recv(ts->Sock, recv_buf_data, buf_size, false);
+ if (ret != 0 && ret != SOCK_LATER)
+ {
+ UCHAR c;
+
+ // Direction of the data is in the first byte that is received
+ c = recv_buf_data[0];
+
+ if (c == 0)
+ {
+ // In the case of 0, Client -> Server
+ ts->State = 1;
+ }
+ else
+ {
+ // Otherwise Server -> Client
+ ts->State = 2;
+ }
+
+ if (ret >= (sizeof(UINT64) + sizeof(UINT64) + 1))
+ {
+ // Session ID
+ ts->SessionId = READ_UINT64(recv_buf_data + 1);
+
+ // Span
+ ts->Span = READ_UINT64(recv_buf_data + sizeof(UINT64) + 1);
+ }
+ }
+ break;
+
+ case 1:
+ // Client -> Server
+ ret = Recv(ts->Sock, recv_buf_data, buf_size, false);
+
+ if (ret != 0 && ret != SOCK_LATER)
+ {
+ // Checking the first byte of received
+ UCHAR c = recv_buf_data[0];
+
+ if (ts->FirstRecvTick == 0)
+ {
+ // Record the time at which the data has been received for the first
+ ts->FirstRecvTick = now;
+ }
+ else
+ {
+ // Check whether the span didn't finish yet
+ if (ts->FirstRecvTick <= now)
+ {
+ if (ts->Span != 0)
+ {
+ UINT64 giveup_tick = ts->FirstRecvTick + ts->Span;
+
+ if (now > giveup_tick)
+ {
+ // Span has expired
+ c = '!';
+ }
+ }
+ }
+ }
+
+ if (c == '!')
+ {
+ // Notice the size information from the server to the client
+ ts->State = 3;
+ Debug("!");
+ }
+ }
+ break;
+
+ case 2:
+ // Server -> Client
+ if (ts->NoMoreSendData == false)
+ {
+ ret = Send(ts->Sock, send_buf_data, buf_size, false);
+ }
+ else
+ {
+ ret = Recv(ts->Sock, recv_buf_data, buf_size, false);
+ }
+ break;
+
+ case 3:
+ // Notice the size information from the server to the client
+ tmp64 = Endian64(ts->NumBytes);
+
+ Recv(ts->Sock, recv_buf_data, buf_size, false);
+
+ if (ts->LastWaitTick == 0 || ts->LastWaitTick <= Tick64())
+ {
+ ret = Send(ts->Sock, &tmp64, sizeof(tmp64), false);
+
+ if (ret != SOCK_LATER)
+ {
+ UINT j;
+
+ ts->LastWaitTick = Tick64() + 100;
+
+ if (ts->SessionId != 0)
+ {
+ // Not to send more data to the socket of the
+ // transmission direction in the same session ID
+ for (j = 0;j < LIST_NUM(tts->TtsSockList);j++)
+ {
+ TTS_SOCK *ts2 = LIST_DATA(tts->TtsSockList, j);
+
+ if (ts2->SessionId == ts->SessionId &&
+ ts2 != ts)
+ {
+ ts2->NoMoreSendData = true;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ if (ret == 0)
+ {
+ // Mark as deleting the socket because it is disconnected
+ Insert(o, ts);
+ }
+ else if (ret == SOCK_LATER)
+ {
+ // Delay has occurred
+ blocked_for_this_socket = true;
+ dont_block_next_time = false;
+ }
+ else
+ {
+ if (ts->State == 1)
+ {
+ ts->NumBytes += (UINT64)ret;
+ }
+ }
+
+ if (blocked_for_this_socket == false)
+ {
+ all_sockets_blocked = false;
+ }
+ }
+
+ if (LIST_NUM(o) != 0)
+ {
+ UINT i;
+ // One or more sockets is disconnected
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ TTS_SOCK *ts = LIST_DATA(o, i);
+
+ UniFormat(tmp, sizeof(tmp), _UU("TTS_DISCONNECTED"), ts->Id, ts->Sock->RemoteHostname);
+ TtPrint(tts->Param, tts->Print, tmp);
+
+ Disconnect(ts->Sock);
+ ReleaseSock(ts->Sock);
+
+ Delete(tts->TtsSockList, ts);
+
+ Free(ts);
+ }
+
+ DeleteAll(o);
+ }
+
+ if (tts->NewSocketArrived || tts->Halt)
+ {
+ tts->NewSocketArrived = false;
+ all_sockets_blocked = true;
+ dont_block_next_time = true;
+ }
+ }
+ }
+ UnlockList(tts->TtsSockList);
+ }
+
+ LockList(tts->TtsSockList);
+ {
+ // Release the sockets of all remaining
+ for (i = 0;i < LIST_NUM(tts->TtsSockList);i++)
+ {
+ TTS_SOCK *ts = LIST_DATA(tts->TtsSockList, i);
+
+ UniFormat(tmp, sizeof(tmp), _UU("TTS_DISCONNECT"), ts->Id, ts->Sock->RemoteHostname);
+ TtPrint(tts->Param, tts->Print, tmp);
+
+ Disconnect(ts->Sock);
+ ReleaseSock(ts->Sock);
+
+ Free(ts);
+ }
+ }
+ UnlockList(tts->TtsSockList);
+
+ // Cleanup
+ ReleaseList(o);
+ ReleaseList(tts->TtsSockList);
+ ReleaseSockEvent(tts->SockEvent);
+ Free(send_buf_data);
+ Free(recv_buf_data);
+}
+
+// Accept thread for IPv6
+void TtsIPv6AcceptThread(THREAD *thread, void *param)
+{
+ TTS *tts = (TTS *)param;
+ // Validate arguments
+ if (tts == NULL || param == NULL)
+ {
+ return;
+ }
+
+ TtsAcceptProc(tts, tts->ListenSocketV6);
+}
+
+// Accept procedure
+void TtsAcceptProc(TTS *tts, SOCK *listen_socket)
+{
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (tts == NULL || listen_socket == NULL)
+ {
+ return;
+ }
+
+ while (tts->Halt == false)
+ {
+ SOCK *s;
+ // Accept
+ s = Accept(listen_socket);
+
+ if (s == NULL)
+ {
+ if (tts->Halt == false)
+ {
+ SleepThread(10);
+ }
+ continue;
+ }
+ else
+ {
+ // Connected from the client
+ AcceptInit(s);
+ tts->NewSocketArrived = true;
+ LockList(tts->TtsSockList);
+ {
+ TTS_SOCK *ts = ZeroMalloc(sizeof(TTS_SOCK));
+
+ ts->Id = (++tts->IdSeed);
+ ts->Sock = s;
+
+ UniFormat(tmp, sizeof(tmp), _UU("TTS_ACCEPTED"), ts->Id,
+ s->RemoteHostname, s->RemotePort);
+ TtPrint(tts->Param, tts->Print, tmp);
+
+ Insert(tts->TtsSockList, ts);
+ tts->NewSocketArrived = true;
+ }
+ UnlockList(tts->TtsSockList);
+
+ SetSockEvent(tts->SockEvent);
+ }
+ }
+}
+
+// Communication throughput measurement server wait thread
+void TtsListenThread(THREAD *thread, void *param)
+{
+ TTS *tts;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ tts = (TTS *)param;
+
+ tts->ListenSocket = NULL;
+ tts->ListenSocket = ListenEx(tts->Port, false);
+ tts->ListenSocketV6 = ListenEx6(tts->Port, false);
+
+ if (tts->ListenSocket == NULL && tts->ListenSocketV6 == NULL)
+ {
+ // Failed to Listen
+ UniFormat(tmp, sizeof(tmp), _UU("TT_LISTEN_FAILED"), tts->Port);
+ TtPrint(tts->Param, tts->Print, tmp);
+
+ // Notify completion of preparation to parent thread
+ NoticeThreadInit(thread);
+
+ tts->ErrorCode = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("TTS_LISTEN_STARTED"), tts->Port);
+ TtPrint(tts->Param, tts->Print, tmp);
+
+ if (tts->ListenSocketV6 != NULL)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("TTS_LISTEN_STARTED_V6"), tts->Port);
+ TtPrint(tts->Param, tts->Print, tmp);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("TTS_LISTEN_FAILED_V6"), tts->Port);
+ TtPrint(tts->Param, tts->Print, tmp);
+ }
+
+ if (tts->ListenSocket != NULL)
+ {
+ AddRef(tts->ListenSocket->ref);
+ }
+ if (tts->ListenSocketV6 != NULL)
+ {
+ AddRef(tts->ListenSocketV6->ref);
+ }
+
+ // Start the worker thread
+ tts->WorkThread = NewThread(TtsWorkerThread, tts);
+ WaitThreadInit(tts->WorkThread);
+
+ // Notify completion of preparation to parent thread
+ NoticeThreadInit(thread);
+
+ // Prepare for IPv6 Accept thread
+ tts->IPv6AcceptThread = NULL;
+ if (tts->ListenSocketV6 != NULL)
+ {
+ tts->IPv6AcceptThread = NewThread(TtsIPv6AcceptThread, tts);
+ }
+
+ TtsAcceptProc(tts, tts->ListenSocket);
+
+ if (tts->IPv6AcceptThread != NULL)
+ {
+ WaitThread(tts->IPv6AcceptThread, INFINITE);
+ ReleaseThread(tts->IPv6AcceptThread);
+ }
+
+ TtPrint(tts->Param, tts->Print, _UU("TTS_LISTEN_STOP"));
+
+ ReleaseSock(tts->ListenSocket);
+ ReleaseSock(tts->ListenSocketV6);
+ SetSockEvent(tts->SockEvent);
+
+ // Wait for stopping the worker thread
+ WaitThread(tts->WorkThread, INFINITE);
+ ReleaseThread(tts->WorkThread);
+ ReleaseSockEvent(tts->SockEvent);
+ }
+}
+
+// String of the direction in which data flows
+wchar_t *GetTtcTypeStr(UINT type)
+{
+ switch (type)
+ {
+ case TRAFFIC_TYPE_DOWNLOAD:
+ return _UU("TTC_TYPE_DOWNLOAD");
+
+ case TRAFFIC_TYPE_UPLOAD:
+ return _UU("TTC_TYPE_UPLOAD");
+
+ default:
+ return _UU("TTC_TYPE_FULL");
+ }
+}
+
+// Show a Summary
+void TtcPrintSummary(TTC *ttc)
+{
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t *tag = L"%-35s %s";
+ // Validate arguments
+ if (ttc == NULL)
+ {
+ return;
+ }
+
+ TtPrint(ttc->Param, ttc->Print, L"");
+ TtPrint(ttc->Param, ttc->Print, _UU("TTC_SUMMARY_BAR"));
+ TtPrint(ttc->Param, ttc->Print, _UU("TTC_SUMMARY_TITLE"));
+ TtPrint(ttc->Param, ttc->Print, L"");
+
+ // Destination host name
+ StrToUni(tmp2, sizeof(tmp2), ttc->Host);
+ UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_HOST"), tmp2);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ // Destination TCP port number
+ UniToStru(tmp2, ttc->Port);
+ UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_PORT"), tmp2);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ // Number of TCP connections to establish
+ UniToStru(tmp2, ttc->NumTcp);
+ UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_NUMTCP"), tmp2);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ // Data transmission direction
+ UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_TYPE"), GetTtcTypeStr(ttc->Type));
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ // Data transmission span
+ UniFormat(tmp2, sizeof(tmp2), _UU("TTC_SPAN_STR"), (double)(ttc->Span) / 1000.0);
+ UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_SPAN"), tmp2);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ // Correct the data for Ethernet frame
+ UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_ETHER"), ttc->Raw ? _UU("SEC_NO") : _UU("SEC_YES"));
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ // Measure the total amount of input and output throughput of relay equipment
+ UniFormat(tmp, sizeof(tmp), tag, _UU("TTC_SUMMARY_DOUBLE"), ttc->Double ? _UU("SEC_YES") : _UU("SEC_NO"));
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ TtPrint(ttc->Param, ttc->Print, _UU("TTC_SUMMARY_BAR"));
+ TtPrint(ttc->Param, ttc->Print, L"");
+}
+
+// Stop the communication throughput measurement client
+void StopTtc(TTC *ttc)
+{
+ // Validate arguments
+ if (ttc == NULL)
+ {
+ return;
+ }
+
+ TtPrint(ttc->Param, ttc->Print, _UU("TTC_STOPPING"));
+
+ ttc->Halt = true;
+ SetSockEvent(ttc->SockEvent);
+}
+
+// Generate a result
+void TtcGenerateResult(TTC *ttc)
+{
+ TT_RESULT *res;
+ UINT i;
+ // Validate arguments
+ if (ttc == NULL)
+ {
+ return;
+ }
+
+ res = &ttc->Result;
+
+ Zero(res, sizeof(TT_RESULT));
+
+ res->Raw = ttc->Raw;
+ res->Double = ttc->Double;
+ res->Span = ttc->RealSpan;
+
+ for (i = 0;i < LIST_NUM(ttc->ItcSockList);i++)
+ {
+ TTC_SOCK *ts = LIST_DATA(ttc->ItcSockList, i);
+
+ if (ts->Download == false)
+ {
+ // Upload
+ res->NumBytesUpload += ts->NumBytes;
+ }
+ else
+ {
+ // Download
+ res->NumBytesDownload += ts->NumBytes;
+ }
+ }
+
+ if (res->Raw == false)
+ {
+ // Correct to match the Ethernet
+ res->NumBytesDownload = (UINT64)((double)res->NumBytesDownload * 1514.0 / 1460.0);
+ res->NumBytesUpload = (UINT64)((double)res->NumBytesUpload * 1514.0 / 1460.0);
+ }
+
+ res->NumBytesTotal = res->NumBytesDownload + res->NumBytesUpload;
+
+ // Measure the throughput
+ if (res->Span != 0)
+ {
+ res->BpsUpload = (UINT64)((double)res->NumBytesUpload * 8.0 / ((double)res->Span / 1000.0));
+ res->BpsDownload = (UINT64)((double)res->NumBytesDownload * 8.0 / ((double)res->Span / 1000.0));
+ }
+
+ if (res->Double)
+ {
+ res->BpsUpload *= 2ULL;
+ res->BpsDownload *= 2ULL;
+ }
+
+ res->BpsTotal = res->BpsUpload + res->BpsDownload;
+}
+
+// Client thread
+void TtcThread(THREAD *thread, void *param)
+{
+ TTC *ttc;
+ UINT i;
+ wchar_t tmp[MAX_SIZE];
+ bool ok = false;
+ UINT buf_size;
+ UCHAR *send_buf_data, *recv_buf_data;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Allocate the data area
+ TtGenerateRandomData(&send_buf_data, &buf_size);
+ TtGenerateRandomData(&recv_buf_data, &buf_size);
+
+ ttc = (TTC *)param;
+
+ ttc->SockEvent = NewSockEvent();
+ AddRef(ttc->SockEvent->ref);
+
+ // Ready
+ NoticeThreadInit(thread);
+
+ TtcPrintSummary(ttc);
+
+ UniFormat(tmp, sizeof(tmp), _UU("TTC_CONNECT_START"),
+ ttc->Host, ttc->Port, ttc->NumTcp);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ // Establish all connections to the client
+ ttc->ItcSockList = NewList(NULL);
+
+ ok = true;
+
+ for (i = 0;i < ttc->NumTcp;i++)
+ {
+ SOCK *s;
+ TTC_SOCK *ts = ZeroMalloc(sizeof(TTC_SOCK));
+
+ ts->Id = i + 1;
+
+ if (ttc->Type == TRAFFIC_TYPE_DOWNLOAD)
+ {
+ ts->Download = true;
+ }
+ else if (ttc->Type == TRAFFIC_TYPE_UPLOAD)
+ {
+ ts->Download = false;
+ }
+ else
+ {
+ ts->Download = ((i % 2) == 0) ? true : false;
+ }
+
+ s = ConnectEx2(ttc->Host, ttc->Port, 0, ttc->Cancel);
+
+ if (s == NULL)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("TTC_CONNECT_FAILED"), i + 1);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+ ok = false;
+ Free(ts);
+ break;
+ }
+ else
+ {
+ char buffer[TRAFFIC_VER_STR_SIZE];
+
+ SetTimeout(s, 5000);
+
+ Zero(buffer, sizeof(buffer));
+ if (Recv(s, buffer, sizeof(buffer), false) != sizeof(buffer) || Cmp(buffer, TRAFFIC_VER_STR, TRAFFIC_VER_STR_SIZE) != 0)
+ {
+ TtPrint(ttc->Param, ttc->Print, _UU("TTC_CONNECT_NOT_SERVER"));
+ ok = false;
+ ReleaseSock(s);
+ Free(ts);
+ break;
+ }
+
+ UniFormat(tmp, sizeof(tmp), _UU("TTC_CONNECT_OK"), i + 1);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("TTC_CONNECT_OK_2"), GetTtcTypeStr(ts->Download ? TRAFFIC_TYPE_DOWNLOAD : TRAFFIC_TYPE_UPLOAD));
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ ts->Sock = s;
+
+ SetTimeout(s, TIMEOUT_INFINITE);
+
+ JoinSockToSockEvent(s, ttc->SockEvent);
+ }
+
+ Insert(ttc->ItcSockList, ts);
+ }
+
+ Set(ttc->InitedEvent);
+
+ if (ttc->StartEvent != NULL)
+ {
+ Wait(ttc->StartEvent, INFINITE);
+ SleepThread(500);
+ }
+
+ if (ok)
+ {
+ bool all_sockets_blocked;
+ bool dont_block_next_time = false;
+ bool halt_flag = false;
+ UINT64 start_tick, end_tick;
+ UINT64 halt_timeout = 0;
+ wchar_t tmp1[MAX_SIZE], tmp2[MAX_SIZE];
+ UINT check_clock_seed = 0;
+ bool halting = false;
+ UINT64 tmp64;
+ UINT64 session_id = Rand64();
+
+ // Record the current time
+ start_tick = Tick64();
+ end_tick = start_tick + ttc->Span;
+
+ // Show start message
+ GetDateTimeStrEx64(tmp1, sizeof(tmp1), SystemToLocal64(TickToTime(start_tick)), NULL);
+ GetDateTimeStrEx64(tmp2, sizeof(tmp2), SystemToLocal64(TickToTime(end_tick)), NULL);
+ UniFormat(tmp, sizeof(tmp), _UU("TTC_COMM_START"), tmp1, tmp2);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+
+ // Main loop
+ while (true)
+ {
+ UINT i;
+
+ if (dont_block_next_time == false)
+ {
+ WaitSockEvent(ttc->SockEvent, 50);
+ }
+
+ dont_block_next_time = false;
+
+ if (ttc->AbnormalTerminated)
+ {
+ // Abnormal termination occured
+ break;
+ }
+
+ if (ttc->Halt || end_tick <= Tick64() || (ttc->Cancel != NULL && (*ttc->Cancel)))
+ {
+ // End measurement
+ if (halting == false)
+ {
+ if (ttc->Halt || (ttc->Cancel != NULL && (*ttc->Cancel)))
+ {
+ // User cancel
+ TtPrint(ttc->Param, ttc->Print, _UU("TTC_COMM_USER_CANCEL"));
+ }
+ else
+ {
+ // Time elapsed
+ UniFormat(tmp, sizeof(tmp), _UU("TTC_COMM_END"),
+ (double)ttc->Span / 1000.0);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+ }
+
+ ttc->RealSpan = Tick64() - start_tick;
+
+ halting = true;
+
+ // Wait for reporting data from the server
+ halt_timeout = Tick64() + 60000ULL;
+ }
+ }
+
+ if (halt_timeout != 0)
+ {
+ bool ok = true;
+
+ // Wait that all TCP connections to finish processing
+ for (i = 0;i < LIST_NUM(ttc->ItcSockList);i++)
+ {
+ TTC_SOCK *ts = LIST_DATA(ttc->ItcSockList, i);
+
+ if (ts->Download == false)
+ {
+ if (ts->ServerUploadReportReceived == false)
+ {
+ ok = false;
+ }
+ }
+ }
+
+ if (ok)
+ {
+ // Measurement completed
+ // Show the result
+ TtcGenerateResult(ttc);
+ break;
+ }
+ else
+ {
+ if (halt_timeout <= Tick64())
+ {
+ // An error occured
+ ttc->AbnormalTerminated = true;
+ ttc->ErrorCode = ERR_PROTOCOL_ERROR;
+ break;
+ }
+ }
+ }
+
+ all_sockets_blocked = false;
+
+ // Continue to send and receive data
+ // until all sockets become block state
+ while (all_sockets_blocked == false)
+ {
+ all_sockets_blocked = true;
+
+ for (i = 0;i < LIST_NUM(ttc->ItcSockList);i++)
+ {
+ UINT ret = SOCK_LATER;
+ TTC_SOCK *ts = LIST_DATA(ttc->ItcSockList, i);
+ bool blocked_for_this_socket = false;
+ UCHAR c = 0;
+ UCHAR c_and_session_id[1 + sizeof(UINT64) + sizeof(UINT64)];
+
+ if (halt_timeout != 0)
+ {
+ if (ts->State != 3 && ts->State != 4)
+ {
+ if (ts->Download == false)
+ {
+ if (ts->State != 0)
+ {
+ ts->State = 3;
+ }
+ else
+ {
+ ts->ServerUploadReportReceived = true;
+ ts->State = 4;
+ }
+ }
+ else
+ {
+ ts->State = 4;
+ }
+ }
+ }
+
+ switch (ts->State)
+ {
+ case 0:
+ // Initial state: Specify the direction of
+ // the data flow between client-server
+ if (ts->Download)
+ {
+ c = 1;
+ }
+ else
+ {
+ c = 0;
+ }
+
+ c_and_session_id[0] = c;
+ WRITE_UINT64(c_and_session_id + 1, session_id);
+ WRITE_UINT64(c_and_session_id + sizeof(UINT64) + 1, ttc->Span);
+
+ ret = Send(ts->Sock, c_and_session_id, 1 + sizeof(UINT64) + sizeof(UINT64), false);
+
+ if (ret != 0 && ret != SOCK_LATER)
+ {
+ if (ts->Download)
+ {
+ ts->State = 1;
+ }
+ else
+ {
+ ts->State = 2;
+ }
+ }
+ break;
+
+ case 1:
+ // Server -> Client (download)
+ ret = Recv(ts->Sock, recv_buf_data, buf_size, false);
+ break;
+
+ case 2:
+ // Client -> Server (upload)
+ ret = Send(ts->Sock, send_buf_data, buf_size, false);
+ break;
+
+ case 3:
+ // Transmission completion client -> server (upload)
+ // Request the data size
+ if (ts->NextSendRequestReportTick == 0 ||
+ (Tick64() >= ts->NextSendRequestReportTick))
+ {
+ UCHAR suprise[MAX_SIZE];
+ UINT i;
+
+ ts->NextSendRequestReportTick = Tick64() + 200ULL;
+
+ for (i = 0;i < sizeof(suprise);i++)
+ {
+ suprise[i] = '!';
+ }
+
+ ret = Send(ts->Sock, suprise, sizeof(suprise), false);
+ }
+
+ ret = Recv(ts->Sock, &tmp64, sizeof(tmp64), false);
+ if (ret != 0 && ret != SOCK_LATER && ret == sizeof(tmp64))
+ {
+ ts->NumBytes = Endian64(tmp64);
+
+ ts->ServerUploadReportReceived = true;
+
+ ts->State = 4;
+ }
+ break;
+
+ case 4:
+ // Do Nothing
+ if (Recv(ts->Sock, recv_buf_data, buf_size, false) == SOCK_LATER)
+ {
+ ret = SOCK_LATER;
+ }
+ break;
+ }
+
+ if (ret == 0)
+ {
+ // The socket is disconnected
+ ttc->AbnormalTerminated = true;
+ ttc->ErrorCode = ERR_PROTOCOL_ERROR;
+ blocked_for_this_socket = true;
+ dont_block_next_time = false;
+
+ if (ts->HideErrMsg == false)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("TTC_COMM_DISCONNECTED"), ts->Id);
+ TtPrint(ttc->Param, ttc->Print, tmp);
+ ts->HideErrMsg = true;
+ }
+ }
+ else if (ret == SOCK_LATER)
+ {
+ // Delay has occurred
+ blocked_for_this_socket = true;
+ dont_block_next_time = false;
+ }
+ else
+ {
+ if (ts->Download)
+ {
+ ts->NumBytes += (UINT64)ret;
+ }
+ }
+
+ if (blocked_for_this_socket == false)
+ {
+ all_sockets_blocked = false;
+ }
+ }
+
+ if (ttc->Halt || (ttc->Cancel != NULL && (*ttc->Cancel)))
+ {
+ all_sockets_blocked = true;
+ dont_block_next_time = true;
+ }
+
+ if (end_tick <= Tick64())
+ {
+ all_sockets_blocked = true;
+ dont_block_next_time = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Abort
+ TtPrint(ttc->Param, ttc->Print, _UU("TTC_ERROR_ABORTED"));
+ ttc->ErrorCode = ERR_CONNECT_FAILED;
+ }
+
+ // Cleanup
+ for (i = 0;i < LIST_NUM(ttc->ItcSockList);i++)
+ {
+ TTC_SOCK *ts = LIST_DATA(ttc->ItcSockList, i);
+
+ Disconnect(ts->Sock);
+ ReleaseSock(ts->Sock);
+ Free(ts);
+ }
+
+ ReleaseSockEvent(ttc->SockEvent);
+ ReleaseList(ttc->ItcSockList);
+ Free(send_buf_data);
+ Free(recv_buf_data);
+}
+
+// Start the communication throughput measurement client
+TTC *NewTtc(char *host, UINT port, UINT numtcp, UINT type, UINT64 span, bool dbl, bool raw, TT_PRINT_PROC *print_proc, void *param)
+{
+ return NewTtcEx(host, port, numtcp, type, span, dbl, raw, print_proc, param, NULL, NULL);
+}
+TTC *NewTtcEx(char *host, UINT port, UINT numtcp, UINT type, UINT64 span, bool dbl, bool raw, TT_PRINT_PROC *print_proc, void *param, EVENT *start_event, bool *cancel)
+{
+ TTC *ttc;
+
+ ttc = ZeroMalloc(sizeof(TTC));
+ ttc->InitedEvent = NewEvent();
+ ttc->Port = port;
+ StrCpy(ttc->Host, sizeof(ttc->Host), host);
+ ttc->NumTcp = numtcp;
+ ttc->Type = type;
+ ttc->Span = span;
+ ttc->Double = dbl;
+ ttc->Raw = raw;
+ ttc->StartEvent = start_event;
+ ttc->Cancel = cancel;
+
+ if (ttc->Type == TRAFFIC_TYPE_FULL && ttc->NumTcp < 2)
+ {
+ ttc->NumTcp = 2;
+ }
+
+ ttc->Print = print_proc;
+ ttc->Param = param;
+ ttc->ErrorCode = ERR_NO_ERROR;
+
+ TtPrint(ttc->Param, ttc->Print, _UU("TTC_INIT"));
+
+ ttc->Thread = NewThread(TtcThread, ttc);
+ WaitThreadInit(ttc->Thread);
+
+ return ttc;
+}
+
+// Wait for stopping the communication throughput measurement client
+UINT FreeTtc(TTC *ttc, TT_RESULT *result)
+{
+ UINT ret;
+ // Validate arguments
+ if (ttc == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ WaitThread(ttc->Thread, INFINITE);
+ ReleaseThread(ttc->Thread);
+
+ TtPrint(ttc->Param, ttc->Print, _UU("TTC_FREE"));
+
+ ret = ttc->ErrorCode;
+
+ if (ret == ERR_NO_ERROR)
+ {
+ if (result != NULL)
+ {
+ Copy(result, &ttc->Result, sizeof(TT_RESULT));
+ }
+ }
+
+ ReleaseSockEvent(ttc->SockEvent);
+ ReleaseEvent(ttc->InitedEvent);
+
+ Free(ttc);
+
+ return ret;
+}
+
+// Start the communication throughput measurement server
+TTS *NewTts(UINT port, void *param, TT_PRINT_PROC *print_proc)
+{
+ TTS *tts;
+ THREAD *t;
+
+ tts = ZeroMalloc(sizeof(TTS));
+ tts->Port = port;
+ tts->Param = param;
+ tts->Print = print_proc;
+
+ TtPrint(param, print_proc, _UU("TTS_INIT"));
+
+ // Creating a thread
+ t = NewThread(TtsListenThread, tts);
+ WaitThreadInit(t);
+
+ tts->Thread = t;
+
+ return tts;
+}
+
+// Wait for stopping the communication throughput measurement server
+UINT FreeTts(TTS *tts)
+{
+ UINT ret;
+ // Validate arguments
+ if (tts == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ TtPrint(tts->Param, tts->Print, _UU("TTS_STOP_INIT"));
+
+ tts->Halt = true;
+ Disconnect(tts->ListenSocket);
+ ReleaseSock(tts->ListenSocket);
+ Disconnect(tts->ListenSocketV6);
+ ReleaseSock(tts->ListenSocketV6);
+
+ // Wait for the termination of the thread
+ WaitThread(tts->Thread, INFINITE);
+
+ ReleaseThread(tts->Thread);
+
+ TtPrint(tts->Param, tts->Print, _UU("TTS_STOP_FINISHED"));
+
+ ret = tts->ErrorCode;
+
+ Free(tts);
+
+ return ret;
+}
+
+// Show the measurement tools prompt
+void PtTrafficPrintProc(void *param, wchar_t *str)
+{
+ CONSOLE *c;
+ // Validate arguments
+ if (param == NULL || str == NULL)
+ {
+ return;
+ }
+
+ c = (CONSOLE *)param;
+
+ if (c->ConsoleType == CONSOLE_LOCAL)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ // Display only if the local console
+ // (Can not be displayed because threads aren't synchronized otherwise?)
+ UniStrCpy(tmp, sizeof(tmp), str);
+ if (UniEndWith(str, L"\n") == false)
+ {
+ UniStrCat(tmp, sizeof(tmp), L"\n");
+ }
+ UniPrint(L"%s", tmp);
+ }
+}
+
+// Display the communication throughput results
+void TtcPrintResult(CONSOLE *c, TT_RESULT *res)
+{
+ CT *ct;
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ char str[MAX_SIZE];
+ // Validate arguments
+ if (c == NULL || res == NULL)
+ {
+ return;
+ }
+
+ c->Write(c, _UU("TTC_RES_TITLE"));
+
+ ct = CtNew();
+ CtInsertColumn(ct, _UU("TTC_RES_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("TTC_RES_COLUMN_2"), true);
+ CtInsertColumn(ct, _UU("TTC_RES_COLUMN_3"), true);
+
+ // Time that was used to measure
+ GetSpanStrMilli(str, sizeof(str), res->Span);
+ StrToUni(tmp, sizeof(tmp), str);
+ CtInsert(ct, _UU("TTC_RES_SPAN"), tmp, L"");
+
+ // Correct the data for Ethernet frame
+ CtInsert(ct, _UU("TTC_RES_ETHER"), res->Raw ? _UU("SEC_NO") : _UU("SEC_YES"), L"");
+
+ // Amount of communication data of download direction
+ ToStr3(str, sizeof(str), res->NumBytesDownload);
+ UniFormat(tmp1, sizeof(tmp1), L"%S Bytes", str);
+ ToStrByte1000(str, sizeof(str), res->NumBytesDownload);
+ StrToUni(tmp2, sizeof(tmp2), str);
+ CtInsert(ct, _UU("TTC_RES_BYTES_DOWNLOAD"), tmp1, tmp2);
+
+ // Amount of communication data of upload direction
+ ToStr3(str, sizeof(str), res->NumBytesUpload);
+ UniFormat(tmp1, sizeof(tmp1), L"%S Bytes", str);
+ ToStrByte1000(str, sizeof(str), res->NumBytesUpload);
+ StrToUni(tmp2, sizeof(tmp2), str);
+ CtInsert(ct, _UU("TTC_RES_BYTES_UPLOAD"), tmp1, tmp2);
+
+ // Total amount of communication data
+ ToStr3(str, sizeof(str), res->NumBytesTotal);
+ UniFormat(tmp1, sizeof(tmp1), L"%S Bytes", str);
+ ToStrByte1000(str, sizeof(str), res->NumBytesTotal);
+ StrToUni(tmp2, sizeof(tmp2), str);
+ CtInsert(ct, _UU("TTC_RES_BYTES_TOTAL"), tmp1, tmp2);
+
+ // Calculate the total throughput of input and output of the relay equipment
+ CtInsert(ct, _UU("TTC_RES_DOUBLE"), (res->Double == false) ? _UU("SEC_NO") : _UU("SEC_YES"), L"");
+
+ // Average throughput of download direction
+ ToStr3(str, sizeof(str), res->BpsDownload);
+ UniFormat(tmp1, sizeof(tmp1), L"%S bps", str);
+ ToStrByte1000(str, sizeof(str), res->BpsDownload);
+ ReplaceStr(str, sizeof(str), str, "Bytes", "bps");
+ StrToUni(tmp2, sizeof(tmp2), str);
+ CtInsert(ct, _UU("TTC_RES_BPS_DOWNLOAD"), tmp1, tmp2);
+
+ // Average throughput of upload direction
+ ToStr3(str, sizeof(str), res->BpsUpload);
+ UniFormat(tmp1, sizeof(tmp1), L"%S bps", str);
+ ToStrByte1000(str, sizeof(str), res->BpsUpload);
+ ReplaceStr(str, sizeof(str), str, "Bytes", "bps");
+ StrToUni(tmp2, sizeof(tmp2), str);
+ CtInsert(ct, _UU("TTC_RES_BPS_UPLOAD"), tmp1, tmp2);
+
+ // Total average throughput
+ ToStr3(str, sizeof(str), res->BpsTotal);
+ UniFormat(tmp1, sizeof(tmp1), L"%S bps", str);
+ ToStrByte1000(str, sizeof(str), res->BpsTotal);
+ ReplaceStr(str, sizeof(str), str, "Bytes", "bps");
+ StrToUni(tmp2, sizeof(tmp2), str);
+ CtInsert(ct, _UU("TTC_RES_BPS_TOTAL"), tmp1, tmp2);
+
+ CtFree(ct, c);
+}
+
+// Execute the communication throughput measurement tool server
+UINT PtTrafficServer(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ UINT ret = ERR_NO_ERROR;
+ UINT port;
+ TTS *tts;
+ PARAM args[] =
+ {
+ {"[port]", NULL, NULL, NULL, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ port = GetParamInt(o, "[port]");
+ if (port == 0)
+ {
+ port = TRAFFIC_DEFAULT_PORT;
+ }
+
+ tts = NewTts(port, c, PtTrafficPrintProc);
+
+ c->Write(c, _UU("TTS_ENTER_TO_EXIT"));
+
+ Free(c->ReadLine(c, L"", true));
+
+ ret = tts->ErrorCode;
+
+ FreeTts(tts);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Execute the communication throughput measurement tool client
+UINT PtTrafficClient(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ TTC *ttc;
+ LIST *o;
+ UINT ret = ERR_NO_ERROR;
+ char *host = NULL;
+ UINT port;
+ UINT num, type;
+ bool dbl = false, raw = false;
+ UINT64 span;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX minmax =
+ {
+ "CMD_TrafficClient_EVAL_NUMTCP",
+ 0, TRAFFIC_NUMTCP_MAX,
+ };
+ PARAM args[] =
+ {
+ {"[host:port]", CmdPrompt, _UU("CMD_TrafficClient_PROMPT_HOST"), CmdEvalNotEmpty, NULL},
+ {"NUMTCP", NULL, NULL, CmdEvalMinMax, &minmax},
+ {"TYPE", NULL, NULL, NULL, NULL},
+ {"SPAN", NULL, NULL, NULL, NULL},
+ {"DOUBLE", NULL, NULL, NULL, NULL},
+ {"RAW", NULL, NULL, NULL, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (ParseHostPort(GetParamStr(o, "[host:port]"), &host, &port, TRAFFIC_DEFAULT_PORT) == false)
+ {
+ c->Write(c, _UU("CMD_TrafficClient_ERROR_HOSTPORT"));
+ ret = ERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ char *s;
+ UINT i;
+
+ Trim(host);
+
+ num = GetParamInt(o, "NUMTCP");
+ if (num == 0)
+ {
+ num = TRAFFIC_NUMTCP_DEFAULT;
+ }
+ s = GetParamStr(o, "TYPE");
+
+ if (StartWith("download", s))
+ {
+ type = TRAFFIC_TYPE_DOWNLOAD;
+ }
+ else if (StartWith("upload", s))
+ {
+ type = TRAFFIC_TYPE_UPLOAD;
+ }
+ else
+ {
+ type = TRAFFIC_TYPE_FULL;
+ }
+
+ i = GetParamInt(o, "SPAN");
+
+ if (i == 0)
+ {
+ i = TRAFFIC_SPAN_DEFAULT;
+ }
+
+ span = (UINT64)i * 1000ULL;
+
+ dbl = GetParamYes(o, "DOUBLE");
+ raw = GetParamYes(o, "RAW");
+
+ if (type == TRAFFIC_TYPE_FULL)
+ {
+ if ((num % 2) != 0)
+ {
+ ret = ERR_INVALID_PARAMETER;
+ c->Write(c, _UU("CMD_TrafficClient_ERROR_NUMTCP"));
+ }
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ TT_RESULT result;
+ ttc = NewTtc(host, port, num, type, span, dbl, raw, PtTrafficPrintProc, c);
+
+ if (c->ConsoleType == CONSOLE_LOCAL)
+ {
+ if (c->Param != NULL && (((LOCAL_CONSOLE_PARAM *)c->Param)->InBuf == NULL))
+ {
+// c->Write(c, _UU("TTC_ENTER_TO_EXIT"));
+// GetLine(NULL, 0);
+// StopTtc(ttc);
+ }
+ }
+
+
+ Zero(&result, sizeof(result));
+ ret = FreeTtc(ttc, &result);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ TtcPrintResult(c, &result);
+ }
+ }
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ Free(host);
+
+ return ret;
+}
+
+// Certificate easy creation tool
+UINT PtMakeCert(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ UINT ret = ERR_NO_ERROR;
+ X *x = NULL;
+ K *pub = NULL;
+ K *pri = NULL;
+ NAME *n;
+ X_SERIAL *x_serial = NULL;
+ BUF *buf;
+ UINT days;
+ X *root_x = NULL;
+ K *root_k = NULL;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX minmax =
+ {
+ "CMD_MakeCert_EVAL_EXPIRES",
+ 0,
+ 10950,
+ };
+ PARAM args[] =
+ {
+ {"CN", CmdPrompt, _UU("CMD_MakeCert_PROMPT_CN"), NULL, NULL},
+ {"O", CmdPrompt, _UU("CMD_MakeCert_PROMPT_O"), NULL, NULL},
+ {"OU", CmdPrompt, _UU("CMD_MakeCert_PROMPT_OU"), NULL, NULL},
+ {"C", CmdPrompt, _UU("CMD_MakeCert_PROMPT_C"), NULL, NULL},
+ {"ST", CmdPrompt, _UU("CMD_MakeCert_PROMPT_ST"), NULL, NULL},
+ {"L", CmdPrompt, _UU("CMD_MakeCert_PROMPT_L"), NULL, NULL},
+ {"SERIAL", CmdPrompt, _UU("CMD_MakeCert_PROMPT_SERIAL"), NULL, NULL},
+ {"EXPIRES", CmdPrompt, _UU("CMD_MakeCert_PROMPT_EXPIRES"), CmdEvalMinMax, &minmax},
+ {"SIGNCERT", NULL, NULL, CmdEvalIsFile, NULL},
+ {"SIGNKEY", NULL, NULL, CmdEvalIsFile, NULL},
+ {"SAVECERT", CmdPrompt, _UU("CMD_MakeCert_PROMPT_SAVECERT"), CmdEvalNotEmpty, NULL},
+ {"SAVEKEY", CmdPrompt, _UU("CMD_MakeCert_PROMPT_SAVEKEY"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "SIGNCERT")) == false && IsEmptyStr(GetParamStr(o, "SIGNKEY")) == false)
+ {
+ root_x = FileToXW(GetParamUniStr(o, "SIGNCERT"));
+ root_k = FileToKW(GetParamUniStr(o, "SIGNKEY"), true, NULL);
+
+ if (root_x == NULL || root_k == NULL || CheckXandK(root_x, root_k) == false)
+ {
+ ret = ERR_INTERNAL_ERROR;
+
+ c->Write(c, _UU("CMD_MakeCert_ERROR_SIGNKEY"));
+ }
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ buf = StrToBin(GetParamStr(o, "SERIAL"));
+ if (buf != NULL && buf->Size >= 1)
+ {
+ x_serial = NewXSerial(buf->Buf, buf->Size);
+ }
+ FreeBuf(buf);
+
+ n = NewName(GetParamUniStr(o, "CN"), GetParamUniStr(o, "O"), GetParamUniStr(o, "OU"),
+ GetParamUniStr(o, "C"), GetParamUniStr(o, "ST"), GetParamUniStr(o, "L"));
+
+ days = GetParamInt(o, "EXPIRES");
+ if (days == 0)
+ {
+ days = 3650;
+ }
+
+ RsaGen(&pri, &pub, 1024);
+
+ if (root_x == NULL)
+ {
+ x = NewRootX(pub, pri, n, days, x_serial);
+ }
+ else
+ {
+ x = NewX(pub, root_k, root_x, n, days, x_serial);
+ }
+
+ FreeXSerial(x_serial);
+ FreeName(n);
+
+ if (x == NULL)
+ {
+ ret = ERR_INTERNAL_ERROR;
+ c->Write(c, _UU("CMD_MakeCert_ERROR_GEN_FAILED"));
+ }
+ else
+ {
+ if (XToFileW(x, GetParamUniStr(o, "SAVECERT"), true) == false)
+ {
+ c->Write(c, _UU("CMD_SAVECERT_FAILED"));
+ }
+ else if (KToFileW(pri, GetParamUniStr(o, "SAVEKEY"), true, NULL) == false)
+ {
+ c->Write(c, _UU("CMD_SAVEKEY_FAILED"));
+ }
+ }
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ FreeX(root_x);
+ FreeK(root_k);
+
+ FreeX(x);
+ FreeK(pri);
+ FreeK(pub);
+
+ return ret;
+}
+
+
+// Client management tool main
+void PcMain(PC *pc)
+{
+ char prompt[MAX_SIZE];
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (pc == NULL)
+ {
+ return;
+ }
+
+ // Display a message that the connection has been made
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_VPNCMD_CLIENT_CONNECTED"),
+ pc->ServerName);
+ pc->Console->Write(pc->Console, tmp);
+ pc->Console->Write(pc->Console, L"");
+
+ while (true)
+ {
+ // Definition of command
+ CMD cmd[] =
+ {
+ {"About", PsAbout},
+ {"Check", PtCheck},
+ {"VersionGet", PcVersionGet},
+ {"PasswordSet", PcPasswordSet},
+ {"PasswordGet", PcPasswordGet},
+ {"CertList", PcCertList},
+ {"CertAdd", PcCertAdd},
+ {"CertDelete", PcCertDelete},
+ {"CertGet", PcCertGet},
+ {"SecureList", PcSecureList},
+ {"SecureSelect", PcSecureSelect},
+ {"SecureGet", PcSecureGet},
+ {"NicCreate", PcNicCreate},
+ {"NicDelete", PcNicDelete},
+ {"NicUpgrade", PcNicUpgrade},
+ {"NicGetSetting", PcNicGetSetting},
+ {"NicSetSetting", PcNicSetSetting},
+ {"NicEnable", PcNicEnable},
+ {"NicDisable", PcNicDisable},
+ {"NicList", PcNicList},
+ {"AccountList", PcAccountList},
+ {"AccountCreate", PcAccountCreate},
+ {"AccountSet", PcAccountSet},
+ {"AccountGet", PcAccountGet},
+ {"AccountDelete", PcAccountDelete},
+ {"AccountUsernameSet", PcAccountUsernameSet},
+ {"AccountAnonymousSet", PcAccountAnonymousSet},
+ {"AccountPasswordSet", PcAccountPasswordSet},
+ {"AccountCertSet", PcAccountCertSet},
+ {"AccountCertGet", PcAccountCertGet},
+ {"AccountEncryptDisable", PcAccountEncryptDisable},
+ {"AccountEncryptEnable", PcAccountEncryptEnable},
+ {"AccountCompressEnable", PcAccountCompressEnable},
+ {"AccountCompressDisable", PcAccountCompressDisable},
+ {"AccountProxyNone", PcAccountProxyNone},
+ {"AccountProxyHttp", PcAccountProxyHttp},
+ {"AccountProxySocks", PcAccountProxySocks},
+ {"AccountServerCertEnable", PcAccountServerCertEnable},
+ {"AccountServerCertDisable", PcAccountServerCertDisable},
+ {"AccountServerCertSet", PcAccountServerCertSet},
+ {"AccountServerCertDelete", PcAccountServerCertDelete},
+ {"AccountServerCertGet", PcAccountServerCertGet},
+ {"AccountDetailSet", PcAccountDetailSet},
+ {"AccountRename", PcAccountRename},
+ {"AccountConnect", PcAccountConnect},
+ {"AccountDisconnect", PcAccountDisconnect},
+ {"AccountStatusGet", PcAccountStatusGet},
+ {"AccountNicSet", PcAccountNicSet},
+ {"AccountStatusShow", PcAccountStatusShow},
+ {"AccountStatusHide", PcAccountStatusHide},
+ {"AccountSecureCertSet", PcAccountSecureCertSet},
+ {"AccountRetrySet", PcAccountRetrySet},
+ {"AccountStartupSet", PcAccountStartupSet},
+ {"AccountStartupRemove", PcAccountStartupRemove},
+ {"AccountExport", PcAccountExport},
+ {"AccountImport", PcAccountImport},
+ {"RemoteEnable", PcRemoteEnable},
+ {"RemoteDisable", PcRemoteDisable},
+ {"KeepEnable", PcKeepEnable},
+ {"KeepDisable", PcKeepDisable},
+ {"KeepSet", PcKeepSet},
+ {"KeepGet", PcKeepGet},
+ {"MakeCert", PtMakeCert},
+ {"TrafficClient", PtTrafficClient},
+ {"TrafficServer", PtTrafficServer},
+ };
+
+ // Generate a prompt
+ StrCpy(prompt, sizeof(prompt), "VPN Client>");
+
+ if (DispatchNextCmdEx(pc->Console, pc->CmdLine, prompt, cmd, sizeof(cmd) / sizeof(cmd[0]), pc) == false)
+ {
+ break;
+ }
+ pc->LastError = pc->Console->RetCode;
+
+ if (pc->LastError == ERR_NO_ERROR && pc->Console->ConsoleType != CONSOLE_CSV)
+ {
+ pc->Console->Write(pc->Console, _UU("CMD_MSG_OK"));
+ pc->Console->Write(pc->Console, L"");
+ }
+
+ if (pc->CmdLine != NULL)
+ {
+ break;
+ }
+ }
+}
+
+// Retrieve the version information of VPN Client service
+UINT PcVersionGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_VERSION t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcGetClientVersion(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ wchar_t tmp[MAX_SIZE];
+ CT *ct;
+
+ // Success
+ ct = CtNewStandard();
+
+ StrToUni(tmp, sizeof(tmp), t.ClientProductName);
+ CtInsert(ct, _UU("CMD_VersionGet_1"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.ClientVersionString);
+ CtInsert(ct, _UU("CMD_VersionGet_2"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.ClientBuildInfoString);
+ CtInsert(ct, _UU("CMD_VersionGet_3"), tmp);
+
+ UniToStru(tmp, t.ProcessId);
+ CtInsert(ct, _UU("CMD_VersionGet_4"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), OsTypeToStr(t.OsType));
+ CtInsert(ct, _UU("CMD_VersionGet_5"), tmp);
+
+ CtFree(ct, c);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set a password to connect to the VPN Client Service
+UINT PcPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_PASSWORD t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[password]", CmdPromptChoosePassword, NULL, NULL, NULL},
+ {"REMOTEONLY", NULL, NULL, NULL, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ StrCpy(t.Password, sizeof(t.Password), GetParamStr(o, "[password]"));
+ t.PasswordRemoteOnly = GetParamYes(o, "REMOTEONLY");
+
+ ret = CcSetPassword(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the settings of the password to connect to the VPN Client service
+UINT PcPasswordGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_PASSWORD_SETTING t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcGetPasswordSetting(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ CT *ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_PasswordGet_1"),
+ t.IsPasswordPresented ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ CtInsert(ct, _UU("CMD_PasswordGet_2"),
+ t.PasswordRemoteOnly ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ CtFree(ct, c);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the list of certificates of the trusted certification authority
+UINT PcCertList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_ENUM_CA t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcEnumCa(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ UINT i;
+ CT *ct = CtNewStandard();
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[64];
+ RPC_CLIENT_ENUM_CA_ITEM *e = t.Items[i];
+
+ GetDateStrEx64(tmp, sizeof(tmp), SystemToLocal64(e->Expires), NULL);
+
+ UniToStru(tmp2, e->Key);
+
+ CtInsert(ct, _UU("CMD_CAList_COLUMN_ID"), tmp2);
+ CtInsert(ct, _UU("CM_CERT_COLUMN_1"), e->SubjectName);
+ CtInsert(ct, _UU("CM_CERT_COLUMN_2"), e->IssuerName);
+ CtInsert(ct, _UU("CM_CERT_COLUMN_3"), tmp);
+
+ if (i != (t.NumItem - 1))
+ {
+ CtInsert(ct, L"---", L"---");
+ }
+ }
+
+ CtFree(ct, c);
+
+ CiFreeClientEnumCa(&t);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Add a certificate of the trusted certification authority
+UINT PcCertAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CERT t;
+ X *x;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[path]", CmdPrompt, _UU("CMD_CAAdd_PROMPT_PATH"), CmdEvalIsFile, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+
+ x = FileToXW(GetParamUniStr(o, "[path]"));
+
+ if (x == NULL)
+ {
+ FreeParamValueList(o);
+ c->Write(c, _UU("CMD_MSG_LOAD_CERT_FAILED"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ t.x = x;
+
+ ret = CcAddCa(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ FreeX(x);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Delete the certificate of the trusted certification authority
+UINT PcCertDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_DELETE_CA t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[id]", CmdPrompt, _UU("CMD_CADelete_PROMPT_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ t.Key = GetParamInt(o, "[id]");
+
+ ret = CcDeleteCa(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the certificate of the trusted certification authority
+UINT PcCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_GET_CA t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[id]", CmdPrompt, _UU("CMD_CAGet_PROMPT_ID"), CmdEvalNotEmpty, NULL},
+ {"SAVECERT", CmdPrompt, _UU("CMD_CAGet_PROMPT_SAVECERT"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ t.Key = GetParamInt(o, "[id]");
+
+ ret = CcGetCa(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ if (XToFileW(t.x, GetParamUniStr(o, "SAVECERT"), true))
+ {
+ // Success
+ }
+ else
+ {
+ // Failure
+ ret = ERR_INTERNAL_ERROR;
+ c->Write(c, _UU("CMD_MSG_SAVE_CERT_FAILED"));
+ }
+
+ CiFreeGetCa(&t);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the list of the type of smart card that can be used
+UINT PcSecureList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_ENUM_SECURE t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcEnumSecure(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ CT *ct;
+ UINT i;
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t *tmp3;
+
+ // Success
+ ct = CtNew();
+ CtInsertColumn(ct, _UU("SEC_COLUMN1"), false);
+ CtInsertColumn(ct, _UU("SEC_COLUMN2"), false);
+ CtInsertColumn(ct, _UU("SEC_COLUMN3"), false);
+ CtInsertColumn(ct, _UU("SEC_COLUMN4"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_SECURE_ITEM *e = t.Items[i];
+
+ // ID
+ UniToStru(tmp1, e->DeviceId);
+
+ // Device name
+ StrToUni(tmp2, sizeof(tmp2), e->DeviceName);
+
+ // Type
+ tmp3 = (e->Type == SECURE_IC_CARD) ? _UU("SEC_SMART_CARD") : _UU("SEC_USB_TOKEN");
+
+ // Manufacturer
+ StrToUni(tmp4, sizeof(tmp4), e->Manufacturer);
+
+ CtInsert(ct, tmp1, tmp2, tmp3, tmp4);
+ }
+
+ CtFreeEx(ct, c, true);
+
+ CiFreeClientEnumSecure(&t);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Select the type of smart card to be used
+UINT PcSecureSelect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_USE_SECURE t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[id]", CmdPrompt, _UU("CMD_SecureSelect_PROMPT_ID"), NULL, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ t.DeviceId = GetParamInt(o, "[id]");
+
+ ret = CcUseSecure(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the type ID of smart card to be used
+UINT PcSecureGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_USE_SECURE t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcGetUseSecure(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ wchar_t tmp[MAX_SIZE];
+
+ if (t.DeviceId != 0)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_SecureGet_Print"), t.DeviceId);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CMD_SecureGet_NoPrint"));
+ }
+ c->Write(c, tmp);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Create a new virtual LAN card
+UINT PcNicCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_CREATE_VLAN t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+
+ ret = CcCreateVLan(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Delete the virtual LAN card
+UINT PcNicDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_CREATE_VLAN t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+
+ ret = CcDeleteVLan(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Upgrading the device driver of the virtual LAN card
+UINT PcNicUpgrade(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_CREATE_VLAN t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+
+ ret = CcUpgradeVLan(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the settings of the virtual LAN card
+UINT PcNicGetSetting(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_VLAN t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+
+ ret = CcGetVLan(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ CT *ct = CtNewStandard();
+ wchar_t tmp[MAX_SIZE];
+
+ StrToUni(tmp, sizeof(tmp), t.DeviceName);
+ CtInsert(ct, _UU("CMD_NicGetSetting_1"), tmp);
+
+ CtInsert(ct, _UU("CMD_NicGetSetting_2"), t.Enabled ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ StrToUni(tmp, sizeof(tmp), t.MacAddress);
+ CtInsert(ct, _UU("CMD_NicGetSetting_3"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.Version);
+ CtInsert(ct, _UU("CMD_NicGetSetting_4"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.FileName);
+ CtInsert(ct, _UU("CMD_NicGetSetting_5"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.Guid);
+ CtInsert(ct, _UU("CMD_NicGetSetting_6"), tmp);
+
+ CtFree(ct, c);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Change the settings for the virtual LAN card
+UINT PcNicSetSetting(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_SET_VLAN t;
+ UCHAR mac_address[6];
+ BUF *b;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ {"MAC", CmdPrompt, _UU("CMD_NicSetSetting_PROMPT_MAC"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Inspect the MAC address
+ Zero(mac_address, sizeof(mac_address));
+ b = StrToBin(GetParamStr(o, "MAC"));
+ if (b != NULL && b->Size == 6)
+ {
+ Copy(mac_address, b->Buf, 6);
+ }
+ FreeBuf(b);
+
+ if (IsZero(mac_address, 6))
+ {
+ // MAC address is invalid
+ FreeParamValueList(o);
+
+ CmdPrintError(c, ERR_INVALID_PARAMETER);
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+ NormalizeMacAddress(t.MacAddress, sizeof(t.MacAddress), GetParamStr(o, "MAC"));
+
+ ret = CcSetVLan(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Enable the virtual LAN card
+UINT PcNicEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_CREATE_VLAN t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+
+ ret = CcEnableVLan(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Disable the virtual LAN card
+UINT PcNicDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_CREATE_VLAN t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_NicCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "[name]"));
+
+ ret = CcDisableVLan(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the Virtual LAN card list
+UINT PcNicList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_ENUM_VLAN t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcEnumVLan(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ CT *ct;
+ UINT i;
+
+ // Success
+ ct = CtNew();
+ CtInsertColumn(ct, _UU("CM_VLAN_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("CM_VLAN_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("CM_VLAN_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("CM_VLAN_COLUMN_4"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ wchar_t name[MAX_SIZE];
+ wchar_t mac[MAX_SIZE];
+ wchar_t ver[MAX_SIZE];
+ wchar_t *status;
+ RPC_CLIENT_ENUM_VLAN_ITEM *v = t.Items[i];
+
+ // Device name
+ StrToUni(name, sizeof(name), v->DeviceName);
+
+ // State
+ status = v->Enabled ? _UU("CM_VLAN_ENABLED") : _UU("CM_VLAN_DISABLED");
+
+ // MAC address
+ StrToUni(mac, sizeof(mac), v->MacAddress);
+
+ // Version
+ StrToUni(ver, sizeof(ver), v->Version);
+
+ CtInsert(ct,
+ name, status, mac, ver);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientEnumVLan(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the protocol name string from ID
+wchar_t *GetProtocolName(UINT n)
+{
+ switch (n)
+ {
+ case PROXY_DIRECT:
+ return _UU("PROTO_DIRECT_TCP");
+ case PROXY_HTTP:
+ return _UU("PROTO_HTTP_PROXY");
+ case PROXY_SOCKS:
+ return _UU("PROTO_SOCKS_PROXY");
+ }
+
+ return _UU("PROTO_UNKNOWN");
+}
+
+// Get the connection settings list
+UINT PcAccountList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_ENUM_ACCOUNT t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcEnumAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ UINT i;
+ CT *ct;
+
+ // Success
+ ct = CtNew();
+ CtInsertColumn(ct, _UU("CM_ACCOUNT_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("CM_ACCOUNT_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("CM_ACCOUNT_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("CM_ACCOUNT_COLUMN_3_2"), false);
+ CtInsertColumn(ct, _UU("CM_ACCOUNT_COLUMN_4"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_CLIENT_ENUM_ACCOUNT_ITEM *e = t.Items[i];
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ IP ip;
+ char ip_str[MAX_SIZE];
+
+ // Special treatment for IPv6 addresses
+ if (StrToIP6(&ip, e->ServerName) && StartWith(e->ServerName, "[") == false)
+ {
+ Format(ip_str, sizeof(ip_str),
+ "[%s]", e->ServerName);
+ }
+ else
+ {
+ StrCpy(ip_str, sizeof(ip_str), e->ServerName);
+ }
+
+ if (e->Port == 0)
+ {
+ // Port number unknown
+ UniFormat(tmp2, sizeof(tmp2), L"%S (%s)", ip_str, GetProtocolName(e->ProxyType));
+ }
+ else
+ {
+ // Port number are also shown
+ UniFormat(tmp2, sizeof(tmp2), L"%S:%u (%s)", ip_str, e->Port, GetProtocolName(e->ProxyType));
+ }
+
+ // Virtual HUB name
+ StrToUni(tmp4, sizeof(tmp4), e->HubName);
+
+ // Add
+ StrToUni(tmp, sizeof(tmp), e->DeviceName);
+
+ CtInsert(ct,
+ e->AccountName,
+ e->Active == false ? _UU("CM_ACCOUNT_OFFLINE") :
+ (e->Connected ? _UU("CM_ACCOUNT_ONLINE") : _UU("CM_ACCOUNT_CONNECTING")),
+ tmp2, tmp4,
+ tmp);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ CiFreeClientEnumAccount(&t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Create new connection settings
+UINT PcAccountCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_CREATE_ACCOUNT t;
+ UINT port = 443;
+ char *host = NULL;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SERVER", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Server"), CmdEvalHostAndPort, NULL},
+ {"HUB", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Hub"), CmdEvalSafe, NULL},
+ {"USERNAME", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Username"), CmdEvalNotEmpty, NULL},
+ {"NICNAME", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Nicname"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 443);
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+ t.ClientOption->Port = port;
+ StrCpy(t.ClientOption->Hostname, sizeof(t.ClientOption->Hostname), host);
+ StrCpy(t.ClientOption->HubName, sizeof(t.ClientOption->HubName), GetParamStr(o, "HUB"));
+ t.ClientOption->NumRetry = INFINITE;
+ t.ClientOption->RetryInterval = 15;
+ t.ClientOption->MaxConnection = 1;
+ t.ClientOption->UseEncrypt = true;
+ t.ClientOption->AdditionalConnectionInterval = 1;
+ StrCpy(t.ClientOption->DeviceName, sizeof(t.ClientOption->DeviceName), GetParamStr(o, "NICNAME"));
+
+ t.ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_ANONYMOUS;
+ StrCpy(t.ClientAuth->Username, sizeof(t.ClientAuth->Username), GetParamStr(o, "USERNAME"));
+
+ Free(host);
+
+ ret = CcCreateAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ CiFreeClientCreateAccount(&t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the destination of the connection settings
+UINT PcAccountSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ char *host = NULL;
+ UINT port = 443;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SERVER", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Server"), CmdEvalHostAndPort, NULL},
+ {"HUB", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Hub"), CmdEvalSafe, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 443);
+
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT c;
+ // Success
+ t.ClientOption->Port = port;
+ StrCpy(t.ClientOption->Hostname, sizeof(t.ClientOption->Hostname), host);
+ StrCpy(t.ClientOption->HubName, sizeof(t.ClientOption->HubName), GetParamStr(o, "HUB"));
+
+ Zero(&c, sizeof(c));
+
+ c.ClientAuth = t.ClientAuth;
+ c.ClientOption = t.ClientOption;
+ c.CheckServerCert = t.CheckServerCert;
+ c.ServerCert = t.ServerCert;
+ c.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &c);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ Free(host);
+
+ return ret;
+}
+
+// Get the configuration of the connection settings
+UINT PcAccountGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Show the contents of the connection settings
+ wchar_t tmp[MAX_SIZE];
+
+ CT *ct = CtNewStandard();
+
+ // Connection settings name
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_NAME"), t.ClientOption->AccountName);
+
+ // Host name of the destination VPN Server
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->Hostname);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_HOSTNAME"), tmp);
+
+ // The port number to connect to VPN Server
+ UniToStru(tmp, t.ClientOption->Port);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PORT"), tmp);
+
+ // Virtual HUB name of the destination VPN Server
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->HubName);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_HUBNAME"), tmp);
+
+ // Type of proxy server to go through
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_TYPE"), GetProxyTypeStr(t.ClientOption->ProxyType));
+
+ if (t.ClientOption->ProxyType != PROXY_DIRECT)
+ {
+ // Host name of the proxy server
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->ProxyName);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_HOSTNAME"), tmp);
+
+ // Port number of the proxy server
+ UniToStru(tmp, t.ClientOption->ProxyPort);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_PORT"), tmp);
+
+ // User name of the proxy server
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->ProxyUsername);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_USERNAME"), tmp);
+ }
+
+ // Verify the server certificate
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_SERVER_CERT_USE"),
+ t.CheckServerCert ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Registered specific certificate
+ if (t.ServerCert != NULL)
+ {
+ GetAllNameFromX(tmp, sizeof(tmp), t.ServerCert);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_SERVER_CERT_NAME"), tmp);
+ }
+
+ // Device name to be used for the connection
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->DeviceName);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_DEVICE_NAME"), tmp);
+
+ // Authentication type
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_AUTH_TYPE"), GetClientAuthTypeStr(t.ClientAuth->AuthType));
+
+ // User name
+ StrToUni(tmp, sizeof(tmp), t.ClientAuth->Username);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_AUTH_USERNAME"), tmp);
+
+ if (t.ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)
+ {
+ if (t.ClientAuth->ClientX != NULL)
+ {
+ // Client certificate name
+ GetAllNameFromX(tmp, sizeof(tmp), t.ClientAuth->ClientX);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_AUTH_CERT_NAME"), tmp);
+ }
+ }
+
+ // Number of TCP connections to be used for VPN communication
+ UniToStru(tmp, t.ClientOption->MaxConnection);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_NUMTCP"), tmp);
+
+ // Establishment interval of each TCP connection
+ UniToStru(tmp, t.ClientOption->AdditionalConnectionInterval);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_TCP_INTERVAL"), tmp);
+
+ // Life span of each TCP connection
+ if (t.ClientOption->ConnectionDisconnectSpan != 0)
+ {
+ UniToStru(tmp, t.ClientOption->ConnectionDisconnectSpan);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CMD_MSG_INFINITE"));
+ }
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_TCP_TTL"), tmp);
+
+ // Use of half-duplex mode
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_TCP_HALF"),
+ t.ClientOption->HalfConnection ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Encryption by SSL
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_ENCRYPT"),
+ t.ClientOption->UseEncrypt ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Data compression
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_COMPRESS"),
+ t.ClientOption->UseCompress ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Connect in bridge / router mode
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_BRIDGE_ROUTER"),
+ t.ClientOption->RequireBridgeRoutingMode ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Connect in monitoring mode
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_MONITOR"),
+ t.ClientOption->RequireMonitorMode ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Not to rewrite the routing table
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_NO_TRACKING"),
+ t.ClientOption->NoRoutingTracking ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Disable the QoS control
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_QOS_DISABLE"),
+ t.ClientOption->DisableQoS ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ CtFree(ct, c);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Delete the connection settings
+UINT PcAccountDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_DELETE_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcDeleteAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the user name used to connect with connection settings
+UINT PcAccountUsernameSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"USERNAME", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Username"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ StrCpy(t.ClientAuth->Username, sizeof(t.ClientAuth->Username), GetParamStr(o, "USERNAME"));
+
+ if (t.ClientAuth->AuthType == CLIENT_AUTHTYPE_PASSWORD)
+ {
+ c->Write(c, _UU("CMD_AccountUsername_Notice"));
+ }
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the type of user authentication of connection settings to anonymous authentication
+UINT PcAccountAnonymousSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_ANONYMOUS;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the type of user authentication of connection settings to the password authentication
+UINT PcAccountPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+ {"TYPE", CmdPrompt, _UU("CMD_CascadePasswordSet_Prompt_Type"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ char *typestr = GetParamStr(o, "TYPE");
+ RPC_CLIENT_CREATE_ACCOUNT z;
+
+ // Change the settings
+ if (StartWith("standard", typestr))
+ {
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_PASSWORD;
+ HashPassword(t.ClientAuth->HashedPassword, t.ClientAuth->Username,
+ GetParamStr(o, "PASSWORD"));
+ }
+ else if (StartWith("radius", typestr) || StartWith("ntdomain", typestr))
+ {
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_PLAIN_PASSWORD;
+
+ StrCpy(t.ClientAuth->PlainPassword, sizeof(t.ClientAuth->PlainPassword),
+ GetParamStr(o, "PASSWORD"));
+ }
+ else
+ {
+ // Error has occured
+ c->Write(c, _UU("CMD_CascadePasswordSet_Type_Invalid"));
+ ret = ERR_INVALID_PARAMETER;
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the type of user authentication of connection settings to the client certificate authentication
+UINT PcAccountCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ X *x;
+ K *k;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL},
+ {"LOADKEY", CmdPrompt, _UU("CMD_LOADKEYPATH"), CmdEvalIsFile, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (CmdLoadCertAndKey(c, &x, &k, GetParamUniStr(o, "LOADCERT"), GetParamUniStr(o, "LOADKEY")) == false)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_CERT;
+ if (t.ClientAuth->ClientX != NULL)
+ {
+ FreeX(t.ClientAuth->ClientX);
+ }
+ if (t.ClientAuth->ClientK != NULL)
+ {
+ FreeK(t.ClientAuth->ClientK);
+ }
+
+ t.ClientAuth->ClientX = CloneX(x);
+ t.ClientAuth->ClientK = CloneK(k);
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ FreeX(x);
+ FreeK(k);
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the client certificate to be used for the connection settings
+UINT PcAccountCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SAVECERT", CmdPrompt, _UU("CMD_SAVECERTPATH"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ if (t.ClientAuth->AuthType != CLIENT_AUTHTYPE_CERT)
+ {
+ c->Write(c, _UU("CMD_CascadeCertSet_Not_Auth_Cert"));
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else if (t.ClientAuth->ClientX == NULL)
+ {
+ c->Write(c, _UU("CMD_CascadeCertSet_Cert_Not_Exists"));
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ XToFileW(t.ClientAuth->ClientX, GetParamUniStr(o, "SAVECERT"), true);
+ }
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Disable communication encryption with the connection settings
+UINT PcAccountEncryptDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.ClientOption->UseEncrypt = false;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Enable communication encryption with the connection settings
+UINT PcAccountEncryptEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.ClientOption->UseEncrypt = true;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Enable communication data compression with the connection settings
+UINT PcAccountCompressEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.ClientOption->UseCompress = true;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Disable communication data compression with the connection settings
+UINT PcAccountCompressDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.ClientOption->UseCompress = false;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the connection method of the connection settings to the direct TCP/IP connection
+UINT PcAccountProxyNone(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.ClientOption->ProxyType = PROXY_DIRECT;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the connection method of the connection settings to the HTTP proxy server connection
+UINT PcAccountProxyHttp(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SERVER", CmdPrompt, _UU("CMD_AccountProxyHttp_Prompt_Server"), CmdEvalHostAndPort, NULL},
+ {"USERNAME", NULL, NULL, NULL, NULL},
+ {"PASSWORD", NULL, NULL, NULL, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ char *host;
+ UINT port;
+
+ // Data change
+ if (ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 8080))
+ {
+ t.ClientOption->ProxyType = PROXY_HTTP;
+ StrCpy(t.ClientOption->ProxyName, sizeof(t.ClientOption->ProxyName), host);
+ t.ClientOption->ProxyPort = port;
+ StrCpy(t.ClientOption->ProxyUsername, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "USERNAME"));
+ StrCpy(t.ClientOption->ProxyPassword, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "PASSWORD"));
+ Free(host);
+ }
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the connection method of the connection settings to the SOCKS proxy server connection
+UINT PcAccountProxySocks(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SERVER", CmdPrompt, _UU("CMD_AccountProxyHttp_Prompt_Server"), CmdEvalHostAndPort, NULL},
+ {"USERNAME", NULL, NULL, NULL, NULL},
+ {"PASSWORD", NULL, NULL, NULL, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ char *host;
+ UINT port;
+
+ // Data change
+ if (ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 8080))
+ {
+ t.ClientOption->ProxyType = PROXY_SOCKS;
+ StrCpy(t.ClientOption->ProxyName, sizeof(t.ClientOption->ProxyName), host);
+ t.ClientOption->ProxyPort = port;
+ StrCpy(t.ClientOption->ProxyUsername, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "USERNAME"));
+ StrCpy(t.ClientOption->ProxyPassword, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "PASSWORD"));
+ Free(host);
+ }
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Enable validation option for server certificate of connection settings
+UINT PcAccountServerCertEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.CheckServerCert = true;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Disable validation option of the server certificate of connection settings
+UINT PcAccountServerCertDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.CheckServerCert = false;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the server-specific certificate of connection settings
+UINT PcAccountServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ X *x;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ x = FileToXW(GetParamUniStr(o, "LOADCERT"));
+ if (x == NULL)
+ {
+ FreeParamValueList(o);
+ c->Write(c, _UU("CMD_LOADCERT_FAILED"));
+ return ERR_INTERNAL_ERROR;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ if (t.ServerCert != NULL)
+ {
+ FreeX(t.ServerCert);
+ }
+ t.ServerCert = CloneX(x);
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ FreeX(x);
+
+ return ret;
+}
+
+// Delete a server-specific certificate of connection settings
+UINT PcAccountServerCertDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ if (t.ServerCert != NULL)
+ {
+ FreeX(t.ServerCert);
+ }
+ t.ServerCert = NULL;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get a server-specific certificate of connection settings
+UINT PcAccountServerCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SAVECERT", CmdPrompt, _UU("CMD_SAVECERTPATH"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ if (t.ServerCert != NULL)
+ {
+ FreeX(t.ServerCert);
+ }
+ t.ServerCert = NULL;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the advanced settings of connection settings
+UINT PcAccountDetailSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ CMD_EVAL_MIN_MAX mm_maxtcp =
+ {
+ "CMD_CascadeDetailSet_Eval_MaxTcp", 1, 32
+ };
+ CMD_EVAL_MIN_MAX mm_interval =
+ {
+ "CMD_CascadeDetailSet_Eval_Interval", 1, 4294967295UL
+ };
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"MAXTCP", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_MaxTcp"), CmdEvalMinMax, &mm_maxtcp},
+ {"INTERVAL", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_Interval"), CmdEvalMinMax, &mm_interval},
+ {"TTL", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_TTL"), NULL, NULL},
+ {"HALF", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_HALF"), NULL, NULL},
+ {"BRIDGE", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_BRIDGE"), NULL, NULL},
+ {"MONITOR", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_MONITOR"), NULL, NULL},
+ {"NOTRACK", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_NOTRACK"), NULL, NULL},
+ {"NOQOS", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_NOQOS"), NULL, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Data change
+ t.ClientOption->MaxConnection = GetParamInt(o, "MAXTCP");
+ t.ClientOption->AdditionalConnectionInterval = GetParamInt(o, "INTERVAL");
+ t.ClientOption->ConnectionDisconnectSpan = GetParamInt(o, "TTL");
+ t.ClientOption->HalfConnection = GetParamYes(o, "HALF");
+ t.ClientOption->RequireBridgeRoutingMode = GetParamYes(o, "BRIDGE");
+ t.ClientOption->RequireMonitorMode = GetParamYes(o, "MONITOR");
+ t.ClientOption->NoRoutingTracking = GetParamYes(o, "NOTRACK");
+ t.ClientOption->DisableQoS = GetParamYes(o, "NOQOS");
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Change the name of the connection settings
+UINT PcAccountRename(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_RENAME_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountRename_PROMPT_OLD"), CmdEvalNotEmpty, NULL},
+ {"NEW", CmdPrompt, _UU("CMD_AccountRename_PROMPT_NEW"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.NewName, sizeof(t.NewName), GetParamUniStr(o, "NEW"));
+ UniStrCpy(t.OldName, sizeof(t.OldName), GetParamUniStr(o, "[name]"));
+
+ ret = CcRenameAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Start to connect to the VPN Server using the connection settings
+UINT PcAccountConnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_CONNECT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcConnect(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Disconnect the connection settings of connected
+UINT PcAccountDisconnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_CONNECT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcDisconnect(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the current state of the connection settings
+UINT PcAccountStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_CONNECTION_STATUS t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccountStatus(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ if (t.Active == false)
+ {
+ // Has been disconnected
+ ret = ERR_ACCOUNT_INACTIVE;
+ }
+ else
+ {
+ CT *ct = CtNewStandard();
+
+ CmdPrintStatusToListView(ct, &t);
+
+ CtFree(ct, c);
+ }
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetConnectionStatus(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set a virtual LAN card to be used in the connection settings
+UINT PcAccountNicSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"NICNAME", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Nicname"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT c;
+ // Success
+ StrCpy(t.ClientOption->DeviceName, sizeof(t.ClientOption->DeviceName),
+ GetParamStr(o, "NICNAME"));
+
+ Zero(&c, sizeof(c));
+
+ c.ClientAuth = t.ClientAuth;
+ c.ClientOption = t.ClientOption;
+ c.CheckServerCert = t.CheckServerCert;
+ c.ServerCert = t.ServerCert;
+ c.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &c);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set to display error screens and connection status while connecting to the VPN Server
+UINT PcAccountStatusShow(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.ClientOption->HideStatusWindow = false;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Configure not to display error screens and connection status while connecting to the VPN Server
+UINT PcAccountStatusHide(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.ClientOption->HideStatusWindow = true;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the type of user authentication of connection settings to the smart card authentication
+UINT PcAccountSecureCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"CERTNAME", CmdPrompt, _UU("CMD_AccountSecureCertSet_PROMPT_CERTNAME"), CmdEvalNotEmpty, NULL},
+ {"KEYNAME", CmdPrompt, _UU("CMD_AccountSecureCertSet_PROMPT_KEYNAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_SECURE;
+ StrCpy(t.ClientAuth->SecurePublicCertName, sizeof(t.ClientAuth->SecurePublicCertName),
+ GetParamStr(o, "CERTNAME"));
+ StrCpy(t.ClientAuth->SecurePrivateKeyName, sizeof(t.ClientAuth->SecurePrivateKeyName),
+ GetParamStr(o, "KEYNAME"));
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the retry interval and number of retries when disconnect or connection failure of connection settings
+UINT PcAccountRetrySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX minmax =
+ {
+ "CMD_AccountRetrySet_EVAL_INTERVAL",
+ 5,
+ 4294967295UL,
+ };
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"NUM", CmdPrompt, _UU("CMD_AccountRetrySet_PROMPT_NUM"), CmdEvalNotEmpty, NULL},
+ {"INTERVAL", CmdPrompt, _UU("CMD_AccountRetrySet_PROMPY_INTERVAL"), CmdEvalMinMax, &minmax},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ UINT num = GetParamInt(o, "NUM");
+ UINT interval = GetParamInt(o, "INTERVAL");
+
+ t.ClientOption->NumRetry = (num == 999) ? INFINITE : num;
+ t.ClientOption->RetryInterval = interval;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+
+// Set to start-up connection the connection settings
+UINT PcAccountStartupSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.StartupAccount = true;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Unset the start-up connection of the connection settings
+UINT PcAccountStartupRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ // Change the settings
+ t.StartupAccount = false;
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ ret = CcSetAccount(pc->RemoteClient, &z);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Export the connection settings
+UINT PcAccountExport(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ RPC_CLIENT_GET_ACCOUNT t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SAVEPATH", CmdPrompt, _UU("CMD_AccountExport_PROMPT_SAVEPATH"), CmdEvalNotEmpty, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = CcGetAccount(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ RPC_CLIENT_CREATE_ACCOUNT z;
+ BUF *b;
+ BUF *b2;
+ char tmp[MAX_SIZE];
+ UCHAR *buf;
+ UINT buf_size;
+ UCHAR bom[] = {0xef, 0xbb, 0xbf, };
+
+ Zero(&z, sizeof(z));
+ z.CheckServerCert = t.CheckServerCert;
+ z.ClientAuth = t.ClientAuth;
+ z.ClientOption = t.ClientOption;
+ z.ServerCert = t.ServerCert;
+ z.StartupAccount = t.StartupAccount;
+
+ b = CiAccountToCfg(&z);
+
+ StrCpy(tmp, sizeof(tmp), GetParamStr(o, "SAVEPATH"));
+ b2 = NewBuf();
+
+ WriteBuf(b2, bom, sizeof(bom));
+
+ // Add the header part
+ buf_size = CalcUniToUtf8(_UU("CM_ACCOUNT_FILE_BANNER"));
+ buf = ZeroMalloc(buf_size + 32);
+ UniToUtf8(buf, buf_size, _UU("CM_ACCOUNT_FILE_BANNER"));
+
+ WriteBuf(b2, buf, StrLen((char *)buf));
+ WriteBuf(b2, b->Buf, b->Size);
+ SeekBuf(b2, 0, 0);
+
+ FreeBuf(b);
+
+ if (DumpBuf(b2, tmp) == false)
+ {
+ c->Write(c, _UU("CMD_SAVEFILE_FAILED"));
+ ret = ERR_INTERNAL_ERROR;
+ }
+
+ FreeBuf(b2);
+ Free(buf);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ CiFreeClientGetAccount(&t);
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Check whether the specified account name exists
+bool CmdIsAccountName(REMOTE_CLIENT *r, wchar_t *name)
+{
+ UINT i;
+ RPC_CLIENT_ENUM_ACCOUNT t;
+ wchar_t tmp[MAX_SIZE];
+ bool b = false;
+ // Validate arguments
+ if (r == NULL || name == NULL)
+ {
+ return false;
+ }
+
+ if (CcEnumAccount(r, &t) != ERR_NO_ERROR)
+ {
+ return false;
+ }
+
+ UniStrCpy(tmp, sizeof(tmp), name);
+ UniTrim(tmp);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ if (UniStrCmpi(t.Items[i]->AccountName, tmp) == 0)
+ {
+ b = true;
+ break;
+ }
+ }
+
+ CiFreeClientEnumAccount(&t);
+
+ return b;
+}
+
+// Generate an import name
+void CmdGenerateImportName(REMOTE_CLIENT *r, wchar_t *name, UINT size, wchar_t *old_name)
+{
+ UINT i;
+ // Validate arguments
+ if (r == NULL || name == NULL || old_name == NULL)
+ {
+ return;
+ }
+
+ for (i = 1;;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ if (i == 1)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_IMPORT_NAME_1"), old_name);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_IMPORT_NAME_2"), old_name, i);
+ }
+
+ if (CmdIsAccountName(r, tmp) == false)
+ {
+ UniStrCpy(name, size, tmp);
+ return;
+ }
+ }
+}
+
+// Import a connection setting
+UINT PcAccountImport(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ BUF *b;
+ wchar_t name[MAX_SIZE];
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[path]", CmdPrompt, _UU("CMD_AccountImport_PROMPT_PATH"), CmdEvalIsFile, NULL},
+ };
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Read the file
+ b = ReadDumpW(GetParamUniStr(o, "[path]"));
+
+ if (b == NULL)
+ {
+ // Read failure
+ c->Write(c, _UU("CMD_LOADFILE_FAILED"));
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ RPC_CLIENT_CREATE_ACCOUNT *t;
+
+ t = CiCfgToAccount(b);
+
+ if (t == NULL)
+ {
+ // Failed to parse
+ c->Write(c, _UU("CMD_AccountImport_FAILED_PARSE"));
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ CmdGenerateImportName(pc->RemoteClient, name, sizeof(name), t->ClientOption->AccountName);
+ UniStrCpy(t->ClientOption->AccountName, sizeof(t->ClientOption->AccountName), name);
+
+ ret = CcCreateAccount(pc->RemoteClient, t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_AccountImport_OK"), name);
+ c->Write(c, tmp);
+ }
+
+ CiFreeClientCreateAccount(t);
+ Free(t);
+ }
+
+ FreeBuf(b);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Allow remote management of the VPN Client Service
+UINT PcRemoteEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ CLIENT_CONFIG t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcGetClientConfig(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ t.AllowRemoteConfig = true;
+ ret = CcSetClientConfig(pc->RemoteClient, &t);
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Prohibit remote management of the VPN Client Service
+UINT PcRemoteDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ CLIENT_CONFIG t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcGetClientConfig(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ t.AllowRemoteConfig = false;
+ ret = CcSetClientConfig(pc->RemoteClient, &t);
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Enable the maintenance function of the Internet connection
+UINT PcKeepEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ CLIENT_CONFIG t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcGetClientConfig(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Change the settings
+ t.UseKeepConnect = true;
+ ret = CcSetClientConfig(pc->RemoteClient, &t);
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Disable the maintenance function of the Internet connection
+UINT PcKeepDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ CLIENT_CONFIG t;
+
+ // Get the parameter list
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcGetClientConfig(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Change the settings
+ t.UseKeepConnect = false;
+ ret = CcSetClientConfig(pc->RemoteClient, &t);
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the maintenance function of the Internet connection
+UINT PcKeepSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ CLIENT_CONFIG t;
+ char *host;
+ UINT port;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"HOST", CmdPrompt, _UU("CMD_KeepSet_PROMPT_HOST"), CmdEvalHostAndPort, NULL},
+ {"PROTOCOL", CmdPrompt, _UU("CMD_KeepSet_PROMPT_PROTOCOL"), CmdEvalTcpOrUdp, NULL},
+ {"INTERVAL", CmdPrompt, _UU("CMD_KeepSet_PROMPT_INTERVAL"), NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcGetClientConfig(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ if (ParseHostPort(GetParamStr(o, "HOST"), &host, &port, 0))
+ {
+ StrCpy(t.KeepConnectHost, sizeof(t.KeepConnectHost), host);
+ t.KeepConnectPort = port;
+ t.KeepConnectInterval = GetParamInt(o, "INTERVAL");
+ t.KeepConnectProtocol = (StrCmpi(GetParamStr(o, "PROTOCOL"), "tcp") == 0) ? 0 : 1;
+ Free(host);
+
+ ret = CcSetClientConfig(pc->RemoteClient, &t);
+ }
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the maintenance function of the Internet connection
+UINT PcKeepGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PC *pc = (PC *)param;
+ UINT ret = ERR_NO_ERROR;
+ CLIENT_CONFIG t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ Zero(&t, sizeof(t));
+
+ ret = CcGetClientConfig(pc->RemoteClient, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ wchar_t tmp[MAX_SIZE];
+ CT *ct = CtNewStandard();
+
+ StrToUni(tmp, sizeof(tmp), t.KeepConnectHost);
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_1"), tmp);
+
+ UniToStru(tmp, t.KeepConnectPort);
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_2"), tmp);
+
+ UniToStru(tmp, t.KeepConnectInterval);
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_3"), tmp);
+
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_4"),
+ t.KeepConnectProtocol == 0 ? L"TCP/IP" : L"UDP/IP");
+
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_5"),
+ t.UseKeepConnect ? _UU("SM_ACCESS_ENABLE") : _UU("SM_ACCESS_DISABLE"));
+
+ CtFree(ct, c);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // Error has occurred
+ CmdPrintError(c, ret);
+ }
+
+ // Release of the parameter list
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+
+// Creat a new client management tool context
+PC *NewPc(CONSOLE *c, REMOTE_CLIENT *remote_client, char *servername, wchar_t *cmdline)
+{
+ PC *pc;
+ // Validate arguments
+ if (c == NULL || remote_client == NULL || servername == NULL)
+ {
+ return NULL;
+ }
+ if (UniIsEmptyStr(cmdline))
+ {
+ cmdline = NULL;
+ }
+
+ pc = ZeroMalloc(sizeof(PC));
+ pc->ConsoleForServer = false;
+ pc->ServerName = CopyStr(servername);
+ pc->Console = c;
+ pc->LastError = 0;
+ pc->RemoteClient = remote_client;
+ pc->CmdLine = CopyUniStr(cmdline);
+
+ return pc;
+}
+
+// Release the client management tools context
+void FreePc(PC *pc)
+{
+ // Validate arguments
+ if (pc == NULL)
+ {
+ return;
+ }
+
+ Free(pc->ServerName);
+ Free(pc->CmdLine);
+ Free(pc);
+}
+
+// Client management tool
+UINT PcConnect(CONSOLE *c, char *target, wchar_t *cmdline, char *password)
+{
+ CEDAR *cedar;
+ REMOTE_CLIENT *client;
+ bool bad_pass;
+ bool no_remote;
+ char pass[MAX_SIZE];
+ UINT ret = 0;
+ // Validate arguments
+ if (c == NULL || target == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ StrCpy(pass, sizeof(pass), password);
+
+ cedar = NewCedar(NULL, NULL);
+
+RETRY:
+ client = CcConnectRpc(target, pass, &bad_pass, &no_remote, 0);
+
+ if (client == NULL)
+ {
+ if (no_remote)
+ {
+ // Remote connection refusal
+ c->Write(c, _UU("CMD_VPNCMD_CLIENT_NO_REMODE"));
+ ReleaseCedar(cedar);
+ return ERR_INTERNAL_ERROR;
+ }
+ else if (bad_pass)
+ {
+ char *tmp;
+ // Password is different
+ c->Write(c, _UU("CMD_VPNCMD_PASSWORD_1"));
+ tmp = c->ReadPassword(c, _UU("CMD_VPNCMD_PASSWORD_2"));
+ c->Write(c, L"");
+
+ if (tmp == NULL)
+ {
+ // Cancel
+ ReleaseCedar(cedar);
+ return ERR_ACCESS_DENIED;
+ }
+ else
+ {
+ StrCpy(pass, sizeof(pass), tmp);
+ Free(tmp);
+ }
+
+ goto RETRY;
+ }
+ else
+ {
+ // Connection failure
+ CmdPrintError(c, ERR_CONNECT_FAILED);
+ ReleaseCedar(cedar);
+ return ERR_CONNECT_FAILED;
+ }
+ }
+ else
+ {
+ // Connection complete
+ PC *pc = NewPc(c, client, target, cmdline);
+ PcMain(pc);
+ ret = pc->LastError;
+ FreePc(pc);
+ }
+
+ CcDisconnectRpc(client);
+
+ ReleaseCedar(cedar);
+
+ return ret;
+}
+
+
+// Server Administration Tool Processor Main
+void PsMain(PS *ps)
+{
+ char prompt[MAX_SIZE];
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (ps == NULL)
+ {
+ return;
+ }
+
+ // If it's not in CSV mode, to display a message that the connection has been made
+ if(ps->Console->ConsoleType != CONSOLE_CSV)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_VPNCMD_SERVER_CONNECTED"),
+ ps->ServerName, ps->ServerPort);
+ ps->Console->Write(ps->Console, tmp);
+ ps->Console->Write(ps->Console, L"");
+
+ if (ps->HubName == NULL)
+ {
+ // Server management mode
+ ps->Console->Write(ps->Console, _UU("CMD_VPNCMD_SERVER_CONNECTED_1"));
+ }
+ else
+ {
+ // Virtual HUB management mode
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_VPNCMD_SERVER_CONNECTED_2"),
+ ps->HubName);
+ ps->Console->Write(ps->Console, tmp);
+ }
+ ps->Console->Write(ps->Console, L"");
+ }
+
+ // Get the Caps
+ ps->CapsList = ScGetCapsEx(ps->Rpc);
+
+ if (ps->AdminHub != NULL)
+ {
+ RPC_HUB_STATUS t;
+ UINT ret;
+ wchar_t tmp[MAX_SIZE];
+
+ // Choose the Virtual HUB that is specified in the ADMINHUB
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->AdminHub);
+
+ ret = ScGetHubStatus(ps->Rpc, &t);
+ if (ret == ERR_NO_ERROR)
+ {
+ // Success
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_Hub_Selected"), t.HubName);
+
+ if (ps->HubName != NULL)
+ {
+ Free(ps->HubName);
+ }
+ ps->HubName = CopyStr(t.HubName);
+
+ if( ps->Console->ConsoleType != CONSOLE_CSV)
+ {
+ ps->Console->Write(ps->Console, tmp);
+ }
+ }
+ else
+ {
+ // Failure
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_Hub_Select_Failed"), ps->AdminHub);
+
+ ps->Console->Write(ps->Console, tmp);
+ CmdPrintError(ps->Console, ret);
+ }
+ }
+
+ while (true)
+ {
+ // Definition of command
+ CMD cmd[] =
+ {
+ {"About", PsAbout},
+ {"Check", PtCheck},
+ {"Crash", PsCrash},
+ {"Flush", PsFlush},
+ {"Debug", PsDebug},
+ {"ServerInfoGet", PsServerInfoGet},
+ {"ServerStatusGet", PsServerStatusGet},
+ {"ListenerCreate", PsListenerCreate},
+ {"ListenerDelete", PsListenerDelete},
+ {"ListenerList", PsListenerList},
+ {"ListenerEnable", PsListenerEnable},
+ {"ListenerDisable", PsListenerDisable},
+ {"ServerPasswordSet", PsServerPasswordSet},
+ {"ClusterSettingGet", PsClusterSettingGet},
+ {"ClusterSettingStandalone", PsClusterSettingStandalone},
+ {"ClusterSettingController", PsClusterSettingController},
+ {"ClusterSettingMember", PsClusterSettingMember},
+ {"ClusterMemberList", PsClusterMemberList},
+ {"ClusterMemberInfoGet", PsClusterMemberInfoGet},
+ {"ClusterMemberCertGet", PsClusterMemberCertGet},
+ {"ClusterConnectionStatusGet", PsClusterConnectionStatusGet},
+ {"ServerCertGet", PsServerCertGet},
+ {"ServerKeyGet", PsServerKeyGet},
+ {"ServerCertSet", PsServerCertSet},
+ {"ServerCipherGet", PsServerCipherGet},
+ {"ServerCipherSet", PsServerCipherSet},
+ {"KeepEnable", PsKeepEnable},
+ {"KeepDisable", PsKeepDisable},
+ {"KeepSet", PsKeepSet},
+ {"KeepGet", PsKeepGet},
+ {"SyslogGet", PsSyslogGet},
+ {"SyslogDisable", PsSyslogDisable},
+ {"SyslogEnable", PsSyslogEnable},
+ {"ConnectionList", PsConnectionList},
+ {"ConnectionGet", PsConnectionGet},
+ {"ConnectionDisconnect", PsConnectionDisconnect},
+ {"BridgeDeviceList", PsBridgeDeviceList},
+ {"BridgeList", PsBridgeList},
+ {"BridgeCreate", PsBridgeCreate},
+ {"BridgeDelete", PsBridgeDelete},
+ {"Caps", PsCaps},
+ {"Reboot", PsReboot},
+ {"ConfigGet", PsConfigGet},
+ {"ConfigSet", PsConfigSet},
+ {"RouterList", PsRouterList},
+ {"RouterAdd", PsRouterAdd},
+ {"RouterDelete", PsRouterDelete},
+ {"RouterStart", PsRouterStart},
+ {"RouterStop", PsRouterStop},
+ {"RouterIfList", PsRouterIfList},
+ {"RouterIfAdd", PsRouterIfAdd},
+ {"RouterIfDel", PsRouterIfDel},
+ {"RouterTableList", PsRouterTableList},
+ {"RouterTableAdd", PsRouterTableAdd},
+ {"RouterTableDel", PsRouterTableDel},
+ {"LogFileList", PsLogFileList},
+ {"LogFileGet", PsLogFileGet},
+ {"HubCreate", PsHubCreate},
+ {"HubCreateDynamic", PsHubCreateDynamic},
+ {"HubCreateStatic", PsHubCreateStatic},
+ {"HubDelete", PsHubDelete},
+ {"HubSetStatic", PsHubSetStatic},
+ {"HubSetDynamic", PsHubSetDynamic},
+ {"HubList", PsHubList},
+ {"Hub", PsHub},
+ {"Online", PsOnline},
+ {"Offline", PsOffline},
+ {"SetMaxSession", PsSetMaxSession},
+ {"SetHubPassword", PsSetHubPassword},
+ {"SetEnumAllow", PsSetEnumAllow},
+ {"SetEnumDeny", PsSetEnumDeny},
+ {"OptionsGet", PsOptionsGet},
+ {"RadiusServerSet", PsRadiusServerSet},
+ {"RadiusServerDelete", PsRadiusServerDelete},
+ {"RadiusServerGet", PsRadiusServerGet},
+ {"StatusGet", PsStatusGet},
+ {"LogGet", PsLogGet},
+ {"LogEnable", PsLogEnable},
+ {"LogDisable", PsLogDisable},
+ {"LogSwitchSet", PsLogSwitchSet},
+ {"LogPacketSaveType", PsLogPacketSaveType},
+ {"CAList", PsCAList},
+ {"CAAdd", PsCAAdd},
+ {"CADelete", PsCADelete},
+ {"CAGet", PsCAGet},
+ {"CascadeList", PsCascadeList},
+ {"CascadeCreate", PsCascadeCreate},
+ {"CascadeSet", PsCascadeSet},
+ {"CascadeGet", PsCascadeGet},
+ {"CascadeDelete", PsCascadeDelete},
+ {"CascadeUsernameSet", PsCascadeUsernameSet},
+ {"CascadeAnonymousSet", PsCascadeAnonymousSet},
+ {"CascadePasswordSet", PsCascadePasswordSet},
+ {"CascadeCertSet", PsCascadeCertSet},
+ {"CascadeCertGet", PsCascadeCertGet},
+ {"CascadeEncryptEnable", PsCascadeEncryptEnable},
+ {"CascadeEncryptDisable", PsCascadeEncryptDisable},
+ {"CascadeCompressEnable", PsCascadeCompressEnable},
+ {"CascadeCompressDisable", PsCascadeCompressDisable},
+ {"CascadeProxyNone", PsCascadeProxyNone},
+ {"CascadeProxyHttp", PsCascadeProxyHttp},
+ {"CascadeProxySocks", PsCascadeProxySocks},
+ {"CascadeServerCertEnable", PsCascadeServerCertEnable},
+ {"CascadeServerCertDisable", PsCascadeServerCertDisable},
+ {"CascadeServerCertSet", PsCascadeServerCertSet},
+ {"CascadeServerCertDelete", PsCascadeServerCertDelete},
+ {"CascadeServerCertGet", PsCascadeServerCertGet},
+ {"CascadeDetailSet", PsCascadeDetailSet},
+ {"CascadePolicySet", PsCascadePolicySet},
+ {"PolicyList", PsPolicyList},
+ {"CascadeStatusGet", PsCascadeStatusGet},
+ {"CascadeRename", PsCascadeRename},
+ {"CascadeOnline", PsCascadeOnline},
+ {"CascadeOffline", PsCascadeOffline},
+ {"AccessAdd", PsAccessAdd},
+ {"AccessAddEx", PsAccessAddEx},
+ {"AccessAdd6", PsAccessAdd6},
+ {"AccessAddEx6", PsAccessAddEx6},
+ {"AccessList", PsAccessList},
+ {"AccessDelete", PsAccessDelete},
+ {"AccessEnable", PsAccessEnable},
+ {"AccessDisable", PsAccessDisable},
+ {"UserList", PsUserList},
+ {"UserCreate", PsUserCreate},
+ {"UserSet", PsUserSet},
+ {"UserDelete", PsUserDelete},
+ {"UserGet", PsUserGet},
+ {"UserAnonymousSet", PsUserAnonymousSet},
+ {"UserPasswordSet", PsUserPasswordSet},
+ {"UserCertSet", PsUserCertSet},
+ {"UserCertGet", PsUserCertGet},
+ {"UserSignedSet", PsUserSignedSet},
+ {"UserRadiusSet", PsUserRadiusSet},
+ {"UserNTLMSet", PsUserNTLMSet},
+ {"UserPolicyRemove", PsUserPolicyRemove},
+ {"UserPolicySet", PsUserPolicySet},
+ {"UserExpiresSet", PsUserExpiresSet},
+ {"GroupList", PsGroupList},
+ {"GroupCreate", PsGroupCreate},
+ {"GroupSet", PsGroupSet},
+ {"GroupDelete", PsGroupDelete},
+ {"GroupGet", PsGroupGet},
+ {"GroupJoin", PsGroupJoin},
+ {"GroupUnjoin", PsGroupUnjoin},
+ {"GroupPolicyRemove", PsGroupPolicyRemove},
+ {"GroupPolicySet", PsGroupPolicySet},
+ {"SessionList", PsSessionList},
+ {"SessionGet", PsSessionGet},
+ {"SessionDisconnect", PsSessionDisconnect},
+ {"MacTable", PsMacTable},
+ {"MacDelete", PsMacDelete},
+ {"IpTable", PsIpTable},
+ {"IpDelete", PsIpDelete},
+ {"SecureNatEnable", PsSecureNatEnable},
+ {"SecureNatDisable", PsSecureNatDisable},
+ {"SecureNatStatusGet", PsSecureNatStatusGet},
+ {"SecureNatHostGet", PsSecureNatHostGet},
+ {"SecureNatHostSet", PsSecureNatHostSet},
+ {"NatGet", PsNatGet},
+ {"NatEnable", PsNatEnable},
+ {"NatDisable", PsNatDisable},
+ {"NatSet", PsNatSet},
+ {"NatTable", PsNatTable},
+ {"DhcpGet", PsDhcpGet},
+ {"DhcpEnable", PsDhcpEnable},
+ {"DhcpDisable", PsDhcpDisable},
+ {"DhcpSet", PsDhcpSet},
+ {"DhcpTable", PsDhcpTable},
+ {"AdminOptionList", PsAdminOptionList},
+ {"AdminOptionSet", PsAdminOptionSet},
+ {"ExtOptionList", PsExtOptionList},
+ {"ExtOptionSet", PsExtOptionSet},
+ {"CrlList", PsCrlList},
+ {"CrlAdd", PsCrlAdd},
+ {"CrlDel", PsCrlDel},
+ {"CrlGet", PsCrlGet},
+ {"AcList", PsAcList},
+ {"AcAdd", PsAcAdd},
+ {"AcAdd6", PsAcAdd6},
+ {"AcDel", PsAcDel},
+ {"MakeCert", PtMakeCert},
+ {"TrafficClient", PtTrafficClient},
+ {"TrafficServer", PtTrafficServer},
+ {"LicenseAdd", PsLicenseAdd},
+ {"LicenseDel", PsLicenseDel},
+ {"LicenseList", PsLicenseList},
+ {"LicenseStatus", PsLicenseStatus},
+ {"IPsecEnable", PsIPsecEnable},
+ {"IPsecGet", PsIPsecGet},
+ {"EtherIpClientAdd", PsEtherIpClientAdd},
+ {"EtherIpClientDelete", PsEtherIpClientDelete},
+ {"EtherIpClientList", PsEtherIpClientList},
+ {"OpenVpnEnable", PsOpenVpnEnable},
+ {"OpenVpnGet", PsOpenVpnGet},
+ {"OpenVpnMakeConfig", PsOpenVpnMakeConfig},
+ {"SstpEnable", PsSstpEnable},
+ {"SstpGet", PsSstpGet},
+ {"ServerCertRegenerate", PsServerCertRegenerate},
+ {"VpnOverIcmpDnsEnable", PsVpnOverIcmpDnsEnable},
+ {"VpnOverIcmpDnsGet", PsVpnOverIcmpDnsGet},
+ {"DynamicDnsGetStatus", PsDynamicDnsGetStatus},
+ {"DynamicDnsSetHostname", PsDynamicDnsSetHostname},
+ {"VpnAzureGetStatus", PsVpnAzureGetStatus},
+ {"VpnAzureSetEnable", PsVpnAzureSetEnable},
+ };
+
+ // Generate a prompt
+ if (ps->HubName == NULL)
+ {
+ Format(prompt, sizeof(prompt), "VPN Server>");
+ }
+ else
+ {
+ Format(prompt, sizeof(prompt), "VPN Server/%s>", ps->HubName);
+ }
+
+ if (DispatchNextCmdEx(ps->Console, ps->CmdLine, prompt, cmd, sizeof(cmd) / sizeof(cmd[0]), ps) == false)
+ {
+ break;
+ }
+ ps->LastError = ps->Console->RetCode;
+
+ if (ps->LastError == ERR_NO_ERROR && ps->Console->ConsoleType != CONSOLE_CSV)
+ {
+ ps->Console->Write(ps->Console, _UU("CMD_MSG_OK"));
+ ps->Console->Write(ps->Console, L"");
+ }
+
+ if (ps->CmdLine != NULL)
+ {
+ break;
+ }
+ }
+
+ // Release the Caps
+ FreeCapsList(ps->CapsList);
+ ps->CapsList = NULL;
+}
+
+// A template for a new command function
+UINT PsXxx(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_LISTENER t;
+ PARAM args[] =
+ {
+ {"[port]", CmdPromptPort, _UU("CMD_ListenerCreate_PortPrompt"), CmdEvalPort, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.Enable = true;
+ t.Port = ToInt(GetParamStr(o, "[port]"));
+
+ ret = ScCreateListener(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set to the stand-alone mode
+UINT PsClusterSettingStandalone(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_FARM t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.ServerType = SERVER_TYPE_STANDALONE;
+
+ // RPC call
+ ret = ScSetFarmSetting(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set to the cluster controller mode
+UINT PsClusterSettingController(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_FARM t;
+ UINT weight;
+ PARAM args[] =
+ {
+ {"WEIGHT", NULL, NULL, NULL, NULL},
+ {"ONLY", NULL, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ weight = GetParamInt(o, "WEIGHT");
+ if (weight == 0)
+ {
+ weight = FARM_DEFAULT_WEIGHT;
+ }
+
+ Zero(&t, sizeof(t));
+ t.ServerType = SERVER_TYPE_FARM_CONTROLLER;
+ t.Weight = weight;
+ t.ControllerOnly = GetParamYes(o, "ONLY");
+
+ // RPC call
+ ret = ScSetFarmSetting(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Evaluate the IP address
+bool CmdEvalIp(CONSOLE *c, wchar_t *str, void *param)
+{
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ if (UniIsEmptyStr(str))
+ {
+ return true;
+ }
+
+ if (UniStrToIP32(str) == 0 && UniStrCmpi(str, L"0.0.0.0") != 0)
+ {
+ wchar_t *msg = (param == NULL) ? _UU("CMD_IP_EVAL_FAILED") : (wchar_t *)param;
+ c->Write(c, msg);
+ return false;
+ }
+
+ return true;
+}
+
+// Convert a string to port list
+LIST *StrToPortList(char *str)
+{
+ LIST *o;
+ TOKEN_LIST *t;
+ UINT i;
+ if (str == NULL)
+ {
+ return NULL;
+ }
+
+ // Convert to token
+ t = ParseToken(str, ", ");
+ if (t == NULL)
+ {
+ return NULL;
+ }
+ if (t->NumTokens == 0)
+ {
+ FreeToken(t);
+ return NULL;
+ }
+
+ o = NewListFast(NULL);
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ char *s = t->Token[i];
+ UINT n;
+ if (IsNum(s) == false)
+ {
+ ReleaseList(o);
+ FreeToken(t);
+ return NULL;
+ }
+ n = ToInt(s);
+ if (n == 0 || n >= 65536)
+ {
+ ReleaseList(o);
+ FreeToken(t);
+ return NULL;
+ }
+ if (IsInList(o, (void *)n))
+ {
+ ReleaseList(o);
+ FreeToken(t);
+ return NULL;
+ }
+ Add(o, (void *)n);
+ }
+
+ FreeToken(t);
+
+ if (LIST_NUM(o) > MAX_PUBLIC_PORT_NUM)
+ {
+ ReleaseList(o);
+ return NULL;
+ }
+
+ return o;
+}
+
+// Set to the cluster member mode
+UINT PsClusterSettingMember(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_FARM t;
+ char *host_and_port;
+ char *host;
+ UINT port;
+ UINT weight;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[server:port]", CmdPrompt, _UU("CMD_ClusterSettingMember_Prompt_HOST_1"), CmdEvalHostAndPort, NULL},
+ {"IP", PsClusterSettingMemberPromptIp, NULL, CmdEvalIp, NULL},
+ {"PORTS", PsClusterSettingMemberPromptPorts, NULL, CmdEvalPortList, NULL},
+ {"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+ {"WEIGHT", NULL, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ weight = GetParamInt(o, "WEIGHT");
+
+ if (weight == 0)
+ {
+ weight = FARM_DEFAULT_WEIGHT;
+ }
+
+ Zero(&t, sizeof(t));
+ host_and_port = GetParamStr(o, "[server:port]");
+ if (ParseHostPort(host_and_port, &host, &port, 0))
+ {
+ char *pw;
+ char *ports_str;
+ LIST *ports;
+ UINT i;
+
+ StrCpy(t.ControllerName, sizeof(t.ControllerName), host);
+ t.ControllerPort = port;
+ Free(host);
+
+ pw = GetParamStr(o, "PASSWORD");
+
+ Hash(t.MemberPassword, pw, StrLen(pw), true);
+ t.PublicIp = StrToIP32(GetParamStr(o, "IP"));
+ t.ServerType = SERVER_TYPE_FARM_MEMBER;
+
+ ports_str = GetParamStr(o, "PORTS");
+
+ ports = StrToPortList(ports_str);
+
+ t.NumPort = LIST_NUM(ports);
+ t.Ports = ZeroMalloc(sizeof(UINT) * t.NumPort);
+
+ for (i = 0;i < t.NumPort;i++)
+ {
+ t.Ports[i] = (UINT)LIST_DATA(ports, i);
+ }
+
+ t.Weight = weight;
+
+ ReleaseList(ports);
+
+ // RPC call
+ ret = ScSetFarmSetting(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcFarm(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Evaluate the port list
+bool CmdEvalPortList(CONSOLE *c, wchar_t *str, void *param)
+{
+ char *s;
+ bool ret = false;
+ LIST *o;
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ s = CopyUniToStr(str);
+
+ o = StrToPortList(s);
+
+ if (o != NULL)
+ {
+ ret = true;
+ }
+
+ ReleaseList(o);
+
+ Free(s);
+
+ if (ret == false)
+ {
+ c->Write(c, _UU("CMD_PORTLIST_EVAL_FAILED"));
+ }
+
+ return ret;
+}
+
+// Check the string of the form of the host name and port number
+bool CmdEvalHostAndPort(CONSOLE *c, wchar_t *str, void *param)
+{
+ char *tmp;
+ bool ret = false;
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ tmp = CopyUniToStr(str);
+
+ ret = ParseHostPort(tmp, NULL, NULL, (UINT)param);
+
+ if (ret == false)
+ {
+ c->Write(c, param == NULL ? _UU("CMD_HOSTPORT_EVAL_FAILED") : (wchar_t *)param);
+ }
+
+ Free(tmp);
+
+ return ret;
+}
+
+// Input the public port number
+wchar_t *PsClusterSettingMemberPromptPorts(CONSOLE *c, void *param)
+{
+ wchar_t *ret;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ c->Write(c, _UU("CMD_ClusterSettingMember_Prompt_PORT_1"));
+ c->Write(c, L"");
+
+ ret = c->ReadLine(c, _UU("CMD_ClusterSettingMember_Prompt_PORT_2"), true);
+
+ return ret;
+}
+
+// Input the public IP address
+wchar_t *PsClusterSettingMemberPromptIp(CONSOLE *c, void *param)
+{
+ wchar_t *ret;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ c->Write(c, _UU("CMD_ClusterSettingMember_Prompt_IP_1"));
+ c->Write(c, L"");
+
+ ret = c->ReadLine(c, _UU("CMD_ClusterSettingMember_Prompt_IP_2"), true);
+
+ return ret;
+}
+
+// Show the cluster members list
+UINT PsClusterMemberList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_FARM t;
+ CT *ct;
+ UINT i;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScEnumFarmMember(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNew();
+
+ CtInsertColumn(ct, _UU("CMD_ID"), true);
+ CtInsertColumn(ct, _UU("SM_FM_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_FM_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_FM_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_FM_COLUMN_4"), true);
+ CtInsertColumn(ct, _UU("SM_FM_COLUMN_5"), true);
+ CtInsertColumn(ct, _UU("SM_FM_COLUMN_6"), true);
+ CtInsertColumn(ct, _UU("SM_FM_COLUMN_7"), true);
+ CtInsertColumn(ct, _UU("SM_FM_COLUMN_8"), true);
+ CtInsertColumn(ct, _UU("SM_FM_COLUMN_9"), true);
+
+ for (i = 0;i < t.NumFarm;i++)
+ {
+ RPC_ENUM_FARM_ITEM *e = &t.Farms[i];
+ wchar_t tmp0[64];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[64];
+ wchar_t tmp4[64];
+ wchar_t tmp5[64];
+ wchar_t tmp6[64];
+ wchar_t tmp7[64];
+ wchar_t tmp8[64];
+
+ GetDateTimeStrEx64(tmp1, sizeof(tmp1), SystemToLocal64(e->ConnectedTime), NULL);
+ StrToUni(tmp2, sizeof(tmp2), e->Hostname);
+ UniToStru(tmp3, e->Point);
+ UniToStru(tmp4, e->NumSessions);
+ UniToStru(tmp5, e->NumTcpConnections);
+ UniToStru(tmp6, e->NumHubs);
+ UniToStru(tmp7, e->AssignedClientLicense);
+ UniToStru(tmp8, e->AssignedBridgeLicense);
+
+ UniToStru(tmp0, e->Id);
+
+ CtInsert(ct, tmp0,
+ e->Controller ? _UU("SM_FM_CONTROLLER") : _UU("SM_FM_MEMBER"),
+ tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8);
+ }
+
+ CtFree(ct, c);
+
+ FreeRpcEnumFarm(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get information of cluster members
+UINT PsClusterMemberInfoGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_FARM_INFO t;
+ CT *ct;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_ClusterMemberInfoGet_PROMPT_ID"), NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.Id = UniToInt(GetParamUniStr(o, "[id]"));
+
+ // RPC call
+ ret = ScGetFarmInfo(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNewStandard();
+
+ {
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+ UINT i;
+
+ CtInsert(ct, _UU("SM_FMINFO_TYPE"),
+ t.Controller ? _UU("SM_FARM_CONTROLLER") : _UU("SM_FARM_MEMBER"));
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.ConnectedTime), NULL);
+ CtInsert(ct, _UU("SM_FMINFO_CONNECT_TIME"), tmp);
+
+ IPToStr32(str, sizeof(str), t.Ip);
+ StrToUni(tmp, sizeof(tmp), str);
+ CtInsert(ct, _UU("SM_FMINFO_IP"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.Hostname);
+ CtInsert(ct, _UU("SM_FMINFO_HOSTNAME"), tmp);
+
+ UniToStru(tmp, t.Point);
+ CtInsert(ct, _UU("SM_FMINFO_POINT"), tmp);
+
+ UniToStru(tmp, t.Weight);
+ CtInsert(ct, _UU("SM_FMINFO_WEIGHT"), tmp);
+
+ UniToStru(tmp, t.NumPort);
+ CtInsert(ct, _UU("SM_FMINFO_NUM_PORT"), tmp);
+
+ for (i = 0;i < t.NumPort;i++)
+ {
+ wchar_t tmp2[MAX_SIZE];
+ UniFormat(tmp, sizeof(tmp), _UU("SM_FMINFO_PORT"), i + 1);
+ UniToStru(tmp2, t.Ports[i]);
+ CtInsert(ct, tmp, tmp2);
+ }
+
+ UniToStru(tmp, t.NumFarmHub);
+ CtInsert(ct, _UU("SM_FMINFO_NUM_HUB"), tmp);
+
+ for (i = 0;i < t.NumFarmHub;i++)
+ {
+ wchar_t tmp2[MAX_SIZE];
+ UniFormat(tmp, sizeof(tmp), _UU("SM_FMINFO_HUB"), i + 1);
+ UniFormat(tmp2, sizeof(tmp2),
+ t.FarmHubs[i].DynamicHub ? _UU("SM_FMINFO_HUB_TAG_2") : _UU("SM_FMINFO_HUB_TAG_1"),
+ t.FarmHubs[i].HubName);
+ CtInsert(ct, tmp, tmp2);
+ }
+
+ UniToStru(tmp, t.NumSessions);
+ CtInsert(ct, _UU("SM_FMINFO_NUM_SESSION"), tmp);
+
+ UniToStru(tmp, t.NumTcpConnections);
+ CtInsert(ct, _UU("SM_FMINFO_NUN_CONNECTION"), tmp);
+ }
+
+ CtFree(ct, c);
+
+ FreeRpcFarmInfo(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get certificates of cluster members
+UINT PsClusterMemberCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_FARM_INFO t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_ClusterMemberCertGet_PROMPT_ID"), NULL, NULL},
+ {"SAVECERT", CmdPrompt, _UU("CMD_SAVECERTPATH"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ t.Id = UniToInt(GetParamUniStr(o, "[id]"));
+
+ // RPC call
+ ret = ScGetFarmInfo(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ X *x = t.ServerCert;
+ wchar_t *filename = GetParamUniStr(o, "SAVECERT");
+
+ if (XToFileW(x, filename, true) == false)
+ {
+ c->Write(c, _UU("CMD_SAVECERT_FAILED"));
+
+ ret = ERR_INTERNAL_ERROR;
+ }
+ }
+
+ FreeRpcFarmInfo(&t);
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the status of the connection to the cluster controller
+UINT PsClusterConnectionStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_FARM_CONNECTION_STATUS t;
+ wchar_t tmp[MAX_SIZE];
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetFarmConnectionStatus(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNewStandard();
+ char str[MAX_SIZE];
+
+ if (t.Online == false)
+ {
+ CtInsert(ct, _UU("SM_FC_IP"), _UU("SM_FC_NOT_CONNECTED"));
+
+ CtInsert(ct, _UU("SM_FC_PORT"), _UU("SM_FC_NOT_CONNECTED"));
+ }
+ else
+ {
+ IPToStr32(str, sizeof(str), t.Ip);
+ StrToUni(tmp, sizeof(tmp), str);
+ CtInsert(ct, _UU("SM_FC_IP"), tmp);
+
+ UniToStru(tmp, t.Port);
+ CtInsert(ct, _UU("SM_FC_PORT"), tmp);
+ }
+
+ CtInsert(ct,
+ _UU("SM_FC_STATUS"),
+ t.Online ? _UU("SM_FC_ONLINE") : _UU("SM_FC_OFFLINE"));
+
+ if (t.Online == false)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SM_FC_ERROR_TAG"), _E(t.LastError), t.LastError);
+ CtInsert(ct,
+ _UU("SM_FC_LAST_ERROR"), tmp);
+ }
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.StartedTime), NULL);
+ CtInsert(ct, _UU("SM_FC_START_TIME"), tmp);
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.FirstConnectedTime), NULL);
+ CtInsert(ct, _UU("SM_FC_FIRST_TIME"), tmp);
+
+ //if (t.Online == false)
+ {
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.CurrentConnectedTime), NULL);
+ CtInsert(ct, _UU("SM_FC_CURRENT_TIME"), tmp);
+ }
+
+ UniToStru(tmp, t.NumTry);
+ CtInsert(ct, _UU("SM_FC_NUM_TRY"), tmp);
+
+ UniToStru(tmp, t.NumConnected);
+ CtInsert(ct, _UU("SM_FC_NUM_CONNECTED"), tmp);
+
+ UniToStru(tmp, t.NumFailed);
+ CtInsert(ct, _UU("SM_FC_NUM_FAILED"), tmp);
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the SSL certificate of the VPN Server
+UINT PsServerCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_KEY_PAIR t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[cert]", CmdPrompt, _UU("CMD_SAVECERTPATH"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetServerCert(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ if (XToFileW(t.Cert, GetParamUniStr(o, "[cert]"), true) == false)
+ {
+ c->Write(c, _UU("CMD_SAVECERT_FAILED"));
+ }
+
+ FreeRpcKeyPair(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the private key of the SSL certificate of the VPN Server
+UINT PsServerKeyGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_KEY_PAIR t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[key]", CmdPrompt, _UU("CMD_SAVEKEYPATH"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetServerCert(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ if (t.Key != NULL)
+ {
+ if (KToFileW(t.Key, GetParamUniStr(o, "[key]"), true, NULL) == false)
+ {
+ c->Write(c, _UU("CMD_SAVEKEY_FAILED"));
+ }
+ }
+ else
+ {
+ ret = ERR_NOT_ENOUGH_RIGHT;
+ CmdPrintError(c, ret);
+ }
+
+ FreeRpcKeyPair(&t);
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Read the certificate and the private key
+bool CmdLoadCertAndKey(CONSOLE *c, X **xx, K **kk, wchar_t *cert_filename, wchar_t *key_filename)
+{
+ X *x;
+ K *k;
+ // Validate arguments
+ if (c == NULL || cert_filename == NULL || key_filename == NULL || xx == NULL || kk == NULL)
+ {
+ return false;
+ }
+
+ x = FileToXW(cert_filename);
+ if (x == NULL)
+ {
+ c->Write(c, _UU("CMD_LOADCERT_FAILED"));
+ return false;
+ }
+
+ k = CmdLoadKey(c, key_filename);
+ if (k == NULL)
+ {
+ c->Write(c, _UU("CMD_LOADKEY_FAILED"));
+ FreeX(x);
+ return false;
+ }
+
+ if (CheckXandK(x, k) == false)
+ {
+ c->Write(c, _UU("CMD_KEYPAIR_FAILED"));
+ FreeX(x);
+ FreeK(k);
+
+ return false;
+ }
+
+ *xx = x;
+ *kk = k;
+
+ return true;
+}
+
+// Read the secret key
+K *CmdLoadKey(CONSOLE *c, wchar_t *filename)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || filename == NULL)
+ {
+ return NULL;
+ }
+
+ b = ReadDumpW(filename);
+ if (b == NULL)
+ {
+ c->Write(c, _UU("CMD_LOADCERT_FAILED"));
+ return NULL;
+ }
+ else
+ {
+ K *key;
+ if (IsEncryptedK(b, true) == false)
+ {
+ key = BufToK(b, true, IsBase64(b), NULL);
+ }
+ else
+ {
+ c->Write(c, _UU("CMD_LOADKEY_ENCRYPTED_1"));
+
+ while (true)
+ {
+ char *pass = c->ReadPassword(c, _UU("CMD_LOADKEY_ENCRYPTED_2"));
+
+ if (pass == NULL)
+ {
+ FreeBuf(b);
+ return NULL;
+ }
+
+ key = BufToK(b, true, IsBase64(b), pass);
+ Free(pass);
+
+ if (key != NULL)
+ {
+ break;
+ }
+
+ c->Write(c, _UU("CMD_LOADKEY_ENCRYPTED_3"));
+ }
+ }
+
+ FreeBuf(b);
+
+ return key;
+ }
+}
+
+// Set the SSL certificate and the private key of the VPN Server
+UINT PsServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_KEY_PAIR t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL},
+ {"LOADKEY", CmdPrompt, _UU("CMD_LOADKEYPATH"), CmdEvalIsFile, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ if (CmdLoadCertAndKey(c, &t.Cert, &t.Key,
+ GetParamUniStr(o, "LOADCERT"),
+ GetParamUniStr(o, "LOADKEY")))
+ {
+ // RPC call
+ ret = ScSetServerCert(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcKeyPair(&t);
+ }
+ else
+ {
+ ret = ERR_INTERNAL_ERROR;
+ }
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the encryption algorithm used for the VPN communication
+UINT PsServerCipherGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_STR t;
+ TOKEN_LIST *ciphers;
+ UINT i;
+ wchar_t tmp[MAX_SIZE];
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetServerCipher(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ciphers = GetCipherList();
+
+ c->Write(c, _UU("CMD_ServerCipherGet_SERVER"));
+
+ UniFormat(tmp, sizeof(tmp), L" %S", t.String);
+ c->Write(c, tmp);
+
+ c->Write(c, L"");
+ c->Write(c, _UU("CMD_ServerCipherGet_CIPHERS"));
+
+ for (i = 0;i < ciphers->NumTokens;i++)
+ {
+ UniFormat(tmp, sizeof(tmp), L" %S", ciphers->Token[i]);
+ c->Write(c, tmp);
+ }
+
+ FreeRpcStr(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the encryption algorithm used for the VPN communication
+UINT PsServerCipherSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_STR t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_ServerCipherSet_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.String = CopyStr(GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScSetServerCipher(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcStr(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enabling the maintenance function of the Internet connection
+UINT PsKeepEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_KEEP t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetKeep(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ t.UseKeepConnect = true;
+
+ ret = ScSetKeep(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disabling the maintenance function of the Internet connection
+UINT PsKeepDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_KEEP t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetKeep(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ t.UseKeepConnect = false;
+
+ ret = ScSetKeep(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Evaluate the UDP or the TCP
+bool CmdEvalTcpOrUdp(CONSOLE *c, wchar_t *str, void *param)
+{
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ if (UniStrCmpi(str, L"tcp") == 0 || UniStrCmpi(str, L"udp") == 0)
+ {
+ return true;
+ }
+
+ c->Write(c, _UU("CMD_KeepSet_EVAL_TCP_UDP"));
+
+ return false;
+}
+
+// Enable the syslog configuration
+UINT PsSyslogEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ SYSLOG_SETTING t;
+ CMD_EVAL_MIN_MAX minmax = {"CMD_SyslogEnable_MINMAX", 1, 3};
+ char *host;
+ UINT port;
+
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[1|2|3]", CmdPrompt, _UU("CMD_SyslogEnable_Prompt_123"), CmdEvalMinMax, &minmax},
+ {"HOST", CmdPrompt, _UU("CMD_SyslogEnable_Prompt_HOST"), CmdEvalHostAndPort, (void *)SYSLOG_PORT},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ if (ParseHostPort(GetParamStr(o, "HOST"), &host, &port, SYSLOG_PORT))
+ {
+ StrCpy(t.Hostname, sizeof(t.Hostname), host);
+ t.Port = port;
+ t.SaveType = GetParamInt(o, "[1|2|3]");
+
+ Free(host);
+
+ // RPC call
+ ret = ScSetSysLog(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disable the syslog configuration
+UINT PsSyslogDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ SYSLOG_SETTING t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetSysLog(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ t.SaveType = SYSLOG_NONE;
+
+ // RPC call
+ ret = ScSetSysLog(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the syslog configuration
+UINT PsSyslogGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ SYSLOG_SETTING t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetSysLog(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ CT *ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_SyslogGet_COLUMN_1"), GetSyslogSettingName(t.SaveType));
+
+ if (t.SaveType != SYSLOG_NONE)
+ {
+ StrToUni(tmp, sizeof(tmp), t.Hostname);
+ CtInsert(ct, _UU("CMD_SyslogGet_COLUMN_2"), tmp);
+
+ UniToStru(tmp, t.Port);
+ CtInsert(ct, _UU("CMD_SyslogGet_COLUMN_3"), tmp);
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the syslog configuration name
+wchar_t *GetSyslogSettingName(UINT n)
+{
+ char tmp[MAX_PATH];
+
+ Format(tmp, sizeof(tmp), "SM_SYSLOG_%u", n);
+
+ return _UU(tmp);
+}
+
+// Setting of maintenance function of the Internet connection
+UINT PsKeepSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_KEEP t;
+ char *host;
+ UINT port;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"HOST", CmdPrompt, _UU("CMD_KeepSet_PROMPT_HOST"), CmdEvalHostAndPort, NULL},
+ {"PROTOCOL", CmdPrompt, _UU("CMD_KeepSet_PROMPT_PROTOCOL"), CmdEvalTcpOrUdp, NULL},
+ {"INTERVAL", CmdPrompt, _UU("CMD_KeepSet_PROMPT_INTERVAL"), NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetKeep(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ if (ParseHostPort(GetParamStr(o, "HOST"), &host, &port, 0))
+ {
+ StrCpy(t.KeepConnectHost, sizeof(t.KeepConnectHost), host);
+ t.KeepConnectPort = port;
+ t.KeepConnectInterval = GetParamInt(o, "INTERVAL");
+ t.KeepConnectProtocol = (StrCmpi(GetParamStr(o, "PROTOCOL"), "tcp") == 0) ? 0 : 1;
+ Free(host);
+
+ // RPC call
+ ret = ScSetKeep(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the maintenance function of the Internet connection
+UINT PsKeepGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_KEEP t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetKeep(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ CT *ct = CtNewStandard();
+
+ StrToUni(tmp, sizeof(tmp), t.KeepConnectHost);
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_1"), tmp);
+
+ UniToStru(tmp, t.KeepConnectPort);
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_2"), tmp);
+
+ UniToStru(tmp, t.KeepConnectInterval);
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_3"), tmp);
+
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_4"),
+ t.KeepConnectProtocol == 0 ? L"TCP/IP" : L"UDP/IP");
+
+ CtInsert(ct, _UU("CMD_KeepGet_COLUMN_5"),
+ t.UseKeepConnect ? _UU("SM_ACCESS_ENABLE") : _UU("SM_ACCESS_DISABLE"));
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the connection type string
+wchar_t *GetConnectionTypeStr(UINT type)
+{
+ char tmp[MAX_SIZE];
+ Format(tmp, sizeof(tmp), "SM_CONNECTION_TYPE_%u", type);
+
+ return _UU(tmp);
+}
+
+// Get the list of TCP connections connected to VPN Server
+UINT PsConnectionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_CONNECTION t;
+ UINT i;
+ CT *ct;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScEnumConnection(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNew();
+ CtInsertColumn(ct, _UU("SM_CONN_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_CONN_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_CONN_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_CONN_COLUMN_4"), false);
+
+ for (i = 0;i < t.NumConnection;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ wchar_t name[MAX_SIZE];
+ wchar_t datetime[MAX_SIZE];
+ RPC_ENUM_CONNECTION_ITEM *e = &t.Connections[i];
+
+ StrToUni(name, sizeof(name), e->Name);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_HOSTNAME_AND_PORT"), e->Hostname, e->Port);
+ GetDateTimeStrEx64(datetime, sizeof(datetime), SystemToLocal64(e->ConnectedTime), NULL);
+
+ CtInsert(ct, name, tmp, datetime,
+ GetConnectionTypeStr(e->Type));
+ }
+
+ CtFree(ct, c);
+
+ FreeRpcEnumConnetion(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the TCP connection information currently connected to the VPN Server
+UINT PsConnectionGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CONNECTION_INFO t;
+ CT *ct;
+ wchar_t tmp[MAX_SIZE];
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_ConnectionGet_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetConnectionInfo(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ ct = CtNewStandard();
+
+ StrToUni(tmp, sizeof(tmp), t.Name);
+ CtInsert(ct, _UU("SM_CONNINFO_NAME"), tmp);
+
+ CtInsert(ct, _UU("SM_CONNINFO_TYPE"), GetConnectionTypeStr(t.Type));
+
+ StrToUni(tmp, sizeof(tmp), t.Hostname);
+ CtInsert(ct, _UU("SM_CONNINFO_HOSTNAME"), tmp);
+
+ UniToStru(tmp, t.Port);
+ CtInsert(ct, _UU("SM_CONNINFO_PORT"), tmp);
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.ConnectedTime), NULL);
+ CtInsert(ct, _UU("SM_CONNINFO_TIME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.ServerStr);
+ CtInsert(ct, _UU("SM_CONNINFO_SERVER_STR"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), L"%u.%02u", t.ServerVer / 100, t.ServerVer % 100);
+ CtInsert(ct, _UU("SM_CONNINFO_SERVER_VER"), tmp);
+
+ UniToStru(tmp, t.ServerBuild);
+ CtInsert(ct, _UU("SM_CONNINFO_SERVER_BUILD"), tmp);
+
+ if (StrLen(t.ClientStr) != 0)
+ {
+ StrToUni(tmp, sizeof(tmp), t.ClientStr);
+ CtInsert(ct, _UU("SM_CONNINFO_CLIENT_STR"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), L"%u.%02u", t.ClientVer / 100, t.ClientVer % 100);
+ CtInsert(ct, _UU("SM_CONNINFO_CLIENT_VER"), tmp);
+
+ UniToStru(tmp, t.ClientBuild);
+ CtInsert(ct, _UU("SM_CONNINFO_CLIENT_BUILD"), tmp);
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disconnect the TCP connection connected to the VPN Server
+UINT PsConnectionDisconnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_DISCONNECT_CONNECTION t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_ConnectionDisconnect_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScDisconnectConnection(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the LAN card list that can be used for local bridge
+UINT PsBridgeDeviceList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_ETH t;
+ UINT i;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScEnumEthernet(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_ETH_ITEM *item = &t.Items[i];
+ wchar_t tmp[MAX_SIZE * 2];
+
+ StrToUni(tmp, sizeof(tmp), item->DeviceName);
+ c->Write(c, tmp);
+ }
+
+ FreeRpcEnumEth(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the list of local bridge connection
+UINT PsBridgeList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_LOCALBRIDGE t;
+ UINT i;
+ CT *ct;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScEnumLocalBridge(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNew();
+
+ CtInsertColumn(ct, _UU("SM_BRIDGE_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_BRIDGE_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_BRIDGE_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_BRIDGE_COLUMN_4"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_LOCALBRIDGE *e = &t.Items[i];
+ wchar_t name[MAX_SIZE];
+ wchar_t nic[MAX_SIZE];
+ wchar_t hub[MAX_SIZE];
+ wchar_t *status = _UU("SM_BRIDGE_OFFLINE");
+
+ UniToStru(name, i + 1);
+ StrToUni(nic, sizeof(nic), e->DeviceName);
+ StrToUni(hub, sizeof(hub), e->HubName);
+
+ if (e->Online)
+ {
+ status = e->Active ? _UU("SM_BRIDGE_ONLINE") : _UU("SM_BRIDGE_ERROR");
+ }
+
+ CtInsert(ct, name, hub, nic, status);
+ }
+
+ CtFree(ct, c);
+
+ FreeRpcEnumLocalBridge(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Create a local bridge connection
+UINT PsBridgeCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_LOCALBRIDGE t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[hubname]", CmdPrompt, _UU("CMD_BridgeCreate_PROMPT_HUBNAME"), CmdEvalNotEmpty, NULL},
+ {"DEVICE", CmdPrompt, _UU("CMD_BridgeCreate_PROMPT_DEVICE"), CmdEvalNotEmpty, NULL},
+ {"TAP", NULL, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ t.Active = true;
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "DEVICE"));
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[hubname]"));
+ t.Online = true;
+ t.TapMode = GetParamYes(o, "TAP");
+
+ // RPC call
+ ret = ScAddLocalBridge(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ c->Write(c, _UU("SM_BRIDGE_INTEL"));
+ c->Write(c, L"");
+
+ if (GetCapsBool(ps->CapsList, "b_is_in_vm"))
+ {
+ // Message in the case of operating in a VM
+ c->Write(c, _UU("D_SM_VMBRIDGE@CAPTION"));
+ c->Write(c, _UU("D_SM_VMBRIDGE@S_1"));
+ c->Write(c, _UU("D_SM_VMBRIDGE@S_2"));
+ c->Write(c, L"");
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the local bridge connection
+UINT PsBridgeDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_LOCALBRIDGE t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[hubname]", CmdPrompt, _UU("CMD_BridgeDelete_PROMPT_HUBNAME"), CmdEvalNotEmpty, NULL},
+ {"DEVICE", CmdPrompt, _UU("CMD_BridgeDelete_PROMPT_DEVICE"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), GetParamStr(o, "DEVICE"));
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[hubname]"));
+
+ // RPC call
+ ret = ScDeleteLocalBridge(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the list of features and capabilities of the server
+UINT PsCaps(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ CAPSLIST *t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // RPC call
+ t = ScGetCapsEx(ps->Rpc);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ CT *ct;
+
+ ct = CtNewStandard();
+
+ for (i = 0;i < LIST_NUM(t->CapsList);i++)
+ {
+ CAPS *c = LIST_DATA(t->CapsList, i);
+ wchar_t title[MAX_SIZE];
+ char name[256];
+
+ Format(name, sizeof(name), "CT_%s", c->Name);
+
+ UniStrCpy(title, sizeof(title), _UU(name));
+
+ if (UniIsEmptyStr(title))
+ {
+ UniFormat(title, sizeof(title), L"%S", (StrLen(c->Name) >= 2) ? c->Name + 2 : c->Name);
+ }
+
+ if (StartWith(c->Name, "b_"))
+ {
+ bool icon_pass = c->Value == 0 ? false : true;
+ if (StrCmpi(c->Name, "b_must_install_pcap") == 0)
+ {
+ // Reverse only item of WinPcap
+ icon_pass = !icon_pass;
+ }
+ CtInsert(ct, title, c->Value == 0 ? _UU("CAPS_NO") : _UU("CAPS_YES"));
+ }
+ else
+ {
+ wchar_t str[64];
+ UniToStru(str, c->Value);
+ CtInsert(ct, title, str);
+ }
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeCapsList(t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Restart the VPN Server service
+UINT PsReboot(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_TEST t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"RESETCONFIG", NULL, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ t.IntValue = GetParamYes(o, "RESETCONFIG") ? 1 : 0;
+
+ // RPC call
+ ret = ScRebootServer(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcTest(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the current configuration of the VPN Server
+UINT PsConfigGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CONFIG t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[path]", NULL, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetConfig(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t *filename = GetParamUniStr(o, "[path]");
+
+ if (IsEmptyUniStr(filename))
+ {
+ // Display on the screen
+ wchar_t tmp[MAX_SIZE];
+ UINT buf_size;
+ wchar_t *buf;
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_ConfigGet_FILENAME"), t.FileName,
+ StrLen(t.FileData));
+ c->Write(c, tmp);
+ c->Write(c, L"");
+
+ buf_size = CalcUtf8ToUni((BYTE *)t.FileData, StrLen(t.FileData));
+ buf = ZeroMalloc(buf_size + 32);
+
+ Utf8ToUni(buf, buf_size, (BYTE *)t.FileData, StrLen(t.FileData));
+
+ c->Write(c, buf);
+ c->Write(c, L"");
+
+ Free(buf);
+ }
+ else
+ {
+ // Save to the file
+ IO *io = FileCreateW(filename);
+
+ if (io == NULL)
+ {
+ c->Write(c, _UU("CMD_ConfigGet_FILE_SAVE_FAILED"));
+
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ FileWrite(io, t.FileData, StrLen(t.FileData));
+ FileClose(io);
+ }
+ }
+ }
+
+ FreeRpcConfig(&t);
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Write the configuration to the VPN Server
+UINT PsConfigSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CONFIG t;
+ wchar_t *filename;
+ BUF *buf;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[path]", CmdPrompt, _UU("CMD_ConfigSet_PROMPT_PATH"), CmdEvalIsFile, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ filename = GetParamUniStr(o, "[path]");
+
+ buf = ReadDumpW(filename);
+ if (buf == NULL)
+ {
+ c->Write(c, _UU("CMD_ConfigSet_FILE_LOAD_FAILED"));
+ }
+ else
+ {
+ Zero(&t, sizeof(t));
+
+ t.FileData = ZeroMalloc(buf->Size + 1);
+ Copy(t.FileData, buf->Buf, buf->Size);
+ FreeBuf(buf);
+
+ // RPC call
+ ret = ScSetConfig(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcConfig(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the Virtual Layer 3 switch list
+UINT PsRouterList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_L3SW t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScEnumL3Switch(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNew();
+ UINT i;
+
+ CtInsertColumn(ct, _UU("SM_L3_SW_COLUMN1"), false);
+ CtInsertColumn(ct, _UU("SM_L3_SW_COLUMN2"), false);
+ CtInsertColumn(ct, _UU("SM_L3_SW_COLUMN3"), true);
+ CtInsertColumn(ct, _UU("SM_L3_SW_COLUMN4"), true);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_L3SW_ITEM *e = &t.Items[i];
+ wchar_t tmp1[MAX_SIZE], *tmp2, tmp3[64], tmp4[64];
+
+ StrToUni(tmp1, sizeof(tmp1), e->Name);
+ if (e->Active == false)
+ {
+ tmp2 = _UU("SM_L3_SW_ST_F_F");
+ }
+ else if (e->Online == false)
+ {
+ tmp2 = _UU("SM_L3_SW_ST_T_F");
+ }
+ else
+ {
+ tmp2 = _UU("SM_L3_SW_ST_T_T");
+ }
+ UniToStru(tmp3, e->NumInterfaces);
+ UniToStru(tmp4, e->NumTables);
+
+ CtInsert(ct,
+ tmp1, tmp2, tmp3, tmp4);
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeRpcEnumL3Sw(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Define a new virtual layer 3 switch
+UINT PsRouterAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_L3SW t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_RouterAdd_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScAddL3Switch(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the Virtual Layer 3 Switch
+UINT PsRouterDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_L3SW t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_RouterDelete_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScDelL3Switch(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Start the Virtual Layer 3 Switch
+UINT PsRouterStart(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_L3SW t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_RouterStart_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScStartL3Switch(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Stop the Virtual Layer 3 Switch
+UINT PsRouterStop(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_L3SW t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_RouterStop_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScStopL3Switch(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the interface list registered on Virtual Layer 3 Switch
+UINT PsRouterIfList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_L3IF t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_RouterIfList_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScEnumL3If(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ CT *ct = CtNew();
+
+ CtInsertColumn(ct, _UU("SM_L3_SW_IF_COLUMN1"), false);
+ CtInsertColumn(ct, _UU("SM_L3_SW_IF_COLUMN2"), false);
+ CtInsertColumn(ct, _UU("SM_L3_SW_IF_COLUMN3"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_L3IF *e = &t.Items[i];
+
+ IPToUniStr32(tmp1, sizeof(tmp1), e->IpAddress);
+ IPToUniStr32(tmp2, sizeof(tmp2), e->SubnetMask);
+ StrToUni(tmp3, sizeof(tmp3), e->HubName);
+
+ CtInsert(ct, tmp1, tmp2, tmp3);
+ }
+
+
+ CtFree(ct, c);
+ }
+
+ FreeRpcEnumL3If(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Evaluate the IP address and mask
+bool CmdEvalIpAndMask4(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[MAX_SIZE];
+ UINT ip, mask;
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+ if (ParseIpAndMask4(tmp, &ip, &mask) == false)
+ {
+ c->Write(c, _UU("CMD_PARSE_IP_MASK_ERROR_1"));
+ return false;
+ }
+
+ return true;
+}
+bool CmdEvalIpAndMask6(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[MAX_SIZE];
+ IP ip, mask;
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+ if (ParseIpAndMask6(tmp, &ip, &mask) == false)
+ {
+ c->Write(c, _UU("CMD_PARSE_IP_MASK_ERROR_1_6"));
+ return false;
+ }
+
+ return true;
+}
+bool CmdEvalIpAndMask46(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[MAX_SIZE];
+ TOKEN_LIST *t;
+ bool ret = false;
+
+ Zero(tmp, sizeof(tmp));
+ UniToStr(tmp, sizeof(tmp), str);
+
+ t = ParseToken(tmp, "/");
+ if (t == NULL)
+ {
+ return false;
+ }
+
+ if (t->NumTokens >= 1)
+ {
+ Trim(t->Token[0]);
+
+ if (IsIpStr4(t->Token[0]))
+ {
+ ret = CmdEvalIpAndMask4(c, str, param);
+ }
+ else
+ {
+ ret = CmdEvalIpAndMask6(c, str, param);
+ }
+ }
+
+ FreeToken(t);
+
+ return ret;
+}
+
+// Evaluate the network address and the subnet mask
+bool CmdEvalNetworkAndSubnetMask4(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[MAX_SIZE];
+ UINT ip, mask;
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+ if (ParseIpAndSubnetMask4(tmp, &ip, &mask) == false)
+ {
+ c->Write(c, _UU("CMD_PARSE_IP_SUBNET_ERROR_1"));
+ return false;
+ }
+
+ if (IsNetworkAddress32(ip, mask) == false)
+ {
+ c->Write(c, _UU("CMD_PARSE_IP_SUBNET_ERROR_2"));
+ return false;
+ }
+
+ return true;
+}
+bool CmdEvalNetworkAndSubnetMask6(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[MAX_SIZE];
+ IP ip, mask;
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+ if (ParseIpAndSubnetMask6(tmp, &ip, &mask) == false)
+ {
+ c->Write(c, _UU("CMD_PARSE_IP_SUBNET_ERROR_1_6"));
+ return false;
+ }
+
+ if (IsNetworkPrefixAddress6(&ip, &mask) == false)
+ {
+ c->Write(c, _UU("CMD_PARSE_IP_SUBNET_ERROR_3"));
+ return false;
+ }
+
+ return true;
+}
+bool CmdEvalNetworkAndSubnetMask46(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[MAX_SIZE];
+ TOKEN_LIST *t;
+ bool ret = false;
+
+ Zero(tmp, sizeof(tmp));
+ UniToStr(tmp, sizeof(tmp), str);
+
+ t = ParseToken(tmp, "/");
+ if (t == NULL)
+ {
+ return false;
+ }
+
+ if (t->NumTokens >= 1)
+ {
+ Trim(t->Token[0]);
+
+ if (IsIpStr4(t->Token[0]))
+ {
+ ret = CmdEvalNetworkAndSubnetMask4(c, str, param);
+ }
+ else
+ {
+ ret = CmdEvalNetworkAndSubnetMask6(c, str, param);
+ }
+ }
+
+ FreeToken(t);
+
+ return ret;
+}
+
+// Evaluate the IP address and subnet mask
+bool CmdEvalHostAndSubnetMask4(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+ if (ParseIpAndSubnetMask4(tmp, NULL, NULL) == false)
+ {
+ c->Write(c, _UU("CMD_PARSE_IP_SUBNET_ERROR_1"));
+ return false;
+ }
+
+ return true;
+}
+
+// Add a virtual interface to the virtual layer 3 switch
+UINT PsRouterIfAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_L3IF t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_RouterIfAdd_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ {"HUB", CmdPrompt, _UU("CMD_RouterIfAdd_PROMPT_HUB"), CmdEvalNotEmpty, NULL},
+ {"IP", CmdPrompt, _UU("CMD_RouterIfAdd_PROMPT_IP"), CmdEvalHostAndSubnetMask4, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+ ParseIpAndSubnetMask4(GetParamStr(o, "IP"), &t.IpAddress, &t.SubnetMask);
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "HUB"));
+
+ // RPC call
+ ret = ScAddL3If(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the virtual interface of the virtual layer 3 switch
+UINT PsRouterIfDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_L3IF t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_RouterIfAdd_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ {"HUB", CmdPrompt, _UU("CMD_RouterIfAdd_PROMPT_HUB"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "HUB"));
+
+ // RPC call
+ ret = ScDelL3If(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the routing table of the Virtual Layer 3 Switch
+UINT PsRouterTableList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_L3TABLE t;
+ CT *ct;
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_RouterTableList_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScEnumL3Table(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+
+ ct = CtNew();
+
+ CtInsertColumn(ct, _UU("SM_L3_SW_TABLE_COLUMN1"), false);
+ CtInsertColumn(ct, _UU("SM_L3_SW_TABLE_COLUMN2"), false);
+ CtInsertColumn(ct, _UU("SM_L3_SW_TABLE_COLUMN3"), false);
+ CtInsertColumn(ct, _UU("SM_L3_SW_TABLE_COLUMN4"), true);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_L3TABLE *e = &t.Items[i];
+
+ IPToUniStr32(tmp1, sizeof(tmp1), e->NetworkAddress);
+ IPToUniStr32(tmp2, sizeof(tmp2), e->SubnetMask);
+ IPToUniStr32(tmp3, sizeof(tmp3), e->GatewayAddress);
+ UniToStru(tmp4, e->Metric);
+
+ CtInsert(ct, tmp1, tmp2, tmp3, tmp4);
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeRpcEnumL3Table(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Add a routing table entry to the Virtual Layer 3 Switch
+UINT PsRouterTableAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_L3TABLE t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ {"NETWORK", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_NETWORK"), CmdEvalNetworkAndSubnetMask4, NULL},
+ {"GATEWAY", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_GATEWAY"), CmdEvalIp, NULL},
+ {"METRIC", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_METRIC"), CmdEvalInt1, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+ ParseIpAndSubnetMask4(GetParamStr(o, "NETWORK"), &t.NetworkAddress, &t.SubnetMask);
+ t.Metric = GetParamInt(o, "METRIC");
+ t.GatewayAddress = StrToIP32(GetParamStr(o, "GATEWAY"));
+
+ // RPC call
+ ret = ScAddL3Table(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the routing table entry of the Virtual Layer 3 Switch
+UINT PsRouterTableDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_L3TABLE t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ {"NETWORK", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_NETWORK"), CmdEvalNetworkAndSubnetMask4, NULL},
+ {"GATEWAY", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_GATEWAY"), CmdEvalIp, NULL},
+ {"METRIC", CmdPrompt, _UU("CMD_RouterTableAdd_PROMPT_METRIC"), CmdEvalInt1, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+ ParseIpAndSubnetMask4(GetParamStr(o, "NETWORK"), &t.NetworkAddress, &t.SubnetMask);
+ t.Metric = GetParamInt(o, "METRIC");
+ t.GatewayAddress = StrToIP32(GetParamStr(o, "GATEWAY"));
+
+ // RPC call
+ ret = ScDelL3Table(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the log files list
+UINT PsLogFileList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_LOG_FILE t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ c->Write(c, _UU("CMD_LogFileList_START"));
+ c->Write(c, L"");
+
+ // RPC call
+ ret = ScEnumLogFile(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ wchar_t tmp[MAX_SIZE];
+ CT *ct;
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_LogFileList_NUM_LOGS"), t.NumItem);
+ c->Write(c, tmp);
+
+ ct = CtNew();
+
+ CtInsertColumn(ct, _UU("SM_LOG_FILE_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_LOG_FILE_COLUMN_2"), true);
+ CtInsertColumn(ct, _UU("SM_LOG_FILE_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_LOG_FILE_COLUMN_4"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_LOG_FILE_ITEM *e = &t.Items[i];
+ wchar_t tmp1[MAX_PATH], tmp2[128], tmp3[128], tmp4[MAX_HOST_NAME_LEN + 1];
+ char tmp[MAX_SIZE];
+
+ StrToUni(tmp1, sizeof(tmp1), e->FilePath);
+
+ ToStrByte(tmp, sizeof(tmp), e->FileSize);
+ StrToUni(tmp2, sizeof(tmp2), tmp);
+
+ GetDateTimeStr64Uni(tmp3, sizeof(tmp3), SystemToLocal64(e->UpdatedTime));
+
+ StrToUni(tmp4, sizeof(tmp4), e->ServerName);
+
+ CtInsert(ct, tmp1, tmp2, tmp3, tmp4);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumLogFile(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Download a log file
+UINT PsLogFileGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ BUF *buf;
+ char *filename = NULL;
+ char *server_name;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_LogFileGet_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ {"SERVER", NULL, NULL, NULL, NULL},
+ {"SAVEPATH", NULL, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ filename = GetParamStr(o, "SAVE");
+
+ c->Write(c, _UU("CMD_LogFileGet_START"));
+
+ server_name = GetParamStr(o, "SERVER");
+
+ buf = DownloadFileFromServer(ps->Rpc, server_name,
+ GetParamStr(o, "[name]"), 0, NULL, NULL);
+
+ if (buf == NULL)
+ {
+ c->Write(c, _UU("CMD_LogFileGet_FAILED"));
+
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ if (IsEmptyStr(filename) == false)
+ {
+ // Save to the file
+ if (DumpBuf(buf, filename) == false)
+ {
+ ret = ERR_INTERNAL_ERROR;
+ c->Write(c, _UU("CMD_LogFileGet_SAVE_FAILED"));
+ }
+ }
+ else
+ {
+ // Display on the screen
+ wchar_t tmp[MAX_SIZE];
+ UINT buf_size;
+ wchar_t *uni_buf;
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_LogFileGet_FILESIZE"),
+ buf->Size);
+ c->Write(c, tmp);
+ c->Write(c, L"");
+
+ buf_size = CalcUtf8ToUni((BYTE *)buf->Buf, buf->Size);
+ uni_buf = ZeroMalloc(buf_size + 32);
+
+ Utf8ToUni(uni_buf, buf_size, (BYTE *)buf->Buf, buf->Size);
+
+ c->Write(c, uni_buf);
+ c->Write(c, L"");
+
+ Free(uni_buf);
+ }
+
+ FreeBuf(buf);
+ }
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Create a New Virtual HUB
+UINT PsHubCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+ char *pass = "";
+ UINT hub_type = HUB_TYPE_STANDALONE;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_HubCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ {"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ RPC_SERVER_INFO t;
+ Zero(&t, sizeof(t));
+ if (ScGetServerInfo(ps->Rpc, &t) == ERR_NO_ERROR)
+ {
+ if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ hub_type = HUB_TYPE_FARM_DYNAMIC;
+ }
+ FreeRpcServerInfo(&t);
+ }
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+ t.HubType = hub_type;
+
+ if (IsEmptyStr(GetParamStr(o, "PASSWORD")) == false)
+ {
+ pass = GetParamStr(o, "PASSWORD");
+ }
+
+ Hash(t.HashedPassword, pass, StrLen(pass), true);
+ HashPassword(t.SecurePassword, ADMINISTRATOR_USERNAME, pass);
+ t.Online = true;
+
+ // RPC call
+ ret = ScCreateHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Create a New Virtual HUB (dynamic mode)
+UINT PsHubCreateDynamic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+ char *pass = "";
+ UINT hub_type = HUB_TYPE_FARM_DYNAMIC;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_HubCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ {"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+ t.HubType = hub_type;
+
+ if (IsEmptyStr(GetParamStr(o, "PASSWORD")) == false)
+ {
+ pass = GetParamStr(o, "PASSWORD");
+ }
+
+ Hash(t.HashedPassword, pass, StrLen(pass), true);
+ HashPassword(t.SecurePassword, ADMINISTRATOR_USERNAME, pass);
+ t.Online = true;
+
+ // RPC call
+ ret = ScCreateHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Create a New Virtual HUB (static mode)
+UINT PsHubCreateStatic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+ char *pass = "";
+ UINT hub_type = HUB_TYPE_FARM_STATIC;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_HubCreate_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ {"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+ t.HubType = hub_type;
+
+ if (IsEmptyStr(GetParamStr(o, "PASSWORD")) == false)
+ {
+ pass = GetParamStr(o, "PASSWORD");
+ }
+
+ Hash(t.HashedPassword, pass, StrLen(pass), true);
+ HashPassword(t.SecurePassword, ADMINISTRATOR_USERNAME, pass);
+ t.Online = true;
+
+ // RPC call
+ ret = ScCreateHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete a Virtual HUB
+UINT PsHubDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_DELETE_HUB t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_HubDelete_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScDeleteHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the Virtual HUB to static
+UINT PsHubSetStatic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_HubChange_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+
+ // Retrieve the current setting first
+ ret = ScGetHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Change the settings
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+ t.HubType = HUB_TYPE_FARM_STATIC;
+
+ // Write
+ ret = ScSetHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Change the type of Virtual HUB to dynamic Virtual HUB
+UINT PsHubSetDynamic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_HubChange_PROMPT_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+
+ // Retrieve the current setting first
+ ret = ScGetHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Change the settings
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+ t.HubType = HUB_TYPE_FARM_DYNAMIC;
+
+ // Write
+ ret = ScSetHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the list of Virtual HUB
+UINT PsHubList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_HUB t;
+ UINT i;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScEnumHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNew();
+
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_4"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_5"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_6"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_7"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_8"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_9"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_10"), false);
+ CtInsertColumn(ct, _UU("SM_HUB_COLUMN_11"), false);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_6"), false);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_7"), false);
+
+ for (i = 0;i < t.NumHub;i++)
+ {
+ RPC_ENUM_HUB_ITEM *e = &t.Hubs[i];
+ wchar_t name[MAX_HUBNAME_LEN + 1];
+ wchar_t s1[64], s2[64], s3[64], s4[64], s5[64];
+ wchar_t s6[64], s7[128], s8[128];
+ wchar_t s9[64], s10[64];
+
+ UniToStru(s1, e->NumUsers);
+ UniToStru(s2, e->NumGroups);
+ UniToStru(s3, e->NumSessions);
+ UniToStru(s4, e->NumMacTables);
+ UniToStru(s5, e->NumIpTables);
+
+ UniToStru(s6, e->NumLogin);
+
+ if (e->LastLoginTime != 0)
+ {
+ GetDateTimeStr64Uni(s7, sizeof(s7), SystemToLocal64(e->LastLoginTime));
+ }
+ else
+ {
+ UniStrCpy(s7, sizeof(s7), _UU("COMMON_UNKNOWN"));
+ }
+
+ if (e->LastCommTime != 0)
+ {
+ GetDateTimeStr64Uni(s8, sizeof(s8), SystemToLocal64(e->LastCommTime));
+ }
+ else
+ {
+ UniStrCpy(s8, sizeof(s8), _UU("COMMON_UNKNOWN"));
+ }
+
+ if (e->IsTrafficFilled == false)
+ {
+ UniStrCpy(s9, sizeof(s9), _UU("CM_ST_NONE"));
+ UniStrCpy(s10, sizeof(s10), _UU("CM_ST_NONE"));
+ }
+ else
+ {
+ UniToStr3(s9, sizeof(s9),
+ e->Traffic.Recv.BroadcastBytes + e->Traffic.Recv.UnicastBytes +
+ e->Traffic.Send.BroadcastBytes + e->Traffic.Send.UnicastBytes);
+
+ UniToStr3(s10, sizeof(s10),
+ e->Traffic.Recv.BroadcastCount + e->Traffic.Recv.UnicastCount +
+ e->Traffic.Send.BroadcastCount + e->Traffic.Send.UnicastCount);
+ }
+
+ StrToUni(name, sizeof(name), e->HubName);
+
+ CtInsert(ct,
+ name,
+ e->Online ? _UU("SM_HUB_ONLINE") : _UU("SM_HUB_OFFLINE"),
+ GetHubTypeStr(e->HubType),
+ s1, s2, s3, s4, s5, s6, s7, s8, s9, s10);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumHub(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Select a Virtual HUB to manage
+UINT PsHub(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_STATUS t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", NULL, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "[name]")) == false)
+ {
+ wchar_t tmp[MAX_SIZE];
+ Zero(&t, sizeof(t));
+
+ // Examine whether the specified Virtual HUB is accessible
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetHubStatus(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Change the selection
+ if (ps->HubName != NULL)
+ {
+ Free(ps->HubName);
+ }
+ ps->HubName = CopyStr(t.HubName);
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_Hub_Selected"), t.HubName);
+ c->Write(c, tmp);
+ }
+ else
+ {
+ // Deselect
+ if (ps->HubName != NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Unselected"));
+ Free(ps->HubName);
+ }
+ ps->HubName = NULL;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the Virtual HUB to online
+UINT PsOnline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_HUB_ONLINE t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Online = true;
+
+ // RPC call
+ ret = ScSetHubOnline(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the Virtual HUB to offline
+UINT PsOffline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_HUB_ONLINE t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Online = false;
+
+ // RPC call
+ ret = ScSetHubOnline(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the maximum number of concurrent connecting sessions of the Virtual HUB
+UINT PsSetMaxSession(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[max_session]", CmdPrompt, _UU("CMD_SetMaxSession_Prompt"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Get current settings of Virtual HUB
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScGetHub(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ t.HubOption.MaxSession = GetParamInt(o, "[max_session]");
+
+ // Write the configuration of Virtual HUB
+ ret = ScSetHub(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the administrative password of the Virtual HUB
+UINT PsSetHubPassword(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+ char *pw;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[password]", CmdPromptChoosePassword, NULL, NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Get current settings of Virtual HUB
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScGetHub(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Change the settings
+ pw = GetParamStr(o, "[password]");
+ HashPassword(t.SecurePassword, ADMINISTRATOR_USERNAME, pw);
+ Hash(t.HashedPassword, pw, StrLen(pw), true);
+
+ // Write the configuration of Virtual HUB
+ ret = ScSetHub(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the Virtual HUB to permit to be enumerated for anonymous users
+UINT PsSetEnumAllow(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Get current settings of Virtual HUB
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScGetHub(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ t.HubOption.NoEnum = false;
+
+ // Write the configuration of Virtual HUB
+ ret = ScSetHub(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the Virtual HUB to deny to be enumerated for anonymous users
+UINT PsSetEnumDeny(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Get current settings of Virtual HUB
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScGetHub(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ t.HubOption.NoEnum = true;
+
+ // Write the configuration of Virtual HUB
+ ret = ScSetHub(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the option settings for the virtual HUB
+UINT PsOptionsGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_HUB t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHub(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct;
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_OptionsGet_TITLE"), ps->HubName);
+ c->Write(c, tmp);
+
+ // Display settings
+ ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_OptionsGet_ENUM"),
+ t.HubOption.NoEnum ? _UU("CMD_MSG_DENY") : _UU("CMD_MSG_ALLOW"));
+
+ if (t.HubOption.MaxSession == 0)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CMD_MSG_INFINITE"));
+ }
+ else
+ {
+ UniToStru(tmp, t.HubOption.MaxSession);
+ }
+ CtInsert(ct, _UU("CMD_OptionsGet_MAXSESSIONS"), tmp);
+
+ CtInsert(ct, _UU("CMD_OptionsGet_STATUS"), t.Online ? _UU("SM_HUB_ONLINE") : _UU("SM_HUB_OFFLINE"));
+
+ CtInsert(ct, _UU("CMD_OptionsGet_TYPE"), GetHubTypeStr(t.HubType));
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Setting the Radius server to use for user authentication
+UINT PsRadiusServerSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_RADIUS t;
+ char *host;
+ UINT port;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX minmax =
+ {
+ "CMD_RadiusServerSet_EVAL_NUMINTERVAL", RADIUS_RETRY_INTERVAL, RADIUS_RETRY_TIMEOUT,
+ };
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[server_name:port]", CmdPrompt, _UU("CMD_RadiusServerSet_Prompt_Host"), CmdEvalNotEmpty, NULL},
+ {"SECRET", CmdPromptChoosePassword, _UU("CMD_RadiusServerSet_Prompt_Secret"), NULL, NULL},
+ {"RETRY_INTERVAL", CmdPrompt, _UU("CMD_RadiusServerSet_Prompt_RetryInterval"), CmdEvalMinMax, &minmax},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (ParseHostPort(GetParamStr(o, "[server_name:port]"), &host, &port, 1812))
+ {
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.RadiusPort = port;
+ StrCpy(t.RadiusServerName, sizeof(t.RadiusServerName), host);
+ StrCpy(t.RadiusSecret, sizeof(t.RadiusSecret), GetParamStr(o, "SECRET"));
+ t.RadiusRetryInterval = GetParamInt(o, "RETRY_INTERVAL");
+
+ Free(host);
+
+ // RPC call
+ ret = ScSetHubRadius(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the Radius server configuration to be used for user authentication
+UINT PsRadiusServerDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_RADIUS t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.RadiusPort = 1812;
+
+ // RPC call
+ ret = ScSetHubRadius(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the Radius server settings to use for user authentication
+UINT PsRadiusServerGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_RADIUS t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubRadius(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct;
+ wchar_t tmp[MAX_SIZE];
+
+ ct = CtNewStandard();
+
+ if (IsEmptyStr(t.RadiusServerName))
+ {
+ CtInsert(ct, _UU("CMD_RadiusServerGet_STATUS"), _UU("CMD_MSG_DISABLE"));
+ }
+ else
+ {
+ CtInsert(ct, _UU("CMD_RadiusServerGet_STATUS"), _UU("CMD_MSG_ENABLE"));
+
+ StrToUni(tmp, sizeof(tmp), t.RadiusServerName);
+ CtInsert(ct, _UU("CMD_RadiusServerGet_HOST"), tmp);
+
+ UniToStri(tmp, t.RadiusPort);
+ CtInsert(ct, _UU("CMD_RadiusServerGet_PORT"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.RadiusSecret);
+ CtInsert(ct, _UU("CMD_RadiusServerGet_SECRET"), tmp);
+
+ UniToStri(tmp, t.RadiusRetryInterval);
+ CtInsert(ct, _UU("CMD_RadiusServerGet_RetryInterval"), tmp);
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the current status of the Virtual HUB
+UINT PsStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_STATUS t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubStatus(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNewStandard();
+ wchar_t *s;
+ wchar_t tmp[MAX_SIZE];
+
+ // HUB name
+ s = CopyStrToUni(t.HubName);
+ CtInsert(ct, _UU("SM_HUB_STATUS_HUBNAME"), s);
+ Free(s);
+
+ // Online
+ CtInsert(ct, _UU("SM_HUB_STATUS_ONLINE"),
+ t.Online ? _UU("SM_HUB_ONLINE") : _UU("SM_HUB_OFFLINE"));
+
+ // Type of HUB
+ CtInsert(ct, _UU("SM_HUB_TYPE"),
+ GetHubTypeStr(t.HubType));
+
+ if (t.HubType == HUB_TYPE_STANDALONE)
+ {
+ // Enable / Disable the SecureNAT
+ CtInsert(ct, _UU("SM_HUB_SECURE_NAT"),
+ t.SecureNATEnabled ? _UU("SM_HUB_SECURE_NAT_YES") : _UU("SM_HUB_SECURE_NAT_NO"));
+ }
+
+ // Other values
+ UniToStru(tmp, t.NumSessions);
+ CtInsert(ct, _UU("SM_HUB_NUM_SESSIONS"), tmp);
+
+ if (t.NumSessionsClient != 0 || t.NumSessionsBridge != 0)
+ {
+ UniToStru(tmp, t.NumSessionsClient);
+ CtInsert(ct, _UU("SM_HUB_NUM_SESSIONS_CLIENT"), tmp);
+ UniToStru(tmp, t.NumSessionsBridge);
+ CtInsert(ct, _UU("SM_HUB_NUM_SESSIONS_BRIDGE"), tmp);
+ }
+
+ UniToStru(tmp, t.NumAccessLists);
+ CtInsert(ct, _UU("SM_HUB_NUM_ACCESSES"), tmp);
+
+ UniToStru(tmp, t.NumUsers);
+ CtInsert(ct, _UU("SM_HUB_NUM_USERS"), tmp);
+ UniToStru(tmp, t.NumGroups);
+ CtInsert(ct, _UU("SM_HUB_NUM_GROUPS"), tmp);
+
+ UniToStru(tmp, t.NumMacTables);
+ CtInsert(ct, _UU("SM_HUB_NUM_MAC_TABLES"), tmp);
+ UniToStru(tmp, t.NumIpTables);
+ CtInsert(ct, _UU("SM_HUB_NUM_IP_TABLES"), tmp);
+
+ // Usage status
+ UniToStru(tmp, t.NumLogin);
+ CtInsert(ct, _UU("SM_HUB_NUM_LOGIN"), tmp);
+
+ if (t.LastLoginTime != 0)
+ {
+ GetDateTimeStr64Uni(tmp, sizeof(tmp), SystemToLocal64(t.LastLoginTime));
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("COMMON_UNKNOWN"));
+ }
+ CtInsert(ct, _UU("SM_HUB_LAST_LOGIN_TIME"), tmp);
+
+ if (t.LastCommTime != 0)
+ {
+ GetDateTimeStr64Uni(tmp, sizeof(tmp), SystemToLocal64(t.LastCommTime));
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("COMMON_UNKNOWN"));
+ }
+ CtInsert(ct, _UU("SM_HUB_LAST_COMM_TIME"), tmp);
+
+ if (t.CreatedTime != 0)
+ {
+ GetDateTimeStr64Uni(tmp, sizeof(tmp), SystemToLocal64(t.CreatedTime));
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("COMMON_UNKNOWN"));
+ }
+ CtInsert(ct, _UU("SM_HUB_CREATED_TIME"), tmp);
+
+ // Traffic information
+ CmdInsertTrafficInfo(ct, &t.Traffic);
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the log switching string
+wchar_t *GetLogSwitchStr(UINT i)
+{
+ char tmp[64];
+
+ Format(tmp, sizeof(tmp), "SM_LOG_SWITCH_%u", i);
+
+ return _UU(tmp);
+}
+
+// Get the packet log name string
+wchar_t *GetPacketLogNameStr(UINT i)
+{
+ char tmp[64];
+
+ Format(tmp, sizeof(tmp), "CMD_Log_%u", i);
+
+ return _UU(tmp);
+}
+
+// Get the log storage settings for the virtual HUB
+UINT PsLogGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_LOG t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubLog(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_Log_SecurityLog"),
+ t.LogSetting.SaveSecurityLog ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+ if (t.LogSetting.SaveSecurityLog)
+ {
+ CtInsert(ct, _UU("CMD_Log_SwitchType"), GetLogSwitchStr(t.LogSetting.SecurityLogSwitchType));
+ }
+
+ CtInsert(ct, L"", L"");
+
+ CtInsert(ct, _UU("CMD_Log_PacketLog"),
+ t.LogSetting.SavePacketLog ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+ if (t.LogSetting.SavePacketLog)
+ {
+ UINT i;
+
+ CtInsert(ct, _UU("CMD_Log_SwitchType"), GetLogSwitchStr(t.LogSetting.PacketLogSwitchType));
+
+ for (i = 0;i <= 7;i++)
+ {
+ wchar_t *tmp = NULL;
+
+ switch (t.LogSetting.PacketLogConfig[i])
+ {
+ case PACKET_LOG_NONE:
+ tmp = _UU("D_SM_LOG@B_PACKET_0_0");
+ break;
+
+ case PACKET_LOG_HEADER:
+ tmp = _UU("D_SM_LOG@B_PACKET_0_1");
+ break;
+
+ case PACKET_LOG_ALL:
+ tmp = _UU("D_SM_LOG@B_PACKET_0_2");
+ break;
+ }
+
+ CtInsert(ct, GetPacketLogNameStr(i),
+ tmp);
+ }
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// LogEnable command
+UINT PsLogEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_LOG t;
+ bool packet_log = false;
+ char *tmp;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[security|packet]", CmdPrompt, _UU("CMD_LogEnable_Prompt"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ tmp = GetParamStr(o, "[security|packet]");
+
+ if (StartWith(tmp, "p"))
+ {
+ packet_log = true;
+ }
+ else if (StartWith(tmp, "s") == false)
+ {
+ c->Write(c, _UU("CMD_LogEnable_Prompt_Error"));
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubLog(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ if (packet_log == false)
+ {
+ t.LogSetting.SaveSecurityLog = true;
+ }
+ else
+ {
+ t.LogSetting.SavePacketLog = true;
+ }
+
+ // RPC call
+ ret = ScSetHubLog(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disable the packet log or the security log
+UINT PsLogDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_LOG t;
+ bool packet_log = false;
+ char *tmp;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[security|packet]", CmdPrompt, _UU("CMD_LogEnable_Prompt"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ tmp = GetParamStr(o, "[security|packet]");
+
+ if (StartWith(tmp, "p"))
+ {
+ packet_log = true;
+ }
+ else if (StartWith(tmp, "s") == false)
+ {
+ c->Write(c, _UU("CMD_LogEnable_Prompt_Error"));
+ FreeParamValueList(o);
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubLog(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ if (packet_log == false)
+ {
+ t.LogSetting.SaveSecurityLog = false;
+ }
+ else
+ {
+ t.LogSetting.SavePacketLog = false;
+ }
+
+ // RPC call
+ ret = ScSetHubLog(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Convert the string to log switching type
+UINT StrToLogSwitchType(char *str)
+{
+ UINT ret = INFINITE;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return INFINITE;
+ }
+
+ if (IsEmptyStr(str) || StartWith("none", str))
+ {
+ ret = LOG_SWITCH_NO;
+ }
+ else if (StartWith("second", str))
+ {
+ ret = LOG_SWITCH_SECOND;
+ }
+ else if (StartWith("minute", str))
+ {
+ ret = LOG_SWITCH_MINUTE;
+ }
+ else if (StartWith("hour", str))
+ {
+ ret = LOG_SWITCH_HOUR;
+ }
+ else if (StartWith("day", str))
+ {
+ ret = LOG_SWITCH_DAY;
+ }
+ else if (StartWith("month", str))
+ {
+ ret = LOG_SWITCH_MONTH;
+ }
+
+ return ret;
+}
+
+// Set the switching period of the log file
+UINT PsLogSwitchSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_LOG t;
+ bool packet_log = false;
+ char *tmp;
+ UINT new_switch_type = 0;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[security|packet]", CmdPrompt, _UU("CMD_LogEnable_Prompt"), CmdEvalNotEmpty, NULL},
+ {"SWITCH", CmdPrompt, _UU("CMD_LogSwitchSet_Prompt"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ tmp = GetParamStr(o, "[security|packet]");
+
+ if (StartWith(tmp, "p"))
+ {
+ packet_log = true;
+ }
+ else if (StartWith(tmp, "s") == false)
+ {
+ c->Write(c, _UU("CMD_LogEnable_Prompt_Error"));
+ FreeParamValueList(o);
+ return ERR_INVALID_PARAMETER;
+ }
+
+ new_switch_type = StrToLogSwitchType(GetParamStr(o, "SWITCH"));
+
+ if (new_switch_type == INFINITE)
+ {
+ c->Write(c, _UU("CMD_LogEnable_Prompt_Error"));
+ FreeParamValueList(o);
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubLog(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ if (packet_log == false)
+ {
+ t.LogSetting.SecurityLogSwitchType = new_switch_type;
+ }
+ else
+ {
+ t.LogSetting.PacketLogSwitchType = new_switch_type;
+ }
+
+ // RPC call
+ ret = ScSetHubLog(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Convert the type string of the packet log contents to an integer
+UINT StrToPacketLogSaveInfoType(char *str)
+{
+ UINT ret = INFINITE;
+ if (str == NULL)
+ {
+ return INFINITE;
+ }
+
+ if (StartWith("none", str) || IsEmptyStr(str))
+ {
+ ret = PACKET_LOG_NONE;
+ }
+ else if (StartWith("header", str))
+ {
+ ret = PACKET_LOG_HEADER;
+ }
+ else if (StartWith("full", str) || StartWith("all", str))
+ {
+ ret = PACKET_LOG_ALL;
+ }
+
+ return ret;
+}
+
+// Convert a packet type string of the packet log to an integer
+UINT StrToPacketLogType(char *str)
+{
+ UINT ret = INFINITE;
+ if (str == NULL || IsEmptyStr(str))
+ {
+ return INFINITE;
+ }
+
+ if (StartWith("tcpconn", str))
+ {
+ ret = PACKET_LOG_TCP_CONN;
+ }
+ else if (StartWith("tcpdata", str))
+ {
+ ret = PACKET_LOG_TCP;
+ }
+ else if (StartWith("dhcp", str))
+ {
+ ret = PACKET_LOG_DHCP;
+ }
+ else if (StartWith("udp", str))
+ {
+ ret = PACKET_LOG_UDP;
+ }
+ else if (StartWith("icmp", str))
+ {
+ ret = PACKET_LOG_ICMP;
+ }
+ else if (StartWith("ip", str))
+ {
+ ret = PACKET_LOG_IP;
+ }
+ else if (StartWith("arp", str))
+ {
+ ret = PACKET_LOG_ARP;
+ }
+ else if (StartWith("ethernet", str))
+ {
+ ret = PACKET_LOG_ETHERNET;
+ }
+
+ return ret;
+}
+
+// Set the detail level and type of packet to be stored in the packet log
+UINT PsLogPacketSaveType(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_LOG t;
+ bool packet_log = false;
+ UINT packet_type = INFINITE;
+ UINT packet_save_info_type = INFINITE;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"TYPE", CmdPrompt, _UU("CMD_LogPacketSaveType_Prompt_TYPE"), NULL, NULL},
+ {"SAVE", CmdPrompt, _UU("CMD_LogPacketSaveType_Prompt_SAVE"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ packet_type = StrToPacketLogType(GetParamStr(o, "TYPE"));
+ packet_save_info_type = StrToPacketLogSaveInfoType(GetParamStr(o, "SAVE"));
+
+ if (packet_type == INFINITE || packet_save_info_type == INFINITE)
+ {
+ c->Write(c, _UU("CMD_LogEnable_Prompt_Error"));
+ FreeParamValueList(o);
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubLog(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ t.LogSetting.PacketLogConfig[packet_type] = packet_save_info_type;
+
+ // RPC call
+ ret = ScSetHubLog(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the list of certificates of the trusted certification authority
+UINT PsCAList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_ENUM_CA t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumCa(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ CT *ct = CtNewStandard();
+
+ for (i = 0;i < t.NumCa;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[64];
+ RPC_HUB_ENUM_CA_ITEM *e = &t.Ca[i];
+
+ GetDateStrEx64(tmp, sizeof(tmp), SystemToLocal64(e->Expires), NULL);
+
+ UniToStru(tmp2, e->Key);
+
+ CtInsert(ct, _UU("CMD_CAList_COLUMN_ID"), tmp2);
+ CtInsert(ct, _UU("CM_CERT_COLUMN_1"), e->SubjectName);
+ CtInsert(ct, _UU("CM_CERT_COLUMN_2"), e->IssuerName);
+ CtInsert(ct, _UU("CM_CERT_COLUMN_3"), tmp);
+
+ if (i != (t.NumCa - 1))
+ {
+ CtInsert(ct, L"---", L"---");
+ }
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeRpcHubEnumCa(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Add a certificate to the trusted certification authority
+UINT PsCAAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_ADD_CA t;
+ X *x;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[path]", CmdPrompt, _UU("CMD_CAAdd_PROMPT_PATH"), CmdEvalIsFile, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ x = FileToXW(GetParamUniStr(o, "[path]"));
+
+ if (x == NULL)
+ {
+ FreeParamValueList(o);
+ c->Write(c, _UU("CMD_MSG_LOAD_CERT_FAILED"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Cert = x;
+
+ // RPC call
+ ret = ScAddCa(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcHubAddCa(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the certificate of the trusted certification authority
+UINT PsCADelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_DELETE_CA t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_CADelete_PROMPT_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Key = GetParamInt(o, "[id]");
+
+ // RPC call
+ ret = ScDeleteCa(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the certificate of the trusted certification authority
+UINT PsCAGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB_GET_CA t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_CAGet_PROMPT_ID"), CmdEvalNotEmpty, NULL},
+ {"SAVECERT", CmdPrompt, _UU("CMD_CAGet_PROMPT_SAVECERT"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Key = GetParamInt(o, "[id]");
+
+ // RPC call
+ ret = ScGetCa(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ if (XToFileW(t.Cert, GetParamUniStr(o, "SAVECERT"), true))
+ {
+ // Success
+ }
+ else
+ {
+ ret = ERR_INTERNAL_ERROR;
+ c->Write(c, _UU("CMD_MSG_SAVE_CERT_FAILED"));
+ }
+ }
+
+ FreeRpcHubGetCa(&t);
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the cascade connection list
+UINT PsCascadeList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_LINK t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNew();
+ UINT i;
+
+ CtInsertColumn(ct, _UU("SM_LINK_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_LINK_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_LINK_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_LINK_COLUMN_4"), false);
+ CtInsertColumn(ct, _UU("SM_LINK_COLUMN_5"), false);
+
+ for (i = 0;i < t.NumLink;i++)
+ {
+ RPC_ENUM_LINK_ITEM *e = &t.Links[i];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+
+ GetDateTimeStrEx64(tmp1, sizeof(tmp1), SystemToLocal64(e->ConnectedTime), NULL);
+ StrToUni(tmp2, sizeof(tmp2), e->Hostname);
+ StrToUni(tmp3, sizeof(tmp3), e->HubName);
+
+ if (e->Online == false)
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_LINK_STATUS_OFFLINE"));
+ }
+ else
+ {
+ if (e->Connected)
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_LINK_STATUS_ONLINE"));
+ }
+ else
+ {
+ if (e->LastError != 0)
+ {
+ UniFormat(tmp4, sizeof(tmp4), _UU("SM_LINK_STATUS_ERROR"), e->LastError, _E(e->LastError));
+ }
+ else
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_LINK_CONNECTING"));
+ }
+ }
+ }
+
+ CtInsert(ct, e->AccountName, tmp4, tmp1, tmp2, tmp3);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumLink(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Creat a new cascade
+UINT PsCascadeCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ char *host = NULL;
+ UINT port = 443;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SERVER", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Server"), CmdEvalHostAndPort, NULL},
+ {"HUB", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Hub"), CmdEvalSafe, NULL},
+ {"USERNAME", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Username"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 443);
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ t.Online = false;
+
+ Copy(&t.Policy, GetDefaultPolicy(), sizeof(POLICY));
+
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+ t.ClientOption->Port = port;
+ StrCpy(t.ClientOption->Hostname, sizeof(t.ClientOption->Hostname), host);
+ StrCpy(t.ClientOption->HubName, sizeof(t.ClientOption->HubName), GetParamStr(o, "HUB"));
+ t.ClientOption->NumRetry = INFINITE;
+ t.ClientOption->RetryInterval = 15;
+ t.ClientOption->MaxConnection = 8;
+ t.ClientOption->UseEncrypt = true;
+ t.ClientOption->AdditionalConnectionInterval = 1;
+ t.ClientOption->RequireBridgeRoutingMode = true;
+
+ t.ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_ANONYMOUS;
+ StrCpy(t.ClientAuth->Username, sizeof(t.ClientAuth->Username), GetParamStr(o, "USERNAME"));
+
+ Free(host);
+
+ // RPC call
+ ret = ScCreateLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the user name and destination of the cascade connection
+UINT PsCascadeSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ char *host = NULL;
+ UINT port = 443;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SERVER", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Server"), CmdEvalHostAndPort, NULL},
+ {"HUB", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Hub"), CmdEvalSafe, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 443);
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ ret = ScGetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ Free(host);
+ return ret;
+ }
+
+ t.ClientOption->Port = port;
+ StrCpy(t.ClientOption->Hostname, sizeof(t.ClientOption->Hostname), host);
+ StrCpy(t.ClientOption->HubName, sizeof(t.ClientOption->HubName), GetParamStr(o, "HUB"));
+
+ Free(host);
+
+ // RPC call
+ ret = ScSetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the type string of proxy
+wchar_t *GetProxyTypeStr(UINT i)
+{
+ switch (i)
+ {
+ case PROXY_DIRECT:
+
+ return _UU("PROTO_DIRECT_TCP");
+
+ case PROXY_HTTP:
+ return _UU("PROTO_HTTP_PROXY");
+
+ case PROXY_SOCKS:
+ return _UU("PROTO_SOCKS_PROXY");
+
+ default:
+ return _UU("PROTO_UNKNOWN");
+ }
+}
+
+// Get type string in user authentication for client
+wchar_t *GetClientAuthTypeStr(UINT i)
+{
+ char tmp[MAX_SIZE];
+
+ Format(tmp, sizeof(tmp), "PW_TYPE_%u", i);
+
+ return _UU(tmp);
+}
+
+// Get the setting of cascade connection
+UINT PsCascadeGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName),
+ GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Show the contents of the connection settings
+ wchar_t tmp[MAX_SIZE];
+
+ CT *ct = CtNewStandard();
+
+ // Connection settings name
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_NAME"), t.ClientOption->AccountName);
+
+ // Host name of the destination VPN Server
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->Hostname);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_HOSTNAME"), tmp);
+
+ // The port number to connect to VPN Server
+ UniToStru(tmp, t.ClientOption->Port);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PORT"), tmp);
+
+ // Virtual HUB name of the destination VPN Server
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->HubName);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_HUBNAME"), tmp);
+
+ // Type of proxy server to go through
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_TYPE"), GetProxyTypeStr(t.ClientOption->ProxyType));
+
+ if (t.ClientOption->ProxyType != PROXY_DIRECT)
+ {
+ // Host name of the proxy server
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->ProxyName);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_HOSTNAME"), tmp);
+
+ // Port number of the proxy server
+ UniToStru(tmp, t.ClientOption->ProxyPort);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_PORT"), tmp);
+
+ // User name of the proxy server
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->ProxyUsername);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_PROXY_USERNAME"), tmp);
+ }
+
+ // To verify the server certificate
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_SERVER_CERT_USE"),
+ t.CheckServerCert ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Registered specific certificate
+ if (t.ServerCert != NULL)
+ {
+ GetAllNameFromX(tmp, sizeof(tmp), t.ServerCert);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_SERVER_CERT_NAME"), tmp);
+ }
+
+ // Device name to be used for the connection
+ StrToUni(tmp, sizeof(tmp), t.ClientOption->DeviceName);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_DEVICE_NAME"), tmp);
+
+ // Authentication type
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_AUTH_TYPE"), GetClientAuthTypeStr(t.ClientAuth->AuthType));
+
+ // User name
+ StrToUni(tmp, sizeof(tmp), t.ClientAuth->Username);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_AUTH_USERNAME"), tmp);
+
+ if (t.ClientAuth->AuthType == CLIENT_AUTHTYPE_CERT)
+ {
+ if (t.ClientAuth->ClientX != NULL)
+ {
+ // Client certificate name
+ GetAllNameFromX(tmp, sizeof(tmp), t.ClientAuth->ClientX);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_AUTH_CERT_NAME"), tmp);
+ }
+ }
+
+ // Number of TCP connections to be used for VPN communication
+ UniToStru(tmp, t.ClientOption->MaxConnection);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_NUMTCP"), tmp);
+
+ // Establishment interval of each TCP connection
+ UniToStru(tmp, t.ClientOption->AdditionalConnectionInterval);
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_TCP_INTERVAL"), tmp);
+
+ // Life span of each TCP connection
+ if (t.ClientOption->ConnectionDisconnectSpan != 0)
+ {
+ UniToStru(tmp, t.ClientOption->ConnectionDisconnectSpan);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CMD_MSG_INFINITE"));
+ }
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_TCP_TTL"), tmp);
+
+ // Use of half-duplex mode
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_TCP_HALF"),
+ t.ClientOption->HalfConnection ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Encryption by SSL
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_ENCRYPT"),
+ t.ClientOption->UseEncrypt ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Data compression
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_COMPRESS"),
+ t.ClientOption->UseCompress ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Connect in bridge / router mode
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_BRIDGE_ROUTER"),
+ t.ClientOption->RequireBridgeRoutingMode ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Connect in monitoring mode
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_MONITOR"),
+ t.ClientOption->RequireMonitorMode ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Not to rewrite the routing table
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_NO_TRACKING"),
+ t.ClientOption->NoRoutingTracking ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ // Disable the QoS control
+ CtInsert(ct, _UU("CMD_ACCOUNT_COLUMN_QOS_DISABLE"),
+ t.ClientOption->DisableQoS ? _UU("CMD_MSG_ENABLE") : _UU("CMD_MSG_DISABLE"));
+
+ CtFree(ct, c);
+
+ // Security policy
+ c->Write(c, L"");
+ c->Write(c, _UU("CMD_CascadeGet_Policy"));
+ PrintPolicy(c, &t.Policy, true);
+ }
+
+ FreeRpcCreateLink(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the cascade connection
+UINT PsCascadeDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScDeleteLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the user name to use for the cascade connection
+UINT PsCascadeUsernameSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"USERNAME", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Username"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Change the settings for the cascade connection
+ StrCpy(t.ClientAuth->Username, sizeof(t.ClientAuth->Username),
+ GetParamStr(o, "USERNAME"));
+
+ if (t.ClientAuth->AuthType == CLIENT_AUTHTYPE_PASSWORD)
+ {
+ c->Write(c, _UU("CMD_CascadeUsername_Notice"));
+ }
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+//Set the type of user authentication of cascade connection to the anonymous authentication
+UINT PsCascadeAnonymousSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Change the settings for the cascade connection
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_ANONYMOUS;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the type of user authentication of cascade connection to the password authentication
+UINT PsCascadePasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+ {"TYPE", CmdPrompt, _UU("CMD_CascadePasswordSet_Prompt_Type"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Change the settings for the cascade connection
+ char *typestr = GetParamStr(o, "TYPE");
+
+ if (StartWith("standard", typestr))
+ {
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_PASSWORD;
+ HashPassword(t.ClientAuth->HashedPassword, t.ClientAuth->Username,
+ GetParamStr(o, "PASSWORD"));
+ }
+ else if (StartWith("radius", typestr) || StartWith("ntdomain", typestr))
+ {
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_PLAIN_PASSWORD;
+
+ StrCpy(t.ClientAuth->PlainPassword, sizeof(t.ClientAuth->PlainPassword),
+ GetParamStr(o, "PASSWORD"));
+ }
+ else
+ {
+ // An error has occured
+ c->Write(c, _UU("CMD_CascadePasswordSet_Type_Invalid"));
+ FreeRpcCreateLink(&t);
+ ret = ERR_INVALID_PARAMETER;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the type of user authentication of cascade connection to the client certificate authentication
+UINT PsCascadeCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ X *x;
+ K *k;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL},
+ {"LOADKEY", CmdPrompt, _UU("CMD_LOADKEYPATH"), CmdEvalIsFile, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (CmdLoadCertAndKey(c, &x, &k, GetParamUniStr(o, "LOADCERT"), GetParamUniStr(o, "LOADKEY")) == false)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ FreeX(x);
+ FreeK(k);
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Change authentication data
+ t.ClientAuth->AuthType = CLIENT_AUTHTYPE_CERT;
+ if (t.ClientAuth->ClientX != NULL)
+ {
+ FreeX(t.ClientAuth->ClientX);
+ }
+ if (t.ClientAuth->ClientK != NULL)
+ {
+ FreeK(t.ClientAuth->ClientK);
+ }
+
+ t.ClientAuth->ClientX = x;
+ t.ClientAuth->ClientK = k;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the client certificate to be used in the cascade connection
+UINT PsCascadeCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SAVECERT", CmdPrompt, _UU("CMD_SAVECERTPATH"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ if (t.ClientAuth->AuthType != CLIENT_AUTHTYPE_CERT)
+ {
+ c->Write(c, _UU("CMD_CascadeCertSet_Not_Auth_Cert"));
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else if (t.ClientAuth->ClientX == NULL)
+ {
+ c->Write(c, _UU("CMD_CascadeCertSet_Cert_Not_Exists"));
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ XToFileW(t.ClientAuth->ClientX, GetParamUniStr(o, "SAVECERT"), true);
+ }
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Enable encryption of communication at the time of the cascade connection
+UINT PsCascadeEncryptEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ t.ClientOption->UseEncrypt = true;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disable encryption of communication at the time of the cascade connection
+UINT PsCascadeEncryptDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ t.ClientOption->UseEncrypt = false;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable data compression at the time of communication of the cascade connection
+UINT PsCascadeCompressEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ t.ClientOption->UseCompress = true;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disable data compression at the time of communication of the cascade connection
+UINT PsCascadeCompressDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ t.ClientOption->UseCompress = false;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the cascade connection method to the TCP/IP direct connection mode
+UINT PsCascadeProxyNone(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ t.ClientOption->ProxyType = PROXY_DIRECT;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the cascade connection method as the mode via HTTP proxy server
+UINT PsCascadeProxyHttp(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SERVER", CmdPrompt, _UU("CMD_CascadeProxyHttp_Prompt_Server"), CmdEvalHostAndPort, NULL},
+ {"USERNAME", NULL, NULL, NULL, NULL},
+ {"PASSWORD", NULL, NULL, NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ char *host;
+ UINT port;
+
+ // Data change
+ if (ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 8080))
+ {
+ t.ClientOption->ProxyType = PROXY_HTTP;
+ StrCpy(t.ClientOption->ProxyName, sizeof(t.ClientOption->ProxyName), host);
+ t.ClientOption->ProxyPort = port;
+ StrCpy(t.ClientOption->ProxyUsername, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "USERNAME"));
+ StrCpy(t.ClientOption->ProxyPassword, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "PASSWORD"));
+ Free(host);
+ }
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the cascade connection method as the mode via SOCKS proxy server
+UINT PsCascadeProxySocks(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SERVER", CmdPrompt, _UU("CMD_CascadeProxyHttp_Prompt_Server"), CmdEvalHostAndPort, NULL},
+ {"USERNAME", NULL, NULL, NULL, NULL},
+ {"PASSWORD", NULL, NULL, NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ char *host;
+ UINT port;
+
+ // Data change
+ if (ParseHostPort(GetParamStr(o, "SERVER"), &host, &port, 8080))
+ {
+ t.ClientOption->ProxyType = PROXY_SOCKS;
+ StrCpy(t.ClientOption->ProxyName, sizeof(t.ClientOption->ProxyName), host);
+ t.ClientOption->ProxyPort = port;
+ StrCpy(t.ClientOption->ProxyUsername, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "USERNAME"));
+ StrCpy(t.ClientOption->ProxyPassword, sizeof(t.ClientOption->ProxyName), GetParamStr(o, "PASSWORD"));
+ Free(host);
+ }
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable the validation options for the server certificate of cascade connection
+UINT PsCascadeServerCertEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ t.CheckServerCert = true;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disable the validation options for the server certificate of cascade connection
+UINT PsCascadeServerCertDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ t.CheckServerCert = false;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Server-specific certificate settings of cascade connection
+UINT PsCascadeServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ X *x;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ x = FileToXW(GetParamUniStr(o, "LOADCERT"));
+ if (x == NULL)
+ {
+ FreeParamValueList(o);
+ c->Write(c, _UU("CMD_LOADCERT_FAILED"));
+ return ERR_INTERNAL_ERROR;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ FreeX(x);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ if (t.ServerCert != NULL)
+ {
+ FreeX(t.ServerCert);
+ }
+ t.ServerCert = x;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the server-specific certificate of cascade connection
+UINT PsCascadeServerCertDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ if (t.ServerCert != NULL)
+ {
+ FreeX(t.ServerCert);
+ }
+ t.ServerCert = NULL;
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the server-specific certificate of cascade connection
+UINT PsCascadeServerCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"SAVECERT", CmdPrompt, _UU("CMD_SAVECERTPATH"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Save the certificate
+ if (t.ServerCert == NULL)
+ {
+ c->Write(c, _UU("CMD_CERT_NOT_EXISTS"));
+ ret = ERR_INTERNAL_ERROR;
+ }
+ else
+ {
+ if (XToFileW(t.ServerCert, GetParamUniStr(o, "SAVECERT"), true) == false)
+ {
+ c->Write(c, _UU("CMD_SAVECERT_FAILED"));
+ ret = ERR_INTERNAL_ERROR;
+ }
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the advanced settings of the cascade connection
+UINT PsCascadeDetailSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ CMD_EVAL_MIN_MAX mm_maxtcp =
+ {
+ "CMD_CascadeDetailSet_Eval_MaxTcp", 1, 32
+ };
+ CMD_EVAL_MIN_MAX mm_interval =
+ {
+ "CMD_CascadeDetailSet_Eval_Interval", 1, 4294967295UL
+ };
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"MAXTCP", CmdPrompt, _UU("CMD_CascadeDetailSet_Prompt_MaxTcp"), CmdEvalMinMax, &mm_maxtcp},
+ {"INTERVAL", CmdPrompt, _UU("CMD_CascadeDetailSet_Prompt_Interval"), CmdEvalMinMax, &mm_interval},
+ {"TTL", CmdPrompt, _UU("CMD_CascadeDetailSet_Prompt_TTL"), NULL, NULL},
+ {"HALF", CmdPrompt, _UU("CMD_CascadeDetailSet_Prompt_HALF"), NULL, NULL},
+ {"NOQOS", CmdPrompt, _UU("CMD_AccountDetailSet_Prompt_NOQOS"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Data change
+ t.ClientOption->MaxConnection = GetParamInt(o, "MAXTCP");
+ t.ClientOption->AdditionalConnectionInterval = GetParamInt(o, "INTERVAL");
+ t.ClientOption->ConnectionDisconnectSpan = GetParamInt(o, "TTL");
+ t.ClientOption->HalfConnection = GetParamYes(o, "HALF");
+ t.ClientOption->DisableQoS = GetParamYes(o, "NOQOS");
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Show a security policy
+void PrintPolicy(CONSOLE *c, POLICY *pol, bool cascade_mode)
+{
+ UINT i;
+ CT *ct;
+ PACK *p;
+ // Validate arguments
+ if (c == NULL || pol == NULL)
+ {
+ return;
+ }
+
+ ct = CtNew();
+ CtInsertColumn(ct, _UU("CMD_PolicyList_Column_1"), false);
+ CtInsertColumn(ct, _UU("CMD_PolicyList_Column_2"), false);
+ CtInsertColumn(ct, _UU("CMD_PolicyList_Column_3"), false);
+
+ p = NewPack();
+ OutRpcPolicy(p, pol);
+
+ // Show the list of all policies
+ for (i = 0; i < PolicyNum();i++)
+ {
+ char name[64];
+ wchar_t *tmp;
+
+ if (cascade_mode == false || PolicyIsSupportedForCascade(i))
+ {
+ wchar_t value_str[256];
+ UINT value;
+ char tmp2[256];
+
+ Format(tmp2, sizeof(tmp2), "policy:%s", PolicyIdToStr(i));
+ value = PackGetInt(p, tmp2);
+
+ tmp = CopyStrToUni(PolicyIdToStr(i));
+
+ FormatPolicyValue(value_str, sizeof(value_str),
+ i, value);
+
+ Format(name, sizeof(name), "POL_%u", i);
+ CtInsert(ct, tmp, _UU(name), value_str);
+
+ Free(tmp);
+ }
+ }
+
+ FreePack(p);
+
+ CtFree(ct, c);
+}
+
+// Show the security policy list
+void PrintPolicyList(CONSOLE *c, char *name)
+{
+ UINT id;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+ if (IsEmptyStr(name))
+ {
+ name = NULL;
+ }
+
+ if (name != NULL)
+ {
+ id = PolicyStrToId(name);
+ if (id == INFINITE)
+ {
+ // Invalid ID
+ c->Write(c, _UU("CMD_PolicyList_Invalid_Name"));
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ char name1[64], name2[64];
+ wchar_t *title, *descript;
+ wchar_t policy_name[MAX_SIZE];
+
+ Format(name1, sizeof(name1), "POL_%u", id);
+ Format(name2, sizeof(name2), "POL_EX_%u", id);
+
+ title = _UU(name1);
+ descript = _UU(name2);
+
+ StrToUni(policy_name, sizeof(policy_name), PolicyIdToStr(id));
+
+ // Policy name
+ c->Write(c, _UU("CMD_PolicyList_Help_1"));
+ UniFormat(tmp2, sizeof(tmp2), L" %s", policy_name);
+ c->Write(c, tmp2);
+ c->Write(c, L"");
+
+ // Simple description of the policy
+ c->Write(c, _UU("CMD_PolicyList_Help_2"));
+ UniFormat(tmp2, sizeof(tmp2), L" %s", title);
+ c->Write(c, tmp2);
+ c->Write(c, L"");
+
+ // Range of the value that can be set
+ GetPolicyValueRangeStr(tmp, sizeof(tmp), id);
+ c->Write(c, _UU("CMD_PolicyList_Help_3"));
+ UniFormat(tmp2, sizeof(tmp2), L" %s", tmp);
+ c->Write(c, tmp2);
+ c->Write(c, L"");
+
+ // Default value
+ FormatPolicyValue(tmp, sizeof(tmp), id, GetPolicyItem(id)->DefaultValue);
+ c->Write(c, _UU("CMD_PolicyList_Help_4"));
+ UniFormat(tmp2, sizeof(tmp2), L" %s", tmp);
+ c->Write(c, tmp2);
+ c->Write(c, L"");
+
+ // Detailed description of the policy
+ c->Write(c, _UU("CMD_PolicyList_Help_5"));
+ c->Write(c, descript);
+ c->Write(c, L"");
+ }
+ }
+ else
+ {
+ UINT i;
+ CT *ct = CtNew();
+ CtInsertColumn(ct, _UU("CMD_PolicyList_Column_1"), false);
+ CtInsertColumn(ct, _UU("CMD_PolicyList_Column_2"), false);
+
+ // Show the list of all policies
+ for (i = 0; i < PolicyNum();i++)
+ {
+ char name[64];
+ wchar_t *tmp;
+
+ tmp = CopyStrToUni(PolicyIdToStr(i));
+
+ Format(name, sizeof(name), "POL_%u", i);
+ CtInsert(ct, tmp, _UU(name));
+
+ Free(tmp);
+ }
+
+ CtFree(ct, c);
+ }
+}
+
+// Editing the contents of the policy
+bool EditPolicy(CONSOLE *c, POLICY *pol, char *name, char *value, bool cascade_mode)
+{
+ PACK *p;
+ ELEMENT *e;
+ POLICY_ITEM *item;
+ UINT id;
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ char pack_name[128];
+ // Validate arguments
+ if (c == NULL || pol == NULL || name == NULL || value == NULL)
+ {
+ return false;
+ }
+
+ p = NewPack();
+
+ OutRpcPolicy(p, pol);
+
+ Format(pack_name, sizeof(pack_name), "policy:%s", PolicyIdToStr(PolicyStrToId(name)));
+
+ if ((e = GetElement(p, pack_name, VALUE_INT)) == NULL || (id = PolicyStrToId(name)) == INFINITE)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_CascadePolicySet_Invalid_Name"), name);
+ c->Write(c, tmp);
+ FreePack(p);
+ return false;
+ }
+
+ if (cascade_mode && (PolicyIsSupportedForCascade(id) == false))
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_CascadePolicySet_Invalid_Name_For_Cadcade"), name);
+ c->Write(c, tmp);
+ FreePack(p);
+ return false;
+ }
+
+ item = GetPolicyItem(id);
+
+ if (item->TypeInt == false)
+ {
+ // bool type
+ e->values[0]->IntValue = (
+ StartWith(value, "y") || StartWith(value, "t") ||
+ ToInt(value) != 0) ? 1 : 0;
+ }
+ else
+ {
+ UINT n = ToInt(value);
+ bool b = true;
+
+ // int type
+ GetPolicyValueRangeStr(tmp, sizeof(tmp), id);
+
+ if (item->AllowZero == false)
+ {
+ if (n == 0)
+ {
+ b = false;
+ }
+ }
+
+ if (n != 0 && (n < item->MinValue || n > item->MaxValue))
+ {
+ b = false;
+ }
+
+ if (b == false)
+ {
+ UniFormat(tmp2, sizeof(tmp2), _UU("CMD_CascadePolicySet_Invalid_Range"), PolicyIdToStr(id), tmp);
+ c->Write(c, tmp2);
+ FreePack(p);
+ return false;
+ }
+
+ e->values[0]->IntValue = n;
+ }
+
+ Zero(pol, sizeof(POLICY));
+
+ InRpcPolicy(pol, p);
+
+ FreePack(p);
+
+ return true;
+}
+
+// Show the list of the type of security policy and possible values
+UINT PsPolicyList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", NULL, NULL, NULL, NULL}
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ PrintPolicyList(c, GetParamStr(o, "[name]"));
+
+ FreeParamValueList(o);
+
+ return ERR_NO_ERROR;
+}
+
+// Set the security policy of the cascade session
+UINT PsCascadePolicySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CREATE_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ {"NAME", CmdPrompt, _UU("CMD_CascadePolicySet_PROMPT_POLNAME"), CmdEvalNotEmpty, NULL},
+ {"VALUE", CmdPrompt, _UU("CMD_CascadePolicySet_PROMPT_POLVALUE"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ if (EditPolicy(c, &t.Policy, GetParamStr(o, "NAME"), GetParamStr(o, "VALUE"), true) == false)
+ {
+ // An error has occured
+ FreeRpcCreateLink(&t);
+ FreeParamValueList(o);
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = ScSetLink(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCreateLink(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Display the status information of the session
+void CmdPrintStatusToListView(CT *ct, RPC_CLIENT_GET_CONNECTION_STATUS *s)
+{
+ CmdPrintStatusToListViewEx(ct, s, false);
+}
+void CmdPrintStatusToListViewEx(CT *ct, RPC_CLIENT_GET_CONNECTION_STATUS *s, bool server_mode)
+{
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+ char vv[128];
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ if (server_mode == false)
+ {
+ CtInsert(ct, _UU("CM_ST_ACCOUNT_NAME"), s->AccountName);
+
+ if (s->Connected == false)
+ {
+ wchar_t *st = _UU("CM_ST_CONNECTED_FALSE");
+ switch (s->SessionStatus)
+ {
+ case CLIENT_STATUS_CONNECTING:
+ st = _UU("CM_ST_CONNECTING");
+ break;
+ case CLIENT_STATUS_NEGOTIATION:
+ st = _UU("CM_ST_NEGOTIATION");
+ break;
+ case CLIENT_STATUS_AUTH:
+ st = _UU("CM_ST_AUTH");
+ break;
+ case CLIENT_STATUS_ESTABLISHED:
+ st = _UU("CM_ST_ESTABLISHED");
+ break;
+ case CLIENT_STATUS_RETRY:
+ st = _UU("CM_ST_RETRY");
+ break;
+ case CLIENT_STATUS_IDLE:
+ st = _UU("CM_ST_IDLE");
+ break;
+ }
+ CtInsert(ct, _UU("CM_ST_CONNECTED"), st);
+ }
+ else
+ {
+ CtInsert(ct, _UU("CM_ST_CONNECTED"), _UU("CM_ST_CONNECTED_TRUE"));
+ }
+ }
+
+ if (s->Connected)
+ {
+ if (s->VLanId == 0)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_ST_NO_VLAN"));
+ }
+ else
+ {
+ UniToStru(tmp, s->VLanId);
+ }
+
+ CtInsert(ct, _UU("CM_ST_VLAN_ID"), tmp);
+
+ if (server_mode == false)
+ {
+ StrToUni(tmp, sizeof(tmp), s->ServerName);
+ CtInsert(ct, _UU("CM_ST_SERVER_NAME"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_PORT_TCP"), s->ServerPort);
+ CtInsert(ct, _UU("CM_ST_SERVER_PORT"), tmp);
+ }
+
+ StrToUni(tmp, sizeof(tmp), s->ServerProductName);
+ CtInsert(ct, _UU("CM_ST_SERVER_P_NAME"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), L"%u.%02u", s->ServerProductVer / 100, s->ServerProductVer % 100);
+ CtInsert(ct, _UU("CM_ST_SERVER_P_VER"), tmp);
+ UniFormat(tmp, sizeof(tmp), L"Build %u", s->ServerProductBuild);
+ CtInsert(ct, _UU("CM_ST_SERVER_P_BUILD"), tmp);
+ }
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->StartTime), NULL);
+ CtInsert(ct, _UU("CM_ST_START_TIME"), tmp);
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->FirstConnectionEstablisiedTime), NULL);
+ CtInsert(ct, _UU("CM_ST_FIRST_ESTAB_TIME"), s->FirstConnectionEstablisiedTime == 0 ? _UU("CM_ST_NONE") : tmp);
+
+ if (s->Connected)
+ {
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(s->CurrentConnectionEstablishTime), NULL);
+ CtInsert(ct, _UU("CM_ST_CURR_ESTAB_TIME"), tmp);
+ }
+
+ if (server_mode == false)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_STR"), s->NumConnectionsEatablished);
+ CtInsert(ct, _UU("CM_ST_NUM_ESTABLISHED"), tmp);
+ }
+
+ if (s->Connected)
+ {
+ CtInsert(ct, _UU("CM_ST_HALF_CONNECTION"), s->HalfConnection ? _UU("CM_ST_HALF_TRUE") : _UU("CM_ST_HALF_FALSE"));
+
+ CtInsert(ct, _UU("CM_ST_QOS"), s->QoS ? _UU("CM_ST_QOS_TRUE") : _UU("CM_ST_QOS_FALSE"));
+
+ UniFormat(tmp, sizeof(tmp), L"%u", s->NumTcpConnections);
+ CtInsert(ct, _UU("CM_ST_NUM_TCP"), tmp);
+
+ if (s->HalfConnection)
+ {
+ UniFormat(tmp, sizeof(tmp), L"%u", s->NumTcpConnectionsUpload);
+ CtInsert(ct, _UU("CM_ST_NUM_TCP_UPLOAD"), tmp);
+ UniFormat(tmp, sizeof(tmp), L"%u", s->NumTcpConnectionsDownload);
+ CtInsert(ct, _UU("CM_ST_NUM_TCP_DOWNLOAD"), tmp);
+ }
+
+ UniFormat(tmp, sizeof(tmp), L"%u", s->MaxTcpConnections);
+ CtInsert(ct, _UU("CM_ST_MAX_TCP"), tmp);
+
+ if (s->UseEncrypt == false)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_ST_USE_ENCRYPT_FALSE"));
+ }
+ else
+ {
+ if (StrLen(s->CipherName) != 0)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_USE_ENCRYPT_TRUE"), s->CipherName);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_USE_ENCRYPT_TRUE2"));
+ }
+ }
+ CtInsert(ct, _UU("CM_ST_USE_ENCRYPT"), tmp);
+
+ if (s->UseCompress)
+ {
+ UINT percent = 0;
+ if ((s->TotalRecvSize + s->TotalSendSize) > 0)
+ {
+ percent = (UINT)((UINT64)100 - (UINT64)(s->TotalRecvSizeReal + s->TotalSendSizeReal) * (UINT64)100 /
+ (s->TotalRecvSize + s->TotalSendSize));
+ percent = MAKESURE(percent, 0, 100);
+ }
+
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_COMPRESS_TRUE"), percent);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CM_ST_COMPRESS_FALSE"));
+ }
+ CtInsert(ct, _UU("CM_ST_USE_COMPRESS"), tmp);
+
+ if (IsEmptyStr(s->UnderlayProtocol) == false)
+ {
+ StrToUni(tmp, sizeof(tmp), s->UnderlayProtocol);
+ CtInsert(ct, _UU("CM_ST_UNDERLAY_PROTOCOL"), tmp);
+ }
+
+ CtInsert(ct, _UU("CM_ST_UDP_ACCEL_ENABLED"), (s->IsUdpAccelerationEnabled ? _UU("CM_ST_YES") : _UU("CM_ST_NO")));
+ CtInsert(ct, _UU("CM_ST_UDP_ACCEL_USING"), (s->IsUsingUdpAcceleration ? _UU("CM_ST_YES") : _UU("CM_ST_NO")));
+
+ StrToUni(tmp, sizeof(tmp), s->SessionName);
+ CtInsert(ct, _UU("CM_ST_SESSION_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), s->ConnectionName);
+ if (UniStrCmpi(tmp, L"INITING") != 0)
+ {
+ CtInsert(ct, _UU("CM_ST_CONNECTION_NAME"), tmp);
+ }
+
+ BinToStr(str, sizeof(str), s->SessionKey, sizeof(s->SessionKey));
+ StrToUni(tmp, sizeof(tmp), str);
+ CtInsert(ct, _UU("CM_ST_SESSION_KEY"), tmp);
+
+ CtInsert(ct, _UU("CM_ST_BRIDGE_MODE"), s->IsBridgeMode ? _UU("CM_ST_YES") : _UU("CM_ST_NO"));
+
+ CtInsert(ct, _UU("CM_ST_MONITOR_MODE"), s->IsMonitorMode ? _UU("CM_ST_YES") : _UU("CM_ST_NO"));
+
+ ToStr3(vv, sizeof(vv), s->TotalSendSize);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_SEND_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->TotalRecvSize);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_RECV_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Send.UnicastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_SEND_UCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Send.UnicastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_SEND_UCAST_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Send.BroadcastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_SEND_BCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Send.BroadcastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_SEND_BCAST_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Recv.UnicastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_RECV_UCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Recv.UnicastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_RECV_UCAST_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Recv.BroadcastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_NUM_PACKET_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_RECV_BCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), s->Traffic.Recv.BroadcastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("CM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("CM_ST_RECV_BCAST_SIZE"), tmp);
+ }
+}
+
+// Get the current state of the cascade connection
+UINT PsCascadeStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_LINK_STATUS t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetLinkStatus(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Get the cascade connection state
+ CT *ct = CtNewStandard();
+
+ CmdPrintStatusToListView(ct, &t.Status);
+
+ CtFree(ct, c);
+
+ FreeRpcLinkStatus(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Rename the cascade connection
+UINT PsCascadeRename(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_RENAME_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeRename_PROMPT_OLD"), CmdEvalNotEmpty, NULL},
+ {"NEW", CmdPrompt, _UU("CMD_CascadeRename_PROMPT_NEW"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ UniStrCpy(t.NewAccountName, sizeof(t.NewAccountName), GetParamUniStr(o, "NEW"));
+ UniStrCpy(t.OldAccountName, sizeof(t.OldAccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScRenameLink(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the cascade connection to on-line state
+UINT PsCascadeOnline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScSetLinkOnline(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the cascade connection to the off-line state
+UINT PsCascadeOffline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_LINK t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_CascadeCreate_Prompt_Name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]"));
+
+ // RPC call
+ ret = ScSetLinkOffline(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Convert the string to pass / discard flag
+bool StrToPassOrDiscard(char *str)
+{
+ // Validate arguments
+ if (str == NULL)
+ {
+ return false;
+ }
+
+ if (ToInt(str) != 0)
+ {
+ return true;
+ }
+
+ if (StartWith(str, "p") || StartWith(str, "y") || StartWith(str, "t"))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Convert the string to the protocol
+UINT StrToProtocol(char *str)
+{
+ if (IsEmptyStr(str))
+ {
+ return 0;
+ }
+
+ if (StartWith("ip", str))
+ {
+ return 0;
+ }
+ else if (StartWith("tcp", str))
+ {
+ return IP_PROTO_TCP;
+ }
+ else if (StartWith("udp", str))
+ {
+ return IP_PROTO_UDP;
+ }
+ else if (StartWith("icmpv4", str))
+ {
+ return IP_PROTO_ICMPV4;
+ }
+ else if (StartWith("icmpv6", str))
+ {
+ return IP_PROTO_ICMPV6;
+ }
+
+ if (ToInt(str) == 0)
+ {
+ if (StrCmpi(str, "0") == 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return INFINITE;
+ }
+ }
+
+ if (ToInt(str) >= 256)
+ {
+ return INFINITE;
+ }
+
+ return ToInt(str);
+}
+
+// Check the protocol name
+bool CmdEvalProtocol(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[64];
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+ if (StrToProtocol(tmp) == INFINITE)
+ {
+ c->Write(c, _UU("CMD_PROTOCOL_EVAL_FAILED"));
+ return false;
+ }
+
+ return true;
+}
+
+// Parse the port range
+bool ParsePortRange(char *str, UINT *start, UINT *end)
+{
+ UINT a = 0, b = 0;
+ TOKEN_LIST *t;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return false;
+ }
+
+ if (IsEmptyStr(str) == false)
+ {
+
+ t = ParseToken(str, "\t -");
+
+ if (t->NumTokens == 1)
+ {
+ a = b = ToInt(t->Token[0]);
+ }
+ else if (t->NumTokens == 2)
+ {
+ a = ToInt(t->Token[0]);
+ b = ToInt(t->Token[1]);
+ }
+
+ FreeToken(t);
+
+ if (a > b)
+ {
+ return false;
+ }
+
+ if (a >= 65536 || b >= 65536)
+ {
+ return false;
+ }
+
+ if (a == 0 && b != 0)
+ {
+ return false;
+ }
+ }
+
+ if (start != NULL)
+ {
+ *start = a;
+ }
+ if (end != NULL)
+ {
+ *end = b;
+ }
+
+ return true;
+}
+
+// Check the port range
+bool CmdEvalPortRange(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[64];
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+ if (ParsePortRange(tmp, NULL, NULL) == false)
+ {
+ c->Write(c, _UU("CMD_PORT_RANGE_EVAL_FAILED"));
+ return false;
+ }
+
+ return true;
+}
+
+// Parse the MAC address and the mask
+bool ParseMacAddressAndMask(char *src, bool *check_mac, UCHAR *mac_bin, UCHAR *mask_bin)
+{
+ TOKEN_LIST *t;
+ char *macstr, *maskstr;
+ UCHAR mac[6], mask[6];
+ bool ok = false;
+
+ // Validate arguments
+ if (src == NULL)
+ {
+ return false;
+ }
+
+ //Zero(mac, sizeof(mac));
+ //Zero(mask, sizeof(mask));
+
+ if(check_mac != NULL && mac_bin != NULL && mask_bin != NULL)
+ {
+ ok = true;
+ }
+ if(IsEmptyStr(src) != false)
+ {
+ if(ok != false)
+ {
+ *check_mac = false;
+ Zero(mac_bin, 6);
+ Zero(mask_bin, 6);
+ }
+ return true;
+ }
+
+ t = ParseToken(src, "/");
+ if(t->NumTokens != 2)
+ {
+ FreeToken(t);
+ return false;
+ }
+
+ macstr = t->Token[0];
+ maskstr = t->Token[1];
+
+ Trim(macstr);
+ Trim(maskstr);
+
+ if(StrToMac(mac, macstr) == false || StrToMac(mask, maskstr) == false)
+ {
+ FreeToken(t);
+ return false;
+ }
+ else
+ {
+ if(ok != false)
+ {
+ Copy(mac_bin, mac, 6);
+ Copy(mask_bin, mask, 6);
+ *check_mac = true;
+ }
+ }
+ FreeToken(t);
+
+ return true;
+}
+
+// Check the MAC address and mask
+bool CmdEvalMacAddressAndMask(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[64];
+ // Validate arguments
+ if(c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+
+ if(ParseMacAddressAndMask(tmp, NULL, NULL, NULL) == false)
+ {
+ c->Write(c, _UU("CMD_MAC_ADDRESS_AND_MASK_EVAL_FAILED"));
+ return false;
+ }
+
+ return true;
+}
+// Parse the status of TCP connection
+bool ParseTcpState(char *src, bool *check_tcp_state, bool *established)
+{
+ bool ok = false;
+ // Validate arguments
+ if(src == NULL)
+ {
+ return false;
+ }
+
+ if(check_tcp_state != NULL && established != NULL)
+ {
+ ok = true;
+ }
+
+ if (IsEmptyStr(src) == false)
+ {
+ if (StartWith("Established", src) == 0)
+ {
+ if(ok != false)
+ {
+ *check_tcp_state = true;
+ *established = true;
+ }
+ }
+ else if (StartWith("Unestablished", src) == 0)
+ {
+ if(ok != false)
+ {
+ *check_tcp_state = true;
+ *established = false;
+ }
+ }
+ else
+ {
+ // Illegal string
+ return false;
+ }
+ }
+ else
+ {
+ if(ok != false)
+ {
+ *check_tcp_state = false;
+ *established = false;
+ }
+ }
+
+ return true;
+}
+// Check the status of the TCP connection
+bool CmdEvalTcpState(CONSOLE *c, wchar_t *str, void *param)
+{
+ char tmp[64];
+ // Validate arguments
+ if(c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+ if(ParseTcpState(tmp, NULL, NULL) == false)
+ {
+ c->Write(c, _UU("CMD_TCP_CONNECTION_STATE_EVAL_FAILED"));
+ return false;
+ }
+
+ return true;
+}
+
+// Adding a rule to the access list (Standard, IPv4)
+UINT PsAccessAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ADD_ACCESS t;
+ ACCESS *a;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX minmax =
+ {
+ "CMD_AccessAdd_Eval_PRIORITY", 1, 4294967295UL,
+ };
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[pass|discard]", CmdPrompt, _UU("CMD_AccessAdd_Prompt_TYPE"), CmdEvalNotEmpty, NULL},
+ {"MEMO", CmdPrompt, _UU("CMD_AccessAdd_Prompt_MEMO"), NULL, NULL},
+ {"PRIORITY", CmdPrompt, _UU("CMD_AccessAdd_Prompt_PRIORITY"), CmdEvalMinMax, &minmax},
+ {"SRCUSERNAME", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCUSERNAME"), NULL, NULL},
+ {"DESTUSERNAME", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTUSERNAME"), NULL, NULL},
+ {"SRCMAC", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCMAC"), CmdEvalMacAddressAndMask, NULL},
+ {"DESTMAC", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTMAC"), CmdEvalMacAddressAndMask, NULL},
+ {"SRCIP", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCIP"), CmdEvalIpAndMask4, NULL},
+ {"DESTIP", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTIP"), CmdEvalIpAndMask4, NULL},
+ {"PROTOCOL", CmdPrompt, _UU("CMD_AccessAdd_Prompt_PROTOCOL"), CmdEvalProtocol, NULL},
+ {"SRCPORT", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCPORT"), CmdEvalPortRange, NULL},
+ {"DESTPORT", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTPORT"), CmdEvalPortRange, NULL},
+ {"TCPSTATE", CmdPrompt, _UU("CMD_AccessAdd_Prompt_TCPSTATE"), CmdEvalTcpState, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ a = &t.Access;
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ UniStrCpy(a->Note, sizeof(a->Note), GetParamUniStr(o, "MEMO"));
+ a->Active = true;
+ a->Priority = GetParamInt(o, "PRIORITY");
+ a->Discard = StrToPassOrDiscard(GetParamStr(o, "[pass|discard]")) ? false : true;
+ StrCpy(a->SrcUsername, sizeof(a->SrcUsername), GetParamStr(o, "SRCUSERNAME"));
+ StrCpy(a->DestUsername, sizeof(a->DestUsername), GetParamStr(o, "DESTUSERNAME"));
+ ParseMacAddressAndMask(GetParamStr(o, "SRCMAC"), &a->CheckSrcMac, a->SrcMacAddress, a->SrcMacMask);
+ ParseMacAddressAndMask(GetParamStr(o, "DESTMAC"), &a->CheckDstMac, a->DstMacAddress, a->DstMacMask);
+ ParseIpAndMask4(GetParamStr(o, "SRCIP"), &a->SrcIpAddress, &a->SrcSubnetMask);
+ ParseIpAndMask4(GetParamStr(o, "DESTIP"), &a->DestIpAddress, &a->DestSubnetMask);
+ a->Protocol = StrToProtocol(GetParamStr(o, "PROTOCOL"));
+ ParsePortRange(GetParamStr(o, "SRCPORT"), &a->SrcPortStart, &a->SrcPortEnd);
+ ParsePortRange(GetParamStr(o, "DESTPORT"), &a->DestPortStart, &a->DestPortEnd);
+ ParseTcpState(GetParamStr(o, "TCPSTATE"), &a->CheckTcpState, &a->Established);
+
+ // RPC call
+ ret = ScAddAccess(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Adding a rule to the access list (Extended, IPv4)
+UINT PsAccessAddEx(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ADD_ACCESS t;
+ ACCESS *a;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX minmax =
+ {
+ "CMD_AccessAdd_Eval_PRIORITY", 1, 4294967295UL,
+ };
+ CMD_EVAL_MIN_MAX minmax_delay =
+ {
+ "CMD_AccessAddEx_Eval_DELAY", 0, HUB_ACCESSLIST_DELAY_MAX,
+ };
+ CMD_EVAL_MIN_MAX minmax_jitter =
+ {
+ "CMD_AccessAddEx_Eval_JITTER", 0, HUB_ACCESSLIST_JITTER_MAX,
+ };
+ CMD_EVAL_MIN_MAX minmax_loss =
+ {
+ "CMD_AccessAddEx_Eval_LOSS", 0, HUB_ACCESSLIST_LOSS_MAX,
+ };
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[pass|discard]", CmdPrompt, _UU("CMD_AccessAdd_Prompt_TYPE"), CmdEvalNotEmpty, NULL},
+ {"MEMO", CmdPrompt, _UU("CMD_AccessAdd_Prompt_MEMO"), NULL, NULL},
+ {"PRIORITY", CmdPrompt, _UU("CMD_AccessAdd_Prompt_PRIORITY"), CmdEvalMinMax, &minmax},
+ {"SRCUSERNAME", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCUSERNAME"), NULL, NULL},
+ {"DESTUSERNAME", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTUSERNAME"), NULL, NULL},
+ {"SRCMAC", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCMAC"), CmdEvalMacAddressAndMask, NULL},
+ {"DESTMAC", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTMAC"), CmdEvalMacAddressAndMask, NULL},
+ {"SRCIP", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCIP"), CmdEvalIpAndMask4, NULL},
+ {"DESTIP", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTIP"), CmdEvalIpAndMask4, NULL},
+ {"PROTOCOL", CmdPrompt, _UU("CMD_AccessAdd_Prompt_PROTOCOL"), CmdEvalProtocol, NULL},
+ {"SRCPORT", CmdPrompt, _UU("CMD_AccessAdd_Prompt_SRCPORT"), CmdEvalPortRange, NULL},
+ {"DESTPORT", CmdPrompt, _UU("CMD_AccessAdd_Prompt_DESTPORT"), CmdEvalPortRange, NULL},
+ {"TCPSTATE", CmdPrompt, _UU("CMD_AccessAdd_Prompt_TCPSTATE"), CmdEvalTcpState, NULL},
+ {"DELAY", CmdPrompt, _UU("CMD_AccessAddEx_Prompt_DELAY"), CmdEvalMinMax, &minmax_delay},
+ {"JITTER", CmdPrompt, _UU("CMD_AccessAddEx_Prompt_JITTER"), CmdEvalMinMax, &minmax_jitter},
+ {"LOSS", CmdPrompt, _UU("CMD_AccessAddEx_Prompt_LOSS"), CmdEvalMinMax, &minmax_loss},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Check whether it is supported
+ if (GetCapsBool(ps->CapsList, "b_support_ex_acl") == false)
+ {
+ c->Write(c, _E(ERR_NOT_SUPPORTED));
+ return ERR_NOT_SUPPORTED;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ a = &t.Access;
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ UniStrCpy(a->Note, sizeof(a->Note), GetParamUniStr(o, "MEMO"));
+ a->Active = true;
+ a->Priority = GetParamInt(o, "PRIORITY");
+ a->Discard = StrToPassOrDiscard(GetParamStr(o, "[pass|discard]")) ? false : true;
+ StrCpy(a->SrcUsername, sizeof(a->SrcUsername), GetParamStr(o, "SRCUSERNAME"));
+ StrCpy(a->DestUsername, sizeof(a->DestUsername), GetParamStr(o, "DESTUSERNAME"));
+ ParseMacAddressAndMask(GetParamStr(o, "SRCMAC"), &a->CheckSrcMac, a->SrcMacAddress, a->SrcMacMask);
+ ParseMacAddressAndMask(GetParamStr(o, "DESTMAC"), &a->CheckDstMac, a->DstMacAddress, a->DstMacMask);
+ ParseIpAndMask4(GetParamStr(o, "SRCIP"), &a->SrcIpAddress, &a->SrcSubnetMask);
+ ParseIpAndMask4(GetParamStr(o, "DESTIP"), &a->DestIpAddress, &a->DestSubnetMask);
+ a->Protocol = StrToProtocol(GetParamStr(o, "PROTOCOL"));
+ ParsePortRange(GetParamStr(o, "SRCPORT"), &a->SrcPortStart, &a->SrcPortEnd);
+ ParsePortRange(GetParamStr(o, "DESTPORT"), &a->DestPortStart, &a->DestPortEnd);
+ ParseTcpState(GetParamStr(o, "TCPSTATE"), &a->CheckTcpState, &a->Established);
+ a->Delay = GetParamInt(o, "DELAY");
+ a->Jitter = GetParamInt(o, "JITTER");
+ a->Loss = GetParamInt(o, "LOSS");
+
+ // RPC call
+ ret = ScAddAccess(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Adding a rule to the access list (Standard, IPv6)
+UINT PsAccessAdd6(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ADD_ACCESS t;
+ ACCESS *a;
+ IP ip, mask;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX minmax =
+ {
+ "CMD_AccessAdd6_Eval_PRIORITY", 1, 4294967295UL,
+ };
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[pass|discard]", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_TYPE"), CmdEvalNotEmpty, NULL},
+ {"MEMO", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_MEMO"), NULL, NULL},
+ {"PRIORITY", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_PRIORITY"), CmdEvalMinMax, &minmax},
+ {"SRCUSERNAME", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCUSERNAME"), NULL, NULL},
+ {"DESTUSERNAME", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTUSERNAME"), NULL, NULL},
+ {"SRCMAC", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCMAC"), CmdEvalMacAddressAndMask, NULL},
+ {"DESTMAC", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTMAC"), CmdEvalMacAddressAndMask, NULL},
+ {"SRCIP", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCIP"), CmdEvalIpAndMask6, NULL},
+ {"DESTIP", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTIP"), CmdEvalIpAndMask6, NULL},
+ {"PROTOCOL", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_PROTOCOL"), CmdEvalProtocol, NULL},
+ {"SRCPORT", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCPORT"), CmdEvalPortRange, NULL},
+ {"DESTPORT", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTPORT"), CmdEvalPortRange, NULL},
+ {"TCPSTATE", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_TCPSTATE"), CmdEvalTcpState, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Check whether it is supported
+ if (GetCapsBool(ps->CapsList, "b_support_ex_acl") == false)
+ {
+ c->Write(c, _E(ERR_NOT_SUPPORTED));
+ return ERR_NOT_SUPPORTED;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ a = &t.Access;
+
+ a->IsIPv6 = true;
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ UniStrCpy(a->Note, sizeof(a->Note), GetParamUniStr(o, "MEMO"));
+ a->Active = true;
+ a->Priority = GetParamInt(o, "PRIORITY");
+ a->Discard = StrToPassOrDiscard(GetParamStr(o, "[pass|discard]")) ? false : true;
+ StrCpy(a->SrcUsername, sizeof(a->SrcUsername), GetParamStr(o, "SRCUSERNAME"));
+ StrCpy(a->DestUsername, sizeof(a->DestUsername), GetParamStr(o, "DESTUSERNAME"));
+ ParseMacAddressAndMask(GetParamStr(o, "SRCMAC"), &a->CheckSrcMac, a->SrcMacAddress, a->SrcMacMask);
+ ParseMacAddressAndMask(GetParamStr(o, "DESTMAC"), &a->CheckDstMac, a->DstMacAddress, a->DstMacMask);
+
+ Zero(&ip, sizeof(ip));
+ Zero(&mask, sizeof(mask));
+
+ ParseIpAndMask6(GetParamStr(o, "SRCIP"), &ip, &mask);
+ IPToIPv6Addr(&a->SrcIpAddress6, &ip);
+ IPToIPv6Addr(&a->SrcSubnetMask6, &mask);
+
+ ParseIpAndMask6(GetParamStr(o, "DESTIP"), &ip, &mask);
+ IPToIPv6Addr(&a->DestIpAddress6, &ip);
+ IPToIPv6Addr(&a->DestSubnetMask6, &mask);
+
+ a->Protocol = StrToProtocol(GetParamStr(o, "PROTOCOL"));
+ ParsePortRange(GetParamStr(o, "SRCPORT"), &a->SrcPortStart, &a->SrcPortEnd);
+ ParsePortRange(GetParamStr(o, "DESTPORT"), &a->DestPortStart, &a->DestPortEnd);
+ ParseTcpState(GetParamStr(o, "TCPSTATE"), &a->CheckTcpState, &a->Established);
+
+ // RPC call
+ ret = ScAddAccess(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Adding a rule to the access list (Extended, IPv6)
+UINT PsAccessAddEx6(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ADD_ACCESS t;
+ ACCESS *a;
+ IP ip, mask;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX minmax =
+ {
+ "CMD_AccessAdd6_Eval_PRIORITY", 1, 4294967295UL,
+ };
+ CMD_EVAL_MIN_MAX minmax_delay =
+ {
+ "CMD_AccessAddEx6_Eval_DELAY", 0, HUB_ACCESSLIST_DELAY_MAX,
+ };
+ CMD_EVAL_MIN_MAX minmax_jitter =
+ {
+ "CMD_AccessAddEx6_Eval_JITTER", 0, HUB_ACCESSLIST_JITTER_MAX,
+ };
+ CMD_EVAL_MIN_MAX minmax_loss =
+ {
+ "CMD_AccessAddEx6_Eval_LOSS", 0, HUB_ACCESSLIST_LOSS_MAX,
+ };
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[pass|discard]", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_TYPE"), CmdEvalNotEmpty, NULL},
+ {"MEMO", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_MEMO"), NULL, NULL},
+ {"PRIORITY", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_PRIORITY"), CmdEvalMinMax, &minmax},
+ {"SRCUSERNAME", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCUSERNAME"), NULL, NULL},
+ {"DESTUSERNAME", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTUSERNAME"), NULL, NULL},
+ {"SRCMAC", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCMAC"), CmdEvalMacAddressAndMask, NULL},
+ {"DESTMAC", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTMAC"), CmdEvalMacAddressAndMask, NULL},
+ {"SRCIP", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCIP"), CmdEvalIpAndMask6, NULL},
+ {"DESTIP", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTIP"), CmdEvalIpAndMask6, NULL},
+ {"PROTOCOL", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_PROTOCOL"), CmdEvalProtocol, NULL},
+ {"SRCPORT", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_SRCPORT"), CmdEvalPortRange, NULL},
+ {"DESTPORT", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_DESTPORT"), CmdEvalPortRange, NULL},
+ {"TCPSTATE", CmdPrompt, _UU("CMD_AccessAdd6_Prompt_TCPSTATE"), CmdEvalTcpState, NULL},
+ {"DELAY", CmdPrompt, _UU("CMD_AccessAddEx6_Prompt_DELAY"), CmdEvalMinMax, &minmax_delay},
+ {"JITTER", CmdPrompt, _UU("CMD_AccessAddEx6_Prompt_JITTER"), CmdEvalMinMax, &minmax_jitter},
+ {"LOSS", CmdPrompt, _UU("CMD_AccessAddEx6_Prompt_LOSS"), CmdEvalMinMax, &minmax_loss},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Check whether it is supported
+ if (GetCapsBool(ps->CapsList, "b_support_ex_acl") == false)
+ {
+ c->Write(c, _E(ERR_NOT_SUPPORTED));
+ return ERR_NOT_SUPPORTED;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ a = &t.Access;
+
+ a->IsIPv6 = true;
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ UniStrCpy(a->Note, sizeof(a->Note), GetParamUniStr(o, "MEMO"));
+ a->Active = true;
+ a->Priority = GetParamInt(o, "PRIORITY");
+ a->Discard = StrToPassOrDiscard(GetParamStr(o, "[pass|discard]")) ? false : true;
+ StrCpy(a->SrcUsername, sizeof(a->SrcUsername), GetParamStr(o, "SRCUSERNAME"));
+ StrCpy(a->DestUsername, sizeof(a->DestUsername), GetParamStr(o, "DESTUSERNAME"));
+ ParseMacAddressAndMask(GetParamStr(o, "SRCMAC"), &a->CheckSrcMac, a->SrcMacAddress, a->SrcMacMask);
+ ParseMacAddressAndMask(GetParamStr(o, "DESTMAC"), &a->CheckDstMac, a->DstMacAddress, a->DstMacMask);
+
+ Zero(&ip, sizeof(ip));
+ Zero(&mask, sizeof(mask));
+
+ ParseIpAndMask6(GetParamStr(o, "SRCIP"), &ip, &mask);
+ IPToIPv6Addr(&a->SrcIpAddress6, &ip);
+ IPToIPv6Addr(&a->SrcSubnetMask6, &mask);
+
+ ParseIpAndMask6(GetParamStr(o, "DESTIP"), &ip, &mask);
+ IPToIPv6Addr(&a->DestIpAddress6, &ip);
+ IPToIPv6Addr(&a->DestSubnetMask6, &mask);
+
+ a->Protocol = StrToProtocol(GetParamStr(o, "PROTOCOL"));
+ ParsePortRange(GetParamStr(o, "SRCPORT"), &a->SrcPortStart, &a->SrcPortEnd);
+ ParsePortRange(GetParamStr(o, "DESTPORT"), &a->DestPortStart, &a->DestPortEnd);
+ ParseTcpState(GetParamStr(o, "TCPSTATE"), &a->CheckTcpState, &a->Established);
+ a->Delay = GetParamInt(o, "DELAY");
+ a->Jitter = GetParamInt(o, "JITTER");
+ a->Loss = GetParamInt(o, "LOSS");
+
+ // RPC call
+ ret = ScAddAccess(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+
+// Get the list of rules in the access list
+UINT PsAccessList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_ACCESS_LIST t;
+ CT *ct;
+ UINT i;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumAccess(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNew();
+ CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_0"), true);
+ CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_1"), true);
+ CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_2"), true);
+ CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_3"), true);
+ CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_6"), true);
+ CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_5"), false);
+ CtInsertColumn(ct, _UU("SM_ACCESS_COLUMN_4"), false);
+
+ for (i = 0;i < t.NumAccess;i++)
+ {
+ ACCESS *a = &t.Accesses[i];
+ char tmp[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+
+ GetAccessListStr(tmp, sizeof(tmp), a);
+ UniToStru(tmp1, a->Priority);
+ StrToUni(tmp2, sizeof(tmp2), tmp);
+ UniToStru(tmp4, a->UniqueId);
+ if (a->UniqueId == 0)
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SEC_NONE"));
+ }
+
+ UniToStru(tmp3, a->Id);
+
+ CtInsert(ct,
+ tmp3,
+ a->Discard ? _UU("SM_ACCESS_DISCARD") : _UU("SM_ACCESS_PASS"),
+ a->Active ? _UU("SM_ACCESS_ENABLE") : _UU("SM_ACCESS_DISABLE"),
+ tmp1,
+ tmp4,
+ tmp2,
+ a->Note);
+ }
+
+ CtFreeEx(ct, c, true);
+
+ FreeRpcEnumAccessList(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Remove a rule from the access list
+UINT PsAccessDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_DELETE_ACCESS t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_Access_Prompt_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Id = GetParamInt(o, "[id]");
+
+ // RPC call
+ ret = ScDeleteAccess(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable the rule of access list
+UINT PsAccessEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_ACCESS_LIST t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_Access_Prompt_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumAccess(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ bool b = false;
+ for (i = 0;i < t.NumAccess;i++)
+ {
+ ACCESS *a = &t.Accesses[i];
+
+ if (a->Id == GetParamInt(o, "[id]"))
+ {
+ b = true;
+
+ a->Active = true;
+ }
+ }
+
+ if (b == false)
+ {
+ // The specified ID is not found
+ ret = ERR_OBJECT_NOT_FOUND;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ FreeRpcEnumAccessList(&t);
+ return ret;
+ }
+
+ ret = ScSetAccessList(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcEnumAccessList(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Disable the rule of access list
+UINT PsAccessDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_ACCESS_LIST t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_Access_Prompt_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumAccess(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ bool b = false;
+ for (i = 0;i < t.NumAccess;i++)
+ {
+ ACCESS *a = &t.Accesses[i];
+
+ if (a->Id == GetParamInt(o, "[id]"))
+ {
+ b = true;
+
+ a->Active = false;
+ }
+ }
+
+ if (b == false)
+ {
+ // The specified ID is not found
+ ret = ERR_OBJECT_NOT_FOUND;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ FreeRpcEnumAccessList(&t);
+ return ret;
+ }
+
+ ret = ScSetAccessList(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcEnumAccessList(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Get the user list
+UINT PsUserList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_USER t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ CT *ct = CtNew();
+
+ CtInsertColumn(ct, _UU("SM_USER_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_USER_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_USER_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_USER_COLUMN_4"), false);
+ CtInsertColumn(ct, _UU("SM_USER_COLUMN_5"), false);
+ CtInsertColumn(ct, _UU("SM_USER_COLUMN_6"), false);
+ CtInsertColumn(ct, _UU("SM_USER_COLUMN_7"), false);
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_5"), false);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_6"), false);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_7"), false);
+
+ for (i = 0;i < t.NumUser;i++)
+ {
+ RPC_ENUM_USER_ITEM *e = &t.Users[i];
+ wchar_t name[MAX_SIZE];
+ wchar_t group[MAX_SIZE];
+ wchar_t num[MAX_SIZE];
+ wchar_t time[MAX_SIZE];
+ wchar_t exp[MAX_SIZE];
+ wchar_t num1[64], num2[64];
+
+ StrToUni(name, sizeof(name), e->Name);
+
+ if (StrLen(e->GroupName) != 0)
+ {
+ StrToUni(group, sizeof(group), e->GroupName);
+ }
+ else
+ {
+ UniStrCpy(group, sizeof(group), _UU("SM_NO_GROUP"));
+ }
+
+ UniToStru(num, e->NumLogin);
+
+ GetDateTimeStrEx64(time, sizeof(time), SystemToLocal64(e->LastLoginTime), NULL);
+
+ if (e->IsExpiresFilled == false)
+ {
+ UniStrCpy(exp, sizeof(exp), _UU("CM_ST_NONE"));
+ }
+ else
+ {
+ if (e->Expires == 0)
+ {
+ UniStrCpy(exp, sizeof(exp), _UU("SM_LICENSE_NO_EXPIRES"));
+ }
+ else
+ {
+ GetDateTimeStrEx64(exp, sizeof(exp), SystemToLocal64(e->Expires), NULL);
+ }
+ }
+
+ if (e->IsTrafficFilled == false)
+ {
+ UniStrCpy(num1, sizeof(num1), _UU("CM_ST_NONE"));
+ UniStrCpy(num2, sizeof(num2), _UU("CM_ST_NONE"));
+ }
+ else
+ {
+ UniToStr3(num1, sizeof(num1),
+ e->Traffic.Recv.BroadcastBytes + e->Traffic.Recv.UnicastBytes +
+ e->Traffic.Send.BroadcastBytes + e->Traffic.Send.UnicastBytes);
+
+ UniToStr3(num2, sizeof(num2),
+ e->Traffic.Recv.BroadcastCount + e->Traffic.Recv.UnicastCount +
+ e->Traffic.Send.BroadcastBytes + e->Traffic.Send.UnicastCount);
+ }
+
+ CtInsert(ct,
+ name, e->Realname, group, e->Note, GetAuthTypeStr(e->AuthType),
+ num, time, exp, num1, num2);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get a string of user authentication method
+wchar_t *GetAuthTypeStr(UINT id)
+{
+ char tmp[MAX_SIZE];
+ Format(tmp, sizeof(tmp), "SM_AUTHTYPE_%u", id);
+
+ return _UU(tmp);
+}
+
+// Creating a user
+UINT PsUserCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"GROUP", CmdPrompt, _UU("CMD_UserCreate_Prompt_GROUP"), NULL, NULL},
+ {"REALNAME", CmdPrompt, _UU("CMD_UserCreate_Prompt_REALNAME"), NULL, NULL},
+ {"NOTE", CmdPrompt, _UU("CMD_UserCreate_Prompt_NOTE"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+ StrCpy(t.GroupName, sizeof(t.GroupName), GetParamStr(o, "GROUP"));
+ UniStrCpy(t.Realname, sizeof(t.Realname), GetParamUniStr(o, "REALNAME"));
+ UniStrCpy(t.Note, sizeof(t.Note), GetParamUniStr(o, "NOTE"));
+
+ Trim(t.Name);
+ if (StrCmpi(t.Name, "*") == 0)
+ {
+ t.AuthType = AUTHTYPE_RADIUS;
+ t.AuthData = NewRadiusAuthData(NULL);
+ }
+ else
+ {
+ UCHAR random_pass[SHA1_SIZE];
+ UCHAR random_pass2[MD5_SIZE];
+
+ Rand(random_pass, sizeof(random_pass));
+ Rand(random_pass2, sizeof(random_pass2));
+ t.AuthType = AUTHTYPE_PASSWORD;
+ t.AuthData = NewPasswordAuthDataRaw(random_pass, random_pass2);
+ }
+
+ // RPC call
+ ret = ScCreateUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Change the user information
+UINT PsUserSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"GROUP", CmdPrompt, _UU("CMD_UserCreate_Prompt_GROUP"), NULL, NULL},
+ {"REALNAME", CmdPrompt, _UU("CMD_UserCreate_Prompt_REALNAME"), NULL, NULL},
+ {"NOTE", CmdPrompt, _UU("CMD_UserCreate_Prompt_NOTE"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Update the information
+ StrCpy(t.GroupName, sizeof(t.GroupName), GetParamStr(o, "GROUP"));
+ UniStrCpy(t.Realname, sizeof(t.Realname), GetParamUniStr(o, "REALNAME"));
+ UniStrCpy(t.Note, sizeof(t.Note), GetParamUniStr(o, "NOTE"));
+
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the user
+UINT PsUserDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_DELETE_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScDeleteUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the user information
+UINT PsUserGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ CT *ct;
+
+ // Display the user's data
+ ct = CtNewStandard();
+
+ // User name
+ StrToUni(tmp, sizeof(tmp), t.Name);
+ CtInsert(ct, _UU("CMD_UserGet_Column_Name"), tmp);
+
+ // Real name
+ CtInsert(ct, _UU("CMD_UserGet_Column_RealName"), t.Realname);
+
+ // Description
+ CtInsert(ct, _UU("CMD_UserGet_Column_Note"), t.Note);
+
+ // Group name
+ if (IsEmptyStr(t.GroupName) == false)
+ {
+ StrToUni(tmp, sizeof(tmp), t.GroupName);
+ CtInsert(ct, _UU("CMD_UserGet_Column_Group"), tmp);
+ }
+
+ // Expiration date
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.ExpireTime), NULL);
+ CtInsert(ct, _UU("CMD_UserGet_Column_Expires"), tmp);
+
+ // Authentication method
+ CtInsert(ct, _UU("CMD_UserGet_Column_AuthType"), GetAuthTypeStr(t.AuthType));
+
+ switch (t.AuthType)
+ {
+ case AUTHTYPE_USERCERT:
+ if (t.AuthData != NULL)
+ {
+ AUTHUSERCERT *auc = (AUTHUSERCERT *)t.AuthData;
+
+ if (auc != NULL && auc->UserX != NULL)
+ {
+ // Registered user-specific certificate
+ GetAllNameFromX(tmp, sizeof(tmp), auc->UserX);
+ CtInsert(ct, _UU("CMD_UserGet_Column_UserCert"), tmp);
+ }
+ }
+ break;
+
+ case AUTHTYPE_ROOTCERT:
+ if (t.AuthData != NULL)
+ {
+ AUTHROOTCERT *arc = (AUTHROOTCERT *)t.AuthData;
+
+ if (IsEmptyUniStr(arc->CommonName) == false)
+ {
+ // Limitation the value of the certificate's CN
+ CtInsert(ct, _UU("CMD_UserGet_Column_RootCert_CN"), arc->CommonName);
+ }
+
+ if (arc->Serial != NULL && arc->Serial->size >= 1)
+ {
+ char tmp2[MAX_SIZE];
+
+ // Limitation the serial number of the certificate
+ BinToStrEx(tmp2, sizeof(tmp2), arc->Serial->data, arc->Serial->size);
+ StrToUni(tmp, sizeof(tmp), tmp2);
+ CtInsert(ct, _UU("CMD_UserGet_Column_RootCert_SERIAL"), tmp);
+ }
+ }
+ break;
+
+ case AUTHTYPE_RADIUS:
+ case AUTHTYPE_NT:
+ if (t.AuthData != NULL)
+ {
+ AUTHRADIUS *ar = (AUTHRADIUS *)t.AuthData;
+
+ // Authentication user name of the external authentication server
+ if (IsEmptyUniStr(ar->RadiusUsername) == false)
+ {
+ CtInsert(ct, _UU("CMD_UserGet_Column_RadiusAlias"), ar->RadiusUsername);
+ }
+ }
+ break;
+ }
+
+ CtInsert(ct, L"---", L"---");
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.CreatedTime), NULL);
+ CtInsert(ct, _UU("SM_USERINFO_CREATE"), tmp);
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.UpdatedTime), NULL);
+ CtInsert(ct, _UU("SM_USERINFO_UPDATE"), tmp);
+
+ CmdInsertTrafficInfo(ct, &t.Traffic);
+
+ UniToStru(tmp, t.NumLogin);
+ CtInsert(ct, _UU("SM_USERINFO_NUMLOGIN"), tmp);
+
+
+ CtFree(ct, c);
+
+ if (t.Policy != NULL)
+ {
+ c->Write(c, L"");
+ c->Write(c, _UU("CMD_UserGet_Policy"));
+ PrintPolicy(c, t.Policy, false);
+ }
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the authentication method for the user to the anonymous authentication
+UINT PsUserAnonymousSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Update the information
+ FreeAuthData(t.AuthType, t.AuthData);
+
+ // Set to anonymous authentication
+ t.AuthType = AUTHTYPE_ANONYMOUS;
+ t.AuthData = NULL;
+
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the authentication method for the user to the password authentication and set a password
+UINT PsUserPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"PASSWORD", CmdPromptChoosePassword, NULL, NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Update the information
+ FreeAuthData(t.AuthType, t.AuthData);
+
+ {
+ AUTHPASSWORD *pw;
+
+ pw = NewPasswordAuthData(t.Name, GetParamStr(o, "PASSWORD"));
+
+ // Set to the password authentication
+ t.AuthType = AUTHTYPE_PASSWORD;
+ t.AuthData = pw;
+ }
+
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the authentication method for the user to the specific certificate authentication and set a certificate
+UINT PsUserCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ X *x;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Read the certificate
+ x = FileToXW(GetParamUniStr(o, "LOADCERT"));
+ if (x == NULL)
+ {
+ c->Write(c, _UU("CMD_LOADCERT_FAILED"));
+
+ FreeParamValueList(o);
+
+ return ERR_INTERNAL_ERROR;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ FreeX(x);
+ return ret;
+ }
+
+ // Update the information
+ FreeAuthData(t.AuthType, t.AuthData);
+
+ {
+ AUTHUSERCERT *c;
+
+ c = NewUserCertAuthData(x);
+
+ FreeX(x);
+
+ // Set to the password authentication
+ t.AuthType = AUTHTYPE_USERCERT;
+ t.AuthData = c;
+ }
+
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get certificates that are registered in the user which uses certificate authentication
+UINT PsUserCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ AUTHUSERCERT *a;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"SAVECERT", CmdPrompt, _UU("CMD_SAVECERTPATH"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ a = (AUTHUSERCERT *)t.AuthData;
+
+ if (t.AuthType != AUTHTYPE_USERCERT || a == NULL || a->UserX == NULL)
+ {
+ // The user is not using specific certificate authentication
+ ret = ERR_INVALID_PARAMETER;
+
+ c->Write(c, _UU("CMD_UserCertGet_Not_Cert"));
+ }
+ else
+ {
+ if (XToFileW(a->UserX, GetParamUniStr(o, "SAVECERT"), true) == false)
+ {
+ c->Write(c, _UU("CMD_SAVECERT_FAILED"));
+ }
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Set the authentication method for the user to the signed certificate authentication
+UINT PsUserSignedSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"CN", CmdPrompt, _UU("CMD_UserSignedSet_Prompt_CN"), NULL, NULL},
+ {"SERIAL", CmdPrompt, _UU("CMD_UserSignedSet_Prompt_SERIAL"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Update the information
+ FreeAuthData(t.AuthType, t.AuthData);
+
+ {
+ AUTHROOTCERT *c;
+ BUF *b;
+ X_SERIAL *serial = NULL;
+
+ b = StrToBin(GetParamStr(o, "SERIAL"));
+
+ if (b != NULL && b->Size >= 1)
+ {
+ serial = NewXSerial(b->Buf, b->Size);
+ }
+
+ FreeBuf(b);
+
+ c = NewRootCertAuthData(serial, GetParamUniStr(o, "CN"));
+
+ FreeXSerial(serial);
+
+ // Set to the signed certificate authentication
+ t.AuthType = AUTHTYPE_ROOTCERT;
+ t.AuthData = c;
+ }
+
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the authentication method for the user to the Radius authentication
+UINT PsUserRadiusSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"ALIAS", CmdPrompt, _UU("CMD_UserRadiusSet_Prompt_ALIAS"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Update the information
+ FreeAuthData(t.AuthType, t.AuthData);
+
+ {
+ AUTHRADIUS *a;
+
+ a = NewRadiusAuthData(GetParamUniStr(o, "ALIAS"));
+
+ // Set to Radius authentication
+ t.AuthType = AUTHTYPE_RADIUS;
+ t.AuthData = a;
+ }
+
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the authentication method for the user to the NT domain authentication
+UINT PsUserNTLMSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"ALIAS", CmdPrompt, _UU("CMD_UserRadiusSet_Prompt_ALIAS"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Update the information
+ FreeAuthData(t.AuthType, t.AuthData);
+
+ {
+ AUTHRADIUS *a;
+
+ a = NewRadiusAuthData(GetParamUniStr(o, "ALIAS"));
+
+ // Set to the NT domain authentication
+ t.AuthType = AUTHTYPE_NT;
+ t.AuthData = a;
+ }
+
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the security policy of the user
+UINT PsUserPolicyRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Update
+ if (t.Policy != NULL)
+ {
+ Free(t.Policy);
+ t.Policy = NULL;
+ }
+
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set a security policy of the user
+UINT PsUserPolicySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"NAME", CmdPrompt, _UU("CMD_CascadePolicySet_PROMPT_POLNAME"), CmdEvalNotEmpty, NULL},
+ {"VALUE", CmdPrompt, _UU("CMD_CascadePolicySet_PROMPT_POLVALUE"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Update
+ if (t.Policy == NULL)
+ {
+ t.Policy = ClonePolicy(GetDefaultPolicy());
+ }
+
+ // Edit
+ if (EditPolicy(c, t.Policy, GetParamStr(o, "NAME"), GetParamStr(o, "VALUE"), false) == false)
+ {
+ ret = ERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Convert the string to a date and time
+UINT64 StrToDateTime64(char *str)
+{
+ UINT64 ret = 0;
+ TOKEN_LIST *t;
+ UINT a, b, c, d, e, f;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return INFINITE;
+ }
+
+ if (IsEmptyStr(str) || StrCmpi(str, "none") == 0)
+ {
+ return 0;
+ }
+
+ t = ParseToken(str, ":/,. \"");
+ if (t->NumTokens != 6)
+ {
+ FreeToken(t);
+ return INFINITE;
+ }
+
+ a = ToInt(t->Token[0]);
+ b = ToInt(t->Token[1]);
+ c = ToInt(t->Token[2]);
+ d = ToInt(t->Token[3]);
+ e = ToInt(t->Token[4]);
+ f = ToInt(t->Token[5]);
+
+ ret = INFINITE;
+
+ if (a >= 1000 && a <= 9999 && b >= 1 && b <= 12 && c >= 1 && c <= 31 &&
+ d >= 0 && d <= 23 && e >= 0 && e <= 59 && f >= 0 && f <= 59)
+ {
+ SYSTEMTIME t;
+
+ Zero(&t, sizeof(t));
+ t.wYear = a;
+ t.wMonth = b;
+ t.wDay = c;
+ t.wHour = d;
+ t.wMinute = e;
+ t.wSecond = f;
+
+ ret = SystemToUINT64(&t);
+ }
+
+ FreeToken(t);
+
+ return ret;
+}
+
+// Evaluate the date and time string
+bool CmdEvalDateTime(CONSOLE *c, wchar_t *str, void *param)
+{
+ UINT64 ret;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniToStr(tmp, sizeof(tmp), str);
+
+ ret = StrToDateTime64(tmp);
+
+ if (ret == INFINITE)
+ {
+ c->Write(c, _UU("CMD_EVAL_DATE_TIME_FAILED"));
+ return false;
+ }
+
+ return true;
+}
+
+// Set the expiration date of the user
+UINT PsUserExpiresSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ UINT64 expires;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_UserCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"EXPIRES", CmdPrompt, _UU("CMD_UserExpiresSet_Prompt_EXPIRES"), CmdEvalDateTime, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ // Get the user object
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ ret = ScGetUser(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Update the information
+ expires = StrToDateTime64(GetParamStr(o, "EXPIRES"));
+
+ if (expires != 0)
+ {
+ expires = LocalToSystem64(expires);
+ }
+
+ t.ExpireTime = expires;
+
+ // Write the user object
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the group list
+UINT PsGroupList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_GROUP t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNew();
+ UINT i;
+
+ CtInsertColumn(ct, _UU("SM_GROUPLIST_NAME"), false);
+ CtInsertColumn(ct, _UU("SM_GROUPLIST_REALNAME"), false);
+ CtInsertColumn(ct, _UU("SM_GROUPLIST_NOTE"), false);
+ CtInsertColumn(ct, _UU("SM_GROUPLIST_NUMUSERS"), false);
+
+ for (i = 0;i < t.NumGroup;i++)
+ {
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ RPC_ENUM_GROUP_ITEM *e = &t.Groups[i];
+
+ StrToUni(tmp1, sizeof(tmp1), e->Name);
+ UniToStru(tmp2, e->NumUsers);
+
+ CtInsert(ct, tmp1, e->Realname, e->Note, tmp2);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumGroup(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Create a group
+UINT PsGroupCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_GROUP t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"REALNAME", CmdPrompt, _UU("CMD_GroupCreate_Prompt_REALNAME"), NULL, NULL},
+ {"NOTE", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NOTE"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+ UniStrCpy(t.Realname, sizeof(t.Realname), GetParamUniStr(o, "REALNAME"));
+ UniStrCpy(t.Note, sizeof(t.Note), GetParamUniStr(o, "NOTE"));
+
+ // RPC call
+ ret = ScCreateGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetGroup(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the group information
+UINT PsGroupSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_GROUP t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"REALNAME", CmdPrompt, _UU("CMD_GroupCreate_Prompt_REALNAME"), NULL, NULL},
+ {"NOTE", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NOTE"), NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ // Information update
+ UniStrCpy(t.Realname, sizeof(t.Realname), GetParamUniStr(o, "REALNAME"));
+ UniStrCpy(t.Note, sizeof(t.Note), GetParamUniStr(o, "NOTE"));
+
+ // RPC call
+ ret = ScSetGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcSetGroup(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete a group
+UINT PsGroupDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_DELETE_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScDeleteGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the group information and the list of users who belong to the group
+UINT PsGroupGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_GROUP t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ char groupname[MAX_USERNAME_LEN + 1];
+ CT *ct = CtNewStandard();
+
+ StrCpy(groupname, sizeof(groupname), t.Name);
+
+ StrToUni(tmp, sizeof(tmp), t.Name);
+ CtInsert(ct, _UU("CMD_GroupGet_Column_NAME"), tmp);
+ CtInsert(ct, _UU("CMD_GroupGet_Column_REALNAME"), t.Realname);
+ CtInsert(ct, _UU("CMD_GroupGet_Column_NOTE"), t.Note);
+
+ CtFree(ct, c);
+
+ if (t.Policy != NULL)
+ {
+ c->Write(c, L"");
+ c->Write(c, _UU("CMD_GroupGet_Column_POLICY"));
+
+ PrintPolicy(c, t.Policy, false);
+ }
+
+ {
+ RPC_ENUM_USER t;
+ bool b = false;
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ if (ScEnumUser(ps->Rpc, &t) == ERR_NO_ERROR)
+ {
+ UINT i;
+
+ for (i = 0;i < t.NumUser;i++)
+ {
+ RPC_ENUM_USER_ITEM *u = &t.Users[i];
+
+ if (StrCmpi(u->GroupName, groupname) == 0)
+ {
+ if (b == false)
+ {
+ b = true;
+ c->Write(c, L"");
+ c->Write(c, _UU("CMD_GroupGet_Column_MEMBERS"));
+ }
+
+ UniFormat(tmp, sizeof(tmp), L" %S", u->Name);
+ c->Write(c, tmp);
+ }
+ }
+ FreeRpcEnumUser(&t);
+
+ if (b)
+ {
+ c->Write(c, L"");
+ }
+ }
+ }
+
+ }
+
+ FreeRpcSetGroup(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Add an user to the group
+UINT PsGroupJoin(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"USERNAME", CmdPrompt, _UU("CMD_GroupJoin_Prompt_USERNAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "USERNAME"));
+
+ // RPC call
+ ret = ScGetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Update the Group
+ StrCpy(t.GroupName, sizeof(t.GroupName), GetParamStr(o, "[name]"));
+
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the user from a group
+UINT PsGroupUnjoin(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_USER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_GroupUnjoin_Prompt_name"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Update the Group
+ StrCpy(t.GroupName, sizeof(t.GroupName), "");
+
+ ret = ScSetUser(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeRpcSetUser(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the security policy of the group
+UINT PsGroupPolicyRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_GROUP t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Update
+ if (t.Policy != NULL)
+ {
+ Free(t.Policy);
+ t.Policy = NULL;
+ }
+
+ ret = ScSetGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeRpcSetGroup(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set a security policy to a group
+UINT PsGroupPolicySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SET_GROUP t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_GroupCreate_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ {"NAME", CmdPrompt, _UU("CMD_CascadePolicySet_PROMPT_POLNAME"), CmdEvalNotEmpty, NULL},
+ {"VALUE", CmdPrompt, _UU("CMD_CascadePolicySet_PROMPT_POLVALUE"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Update
+ if (t.Policy == NULL)
+ {
+ t.Policy = ClonePolicy(GetDefaultPolicy());
+ }
+
+ if (EditPolicy(c, t.Policy, GetParamStr(o, "NAME"), GetParamStr(o, "VALUE"), false) == false)
+ {
+ // An error has occured
+ FreeRpcSetGroup(&t);
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ERR_INTERNAL_ERROR;
+ }
+
+ ret = ScSetGroup(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeRpcSetGroup(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the connected session list
+UINT PsSessionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_SESSION t;
+ UINT server_type = 0;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ {
+ // Get the server type
+ RPC_SERVER_INFO t;
+
+ Zero(&t, sizeof(t));
+
+ if (ScGetServerInfo(ps->Rpc, &t) == ERR_NO_ERROR)
+ {
+ server_type = t.ServerType;
+
+ FreeRpcServerInfo(&t);
+ }
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumSession(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNew();
+ UINT i;
+
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_8"), false);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_4"), false);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_5"), true);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_6"), true);
+ CtInsertColumn(ct, _UU("SM_SESS_COLUMN_7"), true);
+
+ for (i = 0;i < t.NumSession;i++)
+ {
+ RPC_ENUM_SESSION_ITEM *e = &t.Sessions[i];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t *tmp2;
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t tmp5[MAX_SIZE];
+ wchar_t tmp6[MAX_SIZE];
+ wchar_t tmp7[MAX_SIZE];
+ wchar_t tmp8[MAX_SIZE];
+ bool free_tmp2 = false;
+
+ StrToUni(tmp1, sizeof(tmp1), e->Name);
+
+ tmp2 = _UU("SM_SESS_NORMAL");
+ if (server_type != SERVER_TYPE_STANDALONE)
+ {
+ if (e->RemoteSession)
+ {
+ tmp2 = ZeroMalloc(MAX_SIZE);
+ UniFormat(tmp2, MAX_SIZE, _UU("SM_SESS_REMOTE"), e->RemoteHostname);
+ free_tmp2 = true;
+ }
+ else
+ {
+ if (StrLen(e->RemoteHostname) == 0)
+ {
+ tmp2 = _UU("SM_SESS_LOCAL");
+ }
+ else
+ {
+ tmp2 = ZeroMalloc(MAX_SIZE);
+ UniFormat(tmp2, MAX_SIZE, _UU("SM_SESS_LOCAL_2"), e->RemoteHostname);
+ free_tmp2 = true;
+ }
+ }
+ }
+ if (e->LinkMode)
+ {
+ if (free_tmp2)
+ {
+ Free(tmp2);
+ free_tmp2 = false;
+ }
+ tmp2 = _UU("SM_SESS_LINK");
+ }
+ else if (e->SecureNATMode)
+ {
+ /*if (free_tmp2)
+ {
+ Free(tmp2);
+ free_tmp2 = false;
+ }*/
+ tmp2 = _UU("SM_SESS_SNAT");
+ }
+
+ StrToUni(tmp3, sizeof(tmp3), e->Username);
+
+ StrToUni(tmp4, sizeof(tmp4), e->Hostname);
+ if (e->LinkMode)
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_LINK_HOSTNAME"));
+ }
+ else if (e->SecureNATMode)
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_SNAT_HOSTNAME"));
+ }
+ else if (e->BridgeMode)
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_BRIDGE_HOSTNAME"));
+ }
+ else if (StartWith(e->Username, L3_USERNAME))
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_LAYER3_HOSTNAME"));
+ }
+
+ UniFormat(tmp5, sizeof(tmp5), L"%u / %u", e->CurrentNumTcp, e->MaxNumTcp);
+ if (e->LinkMode)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_SESS_LINK_TCP"));
+ }
+ else if (e->SecureNATMode)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_SESS_SNAT_TCP"));
+ }
+ else if (e->BridgeMode)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_SESS_BRIDGE_TCP"));
+ }
+
+ UniToStr3(tmp6, sizeof(tmp6), e->PacketSize);
+ UniToStr3(tmp7, sizeof(tmp7), e->PacketNum);
+
+ if (e->VLanId == 0)
+ {
+ UniStrCpy(tmp8, sizeof(tmp8), _UU("CM_ST_NO_VLAN"));
+ }
+ else
+ {
+ UniToStru(tmp8, e->VLanId);
+ }
+
+ CtInsert(ct, tmp1, tmp8, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7);
+
+ if (free_tmp2)
+ {
+ Free(tmp2);
+ }
+ }
+
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumSession(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Display the NODE_INFO
+void CmdPrintNodeInfo(CT *ct, NODE_INFO *info)
+{
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+ // Validate arguments
+ if (ct == NULL || info == NULL)
+ {
+ return;
+ }
+
+ StrToUni(tmp, sizeof(tmp), info->ClientProductName);
+ CtInsert(ct, _UU("SM_NODE_CLIENT_NAME"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), L"%u.%02u", Endian32(info->ClientProductVer) / 100, Endian32(info->ClientProductVer) % 100);
+ CtInsert(ct, _UU("SM_NODE_CLIENT_VER"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), L"Build %u", Endian32(info->ClientProductBuild));
+ CtInsert(ct, _UU("SM_NODE_CLIENT_BUILD"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), info->ClientOsName);
+ CtInsert(ct, _UU("SM_NODE_CLIENT_OS_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), info->ClientOsVer);
+ CtInsert(ct, _UU("SM_NODE_CLIENT_OS_VER"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), info->ClientOsProductId);
+ CtInsert(ct, _UU("SM_NODE_CLIENT_OS_PID"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), info->ClientHostname);
+ CtInsert(ct, _UU("SM_NODE_CLIENT_HOST"), tmp);
+
+ IPToStr4or6(str, sizeof(str), info->ClientIpAddress, info->ClientIpAddress6);
+ StrToUni(tmp, sizeof(tmp), str);
+ CtInsert(ct, _UU("SM_NODE_CLIENT_IP"), tmp);
+
+ UniToStru(tmp, Endian32(info->ClientPort));
+ CtInsert(ct, _UU("SM_NODE_CLIENT_PORT"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), info->ServerHostname);
+ CtInsert(ct, _UU("SM_NODE_SERVER_HOST"), tmp);
+
+ IPToStr4or6(str, sizeof(str), info->ServerIpAddress, info->ServerIpAddress6);
+ StrToUni(tmp, sizeof(tmp), str);
+ CtInsert(ct, _UU("SM_NODE_SERVER_IP"), tmp);
+
+ UniToStru(tmp, Endian32(info->ServerPort));
+ CtInsert(ct, _UU("SM_NODE_SERVER_PORT"), tmp);
+
+ if (StrLen(info->ProxyHostname) != 0)
+ {
+ StrToUni(tmp, sizeof(tmp), info->ProxyHostname);
+ CtInsert(ct, _UU("SM_NODE_PROXY_HOSTNAME"), tmp);
+
+ IPToStr4or6(str, sizeof(str), info->ProxyIpAddress, info->ProxyIpAddress6);
+ StrToUni(tmp, sizeof(tmp), str);
+ CtInsert(ct, _UU("SM_NODE_PROXY_IP"), tmp);
+
+ UniToStru(tmp, Endian32(info->ProxyPort));
+ CtInsert(ct, _UU("SM_NODE_PROXY_PORT"), tmp);
+ }
+}
+
+// Get the session information
+UINT PsSessionGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SESSION_STATUS t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_SessionGet_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScGetSessionStatus(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+ CT *ct = CtNewStandard();
+
+ if (t.ClientIp != 0)
+ {
+ IPToStr4or6(str, sizeof(str), t.ClientIp, t.ClientIp6);
+ StrToUni(tmp, sizeof(tmp), str);
+ CtInsert(ct, _UU("SM_CLIENT_IP"), tmp);
+ }
+
+ if (StrLen(t.ClientHostName) != 0)
+ {
+ StrToUni(tmp, sizeof(tmp), t.ClientHostName);
+ CtInsert(ct, _UU("SM_CLIENT_HOSTNAME"), tmp);
+ }
+
+ StrToUni(tmp, sizeof(tmp), t.Username);
+ CtInsert(ct, _UU("SM_SESS_STATUS_USERNAME"), tmp);
+
+ if (StrCmpi(t.Username, LINK_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, SNAT_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, BRIDGE_USER_NAME_PRINT) != 0)
+ {
+ StrToUni(tmp, sizeof(tmp), t.RealUsername);
+ CtInsert(ct, _UU("SM_SESS_STATUS_REALUSER"), tmp);
+ }
+
+ if (IsEmptyStr(t.GroupName) == false)
+ {
+ StrToUni(tmp, sizeof(tmp), t.GroupName);
+ CtInsert(ct, _UU("SM_SESS_STATUS_GROUPNAME"), tmp);
+ }
+
+
+ CmdPrintStatusToListViewEx(ct, &t.Status, true);
+
+ if (StrCmpi(t.Username, LINK_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, SNAT_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, BRIDGE_USER_NAME_PRINT) != 0 &&
+ StartWith(t.Username, L3_USERNAME) == false)
+ {
+ CmdPrintNodeInfo(ct, &t.NodeInfo);
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeRpcSessionStatus(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disconnect the session
+UINT PsSessionDisconnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_DELETE_SESSION t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_SessionGet_Prompt_NAME"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ StrCpy(t.Name, sizeof(t.Name), GetParamStr(o, "[name]"));
+
+ // RPC call
+ ret = ScDeleteSession(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the MAC address table database
+UINT PsMacTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_MAC_TABLE t;
+ UINT i;
+
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[session_name]", NULL, NULL, NULL, NULL,}
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumMacTable(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNew();
+ char *session_name = GetParamStr(o, "[session_name]");
+
+ if (IsEmptyStr(session_name))
+ {
+ session_name = NULL;
+ }
+
+ CtInsertColumn(ct, _UU("CMD_ID"), false);
+ CtInsertColumn(ct, _UU("SM_MAC_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_MAC_COLUMN_1A"), false);
+ CtInsertColumn(ct, _UU("SM_MAC_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_MAC_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_MAC_COLUMN_4"), false);
+ CtInsertColumn(ct, _UU("SM_MAC_COLUMN_5"), false);
+
+ for (i = 0;i < t.NumMacTable;i++)
+ {
+ char str[MAX_SIZE];
+ wchar_t tmp0[128];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t tmp5[MAX_SIZE];
+ wchar_t tmp6[MAX_SIZE];
+
+ RPC_ENUM_MAC_TABLE_ITEM *e = &t.MacTables[i];
+
+ if (session_name == NULL || StrCmpi(e->SessionName, session_name) == 0)
+ {
+ UniToStru(tmp0, e->Key);
+
+ StrToUni(tmp1, sizeof(tmp1), e->SessionName);
+
+ MacToStr(str, sizeof(str), e->MacAddress);
+ StrToUni(tmp2, sizeof(tmp2), str);
+
+ GetDateTimeStr64Uni(tmp3, sizeof(tmp3), SystemToLocal64(e->CreatedTime));
+
+ GetDateTimeStr64Uni(tmp4, sizeof(tmp4), SystemToLocal64(e->UpdatedTime));
+
+ if (StrLen(e->RemoteHostname) == 0)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_MACIP_LOCAL"));
+ }
+ else
+ {
+ UniFormat(tmp5, sizeof(tmp5), _UU("SM_MACIP_SERVER"), e->RemoteHostname);
+ }
+
+ UniToStru(tmp6, e->VlanId);
+ if (e->VlanId == 0)
+ {
+ UniStrCpy(tmp6, sizeof(tmp6), _UU("CM_ST_NONE"));
+ }
+
+ CtInsert(ct,
+ tmp0, tmp1, tmp6, tmp2, tmp3, tmp4, tmp5);
+ }
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumMacTable(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete a MAC address table entry
+UINT PsMacDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_DELETE_TABLE t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_MacDelete_Prompt"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Key = GetParamInt(o, "[id]");
+
+ // RPC call
+ ret = ScDeleteMacTable(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the IP address table database
+UINT PsIpTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_IP_TABLE t;
+ UINT i;
+
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[session_name]", NULL, NULL, NULL, NULL,}
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumIpTable(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNew();
+ char *session_name = GetParamStr(o, "[session_name]");
+
+ if (IsEmptyStr(session_name))
+ {
+ session_name = NULL;
+ }
+
+ CtInsertColumn(ct, _UU("CMD_ID"), false);
+ CtInsertColumn(ct, _UU("SM_IP_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_IP_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_IP_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_IP_COLUMN_4"), false);
+ CtInsertColumn(ct, _UU("SM_IP_COLUMN_5"), false);
+
+ for (i = 0;i < t.NumIpTable;i++)
+ {
+ char str[MAX_SIZE];
+ wchar_t tmp0[128];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t tmp5[MAX_SIZE];
+ RPC_ENUM_IP_TABLE_ITEM *e = &t.IpTables[i];
+
+ if (session_name == NULL || StrCmpi(e->SessionName, session_name) == 0)
+ {
+ UniToStru(tmp0, e->Key);
+
+ StrToUni(tmp1, sizeof(tmp1), e->SessionName);
+
+ if (e->DhcpAllocated == false)
+ {
+ IPToStr(str, sizeof(str), &e->IpV6);
+ StrToUni(tmp2, sizeof(tmp2), str);
+ }
+ else
+ {
+ IPToStr(str, sizeof(str), &e->IpV6);
+ UniFormat(tmp2, sizeof(tmp2), _UU("SM_MAC_IP_DHCP"), str);
+ }
+
+ GetDateTimeStr64Uni(tmp3, sizeof(tmp3), SystemToLocal64(e->CreatedTime));
+
+ GetDateTimeStr64Uni(tmp4, sizeof(tmp4), SystemToLocal64(e->UpdatedTime));
+
+ if (StrLen(e->RemoteHostname) == 0)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_MACIP_LOCAL"));
+ }
+ else
+ {
+ UniFormat(tmp5, sizeof(tmp5), _UU("SM_MACIP_SERVER"), e->RemoteHostname);
+ }
+
+ CtInsert(ct,
+ tmp0, tmp1, tmp2, tmp3, tmp4, tmp5);
+ }
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumIpTable(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the IP address table entry
+UINT PsIpDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_DELETE_TABLE t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_MacDelete_Prompt"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Key = GetParamInt(o, "[id]");
+
+ // RPC call
+ ret = ScDeleteIpTable(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable the DHCP server function and the virtual NAT (SecureNAT function)
+UINT PsSecureNatEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnableSecureNAT(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disable the DHCP server function and the virtual NAT (SecureNAT function)
+UINT PsSecureNatDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_HUB t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScDisableSecureNAT(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the operating status of the DHCP server function and the virtual NAT (SecureNAT function)
+UINT PsSecureNatStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_NAT_STATUS t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATStatus(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ CT *ct = CtNewStandard();
+
+ StrToUni(tmp, sizeof(tmp), ps->HubName);
+ CtInsert(ct, _UU("SM_HUB_COLUMN_1"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumTcpSessions);
+ CtInsert(ct, _UU("NM_STATUS_TCP"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumUdpSessions);
+ CtInsert(ct, _UU("NM_STATUS_UDP"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumIcmpSessions);
+ CtInsert(ct, _UU("NM_STATUS_ICMP"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumDnsSessions);
+ CtInsert(ct, _UU("NM_STATUS_DNS"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_CLIENT"), t.NumDhcpClients);
+ CtInsert(ct, _UU("NM_STATUS_DHCP"), tmp);
+
+ CtInsert(ct, _UU("SM_SNAT_IS_KERNEL"), t.IsKernelMode ? _UU("SEC_YES") : _UU("SEC_NO"));
+
+ CtFree(ct, c);
+ }
+
+ FreeRpcNatStatus(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the network interface settings for a virtual host of SecureNAT function
+UINT PsSecureNatHostGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+ CT *ct = CtNewStandard();
+
+ // Flags
+ // MAC Address
+ MacToStr(str, sizeof(str), t.MacAddress);
+ StrToUni(tmp, sizeof(tmp), str);
+ CtInsert(ct, _UU("CMD_SecureNatHostGet_Column_MAC"), tmp);
+
+ // IP address
+ IPToUniStr(tmp, sizeof(tmp), &t.Ip);
+ CtInsert(ct, _UU("CMD_SecureNatHostGet_Column_IP"), tmp);
+
+ // Subnet mask
+ IPToUniStr(tmp, sizeof(tmp), &t.Mask);
+ CtInsert(ct, _UU("CMD_SecureNatHostGet_Column_MASK"), tmp);
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Change the network interface settings for a virtual host of SecureNAT function
+UINT PsSecureNatHostSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"MAC", CmdPrompt, _UU("CMD_SecureNatHostSet_Prompt_MAC"), NULL, NULL},
+ {"IP", CmdPrompt, _UU("CMD_SecureNatHostSet_Prompt_IP"), CmdEvalIp, NULL},
+ {"MASK", CmdPrompt, _UU("CMD_SecureNatHostSet_Prompt_MASK"), CmdEvalIp, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ char *mac, *ip, *mask;
+ bool ok = true;
+
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ mac = GetParamStr(o, "MAC");
+ ip = GetParamStr(o, "IP");
+ mask = GetParamStr(o, "MASK");
+
+ if (IsEmptyStr(mac) == false)
+ {
+ BUF *b = StrToBin(mac);
+
+ if (b == NULL || b->Size != 6)
+ {
+ ok = false;
+ }
+ else
+ {
+ Copy(t.MacAddress, b->Buf, 6);
+ }
+
+ FreeBuf(b);
+ }
+
+ if (IsEmptyStr(ip) == false)
+ {
+ if (IsIpStr4(ip) == false)
+ {
+ ok = false;
+ }
+ else
+ {
+ UINT u = StrToIP32(ip);
+
+ if (u == 0 || u == 0xffffffff)
+ {
+ ok = false;
+ }
+ else
+ {
+ UINTToIP(&t.Ip, u);
+ }
+ }
+ }
+
+ if (IsEmptyStr(mask) == false)
+ {
+ if (IsIpStr4(mask) == false)
+ {
+ ok = false;
+ }
+ else
+ {
+ StrToIP(&t.Mask, mask);
+ }
+ }
+
+ if (ok == false)
+ {
+ // Parameter is invalid
+ ret = ERR_INVALID_PARAMETER;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the settings for the virtual NAT function of the SecureNAT function
+UINT PsNatGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ CT *ct = CtNewStandard();
+
+ // Use the virtual NAT function
+ CtInsert(ct, _UU("CMD_NatGet_Column_USE"), t.UseNat ? _UU("SEC_YES") : _UU("SEC_NO"));
+
+ // MTU value
+ UniToStru(tmp, t.Mtu);
+ CtInsert(ct, _UU("CMD_NetGet_Column_MTU"), tmp);
+
+ // TCP session timeout (in seconds)
+ UniToStru(tmp, t.NatTcpTimeout);
+ CtInsert(ct, _UU("CMD_NatGet_Column_TCP"), tmp);
+
+ // UDP session timeout (in seconds)
+ UniToStru(tmp, t.NatUdpTimeout);
+ CtInsert(ct, _UU("CMD_NatGet_Column_UDP"), tmp);
+
+ // To save the log
+ CtInsert(ct, _UU("CMD_SecureNatHostGet_Column_LOG"), t.SaveLog ? _UU("SEC_YES") : _UU("SEC_NO"));
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable the virtual NAT function of the SecureNAT function
+UINT PsNatEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ bool ok = true;
+
+ t.UseNat = true;
+
+ if (ok == false)
+ {
+ // Parameter is invalid
+ ret = ERR_INVALID_PARAMETER;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disable the virtual NAT function of the SecureNAT function
+UINT PsNatDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ bool ok = true;
+
+ t.UseNat = false;
+
+ if (ok == false)
+ {
+ // Parameter is invalid
+ ret = ERR_INVALID_PARAMETER;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Change the settings for the virtual NAT function of the SecureNAT function
+UINT PsNatSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX mtu_mm =
+ {
+ "CMD_NatSet_Eval_MTU", TCP_HEADER_SIZE + IP_HEADER_SIZE + MAC_HEADER_SIZE + 8, MAX_L3_DATA_SIZE,
+ };
+ CMD_EVAL_MIN_MAX tcp_mm =
+ {
+ "CMD_NatSet_Eval_TCP", NAT_TCP_MIN_TIMEOUT / 1000, NAT_TCP_MAX_TIMEOUT / 1000,
+ };
+ CMD_EVAL_MIN_MAX udp_mm =
+ {
+ "CMD_NatSet_Eval_UDP", NAT_UDP_MIN_TIMEOUT / 1000, NAT_UDP_MAX_TIMEOUT / 1000,
+ };
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"MTU", CmdPrompt, _UU("CMD_NatSet_Prompt_MTU"), CmdEvalMinMax, &mtu_mm},
+ {"TCPTIMEOUT", CmdPrompt, _UU("CMD_NatSet_Prompt_TCPTIMEOUT"), CmdEvalMinMax, &tcp_mm},
+ {"UDPTIMEOUT", CmdPrompt, _UU("CMD_NatSet_Prompt_UDPTIMEOUT"), CmdEvalMinMax, &udp_mm},
+ {"LOG", CmdPrompt, _UU("CMD_NatSet_Prompt_LOG"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ bool ok = true;
+
+ t.Mtu = GetParamInt(o, "MTU");
+ t.NatTcpTimeout = GetParamInt(o, "TCPTIMEOUT");
+ t.NatUdpTimeout = GetParamInt(o, "UDPTIMEOUT");
+ t.SaveLog = GetParamYes(o, "LOG");
+
+ if (ok == false)
+ {
+ // Parameter is invalid
+ ret = ERR_INVALID_PARAMETER;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the session table of the virtual NAT function of the SecureNAT function
+UINT PsNatTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_NAT t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumNAT(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNew();
+ UINT i;
+
+ CtInsertColumn(ct, _UU("NM_NAT_ID"), false);
+ CtInsertColumn(ct, _UU("NM_NAT_PROTOCOL"), false);
+ CtInsertColumn(ct, _UU("NM_NAT_SRC_HOST"), false);
+ CtInsertColumn(ct, _UU("NM_NAT_SRC_PORT"), false);
+ CtInsertColumn(ct, _UU("NM_NAT_DST_HOST"), false);
+ CtInsertColumn(ct, _UU("NM_NAT_DST_PORT"), false);
+ CtInsertColumn(ct, _UU("NM_NAT_CREATED"), false);
+ CtInsertColumn(ct, _UU("NM_NAT_LAST_COMM"), false);
+ CtInsertColumn(ct, _UU("NM_NAT_SIZE"), false);
+ CtInsertColumn(ct, _UU("NM_NAT_TCP_STATUS"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_NAT_ITEM *e = &t.Items[i];
+ wchar_t tmp0[MAX_SIZE];
+ wchar_t *tmp1 = L"";
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t tmp5[MAX_SIZE];
+ wchar_t tmp6[MAX_SIZE];
+ wchar_t tmp7[MAX_SIZE];
+ wchar_t tmp8[MAX_SIZE];
+ wchar_t *tmp9 = L"";
+ char v1[128], v2[128];
+
+ // ID
+ UniToStru(tmp0, e->Id);
+
+ // Protocol
+ switch (e->Protocol)
+ {
+ case NAT_TCP:
+ tmp1 = _UU("NM_NAT_PROTO_TCP");
+ break;
+ case NAT_UDP:
+ tmp1 = _UU("NM_NAT_PROTO_UDP");
+ break;
+ case NAT_DNS:
+ tmp1 = _UU("NM_NAT_PROTO_DNS");
+ break;
+ case NAT_ICMP:
+ tmp1 = _UU("NM_NAT_PROTO_ICMP");
+ break;
+ }
+
+ // Source host
+ StrToUni(tmp2, sizeof(tmp2), e->SrcHost);
+
+ // Source port
+ UniToStru(tmp3, e->SrcPort);
+
+ // Destination host
+ StrToUni(tmp4, sizeof(tmp4), e->DestHost);
+
+ // Destination port
+ UniToStru(tmp5, e->DestPort);
+
+ // Creation date and time of the session
+ GetDateTimeStrEx64(tmp6, sizeof(tmp6), SystemToLocal64(e->CreatedTime), NULL);
+
+ // Last communication date and time
+ GetDateTimeStrEx64(tmp7, sizeof(tmp7), SystemToLocal64(e->LastCommTime), NULL);
+
+ // Communication amount
+ ToStr3(v1, sizeof(v1), e->RecvSize);
+ ToStr3(v2, sizeof(v2), e->SendSize);
+ UniFormat(tmp8, sizeof(tmp8), L"%S / %S", v1, v2);
+
+ // TCP state
+ if (e->Protocol == NAT_TCP)
+ {
+ switch (e->TcpStatus)
+ {
+ case NAT_TCP_CONNECTING:
+ tmp9 = _UU("NAT_TCP_CONNECTING");
+ break;
+ case NAT_TCP_SEND_RESET:
+ tmp9 = _UU("NAT_TCP_SEND_RESET");
+ break;
+ case NAT_TCP_CONNECTED:
+ tmp9 = _UU("NAT_TCP_CONNECTED");
+ break;
+ case NAT_TCP_ESTABLISHED:
+ tmp9 = _UU("NAT_TCP_ESTABLISHED");
+ break;
+ case NAT_TCP_WAIT_DISCONNECT:
+ tmp9 = _UU("NAT_TCP_WAIT_DISCONNECT");
+ break;
+ }
+ }
+
+ CtInsert(ct,
+ tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumNat(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the settings for a virtual DHCP server function of the SecureNAT function
+UINT PsDhcpGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ CT *ct = CtNewStandard();
+
+ // To use the virtual DHCP function
+ CtInsert(ct, _UU("CMD_DhcpGet_Column_USE"), t.UseDhcp ? _UU("SEC_YES") : _UU("SEC_NO"));
+
+ // Start address of the distributing address zone
+ IPToUniStr(tmp, sizeof(tmp), &t.DhcpLeaseIPStart);
+ CtInsert(ct, _UU("CMD_DhcpGet_Column_IP1"), tmp);
+
+ // End address of the distributing address zone
+ IPToUniStr(tmp, sizeof(tmp), &t.DhcpLeaseIPEnd);
+ CtInsert(ct, _UU("CMD_DhcpGet_Column_IP2"), tmp);
+
+ // Subnet mask
+ IPToUniStr(tmp, sizeof(tmp), &t.DhcpSubnetMask);
+ CtInsert(ct, _UU("CMD_DhcpGet_Column_MASK"), tmp);
+
+ // Lease time (in seconds)
+ UniToStru(tmp, t.DhcpExpireTimeSpan);
+ CtInsert(ct, _UU("CMD_DhcpGet_Column_LEASE"), tmp);
+
+ // Default gateway address
+ UniStrCpy(tmp, sizeof(tmp), _UU("SEC_NONE"));
+ if (IPToUINT(&t.DhcpGatewayAddress) != 0)
+ {
+ IPToUniStr(tmp, sizeof(tmp), &t.DhcpGatewayAddress);
+ }
+ CtInsert(ct, _UU("CMD_DhcpGet_Column_GW"), tmp);
+
+ // DNS server address 1
+ UniStrCpy(tmp, sizeof(tmp), _UU("SEC_NONE"));
+ if (IPToUINT(&t.DhcpDnsServerAddress) != 0)
+ {
+ IPToUniStr(tmp, sizeof(tmp), &t.DhcpDnsServerAddress);
+ }
+ CtInsert(ct, _UU("CMD_DhcpGet_Column_DNS"), tmp);
+
+ // DNS server address 2
+ UniStrCpy(tmp, sizeof(tmp), _UU("SEC_NONE"));
+ if (IPToUINT(&t.DhcpDnsServerAddress2) != 0)
+ {
+ IPToUniStr(tmp, sizeof(tmp), &t.DhcpDnsServerAddress2);
+ }
+ CtInsert(ct, _UU("CMD_DhcpGet_Column_DNS2"), tmp);
+
+ // Domain name
+ StrToUni(tmp, sizeof(tmp), t.DhcpDomainName);
+ CtInsert(ct, _UU("CMD_DhcpGet_Column_DOMAIN"), tmp);
+
+ // To save the log
+ CtInsert(ct, _UU("CMD_SecureNatHostGet_Column_LOG"), t.SaveLog ? _UU("SEC_YES") : _UU("SEC_NO"));
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable the Virtual DHCP server function of SecureNAT function
+UINT PsDhcpEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ bool ok = true;
+
+ t.UseDhcp = true;
+
+ if (ok == false)
+ {
+ // Parameter is invalid
+ ret = ERR_INVALID_PARAMETER;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Disable the virtual DHCP server function of SecureNAT function
+UINT PsDhcpDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ bool ok = true;
+
+ t.UseDhcp = false;
+
+ if (ok == false)
+ {
+ // Parameter is invalid
+ ret = ERR_INVALID_PARAMETER;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Change the settings for a virtual DHCP server function of the SecureNAT function
+UINT PsDhcpSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ VH_OPTION t;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX mm =
+ {
+ "CMD_NatSet_Eval_UDP", NAT_UDP_MIN_TIMEOUT / 1000, NAT_UDP_MAX_TIMEOUT / 1000,
+ };
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"START", CmdPrompt, _UU("CMD_DhcpSet_Prompt_START"), CmdEvalIp, NULL},
+ {"END", CmdPrompt, _UU("CMD_DhcpSet_Prompt_END"), CmdEvalIp, NULL},
+ {"MASK", CmdPrompt, _UU("CMD_DhcpSet_Prompt_MASK"), CmdEvalIp, NULL},
+ {"EXPIRE", CmdPrompt, _UU("CMD_DhcpSet_Prompt_EXPIRE"), CmdEvalMinMax, &mm},
+ {"GW", CmdPrompt, _UU("CMD_DhcpSet_Prompt_GW"), CmdEvalIp, NULL},
+ {"DNS", CmdPrompt, _UU("CMD_DhcpSet_Prompt_DNS"), CmdEvalIp, NULL},
+ {"DNS2", CmdPrompt, _UU("CMD_DhcpSet_Prompt_DNS2"), CmdEvalIp, NULL},
+ {"DOMAIN", CmdPrompt, _UU("CMD_DhcpSet_Prompt_DOMAIN"), NULL, NULL},
+ {"LOG", CmdPrompt, _UU("CMD_NatSet_Prompt_LOG"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ bool ok = true;
+
+ StrToIP(&t.DhcpLeaseIPStart, GetParamStr(o, "START"));
+ StrToIP(&t.DhcpLeaseIPEnd, GetParamStr(o, "END"));
+ StrToIP(&t.DhcpSubnetMask, GetParamStr(o, "MASK"));
+ t.DhcpExpireTimeSpan = GetParamInt(o, "EXPIRE");
+ StrToIP(&t.DhcpGatewayAddress, GetParamStr(o, "GW"));
+ StrToIP(&t.DhcpDnsServerAddress, GetParamStr(o, "DNS"));
+ StrToIP(&t.DhcpDnsServerAddress2, GetParamStr(o, "DNS2"));
+ StrCpy(t.DhcpDomainName, sizeof(t.DhcpDomainName), GetParamStr(o, "DOMAIN"));
+ t.SaveLog = GetParamYes(o, "LOG");
+
+ if (ok == false)
+ {
+ // Parameter is invalid
+ ret = ERR_INVALID_PARAMETER;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScSetSecureNATOption(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the lease table of virtual DHCP server function of the SecureNAT function
+UINT PsDhcpTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_DHCP t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumDHCP(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNew();
+ UINT i;
+
+ CtInsertColumn(ct, _UU("DHCP_DHCP_ID"), false);
+ CtInsertColumn(ct, _UU("DHCP_LEASED_TIME"), false);
+ CtInsertColumn(ct, _UU("DHCP_EXPIRE_TIME"), false);
+ CtInsertColumn(ct, _UU("DHCP_MAC_ADDRESS"), false);
+ CtInsertColumn(ct, _UU("DHCP_IP_ADDRESS"), false);
+ CtInsertColumn(ct, _UU("DHCP_HOSTNAME"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_DHCP_ITEM *e = &t.Items[i];
+ wchar_t tmp0[MAX_SIZE];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t tmp5[MAX_SIZE];
+ char str[MAX_SIZE];
+
+ // ID
+ UniToStru(tmp0, e->Id);
+
+ // Time
+ GetDateTimeStrEx64(tmp1, sizeof(tmp1), SystemToLocal64(e->LeasedTime), NULL);
+ GetDateTimeStrEx64(tmp2, sizeof(tmp2), SystemToLocal64(e->ExpireTime), NULL);
+
+ MacToStr(str, sizeof(str), e->MacAddress);
+ StrToUni(tmp3, sizeof(tmp3), str);
+
+ IPToStr32(str, sizeof(str), e->IpAddress);
+ StrToUni(tmp4, sizeof(tmp4), str);
+
+ StrToUni(tmp5, sizeof(tmp5), e->Hostname);
+
+ CtInsert(ct,
+ tmp0, tmp1, tmp2, tmp3, tmp4, tmp5);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumDhcp(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the list of Virtual HUB management options
+UINT PsAdminOptionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ADMIN_OPTION t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubAdminOptions(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNewStandardEx();
+ UINT i;
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ ADMIN_OPTION *e = &t.Items[i];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+
+ StrToUni(tmp1, sizeof(tmp1), e->Name);
+ UniToStru(tmp2, e->Value);
+
+ CtInsert(ct, tmp1, tmp2, GetHubAdminOptionHelpString(e->Name));
+
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcAdminOption(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the value of a Virtual HUB management option
+UINT PsAdminOptionSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ADMIN_OPTION t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_AdminOptionSet_Prompt_name"), CmdEvalNotEmpty, NULL},
+ {"VALUE", CmdPrompt, _UU("CMD_AdminOptionSet_Prompt_VALUE"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubAdminOptions(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ bool b = false;
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ if (StrCmpi(t.Items[i].Name, GetParamStr(o, "[name]")) == 0)
+ {
+ t.Items[i].Value = GetParamInt(o, "VALUE");
+ b = true;
+ }
+ }
+
+ if (b == false)
+ {
+ // An error has occured
+ ret = ERR_OBJECT_NOT_FOUND;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ FreeRpcAdminOption(&t);
+ return ret;
+ }
+ else
+ {
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScSetHubAdminOptions(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+ }
+
+ FreeRpcAdminOption(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the list of Virtual HUB extended options
+UINT PsExtOptionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ADMIN_OPTION t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubExtOptions(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNewStandardEx();
+ UINT i;
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ ADMIN_OPTION *e = &t.Items[i];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+
+ StrToUni(tmp1, sizeof(tmp1), e->Name);
+ UniToStru(tmp2, e->Value);
+
+ CtInsert(ct, tmp1, tmp2, GetHubAdminOptionHelpString(e->Name));
+
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcAdminOption(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the value of a Virtual HUB extended option
+UINT PsExtOptionSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ADMIN_OPTION t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[name]", CmdPrompt, _UU("CMD_AdminOptionSet_Prompt_name"), CmdEvalNotEmpty, NULL},
+ {"VALUE", CmdPrompt, _UU("CMD_AdminOptionSet_Prompt_VALUE"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetHubExtOptions(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ bool b = false;
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ if (StrCmpi(t.Items[i].Name, GetParamStr(o, "[name]")) == 0)
+ {
+ t.Items[i].Value = GetParamInt(o, "VALUE");
+ b = true;
+ }
+ }
+
+ if (b == false)
+ {
+ // An error has occured
+ ret = ERR_OBJECT_NOT_FOUND;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ FreeRpcAdminOption(&t);
+ return ret;
+ }
+ else
+ {
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ ret = ScSetHubExtOptions(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+ }
+
+ FreeRpcAdminOption(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the list of revoked certificate list
+UINT PsCrlList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_CRL t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScEnumCrl(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ CT *ct = CtNew();
+
+ CtInsertColumn(ct, _UU("CMD_ID"), false);
+ CtInsertColumn(ct, _UU("SM_CRL_COLUMN_1"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ wchar_t tmp[64];
+ RPC_ENUM_CRL_ITEM *e = &t.Items[i];
+
+ UniToStru(tmp, e->Key);
+ CtInsert(ct, tmp, e->CrlInfo);
+ }
+
+ CtFreeEx(ct, c, true);
+ }
+
+ FreeRpcEnumCrl(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Add a revoked certificate
+UINT PsCrlAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CRL t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ {"SERIAL", NULL, NULL, NULL, NULL},
+ {"MD5", NULL, NULL, NULL, NULL},
+ {"SHA1", NULL, NULL, NULL, NULL},
+ {"CN", NULL, NULL, NULL, NULL},
+ {"O", NULL, NULL, NULL, NULL},
+ {"OU", NULL, NULL, NULL, NULL},
+ {"C", NULL, NULL, NULL, NULL},
+ {"ST", NULL, NULL, NULL, NULL},
+ {"L", NULL, NULL, NULL, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ {
+ bool param_exists = false;
+ CRL *crl = ZeroMalloc(sizeof(CRL));
+ NAME *n;
+ n = crl->Name = ZeroMalloc(sizeof(NAME));
+
+ if (IsEmptyStr(GetParamStr(o, "CN")) == false)
+ {
+ n->CommonName = CopyUniStr(GetParamUniStr(o, "CN"));
+ param_exists = true;
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "O")) == false)
+ {
+ n->CommonName = CopyUniStr(GetParamUniStr(o, "O"));
+ param_exists = true;
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "OU")) == false)
+ {
+ n->CommonName = CopyUniStr(GetParamUniStr(o, "OU"));
+ param_exists = true;
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "C")) == false)
+ {
+ n->CommonName = CopyUniStr(GetParamUniStr(o, "C"));
+ param_exists = true;
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "ST")) == false)
+ {
+ n->CommonName = CopyUniStr(GetParamUniStr(o, "ST"));
+ param_exists = true;
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "L")) == false)
+ {
+ n->CommonName = CopyUniStr(GetParamUniStr(o, "L"));
+ param_exists = true;
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "SERIAL")) == false)
+ {
+ BUF *b;
+
+ b = StrToBin(GetParamStr(o, "SERIAL"));
+
+ if (b != NULL && b->Size >= 1)
+ {
+ crl->Serial = NewXSerial(b->Buf, b->Size);
+ param_exists = true;
+ }
+
+ FreeBuf(b);
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "MD5")) == false)
+ {
+ BUF *b;
+
+ b = StrToBin(GetParamStr(o, "MD5"));
+
+ if (b != NULL && b->Size == MD5_SIZE)
+ {
+ Copy(crl->DigestMD5, b->Buf, MD5_SIZE);
+ param_exists = true;
+ }
+
+ FreeBuf(b);
+ }
+
+ if (IsEmptyStr(GetParamStr(o, "SHA1")) == false)
+ {
+ BUF *b;
+
+ b = StrToBin(GetParamStr(o, "SHA1"));
+
+ if (b != NULL && b->Size == SHA1_SIZE)
+ {
+ Copy(crl->DigestSHA1, b->Buf, SHA1_SIZE);
+ param_exists = true;
+ }
+
+ FreeBuf(b);
+ }
+
+ t.Crl = crl;
+
+ if (param_exists == false)
+ {
+ FreeRpcCrl(&t);
+ ret = ERR_INVALID_PARAMETER;
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ // RPC call
+ ret = ScAddCrl(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCrl(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the revoked certificate
+UINT PsCrlDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CRL t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_CrlDel_Prompt_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Key = GetParamInt(o, "[id]");
+
+ // RPC call
+ ret = ScDelCrl(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeRpcCrl(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the revoked certificate
+UINT PsCrlGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_CRL t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_CrlGet_Prompt_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+ t.Key = GetParamInt(o, "[id]");
+
+ // RPC call
+ ret = ScGetCrl(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Show contents
+ CT *ct = CtNewStandard();
+ CRL *crl = t.Crl;
+ NAME *n;
+
+ if (crl != NULL)
+ {
+ n = crl->Name;
+
+ if (n != NULL)
+ {
+ if (UniIsEmptyStr(n->CommonName) == false)
+ {
+ CtInsert(ct, _UU("CMD_CrlGet_CN"), n->CommonName);
+ }
+ if (UniIsEmptyStr(n->Organization) == false)
+ {
+ CtInsert(ct, _UU("CMD_CrlGet_O"), n->Organization);
+ }
+ if (UniIsEmptyStr(n->Unit) == false)
+ {
+ CtInsert(ct, _UU("CMD_CrlGet_OU"), n->Unit);
+ }
+ if (UniIsEmptyStr(n->Country) == false)
+ {
+ CtInsert(ct, _UU("CMD_CrlGet_C"), n->Country);
+ }
+ if (UniIsEmptyStr(n->State) == false)
+ {
+ CtInsert(ct, _UU("CMD_CrlGet_ST"), n->State);
+ }
+ if (UniIsEmptyStr(n->Local) == false)
+ {
+ CtInsert(ct, _UU("CMD_CrlGet_L"), n->Local);
+ }
+ }
+
+ if (crl->Serial != NULL && crl->Serial->size >= 1)
+ {
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+
+ BinToStrEx(str, sizeof(str), crl->Serial->data, crl->Serial->size);
+ StrToUni(tmp, sizeof(tmp), str);
+
+ CtInsert(ct, _UU("CMD_CrlGet_SERI"), tmp);
+ }
+
+ if (IsZero(crl->DigestMD5, MD5_SIZE) == false)
+ {
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+
+ BinToStrEx(str, sizeof(str), crl->DigestMD5, MD5_SIZE);
+ StrToUni(tmp, sizeof(tmp), str);
+
+ CtInsert(ct, _UU("CMD_CrlGet_MD5_HASH"), tmp);
+ }
+
+ if (IsZero(crl->DigestSHA1, SHA1_SIZE) == false)
+ {
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+
+ BinToStrEx(str, sizeof(str), crl->DigestSHA1, SHA1_SIZE);
+ StrToUni(tmp, sizeof(tmp), str);
+
+ CtInsert(ct, _UU("CMD_CrlGet_SHA1_HASH"), tmp);
+ }
+ }
+ CtFree(ct, c);
+ }
+
+ FreeRpcCrl(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the rules of IP access control list
+UINT PsAcList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_AC_LIST t;
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetAcList(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ UINT i;
+ CT *ct;
+
+ ct = CtNew();
+ CtInsertColumn(ct, _UU("SM_AC_COLUMN_1"), true);
+ CtInsertColumn(ct, _UU("SM_AC_COLUMN_2"), true);
+ CtInsertColumn(ct, _UU("SM_AC_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_AC_COLUMN_4"), false);
+
+ for (i = 0;i < LIST_NUM(t.o);i++)
+ {
+ wchar_t tmp1[32], *tmp2, tmp3[MAX_SIZE], tmp4[32];
+ char *tmp_str;
+ AC *ac = LIST_DATA(t.o, i);
+
+ UniToStru(tmp1, ac->Id);
+ tmp2 = ac->Deny ? _UU("SM_AC_DENY") : _UU("SM_AC_PASS");
+ tmp_str = GenerateAcStr(ac);
+ StrToUni(tmp3, sizeof(tmp3), tmp_str);
+
+ Free(tmp_str);
+
+ UniToStru(tmp4, ac->Priority);
+
+ CtInsert(ct, tmp1, tmp4, tmp2, tmp3);
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeRpcAcList(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Add a rule to the IP access control list (IPv4)
+UINT PsAcAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_AC_LIST t;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX mm =
+ {
+ "CMD_AcAdd_Eval_PRIORITY", 1, 4294967295UL,
+ };
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[allow|deny]", CmdPrompt, _UU("CMD_AcAdd_Prompt_AD"), CmdEvalNotEmpty, NULL},
+ {"PRIORITY", CmdPrompt, _UU("CMD_AcAdd_Prompt_PRIORITY"), CmdEvalMinMax, &mm},
+ {"IP", CmdPrompt, _UU("CMD_AcAdd_Prompt_IP"), CmdEvalIpAndMask4, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetAcList(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Add a new item to the list
+ AC *ac = ZeroMalloc(sizeof(AC));
+ char *test = GetParamStr(o, "[allow|deny]");
+ UINT u_ip, u_mask;
+
+ if (StartWith("deny", test))
+ {
+ ac->Deny = true;
+ }
+
+ ParseIpAndMask4(GetParamStr(o, "IP"), &u_ip, &u_mask);
+ UINTToIP(&ac->IpAddress, u_ip);
+
+ if (u_mask == 0xffffffff)
+ {
+ ac->Masked = false;
+ }
+ else
+ {
+ ac->Masked = true;
+ UINTToIP(&ac->SubnetMask, u_mask);
+ }
+
+ ac->Priority = GetParamInt(o, "PRIORITY");
+
+ Insert(t.o, ac);
+
+ ret = ScSetAcList(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeRpcAcList(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Add a rule to the IP access control list (IPv6)
+UINT PsAcAdd6(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_AC_LIST t;
+ // Parameter list that can be specified
+ CMD_EVAL_MIN_MAX mm =
+ {
+ "CMD_AcAdd6_Eval_PRIORITY", 1, 4294967295UL,
+ };
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[allow|deny]", CmdPrompt, _UU("CMD_AcAdd6_Prompt_AD"), CmdEvalNotEmpty, NULL},
+ {"PRIORITY", CmdPrompt, _UU("CMD_AcAdd6_Prompt_PRIORITY"), CmdEvalMinMax, &mm},
+ {"IP", CmdPrompt, _UU("CMD_AcAdd6_Prompt_IP"), CmdEvalIpAndMask6, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetAcList(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Add a new item to the list
+ AC *ac = ZeroMalloc(sizeof(AC));
+ char *test = GetParamStr(o, "[allow|deny]");
+ IP u_ip, u_mask;
+
+ if (StartWith("deny", test))
+ {
+ ac->Deny = true;
+ }
+
+ ParseIpAndMask6(GetParamStr(o, "IP"), &u_ip, &u_mask);
+ Copy(&ac->IpAddress, &u_ip, sizeof(IP));
+
+ if (SubnetMaskToInt6(&u_mask) == 128)
+ {
+ ac->Masked = false;
+ }
+ else
+ {
+ ac->Masked = true;
+ Copy(&ac->SubnetMask, &u_mask, sizeof(IP));
+ }
+
+ ac->Priority = GetParamInt(o, "PRIORITY");
+
+ Insert(t.o, ac);
+
+ ret = ScSetAcList(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeRpcAcList(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Run the debug command
+UINT PsDebug(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ UINT id;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", NULL, NULL, NULL, NULL},
+ {"ARG", NULL, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ id = GetParamInt(o, "[id]");
+
+ if (true)
+ {
+ RPC_TEST t;
+ UINT ret;
+
+ c->Write(c, _UU("CMD_Debug_Msg1"));
+
+ Zero(&t, sizeof(t));
+
+ t.IntValue = id;
+ StrCpy(t.StrValue, sizeof(t.StrValue), GetParamStr(o, "ARG"));
+
+ ret = ScDebug(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[sizeof(t.StrValue)];
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_Debug_Msg2"), t.StrValue);
+ c->Write(c, tmp);
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Flush the configuration file on the server
+UINT PsFlush(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ if (true)
+ {
+ RPC_TEST t;
+ UINT ret;
+ wchar_t tmp[MAX_SIZE];
+ char sizestr[MAX_SIZE];
+
+ c->Write(c, _UU("CMD_Flush_Msg1"));
+
+ Zero(&t, sizeof(t));
+
+ ret = ScFlush(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ToStr3(sizestr, sizeof(sizestr), (UINT64)t.IntValue);
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_Flush_Msg2"), sizestr);
+ c->Write(c, tmp);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Crash
+UINT PsCrash(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ char *yes;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[yes]", CmdPrompt, _UU("CMD_Crash_Confirm"), NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ yes = GetParamStr(o, "[yes]");
+
+ if (StrCmpi(yes, "yes") != 0)
+ {
+ c->Write(c, _UU("CMD_Crash_Aborted"));
+ }
+ else
+ {
+ RPC_TEST t;
+ UINT ret;
+
+ c->Write(c, _UU("CMD_Crash_Msg"));
+
+ Zero(&t, sizeof(t));
+
+ ret = ScCrash(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Remove a rule in the IP access control list
+UINT PsAcDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_AC_LIST t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_AcDel_Prompt_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ // If virtual HUB is not selected, it's an error
+ if (ps->HubName == NULL)
+ {
+ c->Write(c, _UU("CMD_Hub_Not_Selected"));
+ return ERR_INVALID_PARAMETER;
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), ps->HubName);
+
+ // RPC call
+ ret = ScGetAcList(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Remove matched ID
+ UINT i;
+ bool b = false;
+
+ for (i = 0;i < LIST_NUM(t.o);i++)
+ {
+ AC *ac = LIST_DATA(t.o, i);
+
+ if (ac->Id == GetParamInt(o, "[id]"))
+ {
+ Delete(t.o, ac);
+ Free(ac);
+ b = true;
+ break;
+ }
+ }
+
+ if (b == false)
+ {
+ ret = ERR_OBJECT_NOT_FOUND;
+ FreeRpcAcList(&t);
+ }
+ else
+ {
+ ret = ScSetAcList(ps->Rpc, &t);
+ }
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ }
+
+ FreeRpcAcList(&t);
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable / Disable the IPsec VPN server function
+UINT PsIPsecEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ IPSEC_SERVICES t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"L2TP", CmdPrompt, _UU("CMD_IPsecEnable_Prompt_L2TP"), CmdEvalNotEmpty, NULL},
+ {"L2TPRAW", CmdPrompt, _UU("CMD_IPsecEnable_Prompt_L2TPRAW"), CmdEvalNotEmpty, NULL},
+ {"ETHERIP", CmdPrompt, _UU("CMD_IPsecEnable_Prompt_ETHERIP"), CmdEvalNotEmpty, NULL},
+ {"PSK", CmdPrompt, _UU("CMD_IPsecEnable_Prompt_PSK"), CmdEvalNotEmpty, NULL},
+ {"DEFAULTHUB", CmdPrompt, _UU("CMD_IPsecEnable_Prompt_DEFAULTHUB"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.L2TP_IPsec = GetParamYes(o, "L2TP");
+ t.L2TP_Raw = GetParamYes(o, "L2TPRAW");
+ t.EtherIP_IPsec = GetParamYes(o, "ETHERIP");
+ StrCpy(t.IPsec_Secret, sizeof(t.IPsec_Secret), GetParamStr(o, "PSK"));
+ StrCpy(t.L2TP_DefaultHub, sizeof(t.L2TP_DefaultHub), GetParamStr(o, "DEFAULTHUB"));
+
+ // RPC call
+ ret = ScSetIPsecServices(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the current configuration of IPsec VPN server function
+UINT PsIPsecGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ IPSEC_SERVICES t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetIPsecServices(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_PATH];
+ CT *ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_IPsecGet_PRINT_L2TP"), _UU(t.L2TP_IPsec ? "SEC_YES" : "SEC_NO"));
+ CtInsert(ct, _UU("CMD_IPsecGet_PRINT_L2TPRAW"), _UU(t.L2TP_Raw ? "SEC_YES" : "SEC_NO"));
+ CtInsert(ct, _UU("CMD_IPsecGet_PRINT_ETHERIP"), _UU(t.EtherIP_IPsec ? "SEC_YES" : "SEC_NO"));
+
+ StrToUni(tmp, sizeof(tmp), t.IPsec_Secret);
+ CtInsert(ct, _UU("CMD_IPsecGet_PRINT_PSK"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.L2TP_DefaultHub);
+ CtInsert(ct, _UU("CMD_IPsecGet_PRINT_DEFAULTHUB"), tmp);
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Add connection settings for accepting connections from client devices of EtherIP / L2TPv3 over IPsec server function
+UINT PsEtherIpClientAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ ETHERIP_ID t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[ID]", CmdPrompt, _UU("CMD_EtherIpClientAdd_Prompt_ID"), CmdEvalNotEmpty, NULL},
+ {"HUB", CmdPrompt, _UU("CMD_EtherIpClientAdd_Prompt_HUB"), CmdEvalNotEmpty, NULL},
+ {"USERNAME", CmdPrompt, _UU("CMD_EtherIpClientAdd_Prompt_USERNAME"), CmdEvalNotEmpty, NULL},
+ {"PASSWORD", CmdPrompt, _UU("CMD_EtherIpClientAdd_Prompt_PASSWORD"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Id, sizeof(t.Id), GetParamStr(o, "[ID]"));
+ StrCpy(t.HubName, sizeof(t.HubName), GetParamStr(o, "HUB"));
+ StrCpy(t.UserName, sizeof(t.UserName), GetParamStr(o, "USERNAME"));
+ StrCpy(t.Password, sizeof(t.Password), GetParamStr(o, "PASSWORD"));
+
+ // RPC call
+ ret = ScAddEtherIpId(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the connection settings for accepting connections from client devices of EtherIP / L2TPv3 over IPsec server function
+UINT PsEtherIpClientDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ ETHERIP_ID t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[ID]", CmdPrompt, _UU("CMD_EtherIpClientDelete_Prompt_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Id, sizeof(t.Id), GetParamStr(o, "[ID]"));
+
+ // RPC call
+ ret = ScDeleteEtherIpId(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Show the list of connection settings for accepting connections from client devices of EtherIP / L2TPv3 over IPsec server function
+UINT PsEtherIpClientList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_ETHERIP_ID t;
+ UINT i;
+ CT *b;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScEnumEtherIpId(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ b = CtNew();
+
+ CtInsertColumn(b, _UU("SM_ETHERIP_COLUMN_0"), false);
+ CtInsertColumn(b, _UU("SM_ETHERIP_COLUMN_1"), false);
+ CtInsertColumn(b, _UU("SM_ETHERIP_COLUMN_2"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ ETHERIP_ID *d = &t.IdList[i];
+ wchar_t id[MAX_SIZE], hubname[MAX_SIZE], username[MAX_SIZE];
+
+ StrToUni(id, sizeof(id), d->Id);
+ StrToUni(hubname, sizeof(hubname), d->HubName);
+ StrToUni(username, sizeof(username), d->UserName);
+
+ CtInsert(b, id, hubname, username);
+ }
+
+ CtFree(b, c);
+
+ FreeRpcEnumEtherIpId(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable / disable the OpenVPN compatible server function
+UINT PsOpenVpnEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ OPENVPN_SSTP_CONFIG t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[yes|no]", CmdPrompt, _UU("CMD_OpenVpnEnable_Prompt_[yes|no]"), CmdEvalNotEmpty, NULL},
+ {"PORTS", CmdPrompt, _UU("CMD_OpenVpnEnable_Prompt_PORTS"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetOpenVpnSstpConfig(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ t.EnableOpenVPN = GetParamYes(o, "[yes|no]");
+ StrCpy(t.OpenVPNPortList, sizeof(t.OpenVPNPortList), GetParamStr(o, "PORTS"));
+
+ // RPC call
+ ret = ScSetOpenVpnSstpConfig(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the current settings for the OpenVPN compatible server function
+UINT PsOpenVpnGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ OPENVPN_SSTP_CONFIG t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetOpenVpnSstpConfig(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ wchar_t tmp[MAX_PATH];
+ CT *ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_OpenVpnGet_PRINT_Enabled"), _UU(t.EnableOpenVPN ? "SEC_YES" : "SEC_NO"));
+
+ StrToUni(tmp, sizeof(tmp), t.OpenVPNPortList);
+ CtInsert(ct, _UU("CMD_OpenVpnGet_PRINT_Ports"), tmp);
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Generate a OpenVPN sample configuration file that can connect to the OpenVPN compatible server function
+UINT PsOpenVpnMakeConfig(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_READ_LOG_FILE t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[ZIP_FileName]", CmdPrompt, _UU("CMD_OpenVpnMakeConfig_Prompt_ZIP"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScMakeOpenVpnConfigFile(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ // Determine the file name to save
+ wchar_t filename[MAX_SIZE];
+ wchar_t tmp[MAX_SIZE];
+
+ UniStrCpy(filename, sizeof(filename), GetParamUniStr(o, "[ZIP_FileName]"));
+
+ if (UniEndWith(filename, L".zip") == false)
+ {
+ UniStrCat(filename, sizeof(filename), L".zip");
+ }
+
+ if (DumpBufW(t.Buffer, filename) == false)
+ {
+ ret = ERR_INTERNAL_ERROR;
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_OpenVpnMakeConfig_ERROR"), filename);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_OpenVpnMakeConfig_OK"), filename);
+ }
+
+ c->Write(c, tmp);
+
+ FreeRpcReadLogFile(&t);
+ }
+
+ FreeParamValueList(o);
+
+ return ret;
+}
+
+// Enable / disable the Microsoft SSTP VPN compatible server function
+UINT PsSstpEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ OPENVPN_SSTP_CONFIG t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[yes|no]", CmdPrompt, _UU("CMD_SstpEnable_Prompt_[yes|no]"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetOpenVpnSstpConfig(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ t.EnableSSTP = GetParamYes(o, "[yes|no]");
+
+ // RPC call
+ ret = ScSetOpenVpnSstpConfig(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the current settings for the Microsoft SSTP VPN compatible server function
+UINT PsSstpGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ OPENVPN_SSTP_CONFIG t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetOpenVpnSstpConfig(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_SstpEnable_PRINT_Enabled"), _UU(t.EnableSSTP ? "SEC_YES" : "SEC_NO"));
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Register to the VPN Server by creating a new self-signed certificate with the specified CN (Common Name)
+UINT PsServerCertRegenerate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_TEST t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[CN]", CmdPrompt, _UU("CMD_ServerCertRegenerate_Prompt_CN"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.StrValue, sizeof(t.StrValue), GetParamStr(o, "[CN]"));
+
+ // RPC call
+ ret = ScRegenerateServerCert(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable / disable the VPN over ICMP / VPN over DNS server function
+UINT PsVpnOverIcmpDnsEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SPECIAL_LISTENER t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"ICMP", CmdPrompt, _UU("CMD_VpnOverIcmpDnsEnable_Prompt_ICMP"), CmdEvalNotEmpty, NULL},
+ {"DNS", CmdPrompt, _UU("CMD_VpnOverIcmpDnsEnable_Prompt_DNS"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.VpnOverIcmpListener = GetParamYes(o, "ICMP");
+ t.VpnOverDnsListener = GetParamYes(o, "DNS");
+
+ // RPC call
+ ret = ScSetSpecialListener(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get current settings of VPN over ICMP / VPN over DNS server function
+UINT PsVpnOverIcmpDnsGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_SPECIAL_LISTENER t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetSpecialListener(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_VpnOverIcmpDnsGet_PRINT_ICMP"), _UU(t.VpnOverIcmpListener ? "SEC_YES" : "SEC_NO"));
+ CtInsert(ct, _UU("CMD_VpnOverIcmpDnsGet_PRINT_DNS"), _UU(t.VpnOverDnsListener ? "SEC_YES" : "SEC_NO"));
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable / disable the VPN Azure function
+UINT PsVpnAzureSetEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_AZURE_STATUS t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[yes|no]", CmdPrompt, _UU("VpnAzureSetEnable_PROMPT"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.IsEnabled = GetParamYes(o, "[yes|no]");
+
+ // RPC call
+ ret = ScSetAzureStatus(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the current state of the VPN Azure function
+UINT PsVpnAzureGetStatus(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_AZURE_STATUS t;
+ DDNS_CLIENT_STATUS t2;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ Zero(&t2, sizeof(t2));
+
+ // RPC call
+ ret = ScGetAzureStatus(ps->Rpc, &t);
+
+ if (ret == ERR_NO_ERROR)
+ {
+ ret = ScGetDDnsClientStatus(ps->Rpc, &t2);
+ }
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_VpnAzureGetStatus_PRINT_ENABLED"), _UU(t.IsEnabled ? "SEC_YES" : "SEC_NO"));
+
+ if (t.IsEnabled)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), L"%S%S", t2.CurrentHostName, AZURE_DOMAIN_SUFFIX);
+
+ CtInsert(ct, _UU("CMD_VpnAzureGetStatus_PRINT_CONNECTED"), _UU(t.IsConnected ? "SEC_YES" : "SEC_NO"));
+ CtInsert(ct, _UU("CMD_VpnAzureGetStatus_PRINT_HOSTNAME"), tmp);
+ }
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the current state of the dynamic DNS function
+UINT PsDynamicDnsGetStatus(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ DDNS_CLIENT_STATUS t;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScGetDDnsClientStatus(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+ else
+ {
+ CT *ct = CtNewStandard();
+ wchar_t tmp[MAX_SIZE];
+
+ // FQDN
+ if (IsEmptyStr(t.CurrentFqdn) == false)
+ {
+ StrToUni(tmp, sizeof(tmp), t.CurrentFqdn);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_DDNS_FQDN_EMPTY"));
+ }
+ CtInsert(ct, _UU("CMD_DynamicDnsGetStatus_PRINT_FQDN"), tmp);
+
+ // Hostname
+ if (IsEmptyStr(t.CurrentHostName) == false)
+ {
+ StrToUni(tmp, sizeof(tmp), t.CurrentHostName);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_DDNS_FQDN_EMPTY"));
+ }
+ CtInsert(ct, _UU("CMD_DynamicDnsGetStatus_PRINT_HOSTNAME"), tmp);
+
+ // Suffix
+ if (IsEmptyStr(t.DnsSuffix) == false)
+ {
+ StrToUni(tmp, sizeof(tmp), t.DnsSuffix);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_DDNS_FQDN_EMPTY"));
+ }
+ CtInsert(ct, _UU("CMD_DynamicDnsGetStatus_PRINT_SUFFIX"), tmp);
+
+ // IPv4
+ if (t.Err_IPv4 == ERR_NO_ERROR)
+ {
+ StrToUni(tmp, sizeof(tmp), t.CurrentIPv4);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _E(t.Err_IPv4));
+ }
+ CtInsert(ct, _UU("CMD_DynamicDnsGetStatus_PRINT_IPv4"), tmp);
+
+ // IPv6
+ if (t.Err_IPv6 == ERR_NO_ERROR)
+ {
+ StrToUni(tmp, sizeof(tmp), t.CurrentIPv6);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _E(t.Err_IPv6));
+ }
+ CtInsert(ct, _UU("CMD_DynamicDnsGetStatus_PRINT_IPv6"), tmp);
+
+ CtFree(ct, c);
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Configure the dynamic DNS host name
+UINT PsDynamicDnsSetHostname(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_TEST t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[hostname]", CmdPrompt, _UU("CMD_DynamicDnsSetHostname_Prompt_hostname"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.StrValue, sizeof(t.StrValue), GetParamStr(o, "[hostname]"));
+
+ // RPC call
+ ret = ScChangeDDnsClientHostname(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Register a new license key
+UINT PsLicenseAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_TEST t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[key]", CmdPrompt, _UU("CMD_LicenseAdd_Prompt_Key"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.StrValue, sizeof(t.StrValue), GetParamStr(o, "[key]"));
+
+ // RPC call
+ ret = ScAddLicenseKey(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the registered license
+UINT PsLicenseDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_TEST t;
+ // Parameter list that can be specified
+ PARAM args[] =
+ {
+ // "name", prompt_proc, prompt_param, eval_proc, eval_param
+ {"[id]", CmdPrompt, _UU("CMD_LicenseDel_Prompt_ID"), CmdEvalNotEmpty, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.IntValue = GetParamInt(o, "[id]");
+
+ // RPC call
+ ret = ScDelLicenseKey(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+
+
+// Get the registered license list
+UINT PsLicenseList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_ENUM_LICENSE_KEY t;
+ CT *ct;
+ UINT i;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ // RPC call
+ ret = ScEnumLicenseKey(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNew();
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_3"), false);
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_4"), false);
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_5"), false);
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_6"), false);
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_7"), false);
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_8"), false);
+ CtInsertColumn(ct, _UU("SM_LICENSE_COLUMN_9"), false);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ wchar_t tmp1[32], tmp2[LICENSE_KEYSTR_LEN + 1], tmp3[LICENSE_MAX_PRODUCT_NAME_LEN + 1],
+ *tmp4, tmp5[128], tmp6[LICENSE_LICENSEID_STR_LEN + 1], tmp7[64],
+ tmp8[64], tmp9[64];
+ RPC_ENUM_LICENSE_KEY_ITEM *e = &t.Items[i];
+
+ UniToStru(tmp1, e->Id);
+ StrToUni(tmp2, sizeof(tmp2), e->LicenseKey);
+ StrToUni(tmp3, sizeof(tmp3), e->LicenseName);
+ tmp4 = LiGetLicenseStatusStr(e->Status);
+ if (e->Expires == 0)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_LICENSE_NO_EXPIRES"));
+ }
+ else
+ {
+ GetDateStrEx64(tmp5, sizeof(tmp5), e->Expires, NULL);
+ }
+ StrToUni(tmp6, sizeof(tmp6), e->LicenseId);
+ UniToStru(tmp7, e->ProductId);
+ UniFormat(tmp8, sizeof(tmp8), L"%I64u", e->SystemId);
+ UniToStru(tmp9, e->SerialId);
+
+ CtInsert(ct,
+ tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9);
+ }
+
+ CtFreeEx(ct, c, true);
+
+ FreeRpcEnumLicenseKey(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the license status of the current VPN Server
+UINT PsLicenseStatus(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret = 0;
+ RPC_LICENSE_STATUS st;
+ CT *ct;
+ wchar_t tmp[MAX_SIZE];
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&st, sizeof(st));
+
+ // RPC call
+ ret = ScGetLicenseStatus(ps->Rpc, &st);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ // An error has occured
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNewStandard();
+
+ if (st.EditionId == LICENSE_EDITION_VPN3_NO_LICENSE)
+ {
+ CtInsert(ct, _UU("SM_NO_LICENSE_COLUMN"), _UU("SM_NO_LICENSE"));
+ }
+ else
+ {
+ // Product edition name
+ StrToUni(tmp, sizeof(tmp), st.EditionStr);
+ CtInsert(ct, _UU("SM_LICENSE_STATUS_EDITION"), tmp);
+
+ // Release date
+ if (st.ReleaseDate != 0)
+ {
+ GetDateStrEx64(tmp, sizeof(tmp), st.ReleaseDate, NULL);
+ CtInsert(ct, _UU("SM_LICENSE_STATUS_RELEASE"), tmp);
+ }
+
+ // Current system ID
+ UniFormat(tmp, sizeof(tmp), L"%I64u", st.SystemId);
+ CtInsert(ct, _UU("SM_LICENSE_STATUS_SYSTEM_ID"), tmp);
+
+ // Expiration date of the current license product
+ if (st.SystemExpires == 0)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_NO_EXPIRES"));
+ }
+ else
+ {
+ GetDateStrEx64(tmp, sizeof(tmp), st.SystemExpires, NULL);
+ }
+ CtInsert(ct, _UU("SM_LICENSE_STATUS_EXPIRES"), tmp);
+
+ // Subscription (support) contract
+ if (st.NeedSubscription == false)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_STATUS_SUBSCRIPTION_NONEED"));
+ }
+ else
+ {
+ if (st.SubscriptionExpires == 0)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_STATUS_SUBSCRIPTION_NONE"));
+ }
+ else
+ {
+ wchar_t dtstr[MAX_PATH];
+
+ GetDateStrEx64(dtstr, sizeof(dtstr), st.SubscriptionExpires, NULL);
+
+ UniFormat(tmp, sizeof(tmp),
+ st.IsSubscriptionExpired ? _UU("SM_LICENSE_STATUS_SUBSCRIPTION_EXPIRED") : _UU("SM_LICENSE_STATUS_SUBSCRIPTION_VALID"),
+ dtstr);
+ }
+ }
+ CtInsert(ct, _UU("SM_LICENSE_STATUS_SUBSCRIPTION"), tmp);
+
+ if (st.NeedSubscription == false && st.SubscriptionExpires != 0)
+ {
+ wchar_t dtstr[MAX_PATH];
+
+ GetDateStrEx64(dtstr, sizeof(dtstr), st.SubscriptionExpires, NULL);
+
+ CtInsert(ct, _UU("SM_LICENSE_STATUS_SUBSCRIPTION_BUILD_STR"), tmp);
+ }
+
+ if (GetCapsBool(ps->CapsList, "b_vpn3"))
+ {
+ // Maximum creatable number of users
+ if (st.NumClientConnectLicense == INFINITE)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_INFINITE"));
+ }
+ else
+ {
+ UniToStru(tmp, st.NumClientConnectLicense);
+ }
+ CtInsert(ct, _UU("SM_LICENSE_NUM_CLIENT"), tmp);
+ }
+
+ // Available number of concurrent client connections
+ if (st.NumBridgeConnectLicense == INFINITE)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_INFINITE"));
+ }
+ else
+ {
+ UniToStru(tmp, st.NumBridgeConnectLicense);
+ }
+ CtInsert(ct, _UU("SM_LICENSE_NUM_BRIDGE"), tmp);
+
+ // Availability of enterprise features
+ CtInsert(ct, _UU("SM_LICENSE_STATUS_ENTERPRISE"),
+ st.AllowEnterpriseFunction ? _UU("SM_LICENSE_STATUS_ENTERPRISE_YES") : _UU("SM_LICENSE_STATUS_ENTERPRISE_NO"));
+ }
+
+ CtFreeEx(ct, c, false);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+
+// Get the cluster configuration
+UINT PsClusterSettingGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_FARM t;
+ CT *ct;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ ret = ScGetFarmSetting(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ if (t.Weight == 0)
+ {
+ t.Weight = FARM_DEFAULT_WEIGHT;
+ }
+
+ // Show the cluster configuration
+ ct = CtNewStandard();
+
+ CtInsert(ct, _UU("CMD_ClusterSettingGet_Current"),
+ GetServerTypeStr(t.ServerType));
+
+ if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ CtInsert(ct, _UU("CMD_ClusterSettingGet_ControllerOnly"), t.ControllerOnly ? _UU("SEC_YES") : _UU("SEC_NO"));
+ }
+
+ if (t.ServerType != SERVER_TYPE_STANDALONE)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniToStru(tmp, t.Weight);
+
+ CtInsert(ct, _UU("CMD_ClusterSettingGet_Weight"), tmp);
+ }
+
+ if (t.ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ wchar_t tmp[MAX_SIZE];
+ UINT i;
+
+ // Public IP address
+ if (t.PublicIp != 0)
+ {
+ IPToUniStr32(tmp, sizeof(tmp), t.PublicIp);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("CMD_ClusterSettingGet_None"));
+ }
+
+ CtInsert(ct, _UU("CMD_ClusterSettingGet_PublicIp"), tmp);
+
+ // Public port list
+ tmp[0] = 0;
+ for (i = 0;i < t.NumPort;i++)
+ {
+ wchar_t tmp2[64];
+
+ UniFormat(tmp2, sizeof(tmp2), L"%u, ", t.Ports[i]);
+
+ UniStrCat(tmp, sizeof(tmp), tmp2);
+ }
+
+ if (UniEndWith(tmp, L", "))
+ {
+ tmp[UniStrLen(tmp) - 2] = 0;
+ }
+
+ CtInsert(ct, _UU("CMD_ClusterSettingGet_PublicPorts"), tmp);
+
+ // Controller to connect
+ UniFormat(tmp, sizeof(tmp), L"%S:%u", t.ControllerName, t.ControllerPort);
+ CtInsert(ct, _UU("CMD_ClusterSettingGet_Controller"), tmp);
+ }
+
+ CtFree(ct, c);
+
+ FreeRpcFarm(&t);
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Set the server password
+UINT PsServerPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_SET_PASSWORD t;
+ char *pw;
+ PARAM args[] =
+ {
+ {"[password]", CmdPromptChoosePassword, NULL, NULL, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ pw = GetParamStr(o, "[password]");
+
+ Zero(&t, sizeof(t));
+ Hash(t.HashedPassword, pw, StrLen(pw), true);
+
+ ret = ScSetServerPassword(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Password decision prompt (for Prompt function)
+wchar_t *CmdPromptChoosePassword(CONSOLE *c, void *param)
+{
+ char *s;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ s = CmdPasswordPrompt(c);
+
+ if (s == NULL)
+ {
+ return NULL;
+ }
+ else
+ {
+ wchar_t *ret = CopyStrToUni(s);
+
+ Free(s);
+
+ return ret;
+ }
+}
+
+// Password input prompt (general-purpose)
+char *CmdPasswordPrompt(CONSOLE *c)
+{
+ char *pw1, *pw2;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ c->Write(c, _UU("CMD_VPNCMD_PWPROMPT_0"));
+
+RETRY:
+ c->Write(c, L"");
+
+
+ pw1 = c->ReadPassword(c, _UU("CMD_VPNCMD_PWPROMPT_1"));
+ if (pw1 == NULL)
+ {
+ return NULL;
+ }
+
+ pw2 = c->ReadPassword(c, _UU("CMD_VPNCMD_PWPROMPT_2"));
+ if (pw2 == NULL)
+ {
+ Free(pw1);
+ return NULL;
+ }
+
+ c->Write(c, L"");
+
+ if (StrCmp(pw1, pw2) != 0)
+ {
+ Free(pw1);
+ Free(pw2);
+ c->Write(c, _UU("CMD_VPNCMD_PWPROMPT_3"));
+ goto RETRY;
+ }
+
+ Free(pw1);
+
+ return pw2;
+}
+
+// Disable the listener
+UINT PsListenerDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_LISTENER t;
+ PARAM args[] =
+ {
+ {"[port]", CmdPromptPort, _UU("CMD_ListenerDisable_PortPrompt"), CmdEvalPort, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.Enable = false;
+ t.Port = ToInt(GetParamStr(o, "[port]"));
+
+ ret = ScEnableListener(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Enable the listener
+UINT PsListenerEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_LISTENER t;
+ PARAM args[] =
+ {
+ {"[port]", CmdPromptPort, _UU("CMD_ListenerEnable_PortPrompt"), CmdEvalPort, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.Enable = true;
+ t.Port = ToInt(GetParamStr(o, "[port]"));
+
+ ret = ScEnableListener(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Draw a row of console table
+void CtPrintRow(CONSOLE *c, UINT num, UINT *widths, wchar_t **strings, bool *rights, char separate_char)
+{
+ UINT i;
+ wchar_t *buf;
+ UINT buf_size;
+ bool is_sep_line = true;
+ // Validate arguments
+ if (c == NULL || num == 0 || widths == NULL || strings == NULL || rights == NULL)
+ {
+ return;
+ }
+
+ buf_size = 32;
+ for (i = 0;i < num;i++)
+ {
+ buf_size += sizeof(wchar_t) * widths[i] + 6;
+ }
+
+ buf = ZeroMalloc(buf_size);
+
+ for (i = 0;i < num;i++)
+ {
+ char *tmp;
+ wchar_t *space_string;
+ UINT w;
+ UINT space = 0;
+ wchar_t *string = strings[i];
+ wchar_t *tmp_line = NULL;
+
+ if (UniStrCmpi(string, L"---") == 0)
+ {
+ char *s = MakeCharArray('-', widths[i]);
+ tmp_line = string = CopyStrToUni(s);
+
+ Free(s);
+ }
+ else
+ {
+ is_sep_line = false;
+ }
+
+ w = UniStrWidth(string);
+
+ if (widths[i] >= w)
+ {
+ space = widths[i] - w;
+ }
+
+ tmp = MakeCharArray(' ', space);
+ space_string = CopyStrToUni(tmp);
+
+ if (rights[i] != false)
+ {
+ UniStrCat(buf, buf_size, space_string);
+ }
+
+ UniStrCat(buf, buf_size, string);
+
+ if (rights[i] == false)
+ {
+ UniStrCat(buf, buf_size, space_string);
+ }
+
+ Free(space_string);
+ Free(tmp);
+
+ if (i < (num - 1))
+ {
+ wchar_t tmp[4];
+ char str[2];
+
+ if (UniStrCmpi(strings[i], L"---") == 0)
+ {
+ str[0] = '+';
+ }
+ else
+ {
+ str[0] = separate_char;
+ }
+ str[1] = 0;
+
+ StrToUni(tmp, sizeof(tmp), str);
+
+ UniStrCat(buf, buf_size, tmp);
+ }
+
+ if (tmp_line != NULL)
+ {
+ Free(tmp_line);
+ }
+ }
+
+ UniTrimRight(buf);
+
+ if (is_sep_line)
+ {
+ if (UniStrLen(buf) > (c->GetWidth(c) - 1))
+ {
+ buf[c->GetWidth(c) - 1] = 0;
+ }
+ }
+
+ c->Write(c, buf);
+
+ Free(buf);
+}
+
+// Draw the console table in standard format
+void CtPrintStandard(CT *ct, CONSOLE *c)
+{
+ CT *t;
+ UINT i, j;
+ // Validate arguments
+ if (ct == NULL || c == NULL)
+ {
+ return;
+ }
+
+ t = CtNewStandard();
+ for (i = 0;i < LIST_NUM(ct->Rows);i++)
+ {
+ CTR *row = LIST_DATA(ct->Rows, i);
+
+ for (j = 0;j < LIST_NUM(ct->Columns);j++)
+ {
+ CTC *column = LIST_DATA(ct->Columns, j);
+
+ CtInsert(t, column->String, row->Strings[j]);
+ }
+
+ if (i != (LIST_NUM(ct->Rows) - 1))
+ {
+ CtInsert(t, L"---", L"---");
+ }
+ }
+
+ CtFree(t, c);
+}
+
+// Draw the console table
+void CtPrint(CT *ct, CONSOLE *c)
+{
+ UINT *widths;
+ UINT num;
+ UINT i, j;
+ wchar_t **header_strings;
+ bool *rights;
+ // Validate arguments
+ if (ct == NULL || c == NULL)
+ {
+ return;
+ }
+
+ num = LIST_NUM(ct->Columns);
+ widths = ZeroMalloc(sizeof(UINT) * num);
+
+ // Calculate the maximum character width of each column
+ for (i = 0;i < num;i++)
+ {
+ CTC *ctc = LIST_DATA(ct->Columns, i);
+ UINT w;
+
+ w = UniStrWidth(ctc->String);
+ widths[i] = MAX(widths[i], w);
+ }
+ for (j = 0;j < LIST_NUM(ct->Rows);j++)
+ {
+ CTR *ctr = LIST_DATA(ct->Rows, j);
+
+ for (i = 0;i < num;i++)
+ {
+ UINT w;
+
+ w = UniStrWidth(ctr->Strings[i]);
+ widths[i] = MAX(widths[i], w);
+ }
+ }
+
+ // Display the header part
+ header_strings = ZeroMalloc(sizeof(wchar_t *) * num);
+ rights = ZeroMalloc(sizeof(bool) * num);
+
+ for (i = 0;i < num;i++)
+ {
+ CTC *ctc = LIST_DATA(ct->Columns, i);
+
+ header_strings[i] = ctc->String;
+ rights[i] = ctc->Right;
+ }
+
+ CtPrintRow(c, num, widths, header_strings, rights, '|');
+
+ for (i = 0;i < num;i++)
+ {
+ char *s;
+
+ s = MakeCharArray('-', widths[i]);
+ header_strings[i] = CopyStrToUni(s);
+ Free(s);
+ }
+
+ CtPrintRow(c, num, widths, header_strings, rights, '+');
+
+ for (i = 0;i < num;i++)
+ {
+ Free(header_strings[i]);
+ }
+
+ // Display the data part
+ for (j = 0;j < LIST_NUM(ct->Rows);j++)
+ {
+ CTR *ctr = LIST_DATA(ct->Rows, j);
+
+ CtPrintRow(c, num, widths, ctr->Strings, rights, '|');
+ }
+
+ Free(rights);
+ Free(header_strings);
+ Free(widths);
+}
+
+// Escape the meta-characters in CSV
+void CtEscapeCsv(wchar_t *dst, UINT size, wchar_t *src){
+ UINT i;
+ UINT len = UniStrLen(src);
+ UINT idx;
+ BOOL need_to_escape = false;
+ wchar_t tmp[2]=L"*";
+
+ // Check the input value
+ if (src==NULL || dst==NULL)
+ {
+ return;
+ }
+
+ // If there is no character that need to be escaped in the input characters, copy it to the output
+ len = UniStrLen(src);
+ for (i=0; i<len; i++)
+ {
+ tmp[0] = src[i];
+ if (tmp[0] == L","[0] || tmp[0] == L"\n"[0] || tmp[0] == L"\""[0])
+ {
+ need_to_escape = true;
+ }
+ }
+ if (need_to_escape == false)
+ {
+ UniStrCpy(dst,size,src);
+ return;
+ }
+
+ // If it contains meta characters (newline, comma, double quote), enclose with "
+ UniStrCpy(dst, size, L"\"");
+ idx = UniStrLen(dst);
+ if(idx<size-1)
+ {
+ for (i=0; i<len; i++)
+ {
+ tmp[0] = src[i];
+ // Convert " to "" in contents(MS-Excel method)
+ if (tmp[0] == L"\""[0])
+ {
+ UniStrCat(dst, size, tmp);
+ }
+ UniStrCat(dst, size, tmp);
+ }
+ }
+ UniStrCat(dst, size, L"\"");
+ return;
+}
+
+// Show a CSV format of console table
+void CtPrintCsv(CT *ct, CONSOLE *c)
+{
+ UINT i, j;
+ UINT num_columns = LIST_NUM(ct->Columns);
+ wchar_t buf[MAX_SIZE];
+ wchar_t fmtbuf[MAX_SIZE];
+
+ // Show the heading row
+ buf[0] = 0;
+ for(i=0; i<num_columns; i++)
+ {
+ CTC *ctc = LIST_DATA(ct->Columns, i);
+ CtEscapeCsv(fmtbuf, MAX_SIZE, ctc->String);
+ UniStrCat(buf, MAX_SIZE, fmtbuf);
+ if(i != num_columns-1)
+ UniStrCat(buf, MAX_SIZE, L",");
+ }
+ c->Write(c, buf);
+
+ // Show the table body
+ for(j=0; j<LIST_NUM(ct->Rows); j++)
+ {
+ CTR *ctr = LIST_DATA(ct->Rows, j);
+ buf[0] = 0;
+ for(i=0; i<num_columns; i++)
+ {
+ CtEscapeCsv(fmtbuf, MAX_SIZE, ctr->Strings[i]);
+ UniStrCat(buf, MAX_SIZE, fmtbuf);
+ if(i != num_columns-1)
+ UniStrCat(buf, MAX_SIZE, L",");
+ }
+ c->Write(c, buf);
+ }
+}
+
+// Delete the console table
+void CtFreeEx(CT *ct, CONSOLE *c, bool standard_view)
+{
+ UINT i, num;
+ // Validate arguments
+ if (ct == NULL)
+ {
+ return;
+ }
+
+ if (c != NULL)
+ {
+ if (c->ConsoleType == CONSOLE_CSV)
+ {
+ CtPrintCsv(ct, c);
+ }
+ else
+ {
+ if (standard_view == false)
+ {
+ CtPrint(ct, c);
+ }
+ else
+ {
+ CtPrintStandard(ct, c);
+ }
+ }
+ }
+
+ num = LIST_NUM(ct->Columns);
+
+ for (i = 0;i < LIST_NUM(ct->Rows);i++)
+ {
+ UINT j;
+ CTR *ctr = LIST_DATA(ct->Rows, i);
+
+ for (j = 0;j < num;j++)
+ {
+ Free(ctr->Strings[j]);
+ }
+
+ Free(ctr->Strings);
+ Free(ctr);
+ }
+
+ for (i = 0;i < LIST_NUM(ct->Columns);i++)
+ {
+ CTC *ctc = LIST_DATA(ct->Columns, i);
+
+ Free(ctc->String);
+ Free(ctc);
+ }
+
+ ReleaseList(ct->Columns);
+ ReleaseList(ct->Rows);
+
+ Free(ct);
+}
+void CtFree(CT *ct, CONSOLE *c)
+{
+ CtFreeEx(ct, c, false);
+}
+
+// Add a row to the table
+void CtInsert(CT *ct, ...)
+{
+ CTR *ctr;
+ UINT num, i;
+ va_list va;
+ // Validate arguments
+ if (ct == NULL)
+ {
+ return;
+ }
+
+ num = LIST_NUM(ct->Columns);
+
+ va_start(va, ct);
+
+ ctr = ZeroMalloc(sizeof(CTR));
+ ctr->Strings = ZeroMalloc(sizeof(wchar_t *) * num);
+
+ for (i = 0;i < num;i++)
+ {
+ wchar_t *s = va_arg(va, wchar_t *);
+
+ ctr->Strings[i] = CopyUniStr(s);
+ }
+
+ va_end(va);
+
+ Insert(ct->Rows, ctr);
+}
+
+// Add a column to the table
+void CtInsertColumn(CT *ct, wchar_t *str, bool right)
+{
+ CTC *ctc;
+ // Validate arguments
+ if (ct == NULL)
+ {
+ return;
+ }
+ if (str == NULL)
+ {
+ str = L"";
+ }
+
+ ctc = ZeroMalloc(sizeof(CTC));
+ ctc->String = CopyUniStr(str);
+ ctc->Right = right;
+
+ Insert(ct->Columns, ctc);
+}
+
+// Create a new console table
+CT *CtNew()
+{
+ CT *ct;
+
+ ct = ZeroMalloc(sizeof(CT));
+ ct->Columns = NewList(NULL);
+ ct->Rows = NewList(NULL);
+
+ return ct;
+}
+
+// Add a standard column to a column in a table
+CT *CtNewStandard()
+{
+ CT *ct = CtNew();
+
+ CtInsertColumn(ct, _UU("CMD_CT_STD_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("CMD_CT_STD_COLUMN_2"), false);
+
+ return ct;
+}
+CT *CtNewStandardEx()
+{
+ CT *ct = CtNew();
+
+ CtInsertColumn(ct, _UU("CMD_CT_STD_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("CMD_CT_STD_COLUMN_2"), false);
+ CtInsertColumn(ct, _UU("CMD_CT_STD_COLUMN_3"), false);
+
+ return ct;
+}
+
+// Get the TCP listener list
+UINT PsListenerList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_LISTENER_LIST t;
+ UINT i;
+ CT *ct;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+
+ ret = ScEnumListener(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNew();
+
+ CtInsertColumn(ct, _UU("CM_LISTENER_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("CM_LISTENER_COLUMN_2"), false);
+
+ for (i = 0;i < t.NumPort;i++)
+ {
+ wchar_t *status = _UU("CM_LISTENER_OFFLINE");
+ wchar_t tmp[128];
+
+ if (t.Errors[i])
+ {
+ status = _UU("CM_LISTENER_ERROR");
+ }
+ else if (t.Enables[i])
+ {
+ status = _UU("CM_LISTENER_ONLINE");
+ }
+
+ UniFormat(tmp, sizeof(tmp), _UU("CM_LISTENER_TCP_PORT"), t.Ports[i]);
+
+ CtInsert(ct, tmp, status);
+ }
+
+ CtFree(ct, c);
+
+ FreeRpcListenerList(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Delete the TCP listener
+UINT PsListenerDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_LISTENER t;
+ PARAM args[] =
+ {
+ {"[port]", CmdPromptPort, _UU("CMD_ListenerDelete_PortPrompt"), CmdEvalPort, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.Enable = true;
+ t.Port = ToInt(GetParamStr(o, "[port]"));
+
+ ret = ScDeleteListener(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Draw a row
+void CmdPrintRow(CONSOLE *c, wchar_t *title, wchar_t *tag, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ wchar_t buf2[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (title == NULL || c == NULL || tag == NULL)
+ {
+ return;
+ }
+
+ va_start(args, tag);
+ UniFormatArgs(buf, sizeof(buf), tag, args);
+
+ UniFormat(buf2, sizeof(buf2), L"[%s] %s", title, buf);
+
+ va_end(args);
+
+ c->Write(c, buf2);
+}
+
+// ServerInfoGet command
+UINT PsServerInfoGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_SERVER_INFO t;
+ CT *ct;
+ wchar_t tmp[MAX_SIZE];
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ ret = ScGetServerInfo(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNew();
+
+ CtInsertColumn(ct, _UU("SM_STATUS_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_STATUS_COLUMN_2"), false);
+
+ // Product name
+ StrToUni(tmp, sizeof(tmp), t.ServerProductName);
+ CtInsert(ct, _UU("SM_INFO_PRODUCT_NAME"), tmp);
+
+ // Version
+ StrToUni(tmp, sizeof(tmp), t.ServerVersionString);
+ CtInsert(ct, _UU("SM_INFO_VERSION"), tmp);
+
+ // Build
+ StrToUni(tmp, sizeof(tmp), t.ServerBuildInfoString);
+ CtInsert(ct, _UU("SM_INFO_BUILD"), tmp);
+
+ // Host name
+ StrToUni(tmp, sizeof(tmp), t.ServerHostName);
+ CtInsert(ct, _UU("SM_INFO_HOSTNAME"), tmp);
+
+ // Type
+ CtInsert(ct, _UU("SM_ST_SERVER_TYPE"), GetServerTypeStr(t.ServerType));
+
+ // OS
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsSystemName);
+ CtInsert(ct, _UU("SM_OS_SYSTEM_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsProductName);
+ CtInsert(ct, _UU("SM_OS_PRODUCT_NAME"), tmp);
+
+ if (t.OsInfo.OsServicePack != 0)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SM_OS_SP_TAG"), t.OsInfo.OsServicePack);
+ CtInsert(ct, _UU("SM_OS_SERVICE_PACK"), tmp);
+ }
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsVendorName);
+ CtInsert(ct, _UU("SM_OS_VENDER_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsVersion);
+ CtInsert(ct, _UU("SM_OS_VERSION"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.KernelName);
+ CtInsert(ct, _UU("SM_OS_KERNEL_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.KernelVersion);
+ CtInsert(ct, _UU("SM_OS_KERNEL_VERSION"), tmp);
+
+ CtFree(ct, c);
+
+ FreeRpcServerInfo(&t);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Get the string for type of the HUB
+wchar_t *GetHubTypeStr(UINT type)
+{
+ if (type == HUB_TYPE_FARM_STATIC)
+ {
+ return _UU("SM_HUB_STATIC");
+ }
+ else if (type == HUB_TYPE_FARM_DYNAMIC)
+ {
+ return _UU("SM_HUB_DYNAMIC");
+ }
+ return _UU("SM_HUB_STANDALONE");
+}
+
+// Get a string of the type of server
+wchar_t *GetServerTypeStr(UINT type)
+{
+ if (type == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ return _UU("SM_FARM_CONTROLLER");
+ }
+ else if (type == SERVER_TYPE_FARM_MEMBER)
+ {
+ return _UU("SM_FARM_MEMBER");
+ }
+ return _UU("SM_SERVER_STANDALONE");
+}
+
+// ServerStatusGet command
+UINT PsServerStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_SERVER_STATUS t;
+ wchar_t tmp[MAX_PATH];
+ char tmp2[MAX_PATH];
+ CT *ct;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ ret = ScGetServerStatus(ps->Rpc, &t);
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ ct = CtNew();
+
+ CtInsertColumn(ct, _UU("SM_STATUS_COLUMN_1"), false);
+ CtInsertColumn(ct, _UU("SM_STATUS_COLUMN_2"), false);
+
+ // Type of server
+ CtInsert(ct, _UU("SM_ST_SERVER_TYPE"),
+ t.ServerType == SERVER_TYPE_STANDALONE ? _UU("SM_SERVER_STANDALONE") :
+ t.ServerType == SERVER_TYPE_FARM_MEMBER ? _UU("SM_FARM_MEMBER") : _UU("SM_FARM_CONTROLLER"));
+
+ // Number of TCP connections
+ UniToStru(tmp, t.NumTcpConnections);
+ CtInsert(ct, _UU("SM_ST_NUM_TCP"), tmp);
+
+ if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ // Number of local TCP connections
+ UniToStru(tmp, t.NumTcpConnectionsLocal);
+ CtInsert(ct, _UU("SM_ST_NUM_TCP_LOCAL"), tmp);
+
+ // Number of remote TCP connections
+ UniToStru(tmp, t.NumTcpConnectionsRemote);
+ CtInsert(ct, _UU("SM_ST_NUM_TCP_REMOTE"), tmp);
+ }
+
+ // Number of Virtual HUBs
+ UniToStru(tmp, t.NumHubTotal);
+ CtInsert(ct, _UU("SM_ST_NUM_HUB_TOTAL"), tmp);
+
+ if (t.ServerType != SERVER_TYPE_STANDALONE)
+ {
+ // Number of static HUBs
+ UniToStru(tmp, t.NumHubStatic);
+ CtInsert(ct, _UU("SM_ST_NUM_HUB_STATIC"), tmp);
+
+ // Number of dynamic HUBs
+ UniToStru(tmp, t.NumHubDynamic);
+ CtInsert(ct, _UU("SM_ST_NUM_HUB_DYNAMIC"), tmp);
+ }
+
+ // Number of sessions
+ UniToStru(tmp, t.NumSessionsTotal);
+ CtInsert(ct, _UU("SM_ST_NUM_SESSION_TOTAL"), tmp);
+
+ if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ // Number of local sessions
+ UniToStru(tmp, t.NumSessionsLocal);
+ CtInsert(ct, _UU("SM_ST_NUM_SESSION_LOCAL"), tmp);
+
+ // Number of remote sessions
+ UniToStru(tmp, t.NumSessionsRemote);
+ CtInsert(ct, _UU("SM_ST_NUM_SESSION_REMOTE"), tmp);
+ }
+
+ // Number of MAC tables
+ UniToStru(tmp, t.NumMacTables);
+ CtInsert(ct, _UU("SM_ST_NUM_MAC_TABLE"), tmp);
+
+ // Number of IP tables
+ UniToStru(tmp, t.NumIpTables);
+ CtInsert(ct, _UU("SM_ST_NUM_IP_TABLE"), tmp);
+
+ // Number of users
+ UniToStru(tmp, t.NumUsers);
+ CtInsert(ct, _UU("SM_ST_NUM_USERS"), tmp);
+
+ // Number of groups
+ UniToStru(tmp, t.NumGroups);
+ CtInsert(ct, _UU("SM_ST_NUM_GROUPS"), tmp);
+
+ // Number of assigned licenses
+ UniToStru(tmp, t.AssignedClientLicenses);
+ CtInsert(ct, _UU("SM_ST_CLIENT_LICENSE"), tmp);
+
+ UniToStru(tmp, t.AssignedBridgeLicenses);
+ CtInsert(ct, _UU("SM_ST_BRIDGE_LICENSE"), tmp);
+
+ if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ UniToStru(tmp, t.AssignedClientLicensesTotal);
+ CtInsert(ct, _UU("SM_ST_CLIENT_LICENSE_EX"), tmp);
+
+ UniToStru(tmp, t.AssignedBridgeLicensesTotal);
+ CtInsert(ct, _UU("SM_ST_BRIDGE_LICENSE_EX"), tmp);
+ }
+
+ // Traffic
+ CmdInsertTrafficInfo(ct, &t.Traffic);
+
+ // Server start-up time
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.StartTime), NULL);
+ CtInsert(ct, _UU("SM_ST_START_TIME"), tmp);
+
+ // Current time
+ GetDateTimeStrMilli64(tmp2, sizeof(tmp2), SystemToLocal64(t.CurrentTime));
+ StrToUni(tmp, sizeof(tmp), tmp2);
+ CtInsert(ct, _UU("SM_ST_CURRENT_TIME"), tmp);
+
+ // Tick value
+ UniFormat(tmp, sizeof(tmp), L"%I64u", t.CurrentTick);
+ CtInsert(ct, _UU("SM_ST_CURRENT_TICK"), tmp);
+
+ // Memory information
+ if (t.MemInfo.TotalMemory != 0)
+ {
+ char vv[128];
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.TotalMemory);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ CtInsert(ct, _UU("SM_ST_TOTAL_MEMORY"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.UsedMemory);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ CtInsert(ct, _UU("SM_ST_USED_MEMORY"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.FreeMemory);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ CtInsert(ct, _UU("SM_ST_FREE_MEMORY"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.TotalPhys);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ CtInsert(ct, _UU("SM_ST_TOTAL_PHYS"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.UsedPhys);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ CtInsert(ct, _UU("SM_ST_USED_PHYS"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.FreePhys);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ CtInsert(ct, _UU("SM_ST_FREE_PHYS"), tmp);
+ }
+
+ CtFree(ct, c);
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// Add traffic information to LVB
+void CmdInsertTrafficInfo(CT *ct, TRAFFIC *t)
+{
+ wchar_t tmp[MAX_SIZE];
+ char vv[128];
+ // Validate arguments
+ if (ct == NULL || t == NULL)
+ {
+ return;
+ }
+
+ // Transmission information
+ ToStr3(vv, sizeof(vv), t->Send.UnicastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+ CtInsert(ct, _UU("SM_ST_SEND_UCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), t->Send.UnicastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("SM_ST_SEND_UCAST_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), t->Send.BroadcastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+ CtInsert(ct, _UU("SM_ST_SEND_BCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), t->Send.BroadcastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("SM_ST_SEND_BCAST_SIZE"), tmp);
+
+ // Reception information
+ ToStr3(vv, sizeof(vv), t->Recv.UnicastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+ CtInsert(ct, _UU("SM_ST_RECV_UCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), t->Recv.UnicastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("SM_ST_RECV_UCAST_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), t->Recv.BroadcastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+ CtInsert(ct, _UU("SM_ST_RECV_BCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), t->Recv.BroadcastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+ CtInsert(ct, _UU("SM_ST_RECV_BCAST_SIZE"), tmp);
+}
+
+// Input a port number
+wchar_t *CmdPromptPort(CONSOLE *c, void *param)
+{
+ wchar_t *prompt_str;
+
+ if (param != NULL)
+ {
+ prompt_str = (wchar_t *)param;
+ }
+ else
+ {
+ prompt_str = _UU("CMD_PROPMT_PORT");
+ }
+
+ return c->ReadLine(c, prompt_str, true);
+}
+
+// Verify the port number
+bool CmdEvalPort(CONSOLE *c, wchar_t *str, void *param)
+{
+ UINT i;
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ i = UniToInt(str);
+
+ if (i >= 1 && i <= 65535)
+ {
+ return true;
+ }
+
+ c->Write(c, _UU("CMD_EVAL_PORT"));
+
+ return false;
+}
+
+// ListenerCreate command
+UINT PsListenerCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ PS *ps = (PS *)param;
+ UINT ret;
+ RPC_LISTENER t;
+ PARAM args[] =
+ {
+ {"[port]", CmdPromptPort, _UU("CMD_ListenerCreate_PortPrompt"), CmdEvalPort, NULL},
+ };
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ Zero(&t, sizeof(t));
+ t.Enable = true;
+ t.Port = ToInt(GetParamStr(o, "[port]"));
+
+ ret = ScCreateListener(ps->Rpc, &t);
+
+ if (ret != ERR_NO_ERROR)
+ {
+ CmdPrintError(c, ret);
+ FreeParamValueList(o);
+ return ret;
+ }
+
+ FreeParamValueList(o);
+
+ return 0;
+}
+
+// About command
+UINT PsAbout(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ BUF *b;
+
+ o = ParseCommandList(c, cmd_name, str, NULL, 0);
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ b = ReadDump("|legal.txt");
+
+ CmdPrintAbout(c);
+ c->Write(c, L"\r\n");
+
+ if (b != NULL)
+ {
+ wchar_t *s;
+
+ SeekBufToEnd(b);
+ WriteBufChar(b, 13);
+ WriteBufChar(b, 10);
+ WriteBufChar(b, 0);
+
+ s = CopyUtfToUni(b->Buf);
+
+ c->Write(c, s);
+
+ Free(s);
+ }
+
+ // Display the version information
+ c->Write(c, _UU("D_ABOUT@S_INFO3"));
+ c->Write(c, L"\r\n");
+ c->Write(c, _UU("D_ABOUT@S_INFO4"));
+ c->Write(c, L"\r\n");
+ CmdPrintAbout(c);
+ c->Write(c, L"\r\n");
+
+ FreeParamValueList(o);
+
+ FreeBuf(b);
+
+ return 0;
+}
+
+// Creat a new server management context
+PS *NewPs(CONSOLE *c, RPC *rpc, char *servername, UINT serverport, char *hubname, char *adminhub, wchar_t *cmdline)
+{
+ PS *ps;
+ // Validate arguments
+ if (c == NULL || rpc == NULL || servername == NULL)
+ {
+ return NULL;
+ }
+
+ if (IsEmptyStr(hubname))
+ {
+ hubname = NULL;
+ }
+ if (IsEmptyStr(adminhub))
+ {
+ adminhub = NULL;
+ }
+ if (UniIsEmptyStr(cmdline))
+ {
+ cmdline = NULL;
+ }
+
+ ps = ZeroMalloc(sizeof(PS));
+ ps->ConsoleForServer = true;
+ ps->ServerPort = serverport;
+ ps->ServerName = CopyStr(servername);
+ ps->Console = c;
+ ps->Rpc = rpc;
+ ps->HubName = CopyStr(hubname);
+ ps->LastError = 0;
+ ps->AdminHub = CopyStr(adminhub);
+ ps->CmdLine = CopyUniStr(cmdline);
+
+ return ps;
+}
+
+// Release the server management context
+void FreePs(PS *ps)
+{
+ // Validate arguments
+ if (ps == NULL)
+ {
+ return;
+ }
+
+ Free(ps->HubName);
+ Free(ps->AdminHub);
+ Free(ps->CmdLine);
+ Free(ps->ServerName);
+
+ Free(ps);
+}
+
+// Server Administration Tool
+UINT PsConnect(CONSOLE *c, char *host, UINT port, char *hub, char *adminhub, wchar_t *cmdline, char *password)
+{
+ UINT retcode = 0;
+ RPC *rpc = NULL;
+ CEDAR *cedar;
+ CLIENT_OPTION o;
+ UCHAR hashed_password[SHA1_SIZE];
+ bool b = false;
+ // Validate arguments
+ if (c == NULL || host == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+ if (port == 0)
+ {
+ port = 443;
+ }
+ if (hub != NULL)
+ {
+ adminhub = NULL;
+ }
+
+ cedar = NewCedar(NULL, NULL);
+
+ Zero(&o, sizeof(o));
+ UniStrCpy(o.AccountName, sizeof(o.AccountName), L"VPNCMD");
+ StrCpy(o.Hostname, sizeof(o.Hostname), host);
+ o.Port = port;
+ o.ProxyType = PROXY_DIRECT;
+
+ Hash(hashed_password, password, StrLen(password), true);
+
+ if (IsEmptyStr(password) == false)
+ {
+ b = true;
+ }
+
+ // Connect
+ while (true)
+ {
+ UINT err;
+
+ rpc = AdminConnectEx(cedar, &o, hub, hashed_password, &err, CEDAR_CUI_STR);
+ if (rpc == NULL)
+ {
+ // Failure
+ retcode = err;
+
+ if (err == ERR_ACCESS_DENIED)
+ {
+ char *pass;
+ // Password is incorrect
+ if (b)
+ {
+ // Input the password
+ c->Write(c, _UU("CMD_VPNCMD_PASSWORD_1"));
+ }
+
+ b = true;
+
+ pass = c->ReadPassword(c, _UU("CMD_VPNCMD_PASSWORD_2"));
+ c->Write(c, L"");
+
+ if (pass != NULL)
+ {
+ Hash(hashed_password, pass, StrLen(pass), true);
+ Free(pass);
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ // Other errors
+ CmdPrintError(c, err);
+ break;
+ }
+ }
+ else
+ {
+ PS *ps;
+
+ // Success
+ ps = NewPs(c, rpc, host, port, hub, adminhub, cmdline);
+ PsMain(ps);
+ retcode = ps->LastError;
+ FreePs(ps);
+ AdminDisconnect(rpc);
+ break;
+ }
+ }
+
+ ReleaseCedar(cedar);
+
+ return retcode;
+}
+
+// Display the error
+void CmdPrintError(CONSOLE *c, UINT err)
+{
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_VPNCMD_ERROR"),
+ err, GetUniErrorStr(err));
+ c->Write(c, tmp);
+
+ if (err == ERR_DISCONNECTED)
+ {
+ c->Write(c, _UU("CMD_DISCONNECTED_MSG"));
+ }
+}
+
+// Display the version information
+void CmdPrintAbout(CONSOLE *c)
+{
+ CEDAR *cedar;
+ wchar_t tmp[MAX_SIZE];
+ char exe[MAX_PATH];
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ cedar = NewCedar(NULL, NULL);
+
+ GetExeName(exe, sizeof(exe));
+
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_VPNCMD_ABOUT"),
+ cedar->VerString, cedar->BuildInfo);
+
+ c->Write(c, tmp);
+
+ ReleaseCedar(cedar);
+}
+
+// Parse the host name and port number (Separated by @)
+bool ParseHostPortAtmark(char *src, char **host, UINT *port, UINT default_port)
+{
+ TOKEN_LIST *t;
+ bool ret = false;
+ // Validate arguments
+ if (src == NULL)
+ {
+ return false;
+ }
+
+ t = ParseToken(src, "@");
+ if (t == NULL)
+ {
+ return false;
+ }
+
+ if (port != NULL)
+ {
+ *port = 0;
+ }
+
+ if (default_port == 0)
+ {
+ if (t->NumTokens < 2)
+ {
+ FreeToken(t);
+ return false;
+ }
+
+ if (ToInt(t->Token[1]) == 0)
+ {
+ FreeToken(t);
+ return false;
+ }
+ }
+
+ if (t->NumTokens >= 2 && ToInt(t->Token[1]) == 0)
+ {
+ FreeToken(t);
+ return false;
+ }
+
+ if (t->NumTokens >= 1 && IsEmptyStr(t->Token[0]) == false)
+ {
+ ret = true;
+
+ if (host != NULL)
+ {
+ *host = CopyStr(t->Token[0]);
+ Trim(*host);
+ }
+
+ if (t->NumTokens >= 2)
+ {
+ if (port != NULL)
+ {
+ *port = ToInt(t->Token[1]);
+ }
+ }
+ }
+
+ if (port != NULL)
+ {
+ if (*port == 0)
+ {
+ *port = default_port;
+ }
+ }
+
+ FreeToken(t);
+
+ return ret;
+}
+
+// Parse the host name and port number
+bool ParseHostPort(char *src, char **host, UINT *port, UINT default_port)
+{
+ TOKEN_LIST *t;
+ bool ret = false;
+ // Validate arguments
+ if (src == NULL)
+ {
+ return false;
+ }
+
+ if (StartWith(src, "["))
+ {
+ if (InStr(src, "]"))
+ {
+ // Format of [target]:port
+ UINT i, n;
+ char tmp[MAX_SIZE];
+
+ StrCpy(tmp, sizeof(tmp), src);
+
+ n = SearchStrEx(tmp, "]", 0, false);
+ if (n != INFINITE)
+ {
+ UINT len = StrLen(tmp);
+
+ for (i = n;i < len;i++)
+ {
+ if (tmp[i] == ':')
+ {
+ tmp[i] = '@';
+ }
+ }
+ }
+
+ return ParseHostPortAtmark(tmp, host, port, default_port);
+ }
+ }
+
+ if (InStr(src, "@"))
+ {
+ // It is separated by @
+ return ParseHostPortAtmark(src, host, port, default_port);
+ }
+
+ t = ParseToken(src, ":");
+ if (t == NULL)
+ {
+ return false;
+ }
+
+ if (port != NULL)
+ {
+ *port = 0;
+ }
+
+ if (default_port == 0)
+ {
+ if (t->NumTokens < 2)
+ {
+ FreeToken(t);
+ return false;
+ }
+
+ if (ToInt(t->Token[1]) == 0)
+ {
+ FreeToken(t);
+ return false;
+ }
+ }
+
+ if (t->NumTokens >= 2 && ToInt(t->Token[1]) == 0)
+ {
+ FreeToken(t);
+ return false;
+ }
+
+ if (t->NumTokens >= 1 && IsEmptyStr(t->Token[0]) == false)
+ {
+ ret = true;
+
+ if (host != NULL)
+ {
+ *host = CopyStr(t->Token[0]);
+ Trim(*host);
+ }
+
+ if (t->NumTokens >= 2)
+ {
+ if (port != NULL)
+ {
+ *port = ToInt(t->Token[1]);
+ }
+ }
+ }
+
+ if (port != NULL)
+ {
+ if (*port == 0)
+ {
+ *port = default_port;
+ }
+ }
+
+ FreeToken(t);
+
+ return ret;
+}
+
+// Vpncmd command procedure
+UINT VpnCmdProc(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
+{
+ LIST *o;
+ char *target;
+ bool server = false;
+ bool client = false;
+ bool tools = false;
+ char *hostname = NULL;
+ char *password;
+ wchar_t *cmdline;
+ bool host_inputted = false;
+ UINT port = 0;
+ UINT retcode = 0;
+ PARAM args[] =
+ {
+ {"[host:port]", NULL, NULL, NULL, NULL},
+ {"CLIENT", NULL, NULL, NULL, NULL},
+ {"SERVER", NULL, NULL, NULL, NULL},
+ {"TOOLS", NULL, NULL, NULL, NULL},
+ {"HUB", NULL, NULL, NULL, NULL},
+ {"ADMINHUB", NULL, NULL, NULL, NULL},
+ {"PASSWORD", NULL, NULL, NULL, NULL},
+ {"IN", NULL, NULL, NULL, NULL},
+ {"OUT", NULL, NULL, NULL, NULL},
+ {"CMD", NULL, NULL, NULL, NULL},
+ {"CSV", NULL, NULL, NULL, NULL},
+ };
+
+#ifdef OS_WIN32
+ if (UniStrCmpi(str, L"/debug") == 0)
+ {
+ // Debug information write mode
+ Win32CmdDebug(false);
+ return 0;
+ }
+ if (UniStrCmpi(str, L"/debug_uac") == 0)
+ {
+ // Debug information write mode
+ Win32CmdDebug(true);
+ return 0;
+ }
+#endif // OS_WIN32
+
+ if (c->ConsoleType == CONSOLE_LOCAL)
+ {
+ // Initialize the execute path information
+ VpnCmdInitBootPath();
+ }
+
+ if(c->ConsoleType != CONSOLE_CSV)
+ {
+ CmdPrintAbout(c);
+ c->Write(c, L"");
+ }
+
+ o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0]));
+
+ if (o == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Specification of the mode of Tools or Server or Client
+ if ((GetParamStr(o, "CLIENT") == NULL && GetParamStr(o, "SERVER") == NULL && GetParamStr(o, "TOOLS") == NULL) ||
+ (GetParamStr(o, "CLIENT") != NULL && GetParamStr(o, "SERVER") != NULL && GetParamStr(o, "TOOLS") != NULL))
+ {
+ wchar_t *ret;
+ UINT code;
+ // The mode of Tools or Server or Client is not specified
+ c->Write(c, _UU("CMD_VPNCMD_CS_1"));
+
+ ret = c->ReadLine(c, _UU("CMD_VPNCMD_CS_2"), true);
+
+ code = UniToInt(ret);
+ Free(ret);
+
+ switch (code)
+ {
+ case 1:
+ // Server
+ server = true;
+ break;
+
+ case 2:
+ // Client
+ client = true;
+ break;
+
+ case 3:
+ // Tools
+ tools = true;
+ break;
+
+ default:
+ // Unspecified
+ FreeParamValueList(o);
+ return ERR_USER_CANCEL;
+ }
+
+ c->Write(c, L"");
+ }
+ else
+ {
+ if (GetParamStr(o, "SERVER") != NULL)
+ {
+ server = true;
+ }
+ else if (GetParamStr(o, "CLIENT") != NULL)
+ {
+ client = true;
+ }
+ else
+ {
+ tools = true;
+ }
+ }
+
+ // Destination host name
+ target = CopyStr(GetParamStr(o, "[host:port]"));
+
+ if (target == NULL && tools == false)
+ {
+ wchar_t *str;
+ // Input a host name
+ if (server)
+ {
+ c->Write(c, _UU("CMD_VPNCMD_HOST_1"));
+ }
+ else if (client)
+ {
+ c->Write(c, _UU("CMD_VPNCMD_HOST_2"));
+ }
+
+ str = c->ReadLine(c, _UU("CMD_VPNCMD_HOST_3"), true);
+ c->Write(c, L"");
+ target = CopyUniToStr(str);
+ Free(str);
+
+ if (target == NULL)
+ {
+ // Cancel
+ FreeParamValueList(o);
+ return ERR_USER_CANCEL;
+ }
+
+ if (IsEmptyStr(target))
+ {
+ Free(target);
+ target = CopyStr("localhost");
+ }
+ }
+ else
+ {
+ // User specifies a host name
+ host_inputted = true;
+ }
+
+ if (tools == false)
+ {
+ if (ParseHostPort(target, &hostname, &port, 443) == false)
+ {
+ c->Write(c, _UU("CMD_MSG_INVALID_HOSTNAME"));
+ Free(target);
+ FreeParamValueList(o);
+ return ERR_INVALID_PARAMETER;
+ }
+ }
+
+ // Password
+ password = GetParamStr(o, "PASSWORD");
+ if (password == NULL)
+ {
+ password = "";
+ }
+
+ // Command line
+ cmdline = GetParamUniStr(o, "CMD");
+
+ if (server)
+ {
+ // Process as the server
+ char *hub;
+ char *adminhub = NULL;
+
+ hub = CopyStr(GetParamStr(o, "HUB"));
+ adminhub = GetParamStr(o, "ADMINHUB");
+
+ // Decide the Virtual HUB to be specified in the Virtual HUB management mode
+ if (hub == NULL)
+ {
+ if (host_inputted == false)
+ {
+ wchar_t *s;
+ // If the user does not specify a host name on the command line,
+ // get also a Virtual HUB name by displaying the prompt
+ c->Write(c, _UU("CMD_VPNCMD_HUB_1"));
+
+ s = c->ReadLine(c, _UU("CMD_VPNCMD_HUB_2"), true);
+
+ hub = CopyUniToStr(s);
+ Free(s);
+ }
+ }
+
+ if (IsEmptyStr(hub))
+ {
+ Free(hub);
+ hub = NULL;
+ }
+ if (IsEmptyStr(adminhub))
+ {
+ adminhub = NULL;
+ }
+
+ retcode = PsConnect(c, hostname, port, hub, adminhub, cmdline, password);
+
+ Free(hub);
+ }
+ else if (client)
+ {
+ // Treated as a client
+ Trim(target);
+
+ retcode = PcConnect(c, target, cmdline, password);
+ }
+ else if (tools)
+ {
+ // Treated as a VPN Tools
+ retcode = PtConnect(c, cmdline);
+ }
+
+ Free(hostname);
+ Free(target);
+ FreeParamValueList(o);
+
+ return retcode;
+}
+
+// Entry point of vpncmd
+UINT CommandMain(wchar_t *command_line)
+{
+ UINT ret = 0;
+ wchar_t *infile, *outfile;
+ char *a_infile, *a_outfile;
+ wchar_t *csvmode;
+ CONSOLE *c;
+
+ // Validate arguments
+ if (command_line == NULL)
+ {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ // Look ahead only items of /in and /out
+ infile = ParseCommand(command_line, L"in");
+ outfile = ParseCommand(command_line, L"out");
+ if (UniIsEmptyStr(infile))
+ {
+ Free(infile);
+ infile = NULL;
+ }
+ if (UniIsEmptyStr(outfile))
+ {
+ Free(outfile);
+ outfile = NULL;
+ }
+
+ a_infile = CopyUniToStr(infile);
+ a_outfile = CopyUniToStr(outfile);
+
+ // Allocate the local console
+ c = NewLocalConsole(infile, outfile);
+ if (c != NULL)
+ {
+ // Definition of commands of vpncmd
+ CMD cmd[] =
+ {
+ {"vpncmd", VpnCmdProc},
+ };
+
+ // Read ahead to check the CSV mode
+ csvmode = ParseCommand(command_line, L"csv");
+ if(csvmode != NULL)
+ {
+ Free(csvmode);
+ c->ConsoleType = CONSOLE_CSV;
+ }
+
+ if (DispatchNextCmdEx(c, command_line, ">", cmd, sizeof(cmd) / sizeof(cmd[0]), NULL) == false)
+ {
+ ret = ERR_INVALID_PARAMETER;
+ }
+ else
+ {
+ ret = c->RetCode;
+ }
+
+ // Release the local console
+ c->Free(c);
+ }
+ else
+ {
+ Print("Error: Couldn't open local console.\n");
+ }
+
+ Free(a_infile);
+ Free(a_outfile);
+ Free(infile);
+ Free(outfile);
+
+ return ret;
+}
+
+#ifdef OS_WIN32
+// Debug information write mode
+void Win32CmdDebug(bool is_uac)
+{
+ wchar_t *dst;
+ wchar_t def_filename[MAX_SIZE];
+ SYSTEMTIME st;
+
+ InitWinUi(_UU("CMD_DEBUG_SOFTNAME"), NULL, 0);
+
+ UniPrint(_UU("CMD_DEBUG_PRINT"));
+
+ if (MsIsWin2000OrGreater() == false)
+ {
+ MsgBox(NULL, 0x00000040L, _UU("CMD_DEBUG_NOT_2000"));
+ goto LABEL_CLEANUP;
+ }
+
+ if ((MsIsVista() == false || is_uac) && MsIsAdmin() == false)
+ {
+ MsgBox(NULL, 0x00000040L, _UU("CMD_DEBUG_NOT_ADMIN"));
+ goto LABEL_CLEANUP;
+ }
+
+ if (MsIsVista() && MsIsAdmin() == false)
+ {
+ void *process_handle = NULL;
+
+ // Launch myself using the UAC
+ if (MsExecuteEx2W(MsGetExeFileNameW(), L"/debug_uac", &process_handle, true) == false)
+ {
+ MsgBox(NULL, 0x00000030L, _UU("CMD_DEBUG_UAC_FAILED"));
+ return;
+ }
+
+ MsCloseHandle(process_handle);
+ goto LABEL_CLEANUP;
+ }
+
+ LocalTime(&st);
+
+ UniFormat(def_filename, sizeof(def_filename), L"vpn_debuginfo_%04u%02u%02u_%02u%02u%02u.zip",
+ st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
+
+ // Specify the destination
+ dst = SaveDlg(NULL, _UU("DLG_ZIP_FILER"), _UU("CMD_DEBUG_SAVE_TITLE"), def_filename, L".zip");
+ if (dst != NULL)
+ {
+ if (MsSaveSystemInfo(dst) == false)
+ {
+ // Failure
+ MsgBoxEx(NULL, 0x00000030L, _UU("CMD_DEBUG_NG"), dst);
+ }
+ else
+ {
+ // Success
+ MsgBoxEx(NULL, 0x00000040L, _UU("CMD_DEBUG_OK"), dst);
+ }
+
+ Free(dst);
+ }
+
+LABEL_CLEANUP:
+ FreeWinUi();
+}
+
+#endif // OS_WIN32
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Command.h b/src/Cedar/Command.h
new file mode 100644
index 00000000..104b7869
--- /dev/null
+++ b/src/Cedar/Command.h
@@ -0,0 +1,648 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Command.h
+// Header of Command.c
+
+#ifndef COMMAND_H
+#define COMMAND_H
+
+// Constants
+#define TRAFFIC_DEFAULT_PORT 9821
+#define TRAFFIC_NUMTCP_MAX 32
+#define TRAFFIC_NUMTCP_DEFAULT 32
+#define TRAFFIC_SPAN_DEFAULT 15
+#define TRAFFIC_TYPE_DOWNLOAD 1
+#define TRAFFIC_TYPE_UPLOAD 2
+#define TRAFFIC_TYPE_FULL 0
+#define TRAFFIC_BUF_SIZE 65535
+#define TRAFFIC_VER_STR_SIZE 16
+#define TRAFFIC_VER_STR "TrafficServer\r\n"
+
+// Constants for Win32
+#define VPNCMD_BOOTSTRAP_REG_KEYNAME "Software\\" GC_REG_COMPANY_NAME "\\VPN Command Line Utility"
+#define VPNCMD_BOOTSTRAP_REG_VALUENAME_VER "InstalledVersion"
+#define VPNCMD_BOOTSTRAP_REG_VALUENAME_PATH "InstalledPath"
+#define VPNCMD_BOOTSTRAP_FILENAME "|vpncmdsys.exe"
+#define VPNCMD_BOOTSTRAP_FILENAME_X64 "|vpncmdsys_x64.exe"
+#define VPNCMD_BOOTSTRAP_FILENAME_IA64 "|vpncmdsys_ia64.exe"
+
+
+// Traffic test results
+struct TT_RESULT
+{
+ bool Raw; // Whether raw data
+ bool Double; // Whether it is doubled
+ UINT64 NumBytesUpload; // Uploaded size
+ UINT64 NumBytesDownload; // Downloaded size
+ UINT64 NumBytesTotal; // Total size
+ UINT64 Span; // Period (in milliseconds)
+ UINT64 BpsUpload; // Upload throughput
+ UINT64 BpsDownload; // Download throughput
+ UINT64 BpsTotal; // Total throughput
+};
+
+// Text display function
+typedef void (TT_PRINT_PROC)(void *param, wchar_t *str);
+
+// Client side socket
+struct TTC_SOCK
+{
+ SOCK *Sock; // Socket
+ UINT State; // State
+ UINT64 NumBytes; // Transmitted bytes
+ bool Download; // Download socket
+ bool ServerUploadReportReceived; // Complete to receive the report of upload amount from the server
+ UINT64 NextSendRequestReportTick; // Time to request a next report
+ UINT Id;
+ bool HideErrMsg;
+};
+
+// Traffic test Client
+struct TTC
+{
+ TT_PRINT_PROC *Print; // Text display function
+ void *Param; // Any parameters
+ bool Double; // Double mode
+ bool Raw; // Raw data mode
+ UINT Port; // Port number
+ char Host[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT NumTcp; // Number of TCP connections
+ UINT Type; // Type
+ UINT64 Span; // Period
+ UINT64 RealSpan; // The actual span
+ THREAD *Thread; // Thread
+ volatile bool Halt; // Halting flag
+ bool *Cancel; // Halting flag 2
+ SOCK_EVENT *SockEvent; // Socket event
+ LIST *ItcSockList; // Client socket list
+ TT_RESULT Result; // Result
+ UINT ErrorCode; // Error code
+ bool AbnormalTerminated; // Abnormal termination
+ EVENT *StartEvent; // Start event
+ EVENT *InitedEvent; // Initialize completion notification event
+};
+
+// Server side socket
+struct TTS_SOCK
+{
+ SOCK *Sock; // Socket
+ UINT State; // State
+ UINT64 NumBytes; // Transmitted bytes
+ bool SockJoined; // Whether it has been added to the event
+ UINT Id; // ID
+ UINT64 LastWaitTick; // Retry waiting time to notify the size information to the client
+ UINT64 SessionId; // Session ID
+ bool NoMoreSendData; // Flag not to send more data
+ UINT64 FirstRecvTick; // Time which the data has been received last
+ UINT64 Span; // Period
+};
+
+// Traffic test server
+struct TTS
+{
+ TT_PRINT_PROC *Print; // Text display function
+ void *Param; // Any parameters
+ volatile bool Halt; // Halting flag
+ UINT Port; // Port number
+ THREAD *Thread; // Thread
+ THREAD *WorkThread; // Worker thread
+ THREAD *IPv6AcceptThread; // IPv6 Accept thread
+ SOCK *ListenSocket; // Socket to wait
+ SOCK *ListenSocketV6; // Socket to wait (IPv6)
+ UINT ErrorCode; // Error code
+ SOCK_EVENT *SockEvent; // Socket event
+ LIST *TtsSockList; // Server socket list
+ bool NewSocketArrived; // New socket has arrived
+ UINT IdSeed; // ID value
+};
+
+// VPN Tools context
+struct PT
+{
+ CONSOLE *Console; // Console
+ UINT LastError; // Last error
+ wchar_t *CmdLine; // Command line to execute
+};
+
+// Server management context
+struct PS
+{
+ bool ConsoleForServer; // Console for the server (always true)
+ CONSOLE *Console; // Console
+ RPC *Rpc; // RPC
+ char *ServerName; // Server name
+ UINT ServerPort; // Port number
+ char *HubName; // Virtual HUB name in the currently managed
+ UINT LastError; // Last error
+ char *AdminHub; // Virtual HUB to be managed by default
+ wchar_t *CmdLine; // Command line to execute
+ CAPSLIST *CapsList; // Caps list
+};
+
+// Client management context
+struct PC
+{
+ bool ConsoleForServer; // Console for the server (always false)
+ CONSOLE *Console; // Console
+ REMOTE_CLIENT *RemoteClient; // Remote client
+ char *ServerName; // Server name
+ UINT LastError; // Last error
+ wchar_t *CmdLine; // Command line
+};
+
+// A column of the table
+struct CTC
+{
+ wchar_t *String; // String
+ bool Right; // Right justification
+};
+
+// A row of the table
+struct CTR
+{
+ wchar_t **Strings; // String list
+};
+
+// Table for console
+struct CT
+{
+ LIST *Columns; // Column list
+ LIST *Rows; // Row list
+};
+
+UINT CommandMain(wchar_t *command_line);
+UINT VpnCmdProc(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+bool ParseHostPort(char *src, char **host, UINT *port, UINT default_port);
+bool ParseHostPortAtmark(char *src, char **host, UINT *port, UINT default_port);
+CT *CtNew();
+void CtFree(CT *ct, CONSOLE *c);
+void CtFreeEx(CT *ct, CONSOLE *c, bool standard_view);
+void CtInsertColumn(CT *ct, wchar_t *str, bool right);
+CT *CtNewStandard();
+CT *CtNewStandardEx();
+void CtInsert(CT *ct, ...);
+void CtPrint(CT *ct, CONSOLE *c);
+void CtPrintStandard(CT *ct, CONSOLE *c);
+void CtPrintRow(CONSOLE *c, UINT num, UINT *widths, wchar_t **strings, bool *rights, char separate_char);
+void VpnCmdInitBootPath();
+void OutRpcTtResult(PACK *p, TT_RESULT *t);
+void InRpcTtResult(PACK *p, TT_RESULT *t);
+
+void CmdPrintError(CONSOLE *c, UINT err);
+void CmdPrintAbout(CONSOLE *c);
+void CmdPrintRow(CONSOLE *c, wchar_t *title, wchar_t *tag, ...);
+wchar_t *CmdPromptPort(CONSOLE *c, void *param);
+wchar_t *CmdPromptChoosePassword(CONSOLE *c, void *param);
+bool CmdEvalPort(CONSOLE *c, wchar_t *str, void *param);
+void CmdInsertTrafficInfo(CT *ct, TRAFFIC *t);
+wchar_t *GetHubTypeStr(UINT type);
+wchar_t *GetServerTypeStr(UINT type);
+char *CmdPasswordPrompt(CONSOLE *c);
+bool CmdEvalIp(CONSOLE *c, wchar_t *str, void *param);
+wchar_t *PsClusterSettingMemberPromptIp(CONSOLE *c, void *param);
+bool CmdEvalHostAndPort(CONSOLE *c, wchar_t *str, void *param);
+LIST *StrToPortList(char *str);
+bool CmdEvalPortList(CONSOLE *c, wchar_t *str, void *param);
+wchar_t *PsClusterSettingMemberPromptPorts(CONSOLE *c, void *param);
+K *CmdLoadKey(CONSOLE *c, wchar_t *filename);
+bool CmdLoadCertAndKey(CONSOLE *c, X **xx, K **kk, wchar_t *cert_filename, wchar_t *key_filename);
+bool CmdEvalTcpOrUdp(CONSOLE *c, wchar_t *str, void *param);
+wchar_t *GetConnectionTypeStr(UINT type);
+bool CmdEvalHostAndSubnetMask4(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalNetworkAndSubnetMask4(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalNetworkAndSubnetMask6(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalNetworkAndSubnetMask46(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalIpAndMask4(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalIpAndMask6(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalIpAndMask46(CONSOLE *c, wchar_t *str, void *param);
+wchar_t *GetLogSwitchStr(UINT i);
+wchar_t *GetPacketLogNameStr(UINT i);
+UINT StrToLogSwitchType(char *str);
+UINT StrToPacketLogType(char *str);
+UINT StrToPacketLogSaveInfoType(char *str);
+wchar_t *GetProxyTypeStr(UINT i);
+wchar_t *GetClientAuthTypeStr(UINT i);
+void PrintPolicyList(CONSOLE *c, char *name);
+void PrintPolicy(CONSOLE *c, POLICY *pol, bool cascade_mode);
+bool EditPolicy(CONSOLE *c, POLICY *pol, char *name, char *value, bool cascade_mode);
+void CmdPrintStatusToListView(CT *ct, RPC_CLIENT_GET_CONNECTION_STATUS *s);
+void CmdPrintStatusToListViewEx(CT *ct, RPC_CLIENT_GET_CONNECTION_STATUS *s, bool server_mode);
+bool CmdEvalPassOrDiscard(CONSOLE *c, wchar_t *str, void *param);
+bool StrToPassOrDiscard(char *str);
+bool CmdEvalProtocol(CONSOLE *c, wchar_t *str, void *param);
+UINT StrToProtocol(char *str);
+bool CmdEvalPortRange(CONSOLE *c, wchar_t *str, void *param);
+bool ParsePortRange(char *str, UINT *start, UINT *end);
+wchar_t *GetAuthTypeStr(UINT id);
+UINT64 StrToDateTime64(char *str);
+bool CmdEvalDateTime(CONSOLE *c, wchar_t *str, void *param);
+void CmdPrintNodeInfo(CT *ct, NODE_INFO *info);
+wchar_t *GetProtocolName(UINT n);
+void CmdGenerateImportName(REMOTE_CLIENT *r, wchar_t *name, UINT size, wchar_t *old_name);
+bool CmdIsAccountName(REMOTE_CLIENT *r, wchar_t *name);
+wchar_t *GetSyslogSettingName(UINT n);
+
+
+void TtPrint(void *param, TT_PRINT_PROC *print_proc, wchar_t *str);
+void TtGenerateRandomData(UCHAR **buf, UINT *size);
+void TtsWorkerThread(THREAD *thread, void *param);
+void TtsListenThread(THREAD *thread, void *param);
+void TtsAcceptProc(TTS *tts, SOCK *listen_socket);
+void TtsIPv6AcceptThread(THREAD *thread, void *param);
+wchar_t *GetTtcTypeStr(UINT type);
+void TtcPrintSummary(TTC *ttc);
+void StopTtc(TTC *ttc);
+void TtcGenerateResult(TTC *ttc);
+void TtcThread(THREAD *thread, void *param);
+TTC *NewTtcEx(char *host, UINT port, UINT numtcp, UINT type, UINT64 span, bool dbl, bool raw, TT_PRINT_PROC *print_proc, void *param, EVENT *start_event, bool *cancel);
+TTC *NewTtc(char *host, UINT port, UINT numtcp, UINT type, UINT64 span, bool dbl, bool raw, TT_PRINT_PROC *print_proc, void *param);
+UINT FreeTtc(TTC *ttc, TT_RESULT *result);
+TTS *NewTts(UINT port, void *param, TT_PRINT_PROC *print_proc);
+UINT FreeTts(TTS *tts);
+void PtTrafficPrintProc(void *param, wchar_t *str);
+void TtcPrintResult(CONSOLE *c, TT_RESULT *res);
+
+
+bool SystemCheck();
+bool CheckKernel();
+bool CheckMemory();
+bool CheckStrings();
+bool CheckFileSystem();
+bool CheckThread();
+bool CheckNetwork();
+void InputToNull(void *p);
+UINT RetZero();
+
+void Win32CmdDebug(bool is_uac);
+
+
+UINT PtConnect(CONSOLE *c, wchar_t *cmdline);
+PT *NewPt(CONSOLE *c, wchar_t *cmdline);
+void FreePt(PT *pt);
+void PtMain(PT *pt);
+UINT PtMakeCert(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PtTrafficClient(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PtTrafficServer(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PtCheck(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+
+
+UINT PcConnect(CONSOLE *c, char *target, wchar_t *cmdline, char *password);
+PC *NewPc(CONSOLE *c, REMOTE_CLIENT *remote_client, char *servername, wchar_t *cmdline);
+void FreePc(PC *pc);
+void PcMain(PC *pc);
+UINT PcAbout(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcVersionGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcPasswordGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcCertList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcCertAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcCertDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcSecureList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcSecureSelect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcSecureGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicUpgrade(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicGetSetting(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicSetSetting(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcNicList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountUsernameSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountAnonymousSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountEncryptDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountEncryptEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountCompressEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountCompressDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountProxyNone(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountProxyHttp(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountProxySocks(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountServerCertEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountServerCertDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountServerCertDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountServerCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountDetailSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountRename(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountConnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountDisconnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountNicSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountStatusShow(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountStatusHide(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountSecureCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountRetrySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountStartupSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountStartupRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountExport(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcAccountImport(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcRemoteEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcRemoteDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcKeepEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcKeepDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcKeepSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PcKeepGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+
+
+PS *NewPs(CONSOLE *c, RPC *rpc, char *servername, UINT serverport, char *hubname, char *adminhub, wchar_t *cmdline);
+void FreePs(PS *ps);
+UINT PsConnect(CONSOLE *c, char *host, UINT port, char *hub, char *adminhub, wchar_t *cmdline, char *password);
+void PsMain(PS *ps);
+UINT PsAbout(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerInfoGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsListenerCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsListenerDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsListenerList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsListenerEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsListenerDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterSettingGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterSettingStandalone(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterSettingController(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterSettingMember(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterMemberList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterMemberInfoGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterMemberCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsClusterConnectionStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCrash(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsFlush(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDebug(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerKeyGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerCipherGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerCipherSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsKeepEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsKeepDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsKeepSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsKeepGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSyslogGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSyslogDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSyslogEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsConnectionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsConnectionGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsConnectionDisconnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsBridgeDeviceList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsBridgeList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsBridgeCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsBridgeDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCaps(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsReboot(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsConfigGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsConfigSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterStart(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterStop(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterIfList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterIfAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterIfDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterTableList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterTableAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRouterTableDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogFileList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogFileGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubCreateDynamic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubCreateStatic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubSetStatic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubSetDynamic(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHubList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsHub(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsOnline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsOffline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSetMaxSession(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSetHubPassword(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSetEnumAllow(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSetEnumDeny(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsOptionsGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRadiusServerSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRadiusServerDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsRadiusServerGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogSwitchSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLogPacketSaveType(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCAList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCAAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCADelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCAGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeUsernameSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeAnonymousSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadePasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeEncryptEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeEncryptDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeCompressEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeCompressDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeProxyNone(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeProxyHttp(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeProxySocks(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeServerCertEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeServerCertDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeServerCertDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeServerCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeDetailSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadePolicyRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadePolicySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsPolicyList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeRename(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeOnline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCascadeOffline(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessAddEx(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessAdd6(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessAddEx6(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAccessDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserAnonymousSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserPasswordSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserSignedSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserRadiusSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserNTLMSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserPolicyRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserPolicySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsUserExpiresSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupCreate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupJoin(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupUnjoin(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupPolicyRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsGroupPolicySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSessionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSessionGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSessionDisconnect(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsMacTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsMacDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsIpTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsIpDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSecureNatEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSecureNatDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSecureNatStatusGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSecureNatHostGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSecureNatHostSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsNatGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsNatEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsNatDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsNatSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsNatTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDhcpGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDhcpEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDhcpDisable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDhcpSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDhcpTable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAdminOptionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAdminOptionSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsExtOptionList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsExtOptionSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCrlList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCrlAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCrlDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsCrlGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAcList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAcAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAcAdd6(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAcGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsAcDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLicenseAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLicenseDel(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLicenseList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsLicenseStatus(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsIPsecEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsIPsecGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsEtherIpClientAdd(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsEtherIpClientDelete(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsEtherIpClientList(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsOpenVpnEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsOpenVpnGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsOpenVpnMakeConfig(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSstpEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsSstpGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsServerCertRegenerate(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsVpnOverIcmpDnsEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsVpnOverIcmpDnsGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDynamicDnsGetStatus(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsDynamicDnsSetHostname(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsVpnAzureSetEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+UINT PsVpnAzureGetStatus(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+
+
+#endif // COMMAND_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Connection.c b/src/Cedar/Connection.c
new file mode 100644
index 00000000..5cc0296c
--- /dev/null
+++ b/src/Cedar/Connection.c
@@ -0,0 +1,3457 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Connection.c
+// Connection Manager
+
+#include "CedarPch.h"
+
+// Determine whether the socket is to use to send
+#define IS_SEND_TCP_SOCK(ts) \
+ ((ts->Direction == TCP_BOTH) || ((ts->Direction == TCP_SERVER_TO_CLIENT) && (s->ServerMode)) || ((ts->Direction == TCP_CLIENT_TO_SERVER) && (s->ServerMode == false)))
+
+// Determine whether the socket is to use to receive
+#define IS_RECV_TCP_SOCK(ts) \
+ ((ts->Direction == TCP_BOTH) || ((ts->Direction == TCP_SERVER_TO_CLIENT) && (s->ServerMode == false)) || ((ts->Direction == TCP_CLIENT_TO_SERVER) && (s->ServerMode)))
+
+// Conversion of SECURE_SIGN
+void InRpcSecureSign(SECURE_SIGN *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(SECURE_SIGN));
+ PackGetStr(p, "SecurePublicCertName", t->SecurePublicCertName, sizeof(t->SecurePublicCertName));
+ PackGetStr(p, "SecurePrivateKeyName", t->SecurePrivateKeyName, sizeof(t->SecurePrivateKeyName));
+ t->ClientCert = PackGetX(p, "ClientCert");
+ PackGetData2(p, "Random", t->Random, sizeof(t->Random));
+ PackGetData2(p, "Signature", t->Signature, sizeof(t->Signature));
+ t->UseSecureDeviceId = PackGetInt(p, "UseSecureDeviceId");
+ t->BitmapId = PackGetInt(p, "BitmapId");
+}
+void OutRpcSecureSign(PACK *p, SECURE_SIGN *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "SecurePublicCertName", t->SecurePublicCertName);
+ PackAddStr(p, "SecurePrivateKeyName", t->SecurePrivateKeyName);
+ PackAddX(p, "ClientCert", t->ClientCert);
+ PackAddData(p, "Random", t->Random, sizeof(t->Random));
+ PackAddData(p, "Signature", t->Signature, sizeof(t->Signature));
+ PackAddInt(p, "UseSecureDeviceId", t->UseSecureDeviceId);
+ PackAddInt(p, "BitmapId", t->BitmapId);
+}
+void FreeRpcSecureSign(SECURE_SIGN *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FreeX(t->ClientCert);
+}
+
+// Generate the next packet
+BUF *NewKeepPacket(bool server_mode)
+{
+ BUF *b = NewBuf();
+ char *string = KEEP_ALIVE_STRING;
+
+ WriteBuf(b, string, StrLen(string));
+
+ SeekBuf(b, 0, 0);
+
+ return b;
+}
+
+// KEEP thread
+void KeepThread(THREAD *thread, void *param)
+{
+ KEEP *k = (KEEP *)param;
+ SOCK *s;
+ char server_name[MAX_HOST_NAME_LEN + 1];
+ UINT server_port;
+ bool udp_mode;
+ bool enabled;
+ // Validate arguments
+ if (thread == NULL || k == NULL)
+ {
+ return;
+ }
+
+WAIT_FOR_ENABLE:
+ Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);
+
+ // Wait until it becomes enabled
+ while (true)
+ {
+ enabled = false;
+ Lock(k->lock);
+ {
+ if (k->Enable)
+ {
+ if (StrLen(k->ServerName) != 0 && k->ServerPort != 0 && k->Interval != 0)
+ {
+ StrCpy(server_name, sizeof(server_name), k->ServerName);
+ server_port = k->ServerPort;
+ udp_mode = k->UdpMode;
+ enabled = true;
+ }
+ }
+ }
+ Unlock(k->lock);
+ if (enabled)
+ {
+ break;
+ }
+ if (k->Halt)
+ {
+ return;
+ }
+ Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);
+ }
+
+ if (udp_mode == false)
+ {
+ // TCP mode
+ // Try until a success to connection
+ while (true)
+ {
+ UINT64 connect_started_tick;
+ bool changed = false;
+ Lock(k->lock);
+ {
+ if (StrCmpi(k->ServerName, server_name) != 0 ||
+ k->ServerPort != server_port || k->Enable == false ||
+ k->UdpMode)
+ {
+ changed = true;
+ }
+ }
+ Unlock(k->lock);
+ if (changed)
+ {
+ // Settings are changed
+ goto WAIT_FOR_ENABLE;
+ }
+
+ if (k->Halt)
+ {
+ // Stop
+ return;
+ }
+
+ // Attempt to connect to the server
+ connect_started_tick = Tick64();
+ s = ConnectEx2(server_name, server_port, KEEP_TCP_TIMEOUT, (bool *)&k->Halt);
+ if (s != NULL)
+ {
+ // Successful connection
+ break;
+ }
+
+ // Connection failure: Wait until timeout or the setting is changed
+ while (true)
+ {
+ changed = false;
+ if (k->Halt)
+ {
+ // Stop
+ return;
+ }
+ Lock(k->lock);
+ {
+ if (StrCmpi(k->ServerName, server_name) != 0 ||
+ k->ServerPort != server_port || k->Enable == false ||
+ k->UdpMode)
+ {
+ changed = true;
+ }
+ }
+ Unlock(k->lock);
+
+ if (changed)
+ {
+ // Settings are changed
+ goto WAIT_FOR_ENABLE;
+ }
+
+ if ((Tick64() - connect_started_tick) >= KEEP_RETRY_INTERVAL)
+ {
+ break;
+ }
+
+ Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);
+ }
+ }
+
+ // Success to connect the server
+ // Send and receive packet data periodically
+ if (s != NULL)
+ {
+ UINT64 last_packet_sent_time = 0;
+ while (true)
+ {
+ SOCKSET set;
+ UINT ret;
+ UCHAR buf[MAX_SIZE];
+ bool changed;
+
+ InitSockSet(&set);
+ AddSockSet(&set, s);
+
+ Select(&set, KEEP_POLLING_INTERVAL, k->Cancel, NULL);
+
+ ret = Recv(s, buf, sizeof(buf), false);
+ if (ret == 0)
+ {
+ // Disconnected
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ }
+
+ if (s != NULL)
+ {
+ if ((Tick64() - last_packet_sent_time) >= (UINT64)k->Interval)
+ {
+ BUF *b;
+
+ // Send the next packet
+ last_packet_sent_time = Tick64();
+
+ b = NewKeepPacket(k->Server);
+
+ ret = Send(s, b->Buf, b->Size, false);
+ FreeBuf(b);
+
+ if (ret == 0)
+ {
+ // Disconnected
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ }
+ }
+ }
+
+ changed = false;
+
+ Lock(k->lock);
+ {
+ if (StrCmpi(k->ServerName, server_name) != 0 ||
+ k->ServerPort != server_port || k->Enable == false ||
+ k->UdpMode)
+ {
+ changed = true;
+ }
+ }
+ Unlock(k->lock);
+
+ if (changed || s == NULL)
+ {
+ // Setting has been changed or disconnected
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ goto WAIT_FOR_ENABLE;
+ }
+ else
+ {
+ if (k->Halt)
+ {
+ // Stop
+ Disconnect(s);
+ ReleaseSock(s);
+ return;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ IP dest_ip;
+ // UDP mode
+ // Try to create socket until it successes
+ while (true)
+ {
+ UINT64 connect_started_tick;
+ bool changed = false;
+ Lock(k->lock);
+ {
+ if (StrCmpi(k->ServerName, server_name) != 0 ||
+ k->ServerPort != server_port || k->Enable == false ||
+ k->UdpMode == false)
+ {
+ changed = true;
+ }
+ }
+ Unlock(k->lock);
+ if (changed)
+ {
+ // Settings are changed
+ goto WAIT_FOR_ENABLE;
+ }
+
+ if (k->Halt)
+ {
+ // Stop
+ return;
+ }
+
+ // Attempt to create a socket
+ connect_started_tick = Tick64();
+
+ // Attempt to resolve the name first
+ if (GetIP(&dest_ip, server_name))
+ {
+ // After successful name resolution, create a socket
+ s = NewUDP(0);
+ if (s != NULL)
+ {
+ // Creating success
+ break;
+ }
+ }
+
+ // Failure to create: wait until timeout or the setting is changed
+ while (true)
+ {
+ changed = false;
+ if (k->Halt)
+ {
+ // Stop
+ return;
+ }
+ Lock(k->lock);
+ {
+ if (StrCmpi(k->ServerName, server_name) != 0 ||
+ k->ServerPort != server_port || k->Enable == false ||
+ k->UdpMode)
+ {
+ changed = true;
+ }
+ }
+ Unlock(k->lock);
+
+ if (changed)
+ {
+ // Settings are changed
+ goto WAIT_FOR_ENABLE;
+ }
+
+ if ((Tick64() - connect_started_tick) >= KEEP_RETRY_INTERVAL)
+ {
+ break;
+ }
+
+ Wait(k->HaltEvent, KEEP_POLLING_INTERVAL);
+ }
+ }
+
+ // Send the packet data periodically
+ if (s != NULL)
+ {
+ UINT64 last_packet_sent_time = 0;
+ UINT num_ignore_errors = 0;
+ while (true)
+ {
+ SOCKSET set;
+ UINT ret;
+ UCHAR buf[MAX_SIZE];
+ bool changed;
+ IP src_ip;
+ UINT src_port;
+
+ InitSockSet(&set);
+ AddSockSet(&set, s);
+
+ Select(&set, KEEP_POLLING_INTERVAL, k->Cancel, NULL);
+
+ // Receive
+ ret = RecvFrom(s, &src_ip, &src_port, buf, sizeof(buf));
+ if (ret == 0)
+ {
+ if (s->IgnoreRecvErr == false)
+ {
+LABEL_DISCONNECTED:
+ // Disconnected
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ }
+ else
+ {
+ if ((num_ignore_errors++) >= MAX_NUM_IGNORE_ERRORS)
+ {
+ goto LABEL_DISCONNECTED;
+ }
+ }
+ }
+
+ if (s != NULL)
+ {
+ if ((Tick64() - last_packet_sent_time) >= (UINT64)k->Interval)
+ {
+ BUF *b;
+
+ // Send the next packet
+ last_packet_sent_time = Tick64();
+
+ b = NewKeepPacket(k->Server);
+
+ ret = SendTo(s, &dest_ip, server_port, b->Buf, b->Size);
+ FreeBuf(b);
+
+ if (ret == 0 && s->IgnoreSendErr == false)
+ {
+ // Disconnected
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ }
+ }
+ }
+
+ changed = false;
+
+ Lock(k->lock);
+ {
+ if (StrCmpi(k->ServerName, server_name) != 0 ||
+ k->ServerPort != server_port || k->Enable == false ||
+ k->UdpMode == false)
+ {
+ changed = true;
+ }
+ }
+ Unlock(k->lock);
+
+ if (changed || s == NULL)
+ {
+ // Setting has been changed or disconnected
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ goto WAIT_FOR_ENABLE;
+ }
+ else
+ {
+ if (k->Halt)
+ {
+ // Stop
+ Disconnect(s);
+ ReleaseSock(s);
+ return;
+ }
+ }
+ }
+ }
+ }
+}
+
+// Stop the KEEP
+void StopKeep(KEEP *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ k->Halt = true;
+ Set(k->HaltEvent);
+ Cancel(k->Cancel);
+
+ WaitThread(k->Thread, INFINITE);
+ ReleaseThread(k->Thread);
+ DeleteLock(k->lock);
+
+ ReleaseCancel(k->Cancel);
+ ReleaseEvent(k->HaltEvent);
+
+ Free(k);
+}
+
+// Start the KEEP
+KEEP *StartKeep()
+{
+ KEEP *k = ZeroMalloc(sizeof(KEEP));
+
+ k->lock = NewLock();
+ k->HaltEvent = NewEvent();
+ k->Cancel = NewCancel();
+
+ // Thread start
+ k->Thread = NewThread(KeepThread, k);
+
+ return k;
+}
+
+// Copy the client authentication data
+CLIENT_AUTH *CopyClientAuth(CLIENT_AUTH *a)
+{
+ CLIENT_AUTH *ret;
+ // Validate arguments
+ if (a == NULL)
+ {
+ return NULL;
+ }
+
+ ret = ZeroMallocEx(sizeof(CLIENT_AUTH), true);
+
+ ret->AuthType = a->AuthType;
+ StrCpy(ret->Username, sizeof(ret->Username), a->Username);
+
+ switch (a->AuthType)
+ {
+ case CLIENT_AUTHTYPE_ANONYMOUS:
+ // Anonymous authentication
+ break;
+
+ case CLIENT_AUTHTYPE_PASSWORD:
+ // Password authentication
+ Copy(ret->HashedPassword, a->HashedPassword, SHA1_SIZE);
+ break;
+
+ case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+ // Plaintext password authentication
+ StrCpy(ret->PlainPassword, sizeof(ret->PlainPassword), a->PlainPassword);
+ break;
+
+ case CLIENT_AUTHTYPE_CERT:
+ // Certificate authentication
+ ret->ClientX = CloneX(a->ClientX);
+ ret->ClientK = CloneK(a->ClientK);
+ break;
+
+ case CLIENT_AUTHTYPE_SECURE:
+ // Secure device authentication
+ StrCpy(ret->SecurePublicCertName, sizeof(ret->SecurePublicCertName), a->SecurePublicCertName);
+ StrCpy(ret->SecurePrivateKeyName, sizeof(ret->SecurePrivateKeyName), a->SecurePrivateKeyName);
+ break;
+ }
+
+ return ret;
+}
+
+// Write data to the transmit FIFO (automatic encryption)
+void WriteSendFifo(SESSION *s, TCPSOCK *ts, void *data, UINT size)
+{
+ // Validate arguments
+ if (s == NULL || ts == NULL || data == NULL)
+ {
+ return;
+ }
+
+ if (s->UseFastRC4)
+ {
+ Encrypt(ts->SendKey, data, data, size);
+ }
+
+ WriteFifo(ts->SendFifo, data, size);
+}
+
+// Write data to the reception FIFO (automatic deccyption)
+void WriteRecvFifo(SESSION *s, TCPSOCK *ts, void *data, UINT size)
+{
+ // Validate arguments
+ if (s == NULL || ts == NULL || data == NULL)
+ {
+ return;
+ }
+
+ if (s->UseFastRC4)
+ {
+ Encrypt(ts->RecvKey, data, data, size);
+ }
+
+ WriteFifo(ts->RecvFifo, data, size);
+}
+
+// TCP socket receive
+UINT TcpSockRecv(SESSION *s, TCPSOCK *ts, void *data, UINT size)
+{
+ // Receive
+ return Recv(ts->Sock, data, size, s->UseSSLDataEncryption);
+}
+
+// TCP socket send
+UINT TcpSockSend(SESSION *s, TCPSOCK *ts, void *data, UINT size)
+{
+ // Transmission
+ return Send(ts->Sock, data, size, s->UseSSLDataEncryption);
+}
+
+// Send the data as UDP packet
+void SendDataWithUDP(SOCK *s, CONNECTION *c)
+{
+ UCHAR *buf;
+ BUF *b;
+ UINT64 dummy_64 = 0;
+ UCHAR dummy_buf[16];
+ UINT64 now = Tick64();
+ UINT ret;
+ bool force_flag = false;
+ bool packet_sent = false;
+ // Validate arguments
+ if (s == NULL || c == NULL)
+ {
+ return;
+ }
+
+ // Allocate the temporary buffer in heap
+ if (c->RecvBuf == NULL)
+ {
+ c->RecvBuf = Malloc(RECV_BUF_SIZE);
+ }
+ buf = c->RecvBuf;
+
+ if (c->Udp->NextKeepAliveTime == 0 || c->Udp->NextKeepAliveTime <= now)
+ {
+ force_flag = true;
+ }
+
+ // Creating a buffer
+ while ((c->SendBlocks->num_item > 0) || force_flag)
+ {
+ UINT *key32;
+ UINT64 *seq;
+ char *sign;
+
+ force_flag = false;
+
+ // Assemble a buffer from the current queue
+ b = NewBuf();
+
+ // Keep an area for packet header (16 bytes)
+ WriteBuf(b, dummy_buf, sizeof(dummy_buf));
+
+ // Pack the packets in transmission queue
+ LockQueue(c->SendBlocks);
+ {
+ while (true)
+ {
+ BLOCK *block;
+
+ if (b->Size > UDP_BUF_SIZE)
+ {
+ break;
+ }
+ block = GetNext(c->SendBlocks);
+ if (block == NULL)
+ {
+ break;
+ }
+
+ if (block->Size != 0)
+ {
+ WriteBufInt(b, block->Size);
+ WriteBuf(b, block->Buf, block->Size);
+
+ c->Session->TotalSendSize += (UINT64)block->SizeofData;
+ c->Session->TotalSendSizeReal += (UINT64)block->Size;
+ }
+
+ FreeBlock(block);
+ break;
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+
+ // Write sequence number and session key
+ sign = (char *)(((UCHAR *)b->Buf));
+ key32 = (UINT *)(((UCHAR *)b->Buf + 4));
+ seq = (UINT64 *)(((UCHAR *)b->Buf + 8));
+ Copy(sign, SE_UDP_SIGN, 4);
+ *key32 = Endian32(c->Session->SessionKey32);
+ *seq = Endian64(c->Udp->Seq++); // Increment the sequence number
+
+// InsertQueue(c->Udp->BufferQueue, b);
+
+ packet_sent = true;
+/* }
+
+ // Send a buffer
+ while (c->Udp->BufferQueue->num_item != 0)
+ {
+ FIFO *f = c->Udp->BufferQueue->fifo;
+ BUF **pb = (BUF**)(((UCHAR *)f->p) + f->pos);
+ BUF *b = *pb;
+
+*/ ret = SendTo(s, &c->Udp->ip, c->Udp->port, b->Buf, b->Size);
+ if (ret == SOCK_LATER)
+ {
+ // Blocking
+ Debug(".");
+// break;
+ }
+ if (ret != b->Size)
+ {
+ if (s->IgnoreSendErr == false)
+ {
+ // Error
+ Debug("******* SendTo Error !!!\n");
+ }
+ }
+
+ // Memory release
+ FreeBuf(b);
+// GetNext(c->Udp->BufferQueue);
+ }
+
+ if (packet_sent)
+ {
+ // KeepAlive time update
+ c->Udp->NextKeepAliveTime = now + (UINT64)GenNextKeepAliveSpan(c);
+ }
+}
+
+// Write the data of the UDP packet to the connection
+void PutUDPPacketData(CONNECTION *c, void *data, UINT size)
+{
+ BUF *b;
+ char sign[4];
+ // Validate arguments
+ if (c == NULL || data == NULL)
+ {
+ return;
+ }
+
+ // Examine the protocol
+ if (c->Protocol != CONNECTION_UDP)
+ {
+ // UDP protocol is not used
+ return;
+ }
+
+ // Buffer configuration
+ b = NewBuf();
+ WriteBuf(b, data, size);
+
+ SeekBuf(b, 0, 0);
+ ReadBuf(b, sign, 4);
+
+ // Signature confirmation
+ if (Cmp(sign, SE_UDP_SIGN, 4) == 0)
+ {
+ UINT key32;
+
+ // Session key number
+ key32 = ReadBufInt(b);
+
+ if (c->Session->SessionKey32 == key32)
+ {
+ UINT64 seq;
+
+ // Read the Sequence number
+ ReadBuf(b, &seq, sizeof(seq));
+ seq = Endian64(seq);
+
+ if ((UINT)(seq - c->Udp->RecvSeq - (UINT64)1))
+ {
+ //Debug("** UDP Seq Lost %u\n", (UINT)(seq - c->Udp->RecvSeq - (UINT64)1));
+ }
+ c->Udp->RecvSeq = seq;
+
+ //Debug("SEQ: %I32u\n", seq);
+
+ while (true)
+ {
+ UINT size;
+
+ size = ReadBufInt(b);
+ if (size == 0)
+ {
+ break;
+ }
+ else if (size <= MAX_PACKET_SIZE)
+ {
+ void *tmp;
+ BLOCK *block;
+
+ tmp = Malloc(size);
+ if (ReadBuf(b, tmp, size) != size)
+ {
+ Free(tmp);
+ break;
+ }
+
+ // Block configuration
+ block = NewBlock(tmp, size, 0);
+
+ // Insert Block
+ InsertReveicedBlockToQueue(c, block);
+ }
+ }
+
+ // Update the last communication time
+ c->Session->LastCommTime = Tick64();
+ }
+ else
+ {
+ Debug("Invalid SessionKey: 0x%X\n", key32);
+ }
+ }
+
+ FreeBuf(b);
+}
+
+// Add a block to the receive queue
+void InsertReveicedBlockToQueue(CONNECTION *c, BLOCK *block)
+{
+ SESSION *s;
+ // Validate arguments
+ if (c == NULL || block == NULL)
+ {
+ return;
+ }
+
+ s = c->Session;
+
+ if (c->Protocol == CONNECTION_TCP)
+ {
+ s->TotalRecvSizeReal += block->SizeofData;
+ s->TotalRecvSize += block->Size;
+ }
+
+ LockQueue(c->ReceivedBlocks);
+ {
+ InsertQueue(c->ReceivedBlocks, block);
+ }
+ UnlockQueue(c->ReceivedBlocks);
+}
+
+// Generate the interval to the next Keep-Alive packet
+// (This should be a random number for the network load reduction)
+UINT GenNextKeepAliveSpan(CONNECTION *c)
+{
+ UINT a, b;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return INFINITE;
+ }
+
+ a = c->Session->Timeout;
+ b = rand() % (a / 2);
+ b = MAX(b, a / 5);
+
+ return b;
+}
+
+// send a Keep-Alive packet
+void SendKeepAlive(CONNECTION *c, TCPSOCK *ts)
+{
+ UINT size, i, num;
+ UINT size_be;
+ SESSION *s;
+ UCHAR *buf;
+ bool insert_natt_port = false;
+ // Validate arguments
+ if (c == NULL || ts == NULL)
+ {
+ return;
+ }
+
+ s = c->Session;
+
+ size = rand() % MAX_KEEPALIVE_SIZE;
+ num = KEEP_ALIVE_MAGIC;
+
+ if (s != NULL && s->UseUdpAcceleration && s->UdpAccel != NULL)
+ {
+ if (s->UdpAccel->MyPortByNatTServer != 0)
+ {
+ size = MAX(size, (StrLen(UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE) + sizeof(USHORT)));
+
+ insert_natt_port = true;
+ }
+ }
+
+ buf = MallocFast(size);
+
+ for (i = 0;i < size;i++)
+ {
+ buf[i] = rand();
+ }
+
+ if (insert_natt_port)
+ {
+ USHORT myport = Endian16((USHORT)s->UdpAccel->MyPortByNatTServer);
+
+ Copy(buf, UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE, StrLen(UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE));
+ Copy(buf + StrLen(UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE), &myport, sizeof(USHORT));
+ }
+
+ num = Endian32(num);
+ size_be = Endian32(size);
+ WriteSendFifo(c->Session, ts, &num, sizeof(UINT));
+ WriteSendFifo(c->Session, ts, &size_be, sizeof(UINT));
+ WriteSendFifo(c->Session, ts, buf, size);
+
+ c->Session->TotalSendSize += sizeof(UINT) * 2 + size;
+ c->Session->TotalSendSizeReal += sizeof(UINT) * 2 + size;
+
+ Free(buf);
+}
+
+// Transmission of block
+void ConnectionSend(CONNECTION *c)
+{
+ UINT i, num;
+ UINT64 now;
+ UINT min_count;
+ UINT64 max_recv_tick;
+ TCPSOCK **tcpsocks;
+ UINT size;
+ SESSION *s;
+ HUB *hub = NULL;
+ bool use_qos;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ s = c->Session;
+ use_qos = s->QoS;
+
+ if (s != NULL)
+ {
+ hub = s->Hub;
+ }
+
+ now = Tick64();
+
+ // Protocol
+ if (c->Protocol == CONNECTION_TCP)
+ {
+ // TCP
+ TCP *tcp = c->Tcp;
+ TCPSOCK *ts;
+ TCPSOCK *ts_hp;
+ UINT num_available;
+ bool is_rudp = false;
+ LockList(tcp->TcpSockList);
+ {
+ num = LIST_NUM(tcp->TcpSockList);
+ tcpsocks = ToArrayEx(tcp->TcpSockList, true);
+ }
+ UnlockList(tcp->TcpSockList);
+
+ if (s != NULL)
+ {
+ is_rudp = s->IsRUDPSession;
+ }
+
+ // Select the socket that will be used to send
+ // Select a socket which have least delay count
+ min_count = INFINITE;
+ max_recv_tick = 0;
+ ts = NULL;
+ ts_hp = NULL;
+
+ num_available = 0;
+
+ if (c->IsInProc == false)
+ {
+ for (i = 0;i < num;i++)
+ {
+ TCPSOCK *tcpsock = tcpsocks[i];
+ if (tcpsock->Sock->Connected && tcpsock->Sock->AsyncMode &&
+ IS_SEND_TCP_SOCK(tcpsock))
+ {
+ // Processing of KeepAlive
+ if (now >= tcpsock->NextKeepAliveTime || tcpsock->NextKeepAliveTime == 0 ||
+ (s != NULL && s->UseUdpAcceleration && s->UdpAccel != NULL && s->UdpAccel->MyPortByNatTServerChanged))
+ {
+ // Send the KeepAlive
+ SendKeepAlive(c, tcpsock);
+ tcpsock->NextKeepAliveTime = now + (UINT64)GenNextKeepAliveSpan(c);
+
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL)
+ {
+ s->UdpAccel->MyPortByNatTServerChanged = false;
+ }
+ }
+
+ // Count the number of available sockets to send
+ num_available++;
+
+ ts_hp = tcpsock;
+ }
+ }
+ }
+
+ for (i = 0;i < num;i++)
+ {
+ TCPSOCK *tcpsock = tcpsocks[i];
+ if (tcpsock->Sock->Connected && tcpsock->Sock->AsyncMode &&
+ IS_SEND_TCP_SOCK(tcpsock))
+ {
+ // Selection of the socket
+ bool b = false;
+
+ if (use_qos == false)
+ {
+ b = true;
+ }
+ else if (num_available < 2)
+ {
+ b = true;
+ }
+ else if (tcpsock != ts_hp)
+ {
+ b = true;
+ }
+
+ if (b)
+ {
+ if (is_rudp == false)
+ {
+ // Use a socket which have minimum delay occurrences in the case of such as a TCP socket
+ if (tcpsock->LateCount <= min_count)
+ {
+ min_count = tcpsock->LateCount;
+ ts = tcpsock;
+ }
+ }
+ else
+ {
+ // Use socket which have the largest last received time in the case of R-UDP socket
+ if (tcpsock->LastRecvTime >= max_recv_tick)
+ {
+ max_recv_tick = tcpsock->LastRecvTime;
+ ts = tcpsock;
+ }
+ }
+ }
+ }
+ }
+
+ if (ts_hp == NULL)
+ {
+ ts_hp = ts;
+ }
+
+ if (use_qos == false)
+ {
+ ts_hp = ts;
+ }
+
+ if (ts == NULL || ts_hp == NULL)
+ {
+ // The socket available to send doesn't currently exist
+ }
+ else
+ {
+ TCPSOCK *tss;
+ UINT j;
+ QUEUE *q;
+
+ if (s->UdpAccel != NULL)
+ {
+ UdpAccelSetTick(s->UdpAccel, now);
+ }
+
+ for (j = 0;j < 2;j++)
+ {
+ if (j == 0)
+ {
+ q = c->SendBlocks2;
+ tss = ts_hp;
+ }
+ else
+ {
+ q = c->SendBlocks;
+ tss = ts;
+ }
+ // I reserve the data to send on the selected socket ts
+ LockQueue(c->SendBlocks);
+ if (q->num_item != 0)
+ {
+ UINT num_data;
+ BLOCK *b;
+
+ if (tss->SendFifo->size >= MAX((MAX_SEND_SOCKET_QUEUE_SIZE / s->MaxConnection), MIN_SEND_SOCKET_QUEUE_SIZE))
+ {
+ // The size of the socket send queue is exceeded
+ // Unable to send
+ while (b = GetNext(q))
+ {
+ if (b != NULL)
+ {
+ c->CurrentSendQueueSize -= b->Size;
+ FreeBlock(b);
+ }
+ }
+ }
+ else
+ {
+ if (c->IsInProc == false)
+ {
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL && UdpAccelIsSendReady(s->UdpAccel, true))
+ {
+ // UDP acceleration mode
+ while (b = GetNext(q))
+ {
+ UdpAccelSendBlock(s->UdpAccel, b);
+
+ s->TotalSendSize += b->Size;
+ s->TotalSendSizeReal += b->Size;
+
+ c->CurrentSendQueueSize -= b->Size;
+
+ FreeBlock(b);
+ }
+ }
+ else if (s->IsRUDPSession && s->EnableBulkOnRUDP && ts->Sock != NULL && ts->Sock->BulkSendTube != NULL)
+ {
+ // R-UDP bulk transfer
+ TUBE *t = ts->Sock->BulkSendTube;
+ bool flush = false;
+ TCP_PAIR_HEADER h;
+
+ Zero(&h, sizeof(h));
+ h.EnableHMac = s->EnableHMacOnBulkOfRUDP;
+
+ while (b = GetNext(q))
+ {
+ if (b->Compressed == false)
+ {
+ // Uncompressed
+ TubeSendEx(t, b->Buf, b->Size, &h, true);
+
+ s->TotalSendSize += b->Size;
+ s->TotalSendSizeReal += b->Size;
+
+ c->CurrentSendQueueSize -= b->Size;
+ }
+ else
+ {
+ // Compressed
+ UCHAR *new_buf = Malloc(b->Size + sizeof(UINT64));
+
+ WRITE_UINT64(new_buf, CONNECTION_BULK_COMPRESS_SIGNATURE);
+
+ Copy(new_buf + sizeof(UINT64), b->Buf, b->Size);
+
+ TubeSendEx(t, new_buf, b->Size + sizeof(UINT64), &h, true);
+
+ s->TotalSendSize += b->SizeofData;
+ s->TotalSendSizeReal += b->Size;
+
+ c->CurrentSendQueueSize -= b->Size;
+ }
+
+ FreeBlock(b);
+
+ flush = true;
+ }
+
+ if (flush)
+ {
+ TubeFlush(t);
+ }
+ }
+ else
+ {
+ // TCP/IP socket
+ bool update_keepalive_timer = false;
+ // Number of data
+ num_data = Endian32(q->num_item);
+ PROBE_DATA2("WriteSendFifo num", &num_data, sizeof(UINT));
+ WriteSendFifo(s, tss, &num_data, sizeof(UINT));
+
+ s->TotalSendSize += sizeof(UINT);
+ s->TotalSendSizeReal += sizeof(UINT);
+
+ while (b = GetNext(q))
+ {
+ // Size data
+ UINT size_data;
+ size_data = Endian32(b->Size);
+ PROBE_DATA2("WriteSendFifo size", &size_data, sizeof(UINT));
+ WriteSendFifo(s, tss, &size_data, sizeof(UINT));
+
+ c->CurrentSendQueueSize -= b->Size;
+
+ s->TotalSendSize += sizeof(UINT);
+ s->TotalSendSizeReal += sizeof(UINT);
+
+ // Data body
+ PROBE_DATA2("WriteSendFifo data", b->Buf, b->Size);
+ WriteSendFifo(s, tss, b->Buf, b->Size);
+
+ s->TotalSendSize += b->SizeofData;
+ s->TotalSendSizeReal += b->Size;
+
+ update_keepalive_timer = true;
+
+ // Block release
+ FreeBlock(b);
+ }
+
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL && UdpAccelIsSendReady(s->UdpAccel, false))
+ {
+ update_keepalive_timer = false;
+ }
+
+ if (update_keepalive_timer)
+ {
+ // Increase the KeepAlive timer
+ tss->NextKeepAliveTime = now + (UINT64)GenNextKeepAliveSpan(c);
+ }
+ }
+ }
+ else
+ {
+ bool flush = false;
+ // In-process socket
+ while (b = GetNext(q))
+ {
+ TubeSendEx(ts->Sock->SendTube, b->Buf, b->Size, NULL, true);
+ flush = true;
+
+ s->TotalSendSize += b->Size;
+ s->TotalSendSizeReal += b->Size;
+
+ c->CurrentSendQueueSize -= b->Size;
+
+ FreeBlock(b);
+ }
+
+ if (flush)
+ {
+ TubeFlush(ts->Sock->SendTube);
+ }
+ }
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+ }
+ }
+
+ // Send the reserved data to send registered in each socket now
+ if (c->IsInProc == false)
+ {
+ for (i = 0;i < num;i++)
+ {
+ ts = tcpsocks[i];
+
+SEND_START:
+ if (ts->Sock->Connected == false)
+ {
+ s->LastTryAddConnectTime = Tick64();
+ // Communication is disconnected
+ LockList(tcp->TcpSockList);
+ {
+ // Remove the socket from socket list
+ Delete(tcp->TcpSockList, ts);
+ // Release of TCPSOCK
+ FreeTcpSock(ts);
+ // Decrement the count
+ Dec(c->CurrentNumConnection);
+ Debug("--- TCP Connection Decremented: %u (%s Line %u)\n", Count(c->CurrentNumConnection), __FILE__, __LINE__);
+ Debug("LIST_NUM(tcp->TcpSockList): %u\n", LIST_NUM(tcp->TcpSockList));
+ }
+ UnlockList(tcp->TcpSockList);
+
+ continue;
+ }
+
+ // Get Fifo size
+ if (ts->SendFifo->size != 0)
+ {
+ UCHAR *buf;
+ UINT want_send_size;
+ // Send only if the data to send exists by 1 byte or more
+ // Get the pointer to the buffer
+ buf = (UCHAR *)ts->SendFifo->p + ts->SendFifo->pos;
+ want_send_size = ts->SendFifo->size;
+
+ PROBE_DATA2("TcpSockSend", buf, want_send_size);
+ size = TcpSockSend(s, ts, buf, want_send_size);
+
+ if (size == 0)
+ {
+ // Disconnected
+ continue;
+ }
+ else if (size == SOCK_LATER)
+ {
+ // Packet is jammed
+ ts->LateCount++; // Increment of the delay counter
+ PROBE_STR("ts->LateCount++;");
+ }
+ else
+ {
+ // Packet is sent only by 'size'
+ // Advance FIFO
+ ReadFifo(ts->SendFifo, NULL, size);
+ if (size < want_send_size)
+ {
+ // Fail to transmit all of the data that has been scheduled
+#ifdef USE_PROBE
+ {
+ char tmp[MAX_SIZE];
+
+ snprintf(tmp, sizeof(tmp), "size < want_send_size: %u < %u",
+ size, want_send_size);
+
+ PROBE_STR(tmp);
+ }
+#endif // USE_PROBE
+ }
+ else
+ {
+ // Because sending all the packets is completed
+ // (The queue is exhausted), reset the delay counter
+ ts->LateCount = 0;
+
+ PROBE_STR("TcpSockSend All Completed");
+ }
+ // Updated the last communication date and time
+ c->Session->LastCommTime = now;
+
+ goto SEND_START;
+ }
+ }
+ }
+ }
+
+ Free(tcpsocks);
+ }
+ else if (c->Protocol == CONNECTION_UDP)
+ {
+ // UDP
+ UDP *udp = c->Udp;
+ SOCK *sock = NULL;
+
+ Lock(c->lock);
+ {
+ sock = udp->s;
+ if (sock != NULL)
+ {
+ AddRef(sock->ref);
+ }
+ }
+ Unlock(c->lock);
+
+ if (sock != NULL)
+ {
+ // Send with UDP
+
+ // KeepAlive sending
+ if ((udp->NextKeepAliveTime == 0 || udp->NextKeepAliveTime <= now) ||
+ (c->SendBlocks->num_item != 0) || (udp->BufferQueue->num_item != 0))
+ {
+ // Send the current queue with UDP
+ SendDataWithUDP(sock, c);
+ }
+ }
+
+ if (sock != NULL)
+ {
+ ReleaseSock(sock);
+ }
+ }
+ else if (c->Protocol == CONNECTION_HUB_SECURE_NAT)
+ {
+ // SecureNAT session
+ SNAT *snat = s->SecureNAT;
+ VH *v = snat->Nat->Virtual;
+
+ LockQueue(c->SendBlocks);
+ {
+ BLOCK *block;
+ UINT num_packet = 0;
+
+ if (hub != NULL)
+ {
+ NatSetHubOption(v, hub->Option);
+ }
+
+ while (block = GetNext(c->SendBlocks))
+ {
+ num_packet++;
+ c->CurrentSendQueueSize -= block->Size;
+ VirtualPutPacket(v, block->Buf, block->Size);
+ Free(block);
+ }
+
+ if (num_packet != 0)
+ {
+ VirtualPutPacket(v, NULL, 0);
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+ }
+ else if (c->Protocol == CONNECTION_HUB_LAYER3)
+ {
+ // Layer-3 session
+ L3IF *f = s->L3If;
+
+ LockQueue(c->SendBlocks);
+ {
+ BLOCK *block;
+ UINT num_packet = 0;
+
+ while (block = GetNext(c->SendBlocks))
+ {
+ num_packet++;
+ c->CurrentSendQueueSize -= block->Size;
+ L3PutPacket(f, block->Buf, block->Size);
+ Free(block);
+ }
+
+ if (num_packet != 0)
+ {
+ L3PutPacket(f, NULL, 0);
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+ }
+ else if (c->Protocol == CONNECTION_HUB_LINK_SERVER)
+ {
+ // HUB Link
+ LINK *k = (LINK *)s->Link;
+
+ if (k != NULL)
+ {
+ LockQueue(c->SendBlocks);
+ {
+ UINT num_blocks = 0;
+ LockQueue(k->SendPacketQueue);
+ {
+ BLOCK *block;
+
+ // Transfer the packet queue to the client thread
+ while (block = GetNext(c->SendBlocks))
+ {
+ num_blocks++;
+ c->CurrentSendQueueSize -= block->Size;
+ InsertQueue(k->SendPacketQueue, block);
+ }
+ }
+ UnlockQueue(k->SendPacketQueue);
+
+ if (num_blocks != 0)
+ {
+ // Issue of cancellation
+ Cancel(k->ClientSession->Cancel1);
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+ }
+ }
+ else if (c->Protocol == CONNECTION_HUB_BRIDGE)
+ {
+ // Local bridge
+ BRIDGE *b = s->Bridge;
+
+ if (b != NULL)
+ {
+ if (b->Active)
+ {
+ LockQueue(c->SendBlocks);
+ {
+ BLOCK *block;
+ UINT num_packet = c->SendBlocks->num_item; // Packet count
+
+ if (num_packet != 0)
+ {
+ // Packet data array
+ void **datas = MallocFast(sizeof(void *) * num_packet);
+ UINT *sizes = MallocFast(sizeof(UINT *) * num_packet);
+ UINT i;
+
+ i = 0;
+ while (block = GetNext(c->SendBlocks))
+ {
+ if (hub != NULL && hub->Option != NULL && hub->Option->DisableUdpFilterForLocalBridgeNic == false &&
+ b->Eth != NULL && IsDhcpPacketForSpecificMac(block->Buf, block->Size, b->Eth->MacAddress))
+ {
+ // DHCP Packet is filtered
+ datas[i] = NULL;
+ sizes[i] = 0;
+
+ Free(block->Buf);
+ }
+ else
+ {
+ datas[i] = block->Buf;
+ sizes[i] = block->Size;
+
+ if (block->Size > 1514)
+ {
+ NormalizeEthMtu(b, c, block->Size);
+ }
+ }
+
+ c->CurrentSendQueueSize -= block->Size;
+ Free(block);
+ i++;
+ }
+
+ // Write the packet
+ EthPutPackets(b->Eth, num_packet, datas, sizes);
+
+ Free(datas);
+ Free(sizes);
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+ }
+ }
+ }
+}
+
+// Reception of the block
+void ConnectionReceive(CONNECTION *c, CANCEL *c1, CANCEL *c2)
+{
+ UINT i, num;
+ SOCKSET set;
+ SESSION *s;
+ TCPSOCK **tcpsocks;
+ UCHAR *buf;
+ UINT size;
+ UINT64 now;
+ UINT time;
+ UINT num_delayed = 0;
+ bool no_spinlock_for_delay = false;
+ HUB *hub = NULL;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ PROBE_STR("ConnectionReceive");
+
+ s = c->Session;
+
+ if (s != NULL)
+ {
+ hub = s->Hub;
+ }
+
+ if (hub != NULL)
+ {
+ no_spinlock_for_delay = hub->Option->NoSpinLockForPacketDelay;
+ }
+
+ now = Tick64();
+
+ if (c->RecvBuf == NULL)
+ {
+ c->RecvBuf = Malloc(RECV_BUF_SIZE);
+ }
+ buf = c->RecvBuf;
+
+ // Protocol
+ if (c->Protocol == CONNECTION_TCP)
+ {
+ // TCP
+ TCP *tcp = c->Tcp;
+ UINT next_delay_packet_diff = 0;
+
+ // Disconnect if disconnection interval is specified
+ if (s->ServerMode == false)
+ {
+ if (s->ClientOption->ConnectionDisconnectSpan != 0)
+ {
+ LockList(tcp->TcpSockList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(tcp->TcpSockList);i++)
+ {
+ TCPSOCK *ts = LIST_DATA(tcp->TcpSockList, i);
+ if (ts->DisconnectTick != 0 &&
+ ts->DisconnectTick <= now)
+ {
+ Debug("ts->DisconnectTick <= now\n");
+ Disconnect(ts->Sock);
+ }
+ }
+ }
+ UnlockList(tcp->TcpSockList);
+ }
+ }
+
+ if (s->HalfConnection && (s->ServerMode == false))
+ {
+ // Check the direction of the current TCP connections.
+ // Disconnect one if the number of connections reaches
+ // the limit and has only one direction
+ LockList(tcp->TcpSockList);
+ {
+ UINT i, num;
+ UINT c2s, s2c;
+ c2s = s2c = 0;
+ num = LIST_NUM(tcp->TcpSockList);
+ if (num >= s->MaxConnection)
+ {
+ TCPSOCK *ts;
+ for (i = 0;i < num;i++)
+ {
+ ts = LIST_DATA(tcp->TcpSockList, i);
+ if (ts->Direction == TCP_SERVER_TO_CLIENT)
+ {
+ s2c++;
+ }
+ else
+ {
+ c2s++;
+ }
+ }
+ if (s2c == 0 || c2s == 0)
+ {
+ // Disconnect the last socket
+ Disconnect(ts->Sock);
+ Debug("Disconnect (s2c=%u, c2s=%u)\n", s2c, c2s);
+ }
+ }
+ }
+ UnlockList(tcp->TcpSockList);
+ }
+
+ // Initializing the socket set
+ InitSockSet(&set);
+ LockList(tcp->TcpSockList);
+ {
+ num = LIST_NUM(tcp->TcpSockList);
+ tcpsocks = ToArrayEx(tcp->TcpSockList, true);
+ }
+ UnlockList(tcp->TcpSockList);
+
+ for (i = 0;i < num;i++)
+ {
+ AddSockSet(&set, tcpsocks[i]->Sock);
+ }
+
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL)
+ {
+ if (s->UdpAccel->UdpSock != NULL)
+ {
+ AddSockSet(&set, s->UdpAccel->UdpSock);
+ }
+ }
+
+ // Select
+ time = SELECT_TIME;
+ if (s->VirtualHost)
+ {
+ time = MIN(time, SELECT_TIME_FOR_NAT);
+ }
+ next_delay_packet_diff = GetNextDelayedPacketTickDiff(s);
+ time = MIN(time, next_delay_packet_diff);
+ num_delayed = LIST_NUM(s->DelayedPacketList);
+
+ PROBE_STR("ConnectionReceive: Select 0");
+
+ if (s->Flag1 != set.NumSocket)
+ {
+ Select(&set, (num_delayed == 0 ? time : 1), c1, c2);
+ s->Flag1 = set.NumSocket;
+ }
+ else
+ {
+ if (no_spinlock_for_delay || time >= 50 || num_delayed == false)
+ {
+ Select(&set, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);
+ s->Flag1 = set.NumSocket;
+ }
+ else
+ {
+ YieldCpu();
+ }
+ }
+
+ PROBE_STR("ConnectionReceive: Select 1");
+
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL)
+ {
+ // Read the data received by the UDP If using the UDP acceleration mode
+ UdpAccelSetTick(s->UdpAccel, now);
+ UdpAccelPoll(s->UdpAccel);
+
+ if (s->UdpAccelMss == 0)
+ {
+ s->UdpAccelMss = UdpAccelCalcMss(s->UdpAccel);
+ }
+
+ while (true)
+ {
+ BLOCK *b = GetNext(s->UdpAccel->RecvBlockQueue);
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ if (b->Size > MAX_PACKET_SIZE)
+ {
+ // Packet size exceeded
+ FreeBlock(b);
+ }
+ else
+ {
+ // Add the data block to queue
+ InsertReveicedBlockToQueue(c, b);
+ }
+ }
+ }
+
+ {
+ bool new_status = UdpAccelIsSendReady(s->UdpAccel, true);
+
+ if (s->IsUsingUdpAcceleration != new_status)
+ {
+ Debug("UDP Status Changed: %u\n", new_status);
+ }
+
+ s->IsUsingUdpAcceleration = new_status;
+ }
+
+ // Read all the data that has arrived to the TCP socket
+ for (i = 0;i < num;i++)
+ {
+ TCPSOCK *ts = tcpsocks[i];
+ SOCK *sock = ts->Sock;
+
+ if (s->IsRUDPSession)
+ {
+ TUBE *t = sock->BulkRecvTube;
+
+ if (s->EnableBulkOnRUDP)
+ {
+ // R-UDP bulk transfer data reception
+ if (t != NULL && IsTubeConnected(t))
+ {
+ while (true)
+ {
+ TUBEDATA *d = TubeRecvAsync(t);
+ BLOCK *block;
+ if (d == NULL)
+ {
+ // All reception complete
+ break;
+ }
+
+ if (d->DataSize > sizeof(UINT64) && READ_UINT64(d->Data) == CONNECTION_BULK_COMPRESS_SIGNATURE)
+ {
+ // Compression
+ block = NewBlock(Clone(((UCHAR *)d->Data) + sizeof(UINT64),
+ d->DataSize - sizeof(UINT64)),
+ d->DataSize - sizeof(UINT64),
+ -1);
+ }
+ else
+ {
+ // Uncompressed
+ block = NewBlock(Clone(d->Data, d->DataSize), d->DataSize, 0);
+ }
+
+ if (block->Size > MAX_PACKET_SIZE)
+ {
+ // Packet size exceeded
+ FreeBlock(block);
+ }
+ else
+ {
+ // Add the data block to queue
+ InsertReveicedBlockToQueue(c, block);
+ }
+
+ FreeTubeData(d);
+
+ ts->LastCommTime = now;
+ ts->LastRecvTime = now;
+ c->Session->LastCommTime = now;
+ }
+ }
+ }
+ }
+
+ if (c->IsInProc)
+ {
+ TUBEDATA *d;
+ // Socket for in-process connection
+ if (IsTubeConnected(sock->RecvTube) == false)
+ {
+ // Communication is disconnected
+ goto DISCONNECT_THIS_TCP;
+ }
+
+ while (true)
+ {
+ BLOCK *block;
+ // Get the packet data from the tube
+ d = TubeRecvAsync(sock->RecvTube);
+ if (d == NULL)
+ {
+ // All acquisition completed
+ break;
+ }
+
+ block = NewBlock(Clone(d->Data, d->DataSize), d->DataSize, 0);
+
+ if (block->Size > MAX_PACKET_SIZE)
+ {
+ // Packet size exceeded
+ FreeBlock(block);
+ }
+ else
+ {
+ // Add the data block to queue
+ InsertReveicedBlockToQueue(c, block);
+ }
+
+ FreeTubeData(d);
+ }
+
+ c->Session->LastCommTime = now;
+ }
+ else
+ {
+ // A normal socket (Not in-process)
+ if (ts->WantSize == 0)
+ {
+ // Read for sizeof(UINT) first
+ ts->WantSize = sizeof(UINT);
+ }
+
+RECV_START:
+ // Receive
+ size = TcpSockRecv(s, ts, buf, RECV_BUF_SIZE);
+/*
+ // Experiment
+ if (c->ServerMode)
+ {
+ if ((ts->EstablishedTick + (UINT64)3000) <= now)
+ {
+ size = 0;
+ WHERE;
+ }
+ }*/
+
+ if (size == 0)
+ {
+DISCONNECT_THIS_TCP:
+ s->LastTryAddConnectTime = Tick64();
+ s->NumDisconnected++;
+ // Communication is disconnected
+ LockList(tcp->TcpSockList);
+ {
+ // Remove the socket from socket list
+ Delete(tcp->TcpSockList, ts);
+ // Release of TCPSOCK
+ FreeTcpSock(ts);
+ // Decrement
+ Dec(c->CurrentNumConnection);
+ Debug("--- TCP Connection Decremented: %u (%s Line %u)\n", Count(c->CurrentNumConnection), __FILE__, __LINE__);
+ Debug("LIST_NUM(tcp->TcpSockList): %u\n", LIST_NUM(tcp->TcpSockList));
+ }
+ UnlockList(tcp->TcpSockList);
+
+ continue;
+ }
+ else if (size == SOCK_LATER)
+ {
+ // State of waiting reception : don't do anything
+ if (IS_RECV_TCP_SOCK(ts))
+ {
+ if ((now > ts->LastCommTime) && ((now - ts->LastCommTime) >= ((UINT64)s->Timeout)))
+ {
+ // The connection has timed out
+ Debug("Connection %u Timeouted.\n", i);
+ goto DISCONNECT_THIS_TCP;
+ }
+ }
+ }
+ else
+ {
+ // Update the last communication time
+ ts->LastCommTime = now;
+ c->Session->LastCommTime = now;
+ ts->LastRecvTime = now;
+
+ // Write the received data into the FIFO
+ PROBE_DATA2("WriteRecvFifo", buf, size);
+ WriteRecvFifo(s, ts, buf, size);
+
+ // Stop receiving when the receive buffer is full
+ if (ts->RecvFifo->size < MAX_SEND_SOCKET_QUEUE_SIZE)
+ {
+ goto RECV_START;
+ }
+ }
+
+ // process the data written to FIFO
+ while (ts->RecvFifo->size >= ts->WantSize)
+ {
+ UCHAR *buf;
+ void *data;
+ BLOCK *block;
+ UINT sz;
+ // A sufficient amount of data is already stored
+ // Get the pointer of the data
+ buf = (UCHAR *)ts->RecvFifo->p + ts->RecvFifo->pos;
+
+ switch (ts->Mode)
+ {
+ case 0:
+ // The number of Data blocks
+ ts->WantSize = sizeof(UINT);
+ Copy(&sz, buf, sizeof(UINT));
+ PROBE_DATA2("ReadFifo 0", buf, sizeof(UINT));
+ sz = Endian32(sz);
+ ts->NextBlockNum = sz;
+ ReadFifo(ts->RecvFifo, NULL, sizeof(UINT));
+
+ s->TotalRecvSize += sizeof(UINT);
+ s->TotalRecvSizeReal += sizeof(UINT);
+
+ ts->CurrentPacketNum = 0;
+ if (ts->NextBlockNum != 0)
+ {
+ if (ts->NextBlockNum == KEEP_ALIVE_MAGIC)
+ {
+ ts->Mode = 3;
+ }
+ else
+ {
+ ts->Mode = 1;
+ }
+ }
+ break;
+
+ case 1:
+ // Data block size
+ Copy(&sz, buf, sizeof(UINT));
+ sz = Endian32(sz);
+ PROBE_DATA2("ReadFifo 1", buf, sizeof(UINT));
+ if (sz > (MAX_PACKET_SIZE * 2))
+ {
+ // received a strange data size
+ // TCP/IP Error?
+ Debug("%s %u sz > (MAX_PACKET_SIZE * 2)\n", __FILE__, __LINE__);
+ Disconnect(ts->Sock);
+ }
+ ts->NextBlockSize = MIN(sz, MAX_PACKET_SIZE * 2);
+ ReadFifo(ts->RecvFifo, NULL, sizeof(UINT));
+
+ s->TotalRecvSize += sizeof(UINT);
+ s->TotalRecvSizeReal += sizeof(UINT);
+
+ ts->WantSize = ts->NextBlockSize;
+ if (ts->WantSize != 0)
+ {
+ ts->Mode = 2;
+ }
+ else
+ {
+ ts->Mode = 1;
+ ts->WantSize = sizeof(UINT);
+ ts->CurrentPacketNum++;
+ if (ts->CurrentPacketNum >= ts->NextBlockNum)
+ {
+ ts->Mode = 0;
+ }
+ }
+ break;
+
+ case 2:
+ // Data block body
+ ts->WantSize = sizeof(UINT);
+ ts->CurrentPacketNum++;
+ data = MallocFast(ts->NextBlockSize);
+ Copy(data, buf, ts->NextBlockSize);
+ PROBE_DATA2("ReadFifo 2", buf, ts->NextBlockSize);
+ ReadFifo(ts->RecvFifo, NULL, ts->NextBlockSize);
+ block = NewBlock(data, ts->NextBlockSize, s->UseCompress ? -1 : 0);
+
+ if (block->Size > MAX_PACKET_SIZE)
+ {
+ // Packet size exceeded
+ FreeBlock(block);
+ }
+ else
+ {
+ // Add the data block to queue
+ InsertReveicedBlockToQueue(c, block);
+ }
+
+ if (ts->CurrentPacketNum >= ts->NextBlockNum)
+ {
+ // Reception of all the data blocks completed
+ ts->Mode = 0;
+ }
+ else
+ {
+ // Receive next data block size
+ ts->Mode = 1;
+ }
+ break;
+
+ case 3:
+ // Keep-Alive packet size
+ ts->Mode = 4;
+ Copy(&sz, buf, sizeof(UINT));
+ PROBE_DATA2("ReadFifo 3", buf, sizeof(UINT));
+ sz = Endian32(sz);
+ if (sz > MAX_KEEPALIVE_SIZE)
+ {
+ // received a strange data size
+ // TCP/IP Error?
+ Debug("%s %u sz > MAX_KEEPALIVE_SIZE\n", __FILE__, __LINE__);
+ Disconnect(ts->Sock);
+ }
+ ts->NextBlockSize = MIN(sz, MAX_KEEPALIVE_SIZE);
+ ReadFifo(ts->RecvFifo, NULL, sizeof(UINT));
+
+ s->TotalRecvSize += sizeof(UINT);
+ s->TotalRecvSizeReal += sizeof(UINT);
+
+ ts->WantSize = sz;
+ break;
+
+ case 4:
+ // Keep-Alive packet body
+ //Debug("KeepAlive Recved.\n");
+ ts->Mode = 0;
+ sz = ts->NextBlockSize;
+
+ if (sz >= (StrLen(UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE) + sizeof(USHORT)))
+ {
+ UCHAR *keep_alive_buffer = FifoPtr(ts->RecvFifo);
+
+ if (Cmp(keep_alive_buffer, UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE, StrLen(UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE)) == 0)
+ {
+ USHORT us = READ_USHORT(keep_alive_buffer + StrLen(UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE));
+
+ if (us != 0)
+ {
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL)
+ {
+ UINT port = (UINT)us;
+
+ if (s->UdpAccel->YourPortByNatTServer != port)
+ {
+ s->UdpAccel->YourPortByNatTServer = port;
+ s->UdpAccel->YourPortByNatTServerChanged = true;
+
+ Debug("s->UdpAccel->YourPortByNatTServer: %u\n",
+ s->UdpAccel->YourPortByNatTServer);
+ }
+ }
+ }
+ }
+ }
+
+ PROBE_DATA2("ReadFifo 4", NULL, 0);
+ ReadFifo(ts->RecvFifo, NULL, sz);
+
+ s->TotalRecvSize += sz;
+ s->TotalRecvSizeReal += sz;
+
+ ts->WantSize = sizeof(UINT);
+ break;
+ }
+ }
+ }
+ }
+
+ Free(tcpsocks);
+ }
+ else if (c->Protocol == CONNECTION_UDP)
+ {
+ // UDP
+ UDP *udp = c->Udp;
+ SOCK *sock = NULL;
+
+ if (s->ServerMode == false)
+ {
+ Lock(c->lock);
+ {
+ if (c->Udp->s != NULL)
+ {
+ sock = c->Udp->s;
+ if (sock != NULL)
+ {
+ AddRef(sock->ref);
+ }
+ }
+ }
+ Unlock(c->lock);
+
+ InitSockSet(&set);
+
+ if (sock != NULL)
+ {
+ AddSockSet(&set, sock);
+ }
+
+ Select(&set, SELECT_TIME, c1, c2);
+
+ if (sock != NULL)
+ {
+ IP ip;
+ UINT port;
+ UCHAR *buf;
+ UINT size;
+
+ while (true)
+ {
+ buf = c->RecvBuf;
+ size = RecvFrom(sock, &ip, &port, buf, RECV_BUF_SIZE);
+ if (size == 0 && sock->IgnoreRecvErr == false)
+ {
+ Debug("UDP Socket Disconnected.\n");
+ Lock(c->lock);
+ {
+ ReleaseSock(udp->s);
+ udp->s = NULL;
+ }
+ Unlock(c->lock);
+ break;
+ }
+ else if (size == SOCK_LATER)
+ {
+ break;
+ }
+ else
+ {
+ if (size)
+ {
+ PutUDPPacketData(c, buf, size);
+ }
+ }
+ }
+ }
+
+ if (sock != NULL)
+ {
+ Release(sock->ref);
+ }
+ }
+ else
+ {
+ Select(NULL, SELECT_TIME, c1, c2);
+ }
+ }
+ else if (c->Protocol == CONNECTION_HUB_SECURE_NAT)
+ {
+ SNAT *snat = c->Session->SecureNAT;
+ VH *v = snat->Nat->Virtual;
+ UINT size;
+ void *data;
+ UINT num;
+ UINT select_wait_time = SELECT_TIME_FOR_NAT;
+ UINT next_delay_packet_diff = 0;
+
+ if (snat->Nat != NULL && snat->Nat->Option.UseNat == false)
+ {
+ select_wait_time = SELECT_TIME;
+ }
+ else
+ {
+ if (snat->Nat != NULL)
+ {
+ LockList(v->NatTable);
+ {
+ if (LIST_NUM(v->NatTable) == 0 && LIST_NUM(v->ArpWaitTable) == 0)
+ {
+ select_wait_time = SELECT_TIME;
+ }
+ }
+ UnlockList(v->NatTable);
+ }
+ }
+
+ next_delay_packet_diff = GetNextDelayedPacketTickDiff(s);
+ select_wait_time = MIN(select_wait_time, next_delay_packet_diff);
+ num_delayed = LIST_NUM(s->DelayedPacketList);
+
+ if (no_spinlock_for_delay || select_wait_time >= 50 || num_delayed == false)
+ {
+ Select(NULL, (num_delayed == 0 ? select_wait_time :
+ (select_wait_time > 100 ? (select_wait_time - 100) : 1)), c1, c2);
+ }
+ else
+ {
+ YieldCpu();
+ }
+
+ num = 0;
+
+ if (hub != NULL)
+ {
+ NatSetHubOption(v, hub->Option);
+ }
+
+ // Receive a packet from the virtual machine
+ while (size = VirtualGetNextPacket(v, &data))
+ {
+ BLOCK *block;
+
+ // Generate packet block
+ block = NewBlock(data, size, 0);
+ if (block->Size > MAX_PACKET_SIZE)
+ {
+ // Packet size exceeded
+ FreeBlock(block);
+ }
+ else
+ {
+ // Add the data block to queue
+ InsertReveicedBlockToQueue(c, block);
+ }
+ num++;
+ if (num >= MAX_SEND_SOCKET_QUEUE_NUM)
+ {
+// WHERE;
+ break;
+ }
+ }
+ }
+ else if (c->Protocol == CONNECTION_HUB_LINK_SERVER)
+ {
+ // HUB Link
+ // Waiting Cancel simply
+ if (c->SendBlocks->num_item == 0)
+ {
+ UINT time = SELECT_TIME;
+ UINT next_delay_packet_diff = 0;
+
+ next_delay_packet_diff = GetNextDelayedPacketTickDiff(s);
+ time = MIN(time, next_delay_packet_diff);
+ num_delayed = LIST_NUM(s->DelayedPacketList);
+
+ if (no_spinlock_for_delay || time >= 50 || num_delayed == false)
+ {
+ Select(NULL, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);
+ }
+ else
+ {
+ YieldCpu();
+ }
+ }
+ }
+ else if (c->Protocol == CONNECTION_HUB_LAYER3)
+ {
+ // Layer-3 switch session
+ L3IF *f = s->L3If;
+ UINT size, num = 0;
+ void *data;
+
+ if (f->SendQueue->num_item == 0)
+ {
+ UINT time = SELECT_TIME_FOR_NAT;
+ UINT next_delay_packet_diff = 0;
+
+ if (f->ArpWaitTable != NULL)
+ {
+ LockList(f->ArpWaitTable);
+ {
+ if (LIST_NUM(f->ArpWaitTable) == 0)
+ {
+ time = SELECT_TIME;
+ }
+ }
+ UnlockList(f->ArpWaitTable);
+ }
+
+ next_delay_packet_diff = GetNextDelayedPacketTickDiff(s);
+ time = MIN(time, next_delay_packet_diff);
+ num_delayed = LIST_NUM(s->DelayedPacketList);
+
+ if (no_spinlock_for_delay || time >= 50 || num_delayed == false)
+ {
+ Select(NULL, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);
+ }
+ else
+ {
+ YieldCpu();
+ }
+ }
+
+ // Get the next packet
+ while (size = L3GetNextPacket(f, &data))
+ {
+ BLOCK *block = NewBlock(data, size, 0);
+ if (block->Size > MAX_PACKET_SIZE)
+ {
+ FreeBlock(block);
+ }
+ else
+ {
+ InsertReveicedBlockToQueue(c, block);
+ }
+
+ num++;
+ if (num >= MAX_SEND_SOCKET_QUEUE_NUM)
+ {
+ break;
+ }
+ }
+ }
+ else if (c->Protocol == CONNECTION_HUB_BRIDGE)
+ {
+ BRIDGE *b = c->Session->Bridge;
+
+ // Bridge session
+ if (b->Active)
+ {
+ void *data;
+ UINT ret;
+ UINT num = 0;
+ bool check_device_num = false;
+ UINT time = SELECT_TIME;
+ UINT next_delay_packet_diff = 0;
+
+ next_delay_packet_diff = GetNextDelayedPacketTickDiff(s);
+ time = MIN(time, next_delay_packet_diff);
+ num_delayed = LIST_NUM(s->DelayedPacketList);
+
+ // Bridge is operating
+ if (no_spinlock_for_delay || time >= 50 || num_delayed == false)
+ {
+ Select(NULL, (num_delayed == 0 ? time : (time > 100 ? (time - 100) : 1)), c1, c2);
+ }
+ else
+ {
+ YieldCpu();
+ }
+
+ if ((b->LastNumDeviceCheck + BRIDGE_NUM_DEVICE_CHECK_SPAN) <= Tick64())
+ {
+ check_device_num = true;
+ b->LastNumDeviceCheck = Tick64();
+ }
+
+ // Get the next packet from the bridge
+ while (true)
+ {
+ if (check_device_num && b->LastNumDevice != GetEthDeviceHash())
+ {
+ ret = INFINITE;
+ }
+ else
+ {
+ ret = EthGetPacket(b->Eth, &data);
+ }
+
+#ifdef OS_WIN32
+ if (c->Session != NULL)
+ {
+ c->Session->BridgeIsEthLoopbackBlock = false;
+ if (b->Eth != NULL && b->Eth->LoopbackBlock)
+ {
+ // Check whether The Ethernet device in the bridge
+ // has the ability to block the loopback packet
+ c->Session->BridgeIsEthLoopbackBlock = true;
+ }
+ }
+#endif // OS_WIN32
+
+ if (ret == INFINITE)
+ {
+ // Error occured: stop the bridge
+ CloseEth(b->Eth);
+ b->Eth = NULL;
+ b->Active = false;
+ ReleaseCancel(s->Cancel2);
+ s->Cancel2 = NULL;
+
+ HLog(s->Hub, "LH_BRIDGE_2", s->Name, b->Name);
+ Debug("Bridge Device Error.\n");
+
+ break;
+ }
+ else if (ret == 0)
+ {
+ // There is no more packet to receive
+ break;
+ }
+ else
+ {
+ if (hub != NULL && hub->Option != NULL && hub->Option->DisableUdpFilterForLocalBridgeNic == false &&
+ b->Eth != NULL && IsDhcpPacketForSpecificMac(data, ret, b->Eth->MacAddress))
+ {
+ // DHCP Packet is filtered.
+ Free(data);
+ }
+ else
+ {
+ // Add the packet to queue
+ BLOCK *block = NewBlock(data, ret, 0);
+
+ PROBE_DATA2("ConnectionReceive: NewBlock", data, ret);
+
+ if (ret > 1514)
+ {
+ NormalizeEthMtu(b, c, ret);
+ }
+
+ if (block->Size > MAX_PACKET_SIZE)
+ {
+ // Packet size exceeded
+ FreeBlock(block);
+ }
+ else
+ {
+ InsertReveicedBlockToQueue(c, block);
+ }
+ num++;
+ if (num >= MAX_SEND_SOCKET_QUEUE_NUM)
+ {
+ // WHERE;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ ETH *e;
+ // Bridge is stopped cureently
+ Select(NULL, SELECT_TIME, c1, NULL);
+
+ if (b->LastBridgeTry == 0 || (b->LastBridgeTry + BRIDGE_TRY_SPAN) <= Tick64())
+ {
+ b->LastBridgeTry = Tick64();
+
+ // Try to open an Ethernet device
+ e = OpenEth(b->Name, b->Local, b->TapMode, b->TapMacAddress);
+ if (e != NULL)
+ {
+ // Success
+ b->Eth = e;
+ b->Active = true;
+ b->LastNumDeviceCheck = Tick64();
+ b->LastNumDevice = GetEthDeviceHash();
+
+ // Update the NIC name of the bridge
+#ifdef OS_WIN32
+ if (IsEmptyStr(e->Title) == false)
+ {
+ StrCpy(b->Name, sizeof(b->Name), e->Title);
+
+ if (b->ParentLocalBridge != NULL)
+ {
+ StrCpy(b->ParentLocalBridge->DeviceName, sizeof(b->ParentLocalBridge->DeviceName), e->Title);
+ }
+ }
+#endif // OS_WIN32
+
+ Debug("Bridge Open Succeed.\n");
+
+ HLog(c->Session->Hub, "LH_BRIDGE_1", c->Session->Name, b->Name);
+
+ s->Cancel2 = EthGetCancel(b->Eth);
+ }
+ }
+ }
+ }
+}
+
+// Normalize the MTU of the Ethernet device
+void NormalizeEthMtu(BRIDGE *b, CONNECTION *c, UINT packet_size)
+{
+ // Validate arguments
+ if (packet_size == 0 || b == NULL || c == NULL)
+ {
+ return;
+ }
+
+ // Raise the MTU when the packet exceeds the current MTU
+ if (EthIsChangeMtuSupported(b->Eth))
+ {
+ UINT currentMtu = EthGetMtu(b->Eth);
+ if (currentMtu != 0)
+ {
+ if (packet_size > currentMtu)
+ {
+ bool ok = EthSetMtu(b->Eth, packet_size);
+
+ if (ok)
+ {
+ HLog(c->Session->Hub, "LH_SET_MTU", c->Session->Name,
+ b->Name, currentMtu, packet_size, packet_size);
+ }
+ else
+ {
+ UINT64 now = Tick64();
+
+ if (b->LastChangeMtuError == 0 ||
+ now >= (b->LastChangeMtuError + 60000ULL))
+ {
+ HLog(c->Session->Hub, "LH_SET_MTU_ERROR", c->Session->Name,
+ b->Name, currentMtu, packet_size, packet_size);
+
+ b->LastChangeMtuError = now;
+ }
+ }
+ }
+ }
+ }
+}
+
+// Release of the block
+void FreeBlock(BLOCK *b)
+{
+ // Validate arguments
+ if (b == NULL)
+ {
+ return;
+ }
+
+ Free(b->Buf);
+ Free(b);
+}
+
+// Create a new block
+BLOCK *NewBlock(void *data, UINT size, int compress)
+{
+ BLOCK *b;
+ // Validate arguments
+ if (data == NULL)
+ {
+ return NULL;
+ }
+
+ b = MallocFast(sizeof(BLOCK));
+
+ b->PriorityQoS = b->Ttl = b->Param1 = 0;
+
+ if (compress == 0)
+ {
+ // Uncompressed
+ b->Compressed = FALSE;
+ b->Buf = data;
+ b->Size = size;
+ b->SizeofData = size;
+ }
+ else if (compress == 1)
+ {
+ UINT max_size;
+
+ // Compressed
+ b->Compressed = TRUE;
+ max_size = CalcCompress(size);
+ b->Buf = MallocFast(max_size);
+ b->Size = Compress(b->Buf, max_size, data, size);
+ b->SizeofData = size;
+
+ // Discard old data block
+ Free(data);
+ }
+ else
+ {
+ // Expand
+ UINT max_size;
+
+ b->Compressed = FALSE;
+ max_size = MAX_PACKET_SIZE;
+ b->Buf = MallocFast(max_size);
+ b->Size = Uncompress(b->Buf, max_size, data, size);
+ b->SizeofData = size;
+
+ // Discard old data
+ Free(data);
+ }
+
+ return b;
+}
+
+// Create a TCP socket
+TCPSOCK *NewTcpSock(SOCK *s)
+{
+ TCPSOCK *ts;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ ts = ZeroMalloc(sizeof(TCPSOCK));
+
+ ts->Sock = s;
+ AddRef(s->ref);
+
+ ts->RecvFifo = NewFifo();
+ ts->SendFifo = NewFifo();
+ ts->EstablishedTick = ts->LastRecvTime = ts->LastCommTime = Tick64();
+
+ // Unset the time-out value
+ SetTimeout(s, TIMEOUT_INFINITE);
+
+ return ts;
+}
+
+// Set a encryption key for the TCP socket
+void InitTcpSockRc4Key(TCPSOCK *ts, bool server_mode)
+{
+ RC4_KEY_PAIR *pair;
+ CRYPT *c1, *c2;
+ // Validate arguments
+ if (ts == NULL)
+ {
+ return;
+ }
+
+ pair = &ts->Rc4KeyPair;
+
+ c1 = NewCrypt(pair->ClientToServerKey, sizeof(pair->ClientToServerKey));
+ c2 = NewCrypt(pair->ServerToClientKey, sizeof(pair->ServerToClientKey));
+
+ if (server_mode)
+ {
+ ts->RecvKey = c1;
+ ts->SendKey = c2;
+ }
+ else
+ {
+ ts->SendKey = c1;
+ ts->RecvKey = c2;
+ }
+}
+
+// Release of TCP socket
+void FreeTcpSock(TCPSOCK *ts)
+{
+ // Validate arguments
+ if (ts == NULL)
+ {
+ return;
+ }
+
+ Disconnect(ts->Sock);
+ ReleaseSock(ts->Sock);
+ ReleaseFifo(ts->RecvFifo);
+ ReleaseFifo(ts->SendFifo);
+
+ if (ts->SendKey)
+ {
+ FreeCrypt(ts->SendKey);
+ }
+ if (ts->RecvKey)
+ {
+ FreeCrypt(ts->RecvKey);
+ }
+
+ Free(ts);
+}
+
+// Exit the tunneling mode of connection
+void EndTunnelingMode(CONNECTION *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Protocol
+ if (c->Protocol == CONNECTION_TCP)
+ {
+ // TCP
+ DisconnectTcpSockets(c);
+ }
+ else
+ {
+ // UDP
+ DisconnectUDPSockets(c);
+ }
+}
+
+// Shift the connection to tunneling mode
+void StartTunnelingMode(CONNECTION *c)
+{
+ SOCK *s;
+ TCP *tcp;
+ TCPSOCK *ts;
+ IP ip;
+ UINT port;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ tcp = c->Tcp;
+
+ // Protocol
+ if (c->Protocol == CONNECTION_TCP)
+ {
+ // TCP
+ s = c->FirstSock;
+
+ if (c->IsInProc)
+ {
+ AddRef(s->ref);
+ c->TubeSock = s;
+ }
+
+ ts = NewTcpSock(s);
+
+ if (c->ServerMode == false)
+ {
+ if (c->Session->ClientOption->ConnectionDisconnectSpan != 0)
+ {
+ ts->DisconnectTick = Tick64() + c->Session->ClientOption->ConnectionDisconnectSpan * (UINT64)1000;
+ }
+ }
+
+ LockList(tcp->TcpSockList);
+ {
+ Add(tcp->TcpSockList, ts);
+ }
+ UnlockList(tcp->TcpSockList);
+ ReleaseSock(s);
+ c->FirstSock = NULL;
+ }
+ else
+ {
+ // UDP
+ s = c->FirstSock;
+ Copy(&ip, &s->RemoteIP, sizeof(IP));
+ // May disconnect TCP connection at this point
+ c->FirstSock = NULL;
+ Disconnect(s);
+ ReleaseSock(s);
+
+ // Initialization of UDP structure
+ c->Udp = ZeroMalloc(sizeof(UDP));
+
+ if (c->ServerMode)
+ {
+ // Server mode
+ // Add an UDP Entry
+ AddUDPEntry(c->Cedar, c->Session);
+ c->Udp->s = NULL;
+ }
+ else
+ {
+ port = c->Session->ClientOption->PortUDP;
+ // Client mode
+ c->Udp->s = NewUDP(0);
+ // Write the IP address and port number
+ Copy(&c->Udp->ip, &ip, sizeof(IP));
+ c->Udp->port = port;
+ }
+
+ // Queue
+ c->Udp->BufferQueue = NewQueue();
+ }
+}
+
+// Generate a random value that depends on each machine
+UINT GetMachineRand()
+{
+ char pcname[MAX_SIZE];
+ UCHAR hash[SHA1_SIZE];
+
+ Zero(pcname, sizeof(pcname));
+ GetMachineName(pcname, sizeof(pcname));
+
+ HashSha1(hash, pcname, StrLen(pcname));
+
+ return READ_UINT(hash);
+}
+
+// Function that accepts a new connection
+void ConnectionAccept(CONNECTION *c)
+{
+ SOCK *s;
+ X *x;
+ K *k;
+ char tmp[128];
+ UCHAR openssl_check_buf[2];
+ char *error_details = NULL;
+ SERVER *server;
+ UCHAR *peek_buf = NULL;
+ UINT peek_buf_size = 1500;
+ char sni[128] = {0};
+ bool native1 = false; // Non-SNI flag
+ bool native2 = false; // Non-TLS flag
+ bool native3 = false; // SSLv2 flag
+ bool no_native = false;
+ UINT peek_size = 0;
+ UINT initial_timeout = CONNECTING_TIMEOUT;
+ bool no_peek_log = false;
+ UCHAR ctoken_hash[SHA1_SIZE];
+ bool no_write_ctoken_log = false;
+
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ Zero(ctoken_hash, sizeof(ctoken_hash));
+
+ peek_buf = ZeroMalloc(peek_buf_size);
+
+ Debug("ConnectionAccept()\n");
+
+ server = c->Cedar->Server;
+
+ // get a socket
+ s = c->FirstSock;
+ AddRef(s->ref);
+
+ Dec(c->Cedar->AcceptingSockets);
+
+ IPToStr(tmp, sizeof(tmp), &s->RemoteIP);
+
+ SLog(c->Cedar, "LS_CONNECTION_START_1", tmp, s->RemoteHostname, (IS_SPECIAL_PORT(s->RemotePort) ? 0 : s->RemotePort), c->Name);
+
+ // Timeout setting
+ initial_timeout += GetMachineRand() % (CONNECTING_TIMEOUT / 2);
+ SetTimeout(s, initial_timeout);
+
+
+ // Peek whether OpenSSL packet
+ if (s->IsReverseAcceptedSocket == false)
+ {
+ if (s->Type == SOCK_TCP && (c->Cedar != NULL && c->Cedar->Server != NULL && c->Cedar->Server->DisableOpenVPNServer == false))
+ {
+ if (Peek(s, openssl_check_buf, sizeof(openssl_check_buf)) == sizeof(openssl_check_buf))
+ {
+ if (OvsCheckTcpRecvBufIfOpenVPNProtocol(openssl_check_buf, sizeof(openssl_check_buf)))
+ {
+ // Detect OpenSSL packet
+ Debug("Detect OpenSSL on TCP!\n");
+
+ no_native = true;
+
+ if (OvsGetNoOpenVpnTcp() == false)
+ {
+ // Do OpenSSL processing
+ c->Type = CONNECTION_TYPE_OPENVPN;
+ if (OvsPerformTcpServer(c->Cedar, s) == false)
+ {
+ error_details = "OpenVPN_TCP_Aborted";
+ }
+ }
+
+ goto ERROR;
+ }
+ }
+ }
+
+
+ }
+
+ // Specify the encryption algorithm
+ Lock(c->Cedar->lock);
+ {
+ if (c->Cedar->CipherList != NULL)
+ {
+ SetWantToUseCipher(s, c->Cedar->CipherList);
+ }
+
+ x = CloneX(c->Cedar->ServerX);
+ k = CloneK(c->Cedar->ServerK);
+ }
+ Unlock(c->Cedar->lock);
+
+ // Start the SSL communication
+ Debug("StartSSL()\n");
+ if (StartSSL(s, x, k) == false)
+ {
+ // Failed
+ AddNoSsl(c->Cedar, &s->RemoteIP);
+ Debug("Failed to StartSSL.\n");
+ FreeX(x);
+ FreeK(k);
+
+ error_details = "StartSSL";
+
+ goto ERROR;
+ }
+
+ FreeX(x);
+ FreeK(k);
+
+ SLog(c->Cedar, "LS_SSL_START", c->Name, s->CipherName);
+
+ Copy(c->CToken_Hash, ctoken_hash, SHA1_SIZE);
+
+ // Accept the connection
+ if (ServerAccept(c) == false)
+ {
+ // Failed
+ Debug("ServerAccept Failed. Err = %u\n", c->Err);
+ goto ERROR;
+ }
+
+ if (c->flag1 == false)
+ {
+ Debug("%s %u c->flag1 == false\n", __FILE__, __LINE__);
+ Disconnect(s);
+ }
+ DelConnection(c->Cedar, c);
+ ReleaseSock(s);
+
+ Free(peek_buf);
+ return;
+
+ERROR:
+ Debug("ConnectionAccept() Error.\n");
+
+
+ Disconnect(s);
+ DelConnection(c->Cedar, c);
+ ReleaseSock(s);
+ Free(peek_buf);
+}
+
+// Stop the threads putting additional connection of all that are currently running
+void StopAllAdditionalConnectThread(CONNECTION *c)
+{
+ UINT i, num;
+ SOCK **socks;
+ THREAD **threads;
+ // Validate arguments
+ if (c == NULL || c->ServerMode != false)
+ {
+ return;
+ }
+
+ // Disconnect the socket first
+ LockList(c->ConnectingSocks);
+ {
+ num = LIST_NUM(c->ConnectingSocks);
+ socks = ToArray(c->ConnectingSocks);
+ DeleteAll(c->ConnectingSocks);
+ }
+ UnlockList(c->ConnectingSocks);
+ for (i = 0;i < num;i++)
+ {
+ Disconnect(socks[i]);
+ ReleaseSock(socks[i]);
+ }
+ Free(socks);
+
+ // Then, wait for the suspension of the thread
+ LockList(c->ConnectingThreads);
+ {
+ num = LIST_NUM(c->ConnectingThreads);
+ Debug("c->ConnectingThreads: %u\n", num);
+ threads = ToArray(c->ConnectingThreads);
+ DeleteAll(c->ConnectingThreads);
+ }
+ UnlockList(c->ConnectingThreads);
+ for (i = 0;i < num;i++)
+ {
+ WaitThread(threads[i], INFINITE);
+ ReleaseThread(threads[i]);
+ }
+ Free(threads);
+}
+
+// Stop the connection
+void StopConnection(CONNECTION *c, bool no_wait)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ Debug("Stop Connection: %s\n", c->Name);
+
+ // Stop flag
+ c->Halt = true;
+ Disconnect(c->FirstSock);
+
+ if (no_wait == false)
+ {
+ // Wait until the thread terminates
+ WaitThread(c->Thread, INFINITE);
+ }
+}
+
+// Close all the UDP socket
+void DisconnectUDPSockets(CONNECTION *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+ if (c->Protocol != CONNECTION_UDP)
+ {
+ return;
+ }
+
+ // Delete entry
+ if (c->ServerMode)
+ {
+ DelUDPEntry(c->Cedar, c->Session);
+ }
+
+ // Delete the UDP structure
+ if (c->Udp != NULL)
+ {
+ if (c->Udp->s != NULL)
+ {
+ ReleaseSock(c->Udp->s);
+ }
+ if (c->Udp->BufferQueue != NULL)
+ {
+ // Release of the queue
+ BUF *b;
+ while (b = GetNext(c->Udp->BufferQueue))
+ {
+ FreeBuf(b);
+ }
+ ReleaseQueue(c->Udp->BufferQueue);
+ }
+ Free(c->Udp);
+ c->Udp = NULL;
+ }
+
+ if (c->FirstSock != NULL)
+ {
+ Disconnect(c->FirstSock);
+ ReleaseSock(c->FirstSock);
+ c->FirstSock = NULL;
+ }
+}
+
+// Close all TCP connections
+void DisconnectTcpSockets(CONNECTION *c)
+{
+ UINT i, num;
+ TCP *tcp;
+ TCPSOCK **tcpsocks;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+ if (c->Protocol != CONNECTION_TCP)
+ {
+ return;
+ }
+
+ tcp = c->Tcp;
+ LockList(tcp->TcpSockList);
+ {
+ tcpsocks = ToArray(tcp->TcpSockList);
+ num = LIST_NUM(tcp->TcpSockList);
+ DeleteAll(tcp->TcpSockList);
+ }
+ UnlockList(tcp->TcpSockList);
+
+ if (num != 0)
+ {
+ Debug("--- SOCKET STATUS ---\n");
+ for (i = 0;i < num;i++)
+ {
+ TCPSOCK *ts = tcpsocks[i];
+ Debug(" SOCK %2u: %u\n", i, ts->Sock->SendSize);
+ FreeTcpSock(ts);
+ }
+ }
+
+ Free(tcpsocks);
+}
+
+// Clean up of the connection
+void CleanupConnection(CONNECTION *c)
+{
+ UINT i, num;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ DeleteLock(c->lock);
+ ReleaseCedar(c->Cedar);
+
+ switch (c->Protocol)
+ {
+ case CONNECTION_TCP:
+ // Release of TCP connection list
+ DisconnectTcpSockets(c);
+ break;
+
+ case CONNECTION_UDP:
+ break;
+ }
+
+ ReleaseList(c->Tcp->TcpSockList);
+ Free(c->Tcp);
+
+ ReleaseSock(c->FirstSock);
+ c->FirstSock = NULL;
+
+ ReleaseSock(c->TubeSock);
+ c->TubeSock = NULL;
+
+ ReleaseThread(c->Thread);
+ Free(c->Name);
+
+ // Release all the receive block and send block
+ if (c->SendBlocks)
+ {
+ LockQueue(c->SendBlocks);
+ {
+ BLOCK *b;
+ while (b = GetNext(c->SendBlocks))
+ {
+ FreeBlock(b);
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+ }
+ if (c->SendBlocks2)
+ {
+ LockQueue(c->SendBlocks2);
+ {
+ BLOCK *b;
+ while (b = GetNext(c->SendBlocks2))
+ {
+ FreeBlock(b);
+ }
+ }
+ UnlockQueue(c->SendBlocks2);
+ }
+ if (c->ReceivedBlocks)
+ {
+ LockQueue(c->ReceivedBlocks);
+ {
+ BLOCK *b;
+ while (b = GetNext(c->ReceivedBlocks))
+ {
+ FreeBlock(b);
+ }
+ }
+ UnlockQueue(c->ReceivedBlocks);
+ }
+
+ if (c->ConnectingThreads)
+ {
+ THREAD **threads;
+ LockList(c->ConnectingThreads);
+ {
+ num = LIST_NUM(c->ConnectingThreads);
+ threads = ToArray(c->ConnectingThreads);
+ for (i = 0;i < num;i++)
+ {
+ ReleaseThread(threads[i]);
+ }
+ Free(threads);
+ }
+ UnlockList(c->ConnectingThreads);
+ ReleaseList(c->ConnectingThreads);
+ }
+
+ if (c->ConnectingSocks)
+ {
+ SOCK **socks;
+ LockList(c->ConnectingSocks);
+ {
+ num = LIST_NUM(c->ConnectingSocks);
+ socks = ToArray(c->ConnectingSocks);
+ for (i = 0;i < num;i++)
+ {
+ Disconnect(socks[i]);
+ ReleaseSock(socks[i]);
+ }
+ Free(socks);
+ }
+ UnlockList(c->ConnectingSocks);
+ ReleaseList(c->ConnectingSocks);
+ }
+
+ if (c->RecvBuf)
+ {
+ Free(c->RecvBuf);
+ }
+
+ if (c->ServerX != NULL)
+ {
+ FreeX(c->ServerX);
+ }
+
+ if (c->ClientX != NULL)
+ {
+ FreeX(c->ClientX);
+ }
+
+ ReleaseQueue(c->ReceivedBlocks);
+ ReleaseQueue(c->SendBlocks);
+ ReleaseQueue(c->SendBlocks2);
+
+ DeleteCounter(c->CurrentNumConnection);
+
+ if (c->CipherName != NULL)
+ {
+ Free(c->CipherName);
+ }
+
+ Free(c);
+}
+
+// Release of the connection
+void ReleaseConnection(CONNECTION *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ if (Release(c->ref) == 0)
+ {
+ CleanupConnection(c);
+ }
+}
+
+// Comparison of connection
+int CompareConnection(void *p1, void *p2)
+{
+ CONNECTION *c1, *c2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ c1 = *(CONNECTION **)p1;
+ c2 = *(CONNECTION **)p2;
+ if (c1 == NULL || c2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(c1->Name, c2->Name);
+}
+
+// Creating a server connection
+CONNECTION *NewServerConnection(CEDAR *cedar, SOCK *s, THREAD *t)
+{
+ CONNECTION *c;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ c = ZeroMalloc(sizeof(CONNECTION));
+ c->ConnectedTick = Tick64();
+ c->lock = NewLock();
+ c->ref = NewRef();
+ c->Cedar = cedar;
+ AddRef(c->Cedar->ref);
+ c->Protocol = CONNECTION_TCP;
+ c->Type = CONNECTION_TYPE_INIT;
+ c->FirstSock = s;
+ if (s != NULL)
+ {
+ AddRef(c->FirstSock->ref);
+ Copy(&c->ClientIp, &s->RemoteIP, sizeof(IP));
+ StrCpy(c->ClientHostname, sizeof(c->ClientHostname), s->RemoteHostname);
+ }
+ c->Tcp = ZeroMalloc(sizeof(TCP));
+ c->Tcp->TcpSockList = NewList(NULL);
+ c->ServerMode = true;
+ c->Status = CONNECTION_STATUS_ACCEPTED;
+ c->Name = CopyStr("INITING");
+ c->Thread = t;
+ AddRef(t->ref);
+ c->CurrentNumConnection = NewCounter();
+ Inc(c->CurrentNumConnection);
+
+ c->ServerVer = cedar->Version;
+ c->ServerBuild = cedar->Build;
+ StrCpy(c->ServerStr, sizeof(c->ServerStr), cedar->ServerStr);
+ GetServerProductName(cedar->Server, c->ServerStr, sizeof(c->ServerStr));
+
+ if (s != NULL && s->RemoteX != NULL)
+ {
+ c->ServerX = CloneX(s->RemoteX);
+ }
+
+ if (s != NULL && s->Type == SOCK_INPROC)
+ {
+ // In-process socket
+ c->IsInProc = true;
+ }
+
+ // Creating a Queue
+ c->ReceivedBlocks = NewQueue();
+ c->SendBlocks = NewQueue();
+ c->SendBlocks2 = NewQueue();
+
+ return c;
+}
+
+// Creating a Client Connection
+CONNECTION *NewClientConnection(SESSION *s)
+{
+ return NewClientConnectionEx(s, NULL, 0, 0);
+}
+CONNECTION *NewClientConnectionEx(SESSION *s, char *client_str, UINT client_ver, UINT client_build)
+{
+ CONNECTION *c;
+
+ // Initialization of CONNECTION object
+ c = ZeroMalloc(sizeof(CONNECTION));
+ c->ConnectedTick = Tick64();
+ c->lock = NewLock();
+ c->ref = NewRef();
+ c->Cedar = s->Cedar;
+ AddRef(c->Cedar->ref);
+ c->Protocol = CONNECTION_TCP;
+ c->Tcp = ZeroMalloc(sizeof(TCP));
+ c->Tcp->TcpSockList = NewList(NULL);
+ c->ServerMode = false;
+ c->Status = CONNECTION_STATUS_CONNECTING;
+ c->Name = CopyStr("CLIENT_CONNECTION");
+ c->Session = s;
+ c->CurrentNumConnection = NewCounter();
+ c->LastCounterResetTick = Tick64();
+ Inc(c->CurrentNumConnection);
+
+ c->ConnectingThreads = NewList(NULL);
+ c->ConnectingSocks = NewList(NULL);
+
+ if (client_str == NULL)
+ {
+ c->ClientVer = s->Cedar->Version;
+ c->ClientBuild = s->Cedar->Build;
+
+ if (c->Session->VirtualHost == false)
+ {
+ if (c->Session->LinkModeClient == false)
+ {
+ StrCpy(c->ClientStr, sizeof(c->ClientStr), CEDAR_CLIENT_STR);
+ }
+ else
+ {
+ StrCpy(c->ClientStr, sizeof(c->ClientStr), CEDAR_SERVER_LINK_STR);
+ }
+ }
+ else
+ {
+ StrCpy(c->ClientStr, sizeof(c->ClientStr), CEDAR_ROUTER_STR);
+ }
+ }
+ else
+ {
+ c->ClientVer = client_ver;
+ c->ClientBuild = client_build;
+ StrCpy(c->ClientStr, sizeof(c->ClientStr), client_str);
+ }
+
+ // Server name and port number
+ StrCpy(c->ServerName, sizeof(c->ServerName), s->ClientOption->Hostname);
+ c->ServerPort = s->ClientOption->Port;
+
+ // TLS 1.0 using flag
+ c->DontUseTls1 = s->ClientOption->NoTls1;
+
+ // Create queues
+ c->ReceivedBlocks = NewQueue();
+ c->SendBlocks = NewQueue();
+ c->SendBlocks2 = NewQueue();
+
+ return c;
+}
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Connection.h b/src/Cedar/Connection.h
new file mode 100644
index 00000000..b83c3188
--- /dev/null
+++ b/src/Cedar/Connection.h
@@ -0,0 +1,341 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Connection.h
+// Header of Connection.c
+
+#ifndef CONNECTION_H
+#define CONNECTION_H
+
+// Magic number indicating that the packet is compressed
+#define CONNECTION_BULK_COMPRESS_SIGNATURE 0xDEADBEEFCAFEFACEULL
+
+#define KEEP_ALIVE_STRING "Internet Connection Keep Alive Packet"
+
+// KEEP CONNECT structure
+struct KEEP
+{
+ LOCK *lock; // Lock
+ bool Server; // Server mode
+ volatile bool Halt; // Stop flag
+ bool Enable; // Enable flag
+ char ServerName[MAX_HOST_NAME_LEN + 1]; // Server name
+ UINT ServerPort; // Server port number
+ bool UdpMode; // UDP mode
+ UINT Interval; // Packet transmission interval
+ THREAD *Thread; // Connection thread
+ EVENT *HaltEvent; // Stop event
+ CANCEL *Cancel; // Cancel
+};
+
+// SECURE_SIGN Structure
+struct SECURE_SIGN
+{
+ char SecurePublicCertName[MAX_SECURE_DEVICE_FILE_LEN + 1]; // Secure device certificate name
+ char SecurePrivateKeyName[MAX_SECURE_DEVICE_FILE_LEN + 1]; // Secure device secret key name
+ X *ClientCert; // Client certificate
+ UCHAR Random[SHA1_SIZE]; // Random value for signature
+ UCHAR Signature[128]; // Signed data
+ UINT UseSecureDeviceId;
+ UINT BitmapId; // Bitmap ID
+};
+
+// Function type declaration
+typedef bool (CHECK_CERT_PROC)(SESSION *s, CONNECTION *c, X *server_x, bool *expired);
+typedef bool (SECURE_SIGN_PROC)(SESSION *s, CONNECTION *c, SECURE_SIGN *sign);
+
+// RC4 key pair
+struct RC4_KEY_PAIR
+{
+ UCHAR ServerToClientKey[16];
+ UCHAR ClientToServerKey[16];
+};
+
+// Client Options
+struct CLIENT_OPTION
+{
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Connection setting name
+ char Hostname[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT Port; // Port number
+ UINT PortUDP; // UDP port number (0: Use only TCP)
+ UINT ProxyType; // Type of proxy
+ char ProxyName[MAX_HOST_NAME_LEN + 1]; // Proxy server name
+ UINT ProxyPort; // Port number of the proxy server
+ char ProxyUsername[MAX_PROXY_USERNAME_LEN + 1]; // Maximum user name length
+ char ProxyPassword[MAX_PROXY_PASSWORD_LEN + 1]; // Maximum password length
+ UINT NumRetry; // Automatic retries
+ UINT RetryInterval; // Retry interval
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB name
+ UINT MaxConnection; // Maximum number of concurrent TCP connections
+ bool UseEncrypt; // Use encrypted communication
+ bool UseCompress; // Use data compression
+ bool HalfConnection; // Use half connection in TCP
+ bool NoRoutingTracking; // Disable the routing tracking
+ char DeviceName[MAX_DEVICE_NAME_LEN + 1]; // VLAN device name
+ UINT AdditionalConnectionInterval; // Connection attempt interval when additional connection establish
+ UINT ConnectionDisconnectSpan; // Disconnection interval
+ bool HideStatusWindow; // Hide the status window
+ bool HideNicInfoWindow; // Hide the NIC status window
+ bool RequireMonitorMode; // Monitor port mode
+ bool RequireBridgeRoutingMode; // Bridge or routing mode
+ bool DisableQoS; // Disable the VoIP / QoS function
+ bool FromAdminPack; // For Administration Pack
+ bool NoTls1; // Do not use TLS 1.0
+ bool NoUdpAcceleration; // Do not use UDP acceleration mode
+ UCHAR HostUniqueKey[SHA1_SIZE]; // Host unique key
+};
+
+// Client authentication data
+struct CLIENT_AUTH
+{
+ UINT AuthType; // Authentication type
+ char Username[MAX_USERNAME_LEN + 1]; // User name
+ UCHAR HashedPassword[SHA1_SIZE]; // Hashed passwords
+ char PlainPassword[MAX_PASSWORD_LEN + 1]; // Password
+ X *ClientX; // Client certificate
+ K *ClientK; // Client private key
+ char SecurePublicCertName[MAX_SECURE_DEVICE_FILE_LEN + 1]; // Secure device certificate name
+ char SecurePrivateKeyName[MAX_SECURE_DEVICE_FILE_LEN + 1]; // Secure device secret key name
+ CHECK_CERT_PROC *CheckCertProc; // Server certificate confirmation procedure
+ SECURE_SIGN_PROC *SecureSignProc; // Security signing procedure
+};
+
+// TCP socket data structure
+struct TCPSOCK
+{
+ SOCK *Sock; // Socket
+ FIFO *RecvFifo; // Reception buffer
+ FIFO *SendFifo; // Transmission buffer
+ UINT Mode; // Read mode
+ UINT WantSize; // Requested data size
+ UINT NextBlockNum; // Total number of blocks that can be read next
+ UINT NextBlockSize; // Block size that is planned to read next
+ UINT CurrentPacketNum; // Current packet number
+ UINT64 LastCommTime; // Last communicated time
+ UINT64 LastRecvTime; // Time the last data received
+ UINT LateCount; // The number of delay occurences
+ UINT Direction; // Direction
+ UINT64 NextKeepAliveTime; // Next time to send a KeepAlive packet
+ RC4_KEY_PAIR Rc4KeyPair; // RC4 key pair
+ CRYPT *SendKey; // Transmission key
+ CRYPT *RecvKey; // Reception key
+ UINT64 DisconnectTick; // Time to disconnect this connection
+ UINT64 EstablishedTick; // Establishment time
+};
+
+// TCP communication data structure
+struct TCP
+{
+ LIST *TcpSockList; // TCP socket list
+};
+
+// UDP communication data structure
+struct UDP
+{
+ SOCK *s; // UDP socket (for transmission)
+ IP ip; // Destination IP address
+ UINT port; // Destination port number
+ UINT64 NextKeepAliveTime; // Next time to send a KeepAlive packet
+ UINT64 Seq; // Packet sequence number
+ UINT64 RecvSeq;
+ QUEUE *BufferQueue; // Queue of buffer to be sent
+};
+
+// Data block
+struct BLOCK
+{
+ BOOL Compressed; // Compression flag
+ UINT Size; // Block size
+ UINT SizeofData; // Data size
+ UCHAR *Buf; // Buffer
+ bool PriorityQoS; // Priority packet for VoIP / QoS function
+ UINT Ttl; // TTL value (Used only in ICMP NAT of Virtual.c)
+ UINT Param1; // Parameter 1
+};
+
+// Connection structure
+struct CONNECTION
+{
+ LOCK *lock; // Lock
+ REF *ref; // Reference counter
+ CEDAR *Cedar; // Cedar
+ struct SESSION *Session; // Session
+ UINT Protocol; // Protocol
+ SOCK *FirstSock; // Socket for negotiation
+ SOCK *TubeSock; // Socket for in-process communication
+ TCP *Tcp; // TCP communication data structure
+ UDP *Udp; // UDP communication data structure
+ bool ServerMode; // Server mode
+ UINT Status; // Status
+ char *Name; // Connection name
+ THREAD *Thread; // Thread
+ volatile bool Halt; // Stop flag
+ UCHAR Random[SHA1_SIZE]; // Random number for Authentication
+ UINT ServerVer; // Server version
+ UINT ServerBuild; // Server build number
+ UINT ClientVer; // Client version
+ UINT ClientBuild; // Client build number
+ char ServerStr[MAX_SERVER_STR_LEN + 1]; // Server string
+ char ClientStr[MAX_CLIENT_STR_LEN + 1]; // Client string
+ UINT Err; // Error value
+ bool ClientConnectError_NoSavePassword; // Don't save the password for the specified user name
+ QUEUE *ReceivedBlocks; // Block queue that is received
+ QUEUE *SendBlocks; // Block queue planned to be sent
+ QUEUE *SendBlocks2; // Send queue (high priority)
+ COUNTER *CurrentNumConnection; // Counter of the number of current connections
+ LIST *ConnectingThreads; // List of connected threads
+ LIST *ConnectingSocks; // List of the connected sockets
+ bool flag1; // Flag 1
+ UCHAR *RecvBuf; // Receive buffer
+ char ServerName[MAX_HOST_NAME_LEN + 1]; // Server name
+ UINT ServerPort; // Port number
+ bool RestoreServerNameAndPort; // Flag to restore the server name and port number to original
+ bool UseTicket; // Ticket using flag
+ UCHAR Ticket[SHA1_SIZE]; // Ticket
+ UINT CurrentSendQueueSize; // Total size of the transmission queue
+ X *ServerX; // Server certificate
+ X *ClientX; // Client certificate
+ char *CipherName; // Encryption algorithm name
+ UINT64 ConnectedTick; // Time it is connected
+ IP ClientIp; // Client IP address
+ char ClientHostname[MAX_HOST_NAME_LEN + 1]; // Client host name
+ UINT Type; // Type
+ bool DontUseTls1; // Do not use TLS 1.0
+ void *hWndForUI; // Parent window
+ bool IsInProc; // In-process
+ char InProcPrefix[64]; // Prefix
+ UINT AdditionalConnectionFailedCounter; // Additional connection failure counter
+ UINT64 LastCounterResetTick; // Time the counter was reset finally
+ bool WasSstp; // Processed the SSTP
+ bool WasDatProxy; // DAT proxy processed
+ UCHAR CToken_Hash[SHA1_SIZE]; // CTOKEN_HASH
+};
+
+
+
+// Function prototypes
+
+CONNECTION *NewClientConnection(SESSION *s);
+CONNECTION *NewClientConnectionEx(SESSION *s, char *client_str, UINT client_ver, UINT client_build);
+CONNECTION *NewServerConnection(CEDAR *cedar, SOCK *s, THREAD *t);
+void ReleaseConnection(CONNECTION *c);
+void CleanupConnection(CONNECTION *c);
+int CompareConnection(void *p1, void *p2);
+void StopConnection(CONNECTION *c, bool no_wait);
+void ConnectionAccept(CONNECTION *c);
+void StartTunnelingMode(CONNECTION *c);
+void EndTunnelingMode(CONNECTION *c);
+void DisconnectTcpSockets(CONNECTION *c);
+void ConnectionReceive(CONNECTION *c, CANCEL *c1, CANCEL *c2);
+void ConnectionSend(CONNECTION *c);
+TCPSOCK *NewTcpSock(SOCK *s);
+void FreeTcpSock(TCPSOCK *ts);
+BLOCK *NewBlock(void *data, UINT size, int compress);
+void FreeBlock(BLOCK *b);
+void StopAllAdditionalConnectThread(CONNECTION *c);
+UINT GenNextKeepAliveSpan(CONNECTION *c);
+void SendKeepAlive(CONNECTION *c, TCPSOCK *ts);
+void DisconnectUDPSockets(CONNECTION *c);
+void PutUDPPacketData(CONNECTION *c, void *data, UINT size);
+void SendDataWithUDP(SOCK *s, CONNECTION *c);
+void InsertReveicedBlockToQueue(CONNECTION *c, BLOCK *block);
+void InitTcpSockRc4Key(TCPSOCK *ts, bool server_mode);
+UINT TcpSockRecv(SESSION *s, TCPSOCK *ts, void *data, UINT size);
+UINT TcpSockSend(SESSION *s, TCPSOCK *ts, void *data, UINT size);
+void WriteSendFifo(SESSION *s, TCPSOCK *ts, void *data, UINT size);
+void WriteRecvFifo(SESSION *s, TCPSOCK *ts, void *data, UINT size);
+CLIENT_AUTH *CopyClientAuth(CLIENT_AUTH *a);
+BUF *NewKeepPacket(bool server_mode);
+void KeepThread(THREAD *thread, void *param);
+KEEP *StartKeep();
+void StopKeep(KEEP *k);
+void InRpcSecureSign(SECURE_SIGN *t, PACK *p);
+void OutRpcSecureSign(PACK *p, SECURE_SIGN *t);
+void FreeRpcSecureSign(SECURE_SIGN *t);
+void NormalizeEthMtu(BRIDGE *b, CONNECTION *c, UINT packet_size);
+UINT GetMachineRand();
+
+
+
+#endif // CONNECTION_H
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Console.c b/src/Cedar/Console.c
new file mode 100644
index 00000000..9c887feb
--- /dev/null
+++ b/src/Cedar/Console.c
@@ -0,0 +1,2510 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Console.c
+// Console Service
+
+#include "CedarPch.h"
+
+
+// Display the help for the command
+void PrintCmdHelp(CONSOLE *c, char *cmd_name, TOKEN_LIST *param_list)
+{
+ wchar_t tmp[MAX_SIZE];
+ wchar_t *buf;
+ UINT buf_size;
+ wchar_t *description, *args, *help;
+ UNI_TOKEN_LIST *t;
+ UINT width;
+ UINT i;
+ char *space;
+ // Validate arguments
+ if (c == NULL || cmd_name == NULL || param_list == NULL)
+ {
+ return;
+ }
+
+ width = GetConsoleWidth(c) - 2;
+
+ buf_size = sizeof(wchar_t) * (width + 32);
+ buf = Malloc(buf_size);
+
+ GetCommandHelpStr(cmd_name, &description, &args, &help);
+
+ space = MakeCharArray(' ', 2);
+
+ // Title
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_HELP_TITLE"), cmd_name);
+ c->Write(c, tmp);
+ c->Write(c, L"");
+
+ // Purpose
+ c->Write(c, _UU("CMD_HELP_DESCRIPTION"));
+ t = SeparateStringByWidth(description, width - 2);
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ UniFormat(buf, buf_size, L"%S%s", space, t->Token[i]);
+ c->Write(c, buf);
+ }
+ UniFreeToken(t);
+ c->Write(c, L"");
+
+ // Description
+ c->Write(c, _UU("CMD_HELP_HELP"));
+ t = SeparateStringByWidth(help, width - 2);
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ UniFormat(buf, buf_size, L"%S%s", space, t->Token[i]);
+ c->Write(c, buf);
+ }
+ UniFreeToken(t);
+ c->Write(c, L"");
+
+ // Usage
+ c->Write(c, _UU("CMD_HELP_USAGE"));
+ t = SeparateStringByWidth(args, width - 2);
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ UniFormat(buf, buf_size, L"%S%s", space, t->Token[i]);
+ c->Write(c, buf);
+ }
+ UniFreeToken(t);
+
+ // Arguments
+ if (param_list->NumTokens >= 1)
+ {
+ c->Write(c, L"");
+ c->Write(c, _UU("CMD_HELP_ARGS"));
+ PrintCandidateHelp(c, cmd_name, param_list, 2);
+ }
+
+ Free(space);
+
+ Free(buf);
+}
+
+// Evaluate whether it is SafeStr
+bool CmdEvalSafe(CONSOLE *c, wchar_t *str, void *param)
+{
+ wchar_t *p = (param == NULL) ? _UU("CMD_EVAL_SAFE") : (wchar_t *)param;
+
+ if (IsSafeUniStr(str))
+ {
+ return true;
+ }
+
+ c->Write(c, p);
+
+ return false;
+}
+
+// String input prompt
+wchar_t *CmdPrompt(CONSOLE *c, void *param)
+{
+ wchar_t *p = (param == NULL) ? _UU("CMD_PROMPT") : (wchar_t *)param;
+
+ return c->ReadLine(c, p, true);
+}
+
+// Evaluation whether the specified file exists
+bool CmdEvalIsFile(CONSOLE *c, wchar_t *str, void *param)
+{
+ wchar_t tmp[MAX_PATH];
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniStrCpy(tmp, sizeof(tmp), str);
+
+ if (IsEmptyUniStr(tmp))
+ {
+ c->Write(c, _UU("CMD_FILE_NAME_EMPTY"));
+ return false;
+ }
+
+ if (IsFileExistsW(tmp) == false)
+ {
+ wchar_t tmp2[MAX_SIZE];
+
+ UniFormat(tmp2, sizeof(tmp2), _UU("CMD_FILE_NOT_FOUND"), tmp);
+ c->Write(c, tmp2);
+
+ return false;
+ }
+
+ return true;
+}
+
+// Evaluation of integer
+bool CmdEvalInt1(CONSOLE *c, wchar_t *str, void *param)
+{
+ wchar_t *p = (param == NULL) ? _UU("CMD_EVAL_INT") : (wchar_t *)param;
+
+ if (UniToInt(str) == 0)
+ {
+ c->Write(c, p);
+
+ return false;
+ }
+
+ return true;
+}
+
+// Evaluation of the parameters that a blank cannot be specified to
+bool CmdEvalNotEmpty(CONSOLE *c, wchar_t *str, void *param)
+{
+ wchar_t *p = (param == NULL) ? _UU("CMD_EVAL_NOT_EMPTY") : (wchar_t *)param;
+
+ if (UniIsEmptyStr(str) == false)
+ {
+ return true;
+ }
+
+ c->Write(c, p);
+
+ return false;
+}
+
+// Evaluation function for minimum / maximum value of the parameter
+bool CmdEvalMinMax(CONSOLE *c, wchar_t *str, void *param)
+{
+ CMD_EVAL_MIN_MAX *e;
+ wchar_t *tag;
+ UINT v;
+ // Validate arguments
+ if (param == NULL)
+ {
+ return false;
+ }
+
+ e = (CMD_EVAL_MIN_MAX *)param;
+
+ if (e->StrName == NULL)
+ {
+ tag = _UU("CMD_EVAL_MIN_MAX");
+ }
+ else
+ {
+ tag = _UU(e->StrName);
+ }
+
+ v = UniToInt(str);
+
+ if (v >= e->MinValue && v <= e->MaxValue)
+ {
+ return true;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), tag, e->MinValue, e->MaxValue);
+ c->Write(c, tmp);
+
+ return false;
+ }
+}
+
+// Get the help string of command
+void GetCommandHelpStr(char *command_name, wchar_t **description, wchar_t **args, wchar_t **help)
+{
+ char tmp1[128], tmp2[128], tmp3[128];
+
+ Format(tmp1, sizeof(tmp1), "CMD_%s", command_name);
+ Format(tmp2, sizeof(tmp2), "CMD_%s_ARGS", command_name);
+ Format(tmp3, sizeof(tmp3), "CMD_%s_HELP", command_name);
+
+ if (description != NULL)
+ {
+ *description = _UU(tmp1);
+ if (UniIsEmptyStr(*description))
+ {
+ *description = _UU("CMD_UNKNOWM");
+ }
+ }
+
+ if (args != NULL)
+ {
+ *args = _UU(tmp2);
+ if (UniIsEmptyStr(*args))
+ {
+ *args = _UU("CMD_UNKNOWN_ARGS");
+ }
+ }
+
+ if (help != NULL)
+ {
+ *help = _UU(tmp3);
+ if (UniIsEmptyStr(*help))
+ {
+ *help = _UU("CMD_UNKNOWN_HELP");
+ }
+ }
+}
+
+// Get the help string for parameter
+void GetCommandParamHelpStr(char *command_name, char *param_name, wchar_t **description)
+{
+ char tmp[160];
+ if (description == NULL)
+ {
+ return;
+ }
+
+ Format(tmp, sizeof(tmp), "CMD_%s_%s", command_name, param_name);
+
+ *description = _UU(tmp);
+
+ if (UniIsEmptyStr(*description))
+ {
+ *description = _UU("CMD_UNKNOWN_PARAM");
+ }
+}
+
+// String comparison function
+int CompareCandidateStr(void *p1, void *p2)
+{
+ char *s1, *s2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ s1 = *(char **)p1;
+ s2 = *(char **)p2;
+ if (s1 == NULL || s2 == NULL)
+ {
+ return 0;
+ }
+
+ if (s1[0] == '[' && s2[0] != '[')
+ {
+ return -1;
+ }
+ else if (s2[0] == '[' && s1[0] != '[')
+ {
+ return 1;
+ }
+
+ return StrCmp(s1, s2);
+}
+
+// Display the help of the candidate list
+void PrintCandidateHelp(CONSOLE *c, char *cmd_name, TOKEN_LIST *candidate_list, UINT left_space)
+{
+ UINT console_width;
+ UINT max_keyword_width;
+ LIST *o;
+ UINT i;
+ wchar_t *tmpbuf;
+ UINT tmpbuf_size;
+ char *left_space_array;
+ char *max_space_array;
+ // Validate arguments
+ if (c == NULL || candidate_list == NULL)
+ {
+ return;
+ }
+
+ // Get the width of the screen
+ console_width = GetConsoleWidth(c) - 1;
+
+ tmpbuf_size = sizeof(wchar_t) * (console_width + 32);
+ tmpbuf = Malloc(tmpbuf_size);
+
+ left_space_array = MakeCharArray(' ', left_space);
+
+ // Sort and enlist the command name
+ // no need to sort the parameter name
+ o = NewListFast(cmd_name == NULL ? CompareCandidateStr : NULL);
+
+ max_keyword_width = 0;
+
+ for (i = 0;i < candidate_list->NumTokens;i++)
+ {
+ UINT keyword_width;
+
+ // Get the width of each keyword
+ Insert(o, candidate_list->Token[i]);
+
+ keyword_width = StrWidth(candidate_list->Token[i]);
+ if (cmd_name != NULL)
+ {
+ if (candidate_list->Token[i][0] != '[')
+ {
+ keyword_width += 1;
+ }
+ else
+ {
+ keyword_width -= 2;
+ }
+ }
+
+ max_keyword_width = MAX(max_keyword_width, keyword_width);
+ }
+
+ max_space_array = MakeCharArray(' ', max_keyword_width);
+
+ // Display the candidate
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ char tmp[128];
+ char *name = LIST_DATA(o, i);
+ UNI_TOKEN_LIST *t;
+ wchar_t *help;
+ UINT j;
+ UINT keyword_start_width = left_space;
+ UINT descript_start_width = left_space + max_keyword_width + 1;
+ UINT descript_width;
+ char *space;
+
+ if (console_width >= (descript_start_width + 5))
+ {
+ descript_width = console_width - descript_start_width - 3;
+ }
+ else
+ {
+ descript_width = 2;
+ }
+
+ // Generate the name
+ if (cmd_name != NULL && name[0] != '[')
+ {
+ // Prepend a "/" in the case of a parameter
+ Format(tmp, sizeof(tmp), "/%s", name);
+ }
+ else
+ {
+ // Use the characters as it is in the case of a command name
+ if (cmd_name == NULL)
+ {
+ StrCpy(tmp, sizeof(tmp), name);
+ }
+ else
+ {
+ StrCpy(tmp, sizeof(tmp), name + 1);
+ if (StrLen(tmp) >= 1)
+ {
+ tmp[StrLen(tmp) - 1] = 0;
+ }
+ }
+ }
+
+ // Get the help string
+ if (cmd_name == NULL)
+ {
+ GetCommandHelpStr(name, &help, NULL, NULL);
+ }
+ else
+ {
+ GetCommandParamHelpStr(cmd_name, name, &help);
+ }
+
+ space = MakeCharArray(' ', max_keyword_width - StrWidth(name) - (cmd_name == NULL ? 0 : (name[0] != '[' ? 1 : -2)));
+
+ t = SeparateStringByWidth(help, descript_width);
+
+ for (j = 0;j < t->NumTokens;j++)
+ {
+ if (j == 0)
+ {
+ UniFormat(tmpbuf, tmpbuf_size, L"%S%S%S - %s",
+ left_space_array, tmp, space, t->Token[j]);
+ }
+ else
+ {
+ UniFormat(tmpbuf, tmpbuf_size, L"%S%S %s",
+ left_space_array, max_space_array, t->Token[j]);
+ }
+
+ c->Write(c, tmpbuf);
+ }
+
+ Free(space);
+
+ UniFreeToken(t);
+ }
+
+ ReleaseList(o);
+
+ Free(max_space_array);
+ Free(tmpbuf);
+ Free(left_space_array);
+}
+
+// Acquisition whether word characters
+bool IsWordChar(wchar_t c)
+{
+ if (c >= L'a' && c <= 'z')
+ {
+ return true;
+ }
+ if (c >= L'A' && c <= 'Z')
+ {
+ return true;
+ }
+ if (c >= L'0' && c <= '9')
+ {
+ return true;
+ }
+ if (c == L'_')
+ {
+ return true;
+ }
+ if (c == L'.')
+ {
+ return true;
+ }
+ if (c == L'\"')
+ {
+ return true;
+ }
+ if (c == L'\'')
+ {
+ return true;
+ }
+ if (c == L',')
+ {
+ return true;
+ }
+ if (c == L')')
+ {
+ return true;
+ }
+ if (c == L']')
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Get the character width of the word that comes next
+UINT GetNextWordWidth(wchar_t *str)
+{
+ UINT i;
+ UINT ret;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return 0;
+ }
+
+ ret = 0;
+
+ for (i = 0;;i++)
+ {
+ wchar_t c = str[i];
+
+ if (c == 0)
+ {
+ break;
+ }
+
+ if (IsWordChar(c) == false)
+ {
+ break;
+ }
+
+ ret++;
+ }
+
+ return ret;
+}
+
+// Split a string into specified width
+UNI_TOKEN_LIST *SeparateStringByWidth(wchar_t *str, UINT width)
+{
+ UINT wp;
+ wchar_t *tmp;
+ UINT len, i;
+ LIST *o;
+ UNI_TOKEN_LIST *ret;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return UniNullToken();
+ }
+ if (width == 0)
+ {
+ width = 1;
+ }
+
+ o = NewListFast(NULL);
+
+ len = UniStrLen(str);
+ tmp = ZeroMalloc(sizeof(wchar_t) * (len + 32));
+ wp = 0;
+
+ for (i = 0;i < (len + 1);i++)
+ {
+ wchar_t c = str[i];
+ UINT next_word_width;
+ UINT remain_width;
+
+ switch (c)
+ {
+ case 0:
+ case L'\r':
+ case L'\n':
+ if (c == L'\r')
+ {
+ if (str[i + 1] == L'\n')
+ {
+ i++;
+ }
+ }
+
+ tmp[wp++] = 0;
+ wp = 0;
+
+ Insert(o, UniCopyStr(tmp));
+ break;
+
+ default:
+ next_word_width = GetNextWordWidth(&str[i]);
+ remain_width = (width - UniStrWidth(tmp));
+
+ if ((remain_width >= 1) && (next_word_width > remain_width) && (next_word_width <= width))
+ {
+ tmp[wp++] = 0;
+ wp = 0;
+
+ Insert(o, UniCopyStr(tmp));
+ }
+
+ tmp[wp++] = c;
+ tmp[wp] = 0;
+ if (UniStrWidth(tmp) >= width)
+ {
+ tmp[wp++] = 0;
+ wp = 0;
+
+ Insert(o, UniCopyStr(tmp));
+ }
+ break;
+ }
+ }
+
+ if (LIST_NUM(o) == 0)
+ {
+ Insert(o, CopyUniStr(L""));
+ }
+
+ ret = ZeroMalloc(sizeof(UNI_TOKEN_LIST));
+ ret->NumTokens = LIST_NUM(o);
+ ret->Token = ZeroMalloc(sizeof(wchar_t *) * ret->NumTokens);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ wchar_t *s = LIST_DATA(o, i);
+
+ UniTrimLeft(s);
+
+ ret->Token[i] = s;
+ }
+
+ ReleaseList(o);
+ Free(tmp);
+
+ return ret;
+}
+
+// Check whether the specified string means 'help'
+bool IsHelpStr(char *str)
+{
+ // Validate arguments
+ if (str == NULL)
+ {
+ return false;
+ }
+
+ if (StrCmpi(str, "help") == 0 || StrCmpi(str, "?") == 0 ||
+ StrCmpi(str, "man") == 0 || StrCmpi(str, "/man") == 0 ||
+ StrCmpi(str, "-man") == 0 || StrCmpi(str, "--man") == 0 ||
+ StrCmpi(str, "/help") == 0 || StrCmpi(str, "/?") == 0 ||
+ StrCmpi(str, "-help") == 0 || StrCmpi(str, "-?") == 0 ||
+ StrCmpi(str, "/h") == 0 || StrCmpi(str, "--help") == 0 ||
+ StrCmpi(str, "--?") == 0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Execution of the command
+bool DispatchNextCmd(CONSOLE *c, char *prompt, CMD cmd[], UINT num_cmd, void *param)
+{
+ return DispatchNextCmdEx(c, NULL, prompt, cmd, num_cmd, param);
+}
+bool DispatchNextCmdEx(CONSOLE *c, wchar_t *exec_command, char *prompt, CMD cmd[], UINT num_cmd, void *param)
+{
+ wchar_t *str;
+ wchar_t *tmp;
+ char *cmd_name;
+ bool b_exit = false;
+ wchar_t *cmd_param;
+ UINT ret = ERR_NO_ERROR;
+ TOKEN_LIST *t;
+ TOKEN_LIST *candidate;
+ bool no_end_crlf = false;
+ UINT i;
+ // Validate arguments
+ if (c == NULL || (num_cmd >= 1 && cmd == NULL))
+ {
+ return false;
+ }
+
+ if (exec_command == NULL)
+ {
+ // Show the prompt
+RETRY:
+ tmp = CopyStrToUni(prompt);
+ str = c->ReadLine(c, tmp, false);
+ Free(tmp);
+
+ if (str != NULL && IsEmptyUniStr(str))
+ {
+ Free(str);
+ goto RETRY;
+ }
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ // Use exec_command
+ if (UniStartWith(exec_command, L"vpncmd") == false)
+ {
+ if (prompt != NULL)
+ {
+ if (c->ConsoleType != CONSOLE_CSV)
+ {
+ UniFormat(tmp, sizeof(tmp), L"%S%s", prompt, exec_command);
+ c->Write(c, tmp);
+ }
+ }
+ }
+ str = CopyUniStr(exec_command);
+ }
+
+ if (str == NULL)
+ {
+ // User canceled
+ return false;
+ }
+
+ UniTrimCrlf(str);
+ UniTrim(str);
+
+ if (UniIsEmptyStr(str))
+ {
+ // Do Nothing
+ Free(str);
+ return true;
+ }
+
+ // Divide into command name and parameter
+ if (SeparateCommandAndParam(str, &cmd_name, &cmd_param) == false)
+ {
+ // Do Nothing
+ Free(str);
+ return true;
+ }
+
+ if (StrLen(cmd_name) >= 2 && cmd_name[0] == '?' && cmd_name[1] != '?')
+ {
+ char tmp[MAX_SIZE];
+ wchar_t *s;
+
+ StrCpy(tmp, sizeof(tmp), cmd_name + 1);
+ StrCpy(cmd_name, 0, tmp);
+
+ s = UniCopyStr(L"/?");
+ Free(cmd_param);
+
+ cmd_param = s;
+ }
+
+ if (StrLen(cmd_name) >= 2 && EndWith(cmd_name, "?") && cmd_name[StrLen(cmd_name) - 2] != '?')
+ {
+ wchar_t *s;
+
+ cmd_name[StrLen(cmd_name) - 1] = 0;
+
+ s = UniCopyStr(L"/?");
+ Free(cmd_param);
+
+ cmd_param = s;
+ }
+
+ // Get the candidate of command
+ t = ZeroMalloc(sizeof(TOKEN_LIST));
+ t->NumTokens = num_cmd;
+ t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ t->Token[i] = CopyStr(cmd[i].Name);
+ }
+
+ if (IsHelpStr(cmd_name))
+ {
+ if (UniIsEmptyStr(cmd_param))
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ // Display the list of commands that can be used
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_HELP_1"), t->NumTokens);
+ c->Write(c, tmp);
+
+ PrintCandidateHelp(c, NULL, t, 1);
+
+ c->Write(c, L"");
+ c->Write(c, _UU("CMD_HELP_2"));
+ }
+ else
+ {
+ char *cmd_name;
+
+ // Display the help for the specified command
+ if (SeparateCommandAndParam(cmd_param, &cmd_name, NULL))
+ {
+ bool b = true;
+
+ if (IsHelpStr(cmd_name))
+ {
+ b = false;
+ }
+
+ if (b)
+ {
+ wchar_t str[MAX_SIZE];
+
+ UniFormat(str, sizeof(str), L"%S /help", cmd_name);
+ DispatchNextCmdEx(c, str, NULL, cmd, num_cmd, param);
+ no_end_crlf = true;
+ }
+
+ Free(cmd_name);
+ }
+ }
+ }
+ else if (StrCmpi(cmd_name, "exit") == 0 || StrCmpi(cmd_name, "quit") == 0)
+ {
+ // Exit
+ b_exit = true;
+ }
+ else
+ {
+ candidate = GetRealnameCandidate(cmd_name, t);
+
+ if (candidate == NULL || candidate->NumTokens == 0)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ // No candidate
+ UniFormat(tmp, sizeof(tmp), _UU("CON_UNKNOWN_CMD"), cmd_name);
+ c->Write(c, tmp);
+
+ c->RetCode = ERR_BAD_COMMAND_OR_PARAM;
+ }
+ else if (candidate->NumTokens >= 2)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ // There is more than one candidate
+ UniFormat(tmp, sizeof(tmp), _UU("CON_AMBIGIOUS_CMD"), cmd_name);
+ c->Write(c, tmp);
+ c->Write(c, _UU("CON_AMBIGIOUS_CMD_1"));
+ PrintCandidateHelp(c, NULL, candidate, 1);
+ c->Write(c, _UU("CON_AMBIGIOUS_CMD_2"));
+
+ c->RetCode = ERR_BAD_COMMAND_OR_PARAM;
+ }
+ else
+ {
+ char *real_cmd_name;
+ UINT i;
+
+ // The candidate was shortlisted to one
+ real_cmd_name = candidate->Token[0];
+
+ for (i = 0;i < num_cmd;i++)
+ {
+ if (StrCmpi(cmd[i].Name, real_cmd_name) == 0)
+ {
+ if (cmd[i].Proc != NULL)
+ {
+ // Show the description of the command if it isn't in CSV mode
+ if(c->ConsoleType != CONSOLE_CSV)
+ {
+ wchar_t tmp[256];
+ wchar_t *note;
+
+ GetCommandHelpStr(cmd[i].Name, &note, NULL, NULL);
+ UniFormat(tmp, sizeof(tmp), _UU("CMD_EXEC_MSG_NAME"), cmd[i].Name, note);
+ c->Write(c, tmp);
+ }
+
+ // Call the procedure of the command
+ ret = cmd[i].Proc(c, cmd[i].Name, cmd_param, param);
+
+ if (ret == INFINITE)
+ {
+ // Exit command
+ b_exit = true;
+ }
+ else
+ {
+ c->RetCode = ret;
+ }
+ }
+ }
+ }
+ }
+
+ FreeToken(candidate);
+ }
+
+ FreeToken(t);
+ Free(str);
+ Free(cmd_name);
+ Free(cmd_param);
+
+ if (no_end_crlf == false)
+ {
+ //c->Write(c, L"");
+ }
+
+ if (b_exit)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Get the width of the current console
+UINT GetConsoleWidth(CONSOLE *c)
+{
+ UINT size;
+
+ size = c->GetWidth(c);
+
+ if (size == 0)
+ {
+ size = 80;
+ }
+
+ if (size < 32)
+ {
+ size = 32;
+ }
+
+ if (size > 65536)
+ {
+ size = 65535;
+ }
+
+ return size;
+}
+
+// Separate the command line into the command and the parameters
+bool SeparateCommandAndParam(wchar_t *src, char **cmd, wchar_t **param)
+{
+ UINT i, len, wp;
+ wchar_t *tmp;
+ wchar_t *src_tmp;
+ // Validate arguments
+ if (src == NULL)
+ {
+ return false;
+ }
+ if (cmd != NULL)
+ {
+ *cmd = NULL;
+ }
+ if (param != NULL)
+ {
+ *param = NULL;
+ }
+
+ src_tmp = UniCopyStr(src);
+ UniTrimCrlf(src_tmp);
+ UniTrim(src_tmp);
+
+ len = UniStrLen(src_tmp);
+ tmp = Malloc(sizeof(wchar_t) * (len + 32));
+ wp = 0;
+
+ for (i = 0;i < (len + 1);i++)
+ {
+ wchar_t c = src_tmp[i];
+
+ switch (c)
+ {
+ case 0:
+ case L' ':
+ case L'\t':
+ tmp[wp] = 0;
+ if (UniIsEmptyStr(tmp))
+ {
+ Free(tmp);
+ Free(src_tmp);
+ return false;
+ }
+ if (cmd != NULL)
+ {
+ *cmd = CopyUniToStr(tmp);
+ Trim(*cmd);
+ }
+ goto ESCAPE;
+
+ default:
+ tmp[wp++] = c;
+ break;
+ }
+ }
+
+ESCAPE:
+ if (param != NULL)
+ {
+ *param = CopyUniStr(&src_tmp[wp]);
+ UniTrim(*param);
+ }
+
+ Free(tmp);
+ Free(src_tmp);
+
+ return true;
+}
+
+// Get the candidates list of of the real command name whose abbreviation matches to the command specified by the user
+TOKEN_LIST *GetRealnameCandidate(char *input_name, TOKEN_LIST *real_name_list)
+{
+ TOKEN_LIST *ret;
+ LIST *o;
+ UINT i;
+ bool ok = false;
+ // Validate arguments
+ if (input_name == NULL || real_name_list == NULL)
+ {
+ return NullToken();
+ }
+
+ o = NewListFast(NULL);
+
+ for (i = 0;i < real_name_list->NumTokens;i++)
+ {
+ char *name = real_name_list->Token[i];
+
+ // Search for an exact match with the highest priority first
+ if (StrCmpi(name, input_name) == 0)
+ {
+ Insert(o, name);
+ ok = true;
+ break;
+ }
+ }
+
+ if (ok == false)
+ {
+ // If there is no command to exact match, check whether it matches to a short form command
+ for (i = 0;i < real_name_list->NumTokens;i++)
+ {
+ char *name = real_name_list->Token[i];
+
+ if (IsOmissionName(input_name, name) || IsNameInRealName(input_name, name))
+ {
+ // A abbreviation is found
+ Insert(o, name);
+ ok = true;
+ }
+ }
+ }
+
+ if (ok)
+ {
+ // One or more candidate is found
+ ret = ListToTokenList(o);
+ }
+ else
+ {
+ ret = NullToken();
+ }
+
+ ReleaseList(o);
+
+ return ret;
+}
+
+// Check whether the command specified by the user is a abbreviation of existing commands
+bool IsOmissionName(char *input_name, char *real_name)
+{
+ char oname[128];
+ // Validate arguments
+ if (input_name == NULL || real_name == NULL)
+ {
+ return false;
+ }
+
+ if (IsAllUpperStr(real_name))
+ {
+ // Command of all capital letters do not take abbreviations
+ return false;
+ }
+
+ GetOmissionName(oname, sizeof(oname), real_name);
+
+ if (IsEmptyStr(oname))
+ {
+ return false;
+ }
+
+ if (StartWith(oname, input_name))
+ {
+ // Example: The oname of AccountSecureCertSet is "ascs".
+ // But if the user enters "asc", returns true
+ return true;
+ }
+
+ if (StartWith(input_name, oname))
+ {
+ // Example: When two commands AccountCreate and AccountConnect exist,
+ // if the user enter "aconnect" , only AccountConnect is true
+
+ if (EndWith(real_name, &input_name[StrLen(oname)]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Get the short name of the specified command
+void GetOmissionName(char *dst, UINT size, char *src)
+{
+ UINT i, len;
+ // Validate arguments
+ if (dst == NULL || src == NULL)
+ {
+ return;
+ }
+
+ StrCpy(dst, size, "");
+ len = StrLen(src);
+
+ for (i = 0;i < len;i++)
+ {
+ char c = src[i];
+
+ if ((c >= '0' && c <= '9') ||
+ (c >= 'A' && c <= 'Z'))
+ {
+ char tmp[2];
+ tmp[0] = c;
+ tmp[1] = 0;
+
+ StrCat(dst, size, tmp);
+ }
+ }
+}
+
+// Check whether the command specified by the user matches the existing commands
+bool IsNameInRealName(char *input_name, char *real_name)
+{
+ // Validate arguments
+ if (input_name == NULL || real_name == NULL)
+ {
+ return false;
+ }
+
+ if (StartWith(real_name, input_name))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Parse the command list
+LIST *ParseCommandList(CONSOLE *c, char *cmd_name, wchar_t *command, PARAM param[], UINT num_param)
+{
+ UINT i;
+ LIST *o;
+ bool ok = true;
+ TOKEN_LIST *param_list;
+ TOKEN_LIST *real_name_list;
+ bool help_mode = false;
+ wchar_t *tmp;
+ // Validate arguments
+ if (c == NULL || command == NULL || (num_param >= 1 && param == NULL) || cmd_name == NULL)
+ {
+ return NULL;
+ }
+
+ // Initialization
+ for (i = 0;i < num_param;i++)
+ {
+ if (IsEmptyStr(param[i].Name) == false)
+ {
+ if (param[i].Name[0] == '[')
+ {
+ param[i].Tmp = "";
+ }
+ else
+ {
+ param[i].Tmp = NULL;
+ }
+ }
+ else
+ {
+ param[i].Tmp = "";
+ }
+ }
+
+ real_name_list = ZeroMalloc(sizeof(TOKEN_LIST));
+ real_name_list->NumTokens = num_param;
+ real_name_list->Token = ZeroMalloc(sizeof(char *) * real_name_list->NumTokens);
+
+ for (i = 0;i < real_name_list->NumTokens;i++)
+ {
+ real_name_list->Token[i] = CopyStr(param[i].Name);
+ }
+
+ // Generate a list of parameter name specified by the user
+ param_list = GetCommandNameList(command);
+
+ for (i = 0;i < param_list->NumTokens;i++)
+ {
+ char *s = param_list->Token[i];
+
+ if (StrCmpi(s, "help") == 0 || StrCmpi(s, "?") == 0)
+ {
+ help_mode = true;
+ break;
+ }
+ }
+
+ tmp = ParseCommand(command, L"");
+ if (tmp != NULL)
+ {
+ if (UniStrCmpi(tmp, L"?") == 0)
+ {
+ help_mode = true;
+ }
+ Free(tmp);
+ }
+
+ if (help_mode)
+ {
+ // Show the help
+ PrintCmdHelp(c, cmd_name, real_name_list);
+ FreeToken(param_list);
+ FreeToken(real_name_list);
+ return NULL;
+ }
+
+ for (i = 0;i < param_list->NumTokens;i++)
+ {
+ // Get the corresponding commands for all parameter names which is specified by the user
+ TOKEN_LIST *candidate = GetRealnameCandidate(param_list->Token[i], real_name_list);
+
+ if (candidate != NULL && candidate->NumTokens >= 1)
+ {
+ if (candidate->NumTokens >= 2)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ // There is more than one candidate
+ UniFormat(tmp, sizeof(tmp), _UU("CON_AMBIGIOUS_PARAM"), param_list->Token[i]);
+ c->Write(c, tmp);
+ UniFormat(tmp, sizeof(tmp), _UU("CON_AMBIGIOUS_PARAM_1"), cmd_name);
+ c->Write(c, tmp);
+
+ PrintCandidateHelp(c, cmd_name, candidate, 1);
+
+ c->Write(c, _UU("CON_AMBIGIOUS_PARAM_2"));
+
+ ok = false;
+ }
+ else
+ {
+ UINT j;
+ char *real_name = candidate->Token[0];
+
+ // There is only one candidate
+ for (j = 0;j < num_param;j++)
+ {
+ if (StrCmpi(param[j].Name, real_name) == 0)
+ {
+ param[j].Tmp = param_list->Token[i];
+ }
+ }
+ }
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ // No candidate
+ UniFormat(tmp, sizeof(tmp), _UU("CON_INVALID_PARAM"), param_list->Token[i], cmd_name, cmd_name);
+ c->Write(c, tmp);
+
+ ok = false;
+ }
+
+ FreeToken(candidate);
+ }
+
+ if (ok == false)
+ {
+ FreeToken(param_list);
+ FreeToken(real_name_list);
+
+ return NULL;
+ }
+
+ // Creating a list
+ o = NewParamValueList();
+
+ // Read all the parameters of the specified name in the parameter list
+ for (i = 0;i < num_param;i++)
+ {
+ bool prompt_input_value = false;
+ PARAM *p = &param[i];
+
+ if (p->Tmp != NULL || p->PromptProc != NULL)
+ {
+ wchar_t *name = CopyStrToUni(p->Name);
+ wchar_t *tmp;
+ wchar_t *str;
+
+ if (p->Tmp != NULL)
+ {
+ tmp = CopyStrToUni(p->Tmp);
+ }
+ else
+ {
+ tmp = CopyStrToUni(p->Name);
+ }
+
+ str = ParseCommand(command, tmp);
+ Free(tmp);
+ if (str != NULL)
+ {
+ wchar_t *unistr;
+ bool ret;
+EVAL_VALUE:
+ // Reading succeeded
+ unistr = str;
+
+ if (p->EvalProc != NULL)
+ {
+ // Evaluate the value if EvalProc is specified
+ ret = p->EvalProc(c, unistr, p->EvalProcParam);
+ }
+ else
+ {
+ // Accept any value if EvalProc is not specified
+ ret = true;
+ }
+
+ if (ret == false)
+ {
+ // The specified value is invalid
+ if (p->PromptProc == NULL)
+ {
+ // Cancel
+ ok = false;
+ Free(name);
+ Free(str);
+ break;
+ }
+ else
+ {
+ // Request to re-enter
+ Free(str);
+ str = NULL;
+ goto SHOW_PROMPT;
+ }
+ }
+ else
+ {
+ PARAM_VALUE *v;
+ // Finished loading, add it to the list
+ v = ZeroMalloc(sizeof(PARAM_VALUE));
+ v->Name = CopyStr(p->Name);
+ v->StrValue = CopyUniToStr(str);
+ v->UniStrValue = CopyUniStr(str);
+ v->IntValue = ToInt(v->StrValue);
+ Insert(o, v);
+ }
+ }
+ else
+ {
+ // Failed to read. The parameter is not specified
+ if (p->PromptProc != NULL)
+ {
+ wchar_t *tmp;
+SHOW_PROMPT:
+ // Prompt because it is a mandatory parameter
+ tmp = p->PromptProc(c, p->PromptProcParam);
+ if (tmp == NULL)
+ {
+ // User canceled
+ ok = false;
+ Free(str);
+ Free(name);
+ break;
+ }
+ else
+ {
+ // Entered by the user
+ c->Write(c, L"");
+ str = tmp;
+ prompt_input_value = true;
+ goto EVAL_VALUE;
+ }
+ }
+ }
+
+ Free(str);
+ Free(name);
+ }
+ }
+
+ FreeToken(param_list);
+ FreeToken(real_name_list);
+
+ if (ok)
+ {
+ return o;
+ }
+ else
+ {
+ FreeParamValueList(o);
+ return NULL;
+ }
+}
+
+// Acquisition of [Yes] or [No]
+bool GetParamYes(LIST *o, char *name)
+{
+ char *s;
+ char tmp[64];
+ // Validate arguments
+ if (o == NULL)
+ {
+ return false;
+ }
+
+ s = GetParamStr(o, name);
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ StrCpy(tmp, sizeof(tmp), s);
+ Trim(tmp);
+
+ if (StartWith(tmp, "y"))
+ {
+ return true;
+ }
+
+ if (StartWith(tmp, "t"))
+ {
+ return true;
+ }
+
+ if (ToInt(tmp) != 0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Acquisition of parameter value Int
+UINT GetParamInt(LIST *o, char *name)
+{
+ PARAM_VALUE *v;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return 0;
+ }
+
+ v = FindParamValue(o, name);
+ if (v == NULL)
+ {
+ return 0;
+ }
+ else
+ {
+ return v->IntValue;
+ }
+}
+
+// Acquisition of parameter value Unicode string
+wchar_t *GetParamUniStr(LIST *o, char *name)
+{
+ PARAM_VALUE *v;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return NULL;
+ }
+
+ v = FindParamValue(o, name);
+ if (v == NULL)
+ {
+ return NULL;
+ }
+ else
+ {
+ return v->UniStrValue;
+ }
+}
+
+// Acquisition of the parameter value string
+char *GetParamStr(LIST *o, char *name)
+{
+ PARAM_VALUE *v;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return NULL;
+ }
+
+ v = FindParamValue(o, name);
+ if (v == NULL)
+ {
+ return NULL;
+ }
+ else
+ {
+ return v->StrValue;
+ }
+}
+
+// Acquisition of parameter value
+PARAM_VALUE *FindParamValue(LIST *o, char *name)
+{
+ PARAM_VALUE t, *ret;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return NULL;
+ }
+ if (name == NULL)
+ {
+ name = "";
+ }
+
+ Zero(&t, sizeof(t));
+ t.Name = name;
+
+ ret = Search(o, &t);
+
+ return ret;
+}
+
+// Release of the parameter value list
+void FreeParamValueList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ PARAM_VALUE *v = LIST_DATA(o, i);
+
+ Free(v->StrValue);
+ Free(v->UniStrValue);
+ Free(v->Name);
+ Free(v);
+ }
+
+ ReleaseList(o);
+}
+
+// Parameter value list sort function
+int CmpParamValue(void *p1, void *p2)
+{
+ PARAM_VALUE *v1, *v2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ v1 = *(PARAM_VALUE **)p1;
+ v2 = *(PARAM_VALUE **)p2;
+ if (v1 == NULL || v2 == NULL)
+ {
+ return 0;
+ }
+
+ if (IsEmptyStr(v1->Name) && IsEmptyStr(v2->Name))
+ {
+ return 0;
+ }
+ return StrCmpi(v1->Name, v2->Name);
+}
+
+// Generation of the parameter value list
+LIST *NewParamValueList()
+{
+ return NewListFast(CmpParamValue);
+}
+
+// Get the list of parameter names that were included in the entered command
+TOKEN_LIST *GetCommandNameList(wchar_t *str)
+{
+ TOKEN_LIST *t;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return NullToken();
+ }
+
+ Free(ParseCommandEx(str, L"dummy_str", &t));
+
+ return t;
+}
+
+// Get the commands that start with the specified name
+wchar_t *ParseCommand(wchar_t *str, wchar_t *name)
+{
+ return ParseCommandEx(str, name, NULL);
+}
+wchar_t *ParseCommandEx(wchar_t *str, wchar_t *name, TOKEN_LIST **param_list)
+{
+ UNI_TOKEN_LIST *t;
+ UINT i;
+ wchar_t *tmp;
+ wchar_t *ret = NULL;
+ LIST *o;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return NULL;
+ }
+ if (name != NULL && UniIsEmptyStr(name))
+ {
+ name = NULL;
+ }
+
+ o = NULL;
+ if (param_list != NULL)
+ {
+ o = NewListFast(CompareStr);
+ }
+
+ tmp = CopyUniStr(str);
+ UniTrim(tmp);
+
+ i = UniSearchStrEx(tmp, L"/CMD ", 0, false);
+
+ if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
+ {
+ i = INFINITE;
+ }
+ if (i == INFINITE)
+ {
+ i = UniSearchStrEx(tmp, L"/CMD\t", 0, false);
+ if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
+ {
+ i = INFINITE;
+ }
+ }
+ if (i == INFINITE)
+ {
+ i = UniSearchStrEx(tmp, L"/CMD:", 0, false);
+ if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
+ {
+ i = INFINITE;
+ }
+ }
+ if (i == INFINITE)
+ {
+ i = UniSearchStrEx(tmp, L"/CMD=", 0, false);
+ if (i != INFINITE && i >= 1 && tmp[i - 1] == L'/')
+ {
+ i = INFINITE;
+ }
+ }
+ if (i == INFINITE)
+ {
+ i = UniSearchStrEx(tmp, L"-CMD ", 0, false);
+ if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
+ {
+ i = INFINITE;
+ }
+ }
+ if (i == INFINITE)
+ {
+ i = UniSearchStrEx(tmp, L"-CMD\t", 0, false);
+ if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
+ {
+ i = INFINITE;
+ }
+ }
+ if (i == INFINITE)
+ {
+ i = UniSearchStrEx(tmp, L"-CMD:", 0, false);
+ if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
+ {
+ i = INFINITE;
+ }
+ }
+ if (i == INFINITE)
+ {
+ i = UniSearchStrEx(tmp, L"-CMD=", 0, false);
+ if (i != INFINITE && i >= 1 && tmp[i - 1] == L'-')
+ {
+ i = INFINITE;
+ }
+ }
+
+ if (i != INFINITE)
+ {
+ char *s = CopyStr("CMD");
+ if (InsertStr(o, s) == false)
+ {
+ Free(s);
+ }
+ if (UniStrCmpi(name, L"CMD") == 0)
+ {
+ ret = CopyUniStr(&str[i + 5]);
+ UniTrim(ret);
+ }
+ else
+ {
+ tmp[i] = 0;
+ }
+ }
+
+ if (ret == NULL)
+ {
+ t = UniParseCmdLine(tmp);
+
+ if (t != NULL)
+ {
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ wchar_t *token = t->Token[i];
+
+ if ((token[0] == L'-' && token[1] != L'-') ||
+ (UniStrCmpi(token, L"--help") == 0) ||
+ (token[0] == L'/' && token[1] != L'/'))
+ {
+ UINT i;
+
+ // Named parameter
+ // Examine whether there is a colon character
+
+ if (UniStrCmpi(token, L"--help") == 0)
+ {
+ token++;
+ }
+
+ i = UniSearchStrEx(token, L":", 0, false);
+ if (i == INFINITE)
+ {
+ i = UniSearchStrEx(token, L"=", 0, false);
+ }
+ if (i != INFINITE)
+ {
+ wchar_t *tmp;
+ char *a;
+
+ // There is a colon character
+ tmp = CopyUniStr(token);
+ tmp[i] = 0;
+
+ a = CopyUniToStr(&tmp[1]);
+ if (InsertStr(o, a) == false)
+ {
+ Free(a);
+ }
+
+ if (UniStrCmpi(name, &tmp[1]) == 0)
+ {
+ if (ret == NULL)
+ {
+ // Content
+ ret = UniCopyStr(&token[i + 1]);
+ }
+ }
+
+ Free(tmp);
+ }
+ else
+ {
+ // There is no colon character
+ char *a;
+
+ a = CopyUniToStr(&token[1]);
+ if (InsertStr(o, a) == false)
+ {
+ Free(a);
+ }
+
+ if (UniStrCmpi(name, &token[1]) == 0)
+ {
+ if (ret == NULL)
+ {
+ // Empty character
+ ret = UniCopyStr(L"");
+ }
+ }
+ }
+ }
+ else
+ {
+ // Nameless argument
+ if (name == NULL)
+ {
+ if (ret == NULL)
+ {
+ if (token[0] == L'-' && token[1] == L'-')
+ {
+ ret = UniCopyStr(&token[1]);
+ }
+ else if (token[0] == L'/' && token[1] == L'/')
+ {
+ ret = UniCopyStr(&token[1]);
+ }
+ else
+ {
+ ret = UniCopyStr(token);
+ }
+ }
+ }
+ }
+ }
+
+ UniFreeToken(t);
+ }
+ }
+
+ Free(tmp);
+
+ if (o != NULL)
+ {
+ TOKEN_LIST *t = ZeroMalloc(sizeof(TOKEN_LIST));
+ UINT i;
+
+ t->NumTokens = LIST_NUM(o);
+ t->Token = ZeroMalloc(sizeof(char *) * t->NumTokens);
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ t->Token[i] = LIST_DATA(o, i);
+ }
+
+ ReleaseList(o);
+
+ *param_list = t;
+ }
+
+ if (UniStrCmpi(ret, L"none") == 0 || UniStrCmpi(ret, L"null") == 0)
+ {
+ // Null and none are reserved words
+ ret[0] = 0;
+ }
+
+ return ret;
+}
+char *ParseCommandA(wchar_t *str, char *name)
+{
+ wchar_t *tmp1, *tmp2;
+ char *ret;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return NULL;
+ }
+
+ if (name != NULL)
+ {
+ tmp1 = CopyStrToUni(name);
+ }
+ else
+ {
+ tmp1 = NULL;
+ }
+
+ tmp2 = ParseCommand(str, tmp1);
+
+ if (tmp2 == NULL)
+ {
+ ret = NULL;
+ }
+ else
+ {
+ ret = CopyUniToStr(tmp2);
+ Free(tmp2);
+ }
+
+ Free(tmp1);
+
+ return ret;
+}
+
+// Password prompt
+bool PasswordPrompt(char *password, UINT size)
+{
+ UINT wp;
+ bool escape = false;
+ void *console;
+ // Validate arguments
+ if (password == NULL || size <= 1)
+ {
+ if (size >= 1)
+ {
+ password[0] = 0;
+ }
+ return false;
+ }
+
+ wp = 0;
+
+ Zero(password, size);
+
+ console = SetConsoleRaw();
+
+ while (true)
+ {
+ int c;
+
+#ifdef OS_WIN32
+ c = getch();
+#else // OS_WIN32
+ c = getc(stdin);
+#endif // OS_WIN32
+
+ if (c >= 0x20 && c <= 0x7E)
+ {
+ // Character
+ if ((wp + 1) < size)
+ {
+ password[wp++] = (char)c;
+ putc('*', stdout);
+ }
+ }
+ else if (c == 0x03)
+ {
+ // Break
+ exit(0);
+ }
+ else if (c == 0x04 || c == 0x1a || c == 0x0D || c==0x0A)
+ {
+ // Exit
+ if (c == 0x04 || c == 0x1a)
+ {
+ escape = true;
+ }
+ break;
+ }
+ else if (c == 0xE0)
+ {
+ // Read one more character
+ c = getch();
+ if (c == 0x4B || c == 0x53)
+ {
+ // Backspace
+ goto BACKSPACE;
+ }
+ }
+ else if (c == 0x08)
+ {
+BACKSPACE:
+ // Backspace
+ if (wp >= 1)
+ {
+ password[--wp] = 0;
+ putc(0x08, stdout);
+ putc(' ', stdout);
+ putc(0x08, stdout);
+ }
+ }
+ }
+ Print("\n");
+
+ RestoreConsole(console);
+
+ return (escape ? false : true);
+}
+
+// Show the prompt
+wchar_t *Prompt(wchar_t *prompt_str)
+{
+ wchar_t *ret = NULL;
+ wchar_t *tmp = NULL;
+ // Validate arguments
+ if (prompt_str == NULL)
+ {
+ prompt_str = L"";
+ }
+
+#ifdef OS_WIN32
+ UniPrint(L"%s", prompt_str);
+ tmp = Malloc(MAX_PROMPT_STRSIZE);
+ if (fgetws(tmp, MAX_PROMPT_STRSIZE - 1, stdin) != NULL)
+ {
+ bool escape = false;
+ UINT i, len;
+
+ len = UniStrLen(tmp);
+ for (i = 0;i < len;i++)
+ {
+ if (tmp[i] == 0x04 || tmp[i] == 0x1A)
+ {
+ escape = true;
+ break;
+ }
+ }
+
+ if (escape == false)
+ {
+ UniTrimCrlf(tmp);
+
+ ret = UniCopyStr(tmp);
+ }
+ }
+ Free(tmp);
+#else // OS_WIN32
+ {
+ char *prompt = CopyUniToStr(prompt_str);
+ char *s = readline(prompt);
+ Free(prompt);
+
+ if (s != NULL)
+ {
+ TrimCrlf(s);
+ Trim(s);
+
+ if (IsEmptyStr(s) == false)
+ {
+ add_history(s);
+ }
+
+ ret = CopyStrToUni(s);
+
+ free(s);
+ }
+ }
+#endif // OS_WIN32
+
+ if (ret == NULL)
+ {
+ Print("\n");
+ }
+
+ return ret;
+}
+char *PromptA(wchar_t *prompt_str)
+{
+ wchar_t *str = Prompt(prompt_str);
+
+ if (str == NULL)
+ {
+ return NULL;
+ }
+ else
+ {
+ char *ret = CopyUniToStr(str);
+
+ Free(str);
+ return ret;
+ }
+}
+
+// Set the console to raw mode
+void *SetConsoleRaw()
+{
+#ifdef OS_UNIX
+ struct termios t, *ret;
+
+ Zero(&t, sizeof(t));
+ if (tcgetattr(0, &t) != 0)
+ {
+ // Failed
+ return NULL;
+ }
+
+ // Copy the current settings
+ ret = Clone(&t, sizeof(t));
+
+ // Change the settings
+ t.c_lflag &= (~ICANON);
+ t.c_lflag &= (~ECHO);
+ t.c_cc[VTIME] = 0;
+ t.c_cc[VMIN] = 1;
+ tcsetattr(0, TCSANOW, &t);
+
+ return ret;
+#else // OS_UNIX
+ return Malloc(0);
+#endif // OS_UNIX
+}
+
+// Restore the mode of the console
+void RestoreConsole(void *p)
+{
+#ifdef OS_UNIX
+ struct termios *t;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ t = (struct termios *)p;
+
+ // Restore the settings
+ tcsetattr(0, TCSANOW, t);
+
+ Free(t);
+#else // OS_UNIX
+ if (p != NULL)
+ {
+ Free(p);
+ }
+#endif // OS_UNIX
+}
+
+////////////////////////////
+// Local console function
+
+// Creating a new local console
+CONSOLE *NewLocalConsole(wchar_t *infile, wchar_t *outfile)
+{
+ IO *in_io = NULL, *out_io = NULL;
+ CONSOLE *c = ZeroMalloc(sizeof(CONSOLE));
+ LOCAL_CONSOLE_PARAM *p;
+ UINT old_size = 0;
+
+#ifdef OS_WIN32
+ if (MsGetConsoleWidth() == 80)
+ {
+ //old_size = MsSetConsoleWidth(WIN32_DEFAULT_CONSOLE_WIDTH);
+ }
+#endif // OS_WIN32
+
+ c->ConsoleType = CONSOLE_LOCAL;
+ c->Free = ConsoleLocalFree;
+ c->ReadLine = ConsoleLocalReadLine;
+ c->ReadPassword = ConsoleLocalReadPassword;
+ c->Write = ConsoleLocalWrite;
+ c->GetWidth = ConsoleLocalGetWidth;
+
+ if (UniIsEmptyStr(infile) == false)
+ {
+ // Input file is specified
+ in_io = FileOpenW(infile, false);
+ if (in_io == NULL)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), _UU("CON_INFILE_ERROR"), infile);
+ c->Write(c, tmp);
+ Free(c);
+ return NULL;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), _UU("CON_INFILE_START"), infile);
+ c->Write(c, tmp);
+ }
+ }
+
+ if (UniIsEmptyStr(outfile) == false)
+ {
+ // Output file is specified
+ out_io = FileCreateW(outfile);
+ if (out_io == NULL)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), _UU("CON_OUTFILE_ERROR"), outfile);
+ c->Write(c, tmp);
+ Free(c);
+
+ if (in_io != NULL)
+ {
+ FileClose(in_io);
+ }
+ return NULL;
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), _UU("CON_OUTFILE_START"), outfile);
+ c->Write(c, tmp);
+ }
+ }
+
+ p = ZeroMalloc(sizeof(LOCAL_CONSOLE_PARAM));
+ c->Param = p;
+
+ p->InFile = in_io;
+ p->OutFile = out_io;
+ p->Win32_OldConsoleWidth = old_size;
+
+ if (in_io != NULL)
+ {
+ UINT size;
+ void *buf;
+
+ size = FileSize(in_io);
+ buf = ZeroMalloc(size + 1);
+ FileRead(in_io, buf, size);
+
+ p->InBuf = NewBuf();
+ WriteBuf(p->InBuf, buf, size);
+ Free(buf);
+
+ p->InBuf->Current = 0;
+ }
+
+ return c;
+}
+
+// Release Console
+void ConsoleLocalFree(CONSOLE *c)
+{
+ LOCAL_CONSOLE_PARAM *p;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ p = (LOCAL_CONSOLE_PARAM *)c->Param;
+
+#ifdef OS_WIN32
+ if (p->Win32_OldConsoleWidth != 0)
+ {
+ MsSetConsoleWidth(p->Win32_OldConsoleWidth);
+ }
+#endif // OS_WIN32
+
+ if (p != NULL)
+ {
+ if (p->InFile != NULL)
+ {
+ FileClose(p->InFile);
+ FreeBuf(p->InBuf);
+ }
+
+ if (p->OutFile != NULL)
+ {
+ FileClose(p->OutFile);
+ }
+
+ Free(p);
+ }
+
+ // Memory release
+ Free(c);
+}
+
+// Get the width of the screen
+UINT ConsoleLocalGetWidth(CONSOLE *c)
+{
+ UINT ret = 0;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return 0;
+ }
+
+#ifdef OS_WIN32
+ ret = MsGetConsoleWidth();
+#else // OS_WIN32
+ {
+ struct winsize t;
+
+ Zero(&t, sizeof(t));
+
+ if (ioctl(1, TIOCGWINSZ, &t) == 0)
+ {
+ ret = t.ws_col;
+ }
+ }
+#endif // OS_WIN32
+
+ return ret;
+}
+
+// Read one line from the console
+wchar_t *ConsoleLocalReadLine(CONSOLE *c, wchar_t *prompt, bool nofile)
+{
+ wchar_t *ret;
+ LOCAL_CONSOLE_PARAM *p;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+ p = (LOCAL_CONSOLE_PARAM *)c->Param;
+ if (prompt == NULL)
+ {
+ prompt = L">";
+ }
+
+ ConsoleWriteOutFile(c, prompt, false);
+
+ if (nofile == false && p->InBuf != NULL)
+ {
+ // Read the next line from the file
+ ret = ConsoleReadNextFromInFile(c);
+
+ if (ret != NULL)
+ {
+ // Display the pseudo prompt
+ UniPrint(L"%s", prompt);
+
+ // Display on the screen
+ UniPrint(L"%s\n", ret);
+ }
+ }
+ else
+ {
+ // Read the following line from the console
+ ret = Prompt(prompt);
+ }
+
+ if (ret != NULL)
+ {
+ ConsoleWriteOutFile(c, ret, true);
+ }
+ else
+ {
+ ConsoleWriteOutFile(c, _UU("CON_USER_CANCEL"), true);
+ }
+
+ return ret;
+}
+
+// Read the password from the console
+char *ConsoleLocalReadPassword(CONSOLE *c, wchar_t *prompt)
+{
+ char tmp[64];
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+ if (prompt == NULL)
+ {
+ prompt = L"Password>";
+ }
+
+ UniPrint(L"%s", prompt);
+ ConsoleWriteOutFile(c, prompt, false);
+
+ if (PasswordPrompt(tmp, sizeof(tmp)))
+ {
+ ConsoleWriteOutFile(c, L"********", true);
+ return CopyStr(tmp);
+ }
+ else
+ {
+ ConsoleWriteOutFile(c, _UU("CON_USER_CANCEL"), true);
+ return NULL;
+ }
+}
+
+// Display a string to the console
+bool ConsoleLocalWrite(CONSOLE *c, wchar_t *str)
+{
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ UniPrint(L"%s%s", str, (UniEndWith(str, L"\n") ? L"" : L"\n"));
+
+ ConsoleWriteOutFile(c, str, true);
+
+ return true;
+}
+
+// Read the next line from the input file
+wchar_t *ConsoleReadNextFromInFile(CONSOLE *c)
+{
+ LOCAL_CONSOLE_PARAM *p;
+ char *str;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ p = (LOCAL_CONSOLE_PARAM *)c->Param;
+
+ if (p->InBuf == NULL)
+ {
+ return NULL;
+ }
+
+ while (true)
+ {
+ str = CfgReadNextLine(p->InBuf);
+
+ if (str == NULL)
+ {
+ return NULL;
+ }
+
+ Trim(str);
+
+ if (IsEmptyStr(str) == false)
+ {
+ UINT size;
+ wchar_t *ret;
+
+ size = CalcUtf8ToUni((BYTE *)str, StrLen(str));
+ ret = ZeroMalloc(size + 32);
+ Utf8ToUni(ret, size, (BYTE *)str, StrLen(str));
+
+ Free(str);
+
+ return ret;
+ }
+
+ Free(str);
+ }
+}
+
+// Write when the output file is specified
+void ConsoleWriteOutFile(CONSOLE *c, wchar_t *str, bool add_last_crlf)
+{
+ LOCAL_CONSOLE_PARAM *p;
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return;
+ }
+
+ p = (LOCAL_CONSOLE_PARAM *)c->Param;
+
+ if (p != NULL && p->OutFile != NULL)
+ {
+ wchar_t *tmp = UniNormalizeCrlf(str);
+ UINT utf8_size;
+ UCHAR *utf8;
+
+ utf8_size = CalcUniToUtf8(tmp);
+ utf8 = ZeroMalloc(utf8_size + 1);
+ UniToUtf8(utf8, utf8_size + 1, tmp);
+
+ FileWrite(p->OutFile, utf8, utf8_size);
+
+ if (UniEndWith(str, L"\n") == false && add_last_crlf)
+ {
+ char *crlf = "\r\n";
+ FileWrite(p->OutFile, "\r\n", StrLen(crlf));
+ }
+
+ Free(utf8);
+ Free(tmp);
+ }
+
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Console.h b/src/Cedar/Console.h
new file mode 100644
index 00000000..45f111a6
--- /dev/null
+++ b/src/Cedar/Console.h
@@ -0,0 +1,222 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Console.h
+// Header of Console.c
+
+#ifndef CONSOLE_H
+#define CONSOLE_H
+
+// Constant
+#define MAX_PROMPT_STRSIZE 65536
+#define WIN32_DEFAULT_CONSOLE_WIDTH 100
+
+// Types of console
+#define CONSOLE_LOCAL 0 // Local console
+#define CONSOLE_CSV 1 // CSV output mode
+
+// Parameters completion prompt function
+typedef wchar_t *(PROMPT_PROC)(CONSOLE *c, void *param);
+
+// Parameter validation prompt function
+typedef bool (EVAL_PROC)(CONSOLE *c, wchar_t *str, void *param);
+
+// Definition of the parameter item
+struct PARAM
+{
+ char *Name; // Parameter name
+ PROMPT_PROC *PromptProc; // Prompt function that automatically invoked if the parameter is not specified
+ // (This is not called in the case of NULL)
+ void *PromptProcParam; // Any pointers to pass to the prompt function
+ EVAL_PROC *EvalProc; // Parameter string validation function
+ void *EvalProcParam; // Any pointers to be passed to the validation function
+ char *Tmp; // Temporary variable
+};
+
+// Parameter value of the internal data
+struct PARAM_VALUE
+{
+ char *Name; // Name
+ char *StrValue; // String value
+ wchar_t *UniStrValue; // Unicode string value
+ UINT IntValue; // Integer value
+};
+
+// Console service structure
+struct CONSOLE
+{
+ UINT ConsoleType; // Type of console
+ UINT RetCode; // The last exit code
+ void *Param; // Data of any
+ void (*Free)(CONSOLE *c); // Release function
+ wchar_t *(*ReadLine)(CONSOLE *c, wchar_t *prompt, bool nofile); // Function to read one line
+ char *(*ReadPassword)(CONSOLE *c, wchar_t *prompt); // Function to read the password
+ bool (*Write)(CONSOLE *c, wchar_t *str); // Function to write a string
+ UINT (*GetWidth)(CONSOLE *c); // Get the width of the screen
+};
+
+// Local console parameters
+struct LOCAL_CONSOLE_PARAM
+{
+ IO *InFile; // Input file
+ BUF *InBuf; // Input buffer
+ IO *OutFile; // Output file
+ UINT Win32_OldConsoleWidth; // Previous console size
+};
+
+// Command procedure
+typedef UINT (COMMAND_PROC)(CONSOLE *c, char *cmd_name, wchar_t *str, void *param);
+
+// Definition of command
+struct CMD
+{
+ char *Name; // Command name
+ COMMAND_PROC *Proc; // Procedure function
+};
+
+// Evaluate the minimum / maximum value of the parameter
+struct CMD_EVAL_MIN_MAX
+{
+ char *StrName;
+ UINT MinValue, MaxValue;
+};
+
+
+// Function prototype
+wchar_t *Prompt(wchar_t *prompt_str);
+char *PromptA(wchar_t *prompt_str);
+bool PasswordPrompt(char *password, UINT size);
+void *SetConsoleRaw();
+void RestoreConsole(void *p);
+wchar_t *ParseCommandEx(wchar_t *str, wchar_t *name, TOKEN_LIST **param_list);
+wchar_t *ParseCommand(wchar_t *str, wchar_t *name);
+TOKEN_LIST *GetCommandNameList(wchar_t *str);
+char *ParseCommandA(wchar_t *str, char *name);
+LIST *NewParamValueList();
+int CmpParamValue(void *p1, void *p2);
+void FreeParamValueList(LIST *o);
+PARAM_VALUE *FindParamValue(LIST *o, char *name);
+char *GetParamStr(LIST *o, char *name);
+wchar_t *GetParamUniStr(LIST *o, char *name);
+UINT GetParamInt(LIST *o, char *name);
+bool GetParamYes(LIST *o, char *name);
+LIST *ParseCommandList(CONSOLE *c, char *cmd_name, wchar_t *command, PARAM param[], UINT num_param);
+bool IsNameInRealName(char *input_name, char *real_name);
+void GetOmissionName(char *dst, UINT size, char *src);
+bool IsOmissionName(char *input_name, char *real_name);
+TOKEN_LIST *GetRealnameCandidate(char *input_name, TOKEN_LIST *real_name_list);
+bool SeparateCommandAndParam(wchar_t *src, char **cmd, wchar_t **param);
+UINT GetConsoleWidth(CONSOLE *c);
+bool DispatchNextCmd(CONSOLE *c, char *prompt, CMD cmd[], UINT num_cmd, void *param);
+bool DispatchNextCmdEx(CONSOLE *c, wchar_t *exec_command, char *prompt, CMD cmd[], UINT num_cmd, void *param);
+void PrintCandidateHelp(CONSOLE *c, char *cmd_name, TOKEN_LIST *candidate_list, UINT left_space);
+UNI_TOKEN_LIST *SeparateStringByWidth(wchar_t *str, UINT width);
+UINT GetNextWordWidth(wchar_t *str);
+bool IsWordChar(wchar_t c);
+void GetCommandHelpStr(char *command_name, wchar_t **description, wchar_t **args, wchar_t **help);
+void GetCommandParamHelpStr(char *command_name, char *param_name, wchar_t **description);
+bool CmdEvalMinMax(CONSOLE *c, wchar_t *str, void *param);
+wchar_t *CmdPrompt(CONSOLE *c, void *param);
+bool CmdEvalNotEmpty(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalInt1(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalIsFile(CONSOLE *c, wchar_t *str, void *param);
+bool CmdEvalSafe(CONSOLE *c, wchar_t *str, void *param);
+void PrintCmdHelp(CONSOLE *c, char *cmd_name, TOKEN_LIST *param_list);
+int CompareCandidateStr(void *p1, void *p2);
+bool IsHelpStr(char *str);
+
+CONSOLE *NewLocalConsole(wchar_t *infile, wchar_t *outfile);
+void ConsoleLocalFree(CONSOLE *c);
+wchar_t *ConsoleLocalReadLine(CONSOLE *c, wchar_t *prompt, bool nofile);
+char *ConsoleLocalReadPassword(CONSOLE *c, wchar_t *prompt);
+bool ConsoleLocalWrite(CONSOLE *c, wchar_t *str);
+void ConsoleWriteOutFile(CONSOLE *c, wchar_t *str, bool add_last_crlf);
+wchar_t *ConsoleReadNextFromInFile(CONSOLE *c);
+UINT ConsoleLocalGetWidth(CONSOLE *c);
+
+
+#endif // CONSOLE_H
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/DDNS.c b/src/Cedar/DDNS.c
new file mode 100644
index 00000000..a74bb7a3
--- /dev/null
+++ b/src/Cedar/DDNS.c
@@ -0,0 +1,984 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// DDNS.c
+// Dynamic DNS Client
+
+#include "CedarPch.h"
+
+// Get the current status of the DDNS client
+void DCGetStatus(DDNS_CLIENT *c, DDNS_CLIENT_STATUS *st)
+{
+ // Validate arguments
+ if (c == NULL || st == NULL)
+ {
+ return;
+ }
+
+ Zero(st, sizeof(DDNS_CLIENT_STATUS));
+
+ Lock(c->Lock);
+ {
+ st->Err_IPv4 = c->Err_IPv4;
+ st->Err_IPv6 = c->Err_IPv6;
+
+ StrCpy(st->CurrentHostName, sizeof(st->CurrentHostName), c->CurrentHostName);
+ StrCpy(st->CurrentFqdn, sizeof(st->CurrentFqdn), c->CurrentFqdn);
+ StrCpy(st->DnsSuffix, sizeof(st->DnsSuffix), c->DnsSuffix);
+ StrCpy(st->CurrentIPv4, sizeof(st->CurrentIPv4), c->CurrentIPv4);
+ StrCpy(st->CurrentIPv6, sizeof(st->CurrentIPv6), c->CurrentIPv6);
+
+ StrCpy(st->CurrentAzureIp, sizeof(st->CurrentAzureIp), c->CurrentAzureIp);
+ st->CurrentAzureTimestamp = c->CurrentAzureTimestamp;
+ StrCpy(st->CurrentAzureSignature, sizeof(st->CurrentAzureSignature), c->CurrentAzureSignature);
+ StrCpy(st->AzureCertHash, sizeof(st->AzureCertHash), c->AzureCertHash);
+
+ Copy(&st->InternetSetting, &c->InternetSetting, sizeof(INTERNET_SETTING));
+ }
+ Unlock(c->Lock);
+}
+
+// Set the Internet settings
+void DCSetInternetSetting(DDNS_CLIENT *c, INTERNET_SETTING *t)
+{
+ // Validate arguments
+ if (c == NULL || t == NULL)
+ {
+ return;
+ }
+
+ Copy(&c->InternetSetting, t, sizeof(INTERNET_SETTING));
+}
+
+// Get the Internet settings
+void DCGetInternetSetting(DDNS_CLIENT *c, INTERNET_SETTING *t)
+{
+ // Validate arguments
+ if (c == NULL || t == NULL)
+ {
+ return;
+ }
+
+ Copy(t, &c->InternetSetting, sizeof(INTERNET_SETTING));
+}
+
+// Changing the host name
+UINT DCChangeHostName(DDNS_CLIENT *c, char *hostname)
+{
+ UINT ret;
+ DDNS_REGISTER_PARAM p;
+ // Validate arguments
+ if (c == NULL || hostname == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ if (StrLen(hostname) > 32)
+ {
+ // The host name is too long
+ return ERR_DDNS_HOSTNAME_TOO_LONG;
+ }
+
+ Zero(&p, sizeof(p));
+
+ StrCpy(p.NewHostname, sizeof(p.NewHostname), hostname);
+
+ // Use one of IPv4 or IPv6 if it seems to be communication
+ if (c->Err_IPv4 == ERR_NO_ERROR)
+ {
+ // IPv4
+ ret = DCRegister(c, false, &p, NULL);
+ }
+ else if (c->Err_IPv6 == ERR_NO_ERROR)
+ {
+ // IPv6
+ ret = DCRegister(c, true, &p, NULL);
+ }
+ else
+ {
+ // Try both
+ ret = DCRegister(c, true, &p, NULL);
+ if (ret != ERR_NO_ERROR)
+ {
+ ret = DCRegister(c, false, &p, NULL);
+ }
+ }
+
+ if (ret == ERR_NO_ERROR)
+ {
+ DDNS_CLIENT_STATUS st;
+
+ DCGetStatus(c, &st);
+
+ SiApplyAzureConfig(c->Cedar->Server, &st);
+ }
+
+ return ret;
+}
+
+// DDNS client thread
+void DCThread(THREAD *thread, void *param)
+{
+ DDNS_CLIENT *c;
+ INTERRUPT_MANAGER *interrput;
+ UINT last_ip_hash = 0;
+ void *route_change_poller = NULL;
+ bool last_time_ip_changed = false;
+ UINT last_azure_ddns_trigger_int = 0;
+ UINT last_vgs_ddns_trigger_int = 0;
+ UINT n;
+ INTERNET_SETTING last_t;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ c = (DDNS_CLIENT *)param;
+
+ interrput = NewInterruptManager();
+
+ route_change_poller = NewRouteChange();
+ IsRouteChanged(route_change_poller);
+
+ Zero(&last_t, sizeof(last_t));
+
+ n = 0;
+
+ while (c->Halt == false)
+ {
+ UINT ip_hash = GetHostIPAddressHash32();
+ UINT interval;
+ UINT64 now = Tick64();
+ bool ip_changed = false;
+ bool azure_client_triggered = false;
+ bool internet_setting_changed = false;
+ bool vgs_server_triggered = false;
+
+
+ if (c->Cedar->Server != NULL && c->Cedar->Server->AzureClient != NULL)
+ {
+ if (c->Cedar->Server->AzureClient->DDnsTriggerInt != last_azure_ddns_trigger_int)
+ {
+ azure_client_triggered = true;
+ last_azure_ddns_trigger_int = c->Cedar->Server->AzureClient->DDnsTriggerInt;
+ last_time_ip_changed = false;
+ Debug("DDNS Thread Triggered by AzureClient.\n");
+ }
+ }
+
+ if (Cmp(&last_t, &c->InternetSetting, sizeof(INTERNET_SETTING)) != 0)
+ {
+ Copy(&last_t, &c->InternetSetting, sizeof(INTERNET_SETTING));
+ internet_setting_changed = true;
+ last_time_ip_changed = false;
+ }
+
+ if (ip_hash != last_ip_hash)
+ {
+ last_time_ip_changed = false;
+ Debug("DDNS Thread Triggered by IP Hash Changed.\n");
+ }
+
+ if ((ip_hash != last_ip_hash) || (IsRouteChanged(route_change_poller)) || azure_client_triggered || internet_setting_changed || vgs_server_triggered)
+ {
+ if (last_time_ip_changed == false)
+ {
+ // Call all getting functions from the beginning if the routing
+ // table or the IP address of this host has changed
+ c->NextRegisterTick_IPv4 = 0;
+ c->NextRegisterTick_IPv6 = 0;
+ c->NextGetMyIpTick_IPv4 = 0;
+ c->NextGetMyIpTick_IPv6 = 0;
+
+ last_ip_hash = ip_hash;
+
+ last_time_ip_changed = true;
+
+ ip_changed = true;
+
+ Debug("DDNS Internet Condition Changed.\n");
+ }
+ }
+ else
+ {
+ last_time_ip_changed = false;
+ }
+
+ if ((n++) >= 1)
+ {
+ // Self IPv4 address acquisition
+ if (c->NextGetMyIpTick_IPv4 == 0 || now >= c->NextGetMyIpTick_IPv4)
+ {
+ UINT next_interval;
+ char ip[MAX_SIZE];
+
+ Zero(ip, sizeof(ip));
+ c->Err_IPv4_GetMyIp = DCGetMyIp(c, false, ip, sizeof(ip), NULL);
+
+ if (c->Err_IPv4_GetMyIp == ERR_NO_ERROR)
+ {
+ if (StrCmpi(c->LastMyIPv4, ip) != 0)
+ {
+ ip_changed = true;
+ StrCpy(c->LastMyIPv4, sizeof(c->LastMyIPv4), ip);
+ }
+
+ next_interval = GenRandInterval(DDNS_GETMYIP_INTERVAL_OK_MIN, DDNS_GETMYIP_INTERVAL_OK_MAX);
+ }
+ else
+ {
+ if (IsEmptyStr(c->LastMyIPv4) == false)
+ {
+ ip_changed = true;
+ }
+
+ Zero(c->LastMyIPv4, sizeof(c->LastMyIPv4));
+ next_interval = GenRandInterval(DDNS_GETMYIP_INTERVAL_NG_MIN, DDNS_GETMYIP_INTERVAL_NG_MAX);
+ }
+
+ c->NextGetMyIpTick_IPv4 = Tick64() + (UINT64)next_interval;
+
+ AddInterrupt(interrput, c->NextGetMyIpTick_IPv4);
+ }
+
+ // Self IPv6 address acquisition
+ if (c->NextGetMyIpTick_IPv6 == 0 || now >= c->NextGetMyIpTick_IPv6)
+ {
+ UINT next_interval;
+ char ip[MAX_SIZE];
+
+ Zero(ip, sizeof(ip));
+ c->Err_IPv6_GetMyIp = DCGetMyIp(c, true, ip, sizeof(ip), NULL);
+
+ if (c->Err_IPv6_GetMyIp == ERR_NO_ERROR)
+ {
+ if (StrCmpi(c->LastMyIPv6, ip) != 0)
+ {
+ ip_changed = true;
+ StrCpy(c->LastMyIPv6, sizeof(c->LastMyIPv6), ip);
+ }
+
+ next_interval = GenRandInterval(DDNS_GETMYIP_INTERVAL_OK_MIN, DDNS_GETMYIP_INTERVAL_OK_MAX);
+ }
+ else
+ {
+ if (IsEmptyStr(c->LastMyIPv6) == false)
+ {
+ ip_changed = true;
+ }
+
+ Zero(c->LastMyIPv6, sizeof(c->LastMyIPv6));
+ next_interval = GenRandInterval(DDNS_GETMYIP_INTERVAL_NG_MIN, DDNS_GETMYIP_INTERVAL_NG_MAX);
+ }
+
+ c->NextGetMyIpTick_IPv6 = Tick64() + (UINT64)next_interval;
+
+ AddInterrupt(interrput, c->NextGetMyIpTick_IPv6);
+ }
+ }
+
+ if (ip_changed)
+ {
+ c->NextRegisterTick_IPv4 = 0;
+ c->NextRegisterTick_IPv6 = 0;
+ }
+
+ // IPv4 host registration
+ if (c->NextRegisterTick_IPv4 == 0 || now >= c->NextRegisterTick_IPv4)
+ {
+ UINT next_interval;
+
+ c->Err_IPv4 = DCRegister(c, false, NULL, NULL);
+
+ if (c->Err_IPv4 == ERR_NO_ERROR)
+ {
+ next_interval = GenRandInterval(DDNS_REGISTER_INTERVAL_OK_MIN, DDNS_REGISTER_INTERVAL_OK_MAX);
+ }
+ else
+ {
+ next_interval = GenRandInterval(DDNS_REGISTER_INTERVAL_NG_MIN, DDNS_REGISTER_INTERVAL_NG_MAX);
+ }
+ //next_interval = 0;
+
+ c->NextRegisterTick_IPv4 = Tick64() + (UINT64)next_interval;
+
+ if (true)
+ {
+ DDNS_CLIENT_STATUS st;
+
+ DCGetStatus(c, &st);
+
+ SiApplyAzureConfig(c->Cedar->Server, &st);
+ }
+
+ AddInterrupt(interrput, c->NextRegisterTick_IPv4);
+ }
+
+ if (c->Halt)
+ {
+ break;
+ }
+
+ // IPv6 host registration
+ if (c->NextRegisterTick_IPv6 == 0 || now >= c->NextRegisterTick_IPv6)
+ {
+ UINT next_interval;
+
+ c->Err_IPv6 = DCRegister(c, true, NULL, NULL);
+
+ if (c->Err_IPv6 == ERR_NO_ERROR)
+ {
+ next_interval = GenRandInterval(DDNS_REGISTER_INTERVAL_OK_MIN, DDNS_REGISTER_INTERVAL_OK_MAX);
+ }
+ else
+ {
+ next_interval = GenRandInterval(DDNS_REGISTER_INTERVAL_NG_MIN, DDNS_REGISTER_INTERVAL_NG_MAX);
+ }
+
+ c->NextRegisterTick_IPv6 = Tick64() + (UINT64)next_interval;
+
+ if (true)
+ {
+ DDNS_CLIENT_STATUS st;
+
+ DCGetStatus(c, &st);
+
+ SiApplyAzureConfig(c->Cedar->Server, &st);
+ }
+
+ AddInterrupt(interrput, c->NextRegisterTick_IPv6);
+ }
+
+ interval = GetNextIntervalForInterrupt(interrput);
+ interval = MIN(interval, 1234);
+
+ if (n == 1)
+ {
+ interval = MIN(interval, 0);
+ }
+
+ if (c->Halt)
+ {
+ break;
+ }
+
+ if (c->KeyChanged)
+ {
+ c->KeyChanged = false;
+ c->NextRegisterTick_IPv4 = c->NextRegisterTick_IPv6 = 0;
+
+ interval = 0;
+ }
+
+ if (last_time_ip_changed)
+ {
+ if (c->Cedar->Server != NULL && c->Cedar->Server->AzureClient != NULL)
+ {
+ c->Cedar->Server->AzureClient->IpStatusRevision++;
+ }
+ }
+
+ Wait(c->Event, interval);
+ }
+
+ FreeRouteChange(route_change_poller);
+ FreeInterruptManager(interrput);
+}
+
+// Command to update immediately
+void DCUpdateNow(DDNS_CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->NextRegisterTick_IPv4 = c->NextRegisterTick_IPv6 = 0;
+
+ Set(c->Event);
+}
+
+// Execution of registration
+UINT DCRegister(DDNS_CLIENT *c, bool ipv6, DDNS_REGISTER_PARAM *p, char *replace_v6)
+{
+ char *url;
+ char url2[MAX_SIZE];
+ char url3[MAX_SIZE];
+ PACK *req, *ret;
+ char key_str[MAX_SIZE];
+ UCHAR machine_key[SHA1_SIZE];
+ char machine_key_str[MAX_SIZE];
+ char machine_name[MAX_SIZE];
+ BUF *cert_hash;
+ UINT err = ERR_INTERNAL_ERROR;
+ UCHAR key_hash[SHA1_SIZE];
+ char key_hash_str[MAX_SIZE];
+ bool use_azure = false;
+ char current_azure_ip[MAX_SIZE];
+ INTERNET_SETTING t;
+ UINT build = 0;
+ bool use_https = false;
+ bool use_vgs = false;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ Zero(current_azure_ip, sizeof(current_azure_ip));
+
+ GetCurrentMachineIpProcessHash(machine_key);
+ BinToStr(machine_key_str, sizeof(machine_key_str), machine_key, sizeof(machine_key));
+
+ GetMachineHostName(machine_name, sizeof(machine_name));
+ StrLower(machine_name);
+
+ if (ipv6 == false)
+ {
+ url = DDNS_URL_V4_GLOBAL;
+
+ if (IsUseAlternativeHostname())
+ {
+ url = DDNS_URL_V4_ALT;
+ }
+ }
+ else
+ {
+ url = DDNS_URL_V6_GLOBAL;
+
+ if (IsUseAlternativeHostname())
+ {
+ url = DDNS_URL_V6_ALT;
+ }
+
+ if (replace_v6)
+ {
+ url = replace_v6;
+ }
+ }
+
+ Zero(&t, sizeof(t));
+ if (ipv6 == false)
+ {
+ // Proxy Setting
+ Copy(&t, &c->InternetSetting, sizeof(INTERNET_SETTING));
+ }
+
+ if (ipv6 == false)
+ {
+ // Get the current status of the VPN Azure Client
+ if (c->Cedar->Server != NULL)
+ {
+ AZURE_CLIENT *ac = c->Cedar->Server->AzureClient;
+
+ if (ac != NULL)
+ {
+ use_azure = SiIsAzureEnabled(c->Cedar->Server);
+
+ if (use_azure)
+ {
+ Lock(ac->Lock);
+ {
+ StrCpy(current_azure_ip, sizeof(current_azure_ip), ac->ConnectingAzureIp);
+ }
+ Unlock(ac->Lock);
+ }
+ }
+ }
+ }
+
+ req = NewPack();
+ BinToStr(key_str, sizeof(key_str), c->Key, sizeof(c->Key));
+ StrUpper(key_str);
+ PackAddStr(req, "key", key_str);
+
+ // Build Number
+ build = c->Cedar->Build;
+
+
+ PackAddInt(req, "build", build);
+ PackAddInt(req, "osinfo", GetOsInfo()->OsType);
+ PackAddInt(req, "is_64bit", Is64());
+#ifdef OS_WIN32
+ PackAddInt(req, "is_windows_64bit", MsIs64BitWindows());
+#endif // OS_WIN32
+ PackAddBool(req, "is_softether", true);
+ PackAddBool(req, "is_packetix", false);
+ PackAddStr(req, "machine_key", machine_key_str);
+ PackAddStr(req, "machine_name", machine_name);
+ PackAddInt(req, "lasterror_ipv4", c->Err_IPv4_GetMyIp);
+ PackAddInt(req, "lasterror_ipv6", c->Err_IPv6_GetMyIp);
+ PackAddBool(req, "use_azure", use_azure);
+ PackAddStr(req, "product_str", CEDAR_PRODUCT_STR);
+ PackAddInt(req, "ddns_protocol_version", DDNS_VERSION);
+
+
+ if (use_azure)
+ {
+ Debug("current_azure_ip = %s\n", current_azure_ip);
+ PackAddStr(req, "current_azure_ip", current_azure_ip);
+ }
+
+ HashSha1(key_hash, key_str, StrLen(key_str));
+ BinToStr(key_hash_str, sizeof(key_hash_str), key_hash, sizeof(key_hash));
+ StrLower(key_hash_str);
+
+ if (p != NULL)
+ {
+ if (IsEmptyStr(p->NewHostname) == false)
+ {
+ PackAddStr(req, "new_hostname", p->NewHostname);
+ }
+ }
+
+
+
+ cert_hash = StrToBin(DDNS_CERT_HASH);
+
+ Format(url2, sizeof(url2), "%s?v=%I64u", url, Rand64());
+ Format(url3, sizeof(url3), url2, key_hash_str[0], key_hash_str[1], key_hash_str[2], key_hash_str[3]);
+
+ if (use_https == false)
+ {
+ ReplaceStr(url3, sizeof(url3), url3, "https://", "http://");
+ }
+
+ ReplaceStr(url3, sizeof(url3), url3, ".servers", ".open.servers");
+
+ Debug("WpcCall: %s\n", url3);
+ ret = WpcCallEx(url3, &t, DDNS_CONNECT_TIMEOUT, DDNS_COMM_TIMEOUT, "register", req,
+ NULL, NULL, ((cert_hash != NULL && cert_hash->Size == SHA1_SIZE) ? cert_hash->Buf : NULL), NULL, DDNS_RPC_MAX_RECV_SIZE);
+ Debug("WpcCall Ret: %u\n", ret);
+
+ FreeBuf(cert_hash);
+
+ FreePack(req);
+
+ err = GetErrorFromPack(ret);
+
+ ExtractAndApplyDynList(ret);
+
+ // Status update
+ Lock(c->Lock);
+ {
+ if (err == ERR_NO_ERROR)
+ {
+ char snat_t[MAX_SIZE];
+
+ // Current host name
+ PackGetStr(ret, "current_hostname", c->CurrentHostName, sizeof(c->CurrentHostName));
+ PackGetStr(ret, "current_fqdn", c->CurrentFqdn, sizeof(c->CurrentFqdn));
+ PackGetStr(ret, "current_ipv4", c->CurrentIPv4, sizeof(c->CurrentIPv4));
+ PackGetStr(ret, "current_ipv6", c->CurrentIPv6, sizeof(c->CurrentIPv6));
+ PackGetStr(ret, "dns_suffix", c->DnsSuffix, sizeof(c->DnsSuffix));
+
+ // SecureNAT connectivity check parameters
+ Zero(snat_t, sizeof(snat_t));
+ PackGetStr(ret, "snat_t", snat_t, sizeof(snat_t));
+ NnSetSecureNatTargetHostname(snat_t);
+
+ if (ipv6 == false)
+ {
+ char cert_hash[MAX_SIZE];
+
+ PackGetStr(ret, "current_azure_ip", c->CurrentAzureIp, sizeof(c->CurrentAzureIp));
+ c->CurrentAzureTimestamp = PackGetInt64(ret, "current_azure_timestamp");
+ PackGetStr(ret, "current_azure_signature", c->CurrentAzureSignature, sizeof(c->CurrentAzureSignature));
+
+ Zero(cert_hash, sizeof(cert_hash));
+ PackGetStr(ret, "azure_cert_hash", cert_hash, sizeof(cert_hash));
+
+ if (IsEmptyStr(cert_hash) == false)
+ {
+ StrCpy(c->AzureCertHash, sizeof(c->AzureCertHash), cert_hash);
+ }
+ }
+
+ StrCpy(c->Cedar->CurrentDDnsFqdn, sizeof(c->Cedar->CurrentDDnsFqdn), c->CurrentFqdn);
+
+ Debug("current_hostname=%s, current_fqdn=%s, current_ipv4=%s, current_ipv6=%s, current_azure_ip=%s, CurrentAzureTimestamp=%I64u, CurrentAzureSignature=%s, CertHash=%s\n",
+ c->CurrentHostName, c->CurrentFqdn,
+ c->CurrentIPv4, c->CurrentIPv6,
+ c->CurrentAzureIp, c->CurrentAzureTimestamp, c->CurrentAzureSignature, c->AzureCertHash);
+ }
+ }
+ Unlock(c->Lock);
+
+ if (IsEmptyStr(c->CurrentFqdn) == false)
+ {
+ SetCurrentDDnsFqdn(c->CurrentFqdn);
+ }
+
+
+ FreePack(ret);
+
+ UniDebug(L"DCRegister Error: %s\n", _E(err));
+
+ if (err == ERR_DUPLICATE_DDNS_KEY)
+ {
+ // Key duplication
+ DCGenNewKey(c->Key);
+ c->KeyChanged = true;
+ }
+
+ if (err == ERR_DISCONNECTED)
+ {
+ err = ERR_DDNS_DISCONNECTED;
+ }
+
+ if (IsUseAlternativeHostname() == false)
+ {
+ if (err == ERR_CONNECT_FAILED)
+ {
+ if (ipv6 && replace_v6 == NULL)
+ {
+ UINT type = DetectFletsType();
+
+ if (type & FLETS_DETECT_TYPE_EAST_BFLETS_PRIVATE && err != ERR_NO_ERROR)
+ {
+ err = DCRegister(c, ipv6, p, DDNS_REPLACE_URL_FOR_EAST_BFLETS);
+ }
+
+ if (type & FLETS_DETECT_TYPE_EAST_NGN_PRIVATE && err != ERR_NO_ERROR)
+ {
+ err = DCRegister(c, ipv6, p, DDNS_REPLACE_URL_FOR_EAST_NGN);
+ }
+
+ if (type & FLETS_DETECT_TYPE_WEST_NGN_PRIVATE && err != ERR_NO_ERROR)
+ {
+ err = DCRegister(c, ipv6, p, DDNS_REPLACE_URL_FOR_WEST_NGN);
+ }
+ }
+ }
+ }
+
+ return err;
+}
+
+// Get the self IP address
+UINT DCGetMyIp(DDNS_CLIENT *c, bool ipv6, char *dst, UINT dst_size, char *replace_v6)
+{
+ UINT ret = ERR_INTERNAL_ERROR;
+
+ ret = DCGetMyIpMain(c, ipv6, dst, dst_size, false, replace_v6);
+
+
+ if (ret == ERR_NO_ERROR)
+ {
+ IP ip;
+
+ if (StrToIP(&ip, dst))
+ {
+ if (ipv6 == false && IsIP4(&ip))
+ {
+ SetCurrentGlobalIP(&ip, false);
+ }
+ else if (ipv6 && IsIP6(&ip))
+ {
+ SetCurrentGlobalIP(&ip, true);
+ }
+ }
+ }
+
+ return ret;
+}
+UINT DCGetMyIpMain(DDNS_CLIENT *c, bool ipv6, char *dst, UINT dst_size, bool use_ssl, char *replace_v6)
+{
+ char *url;
+ char url2[MAX_SIZE];
+ UINT ret = ERR_INTERNAL_ERROR;
+ URL_DATA data;
+ BUF *recv;
+ BUF *cert_hash;
+ // Validate arguments
+ if (dst == NULL || c == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ if (ipv6 == false)
+ {
+ url = DDNS_URL2_V4_GLOBAL;
+
+ if (IsUseAlternativeHostname())
+ {
+ url = DDNS_URL2_V4_ALT;
+ }
+ }
+ else
+ {
+ url = DDNS_URL2_V6_GLOBAL;
+
+ if (IsUseAlternativeHostname())
+ {
+ url = DDNS_URL2_V6_ALT;
+ }
+
+ if (replace_v6)
+ {
+ url = replace_v6;
+ }
+ }
+
+ Format(url2, sizeof(url2), "%s?v=%I64u", url, Rand64());
+
+ if (use_ssl)
+ {
+ ReplaceStr(url2, sizeof(url2), url2, "http://", "https://");
+ }
+
+ if (ParseUrl(&data, url2, false, NULL) == false)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ cert_hash = StrToBin(DDNS_CERT_HASH);
+
+ recv = HttpRequest(&data, (ipv6 ? NULL : &c->InternetSetting), DDNS_CONNECT_TIMEOUT, DDNS_COMM_TIMEOUT, &ret, false, NULL, NULL,
+ NULL, ((cert_hash != NULL && cert_hash->Size == SHA1_SIZE) ? cert_hash->Buf : NULL));
+
+ FreeBuf(cert_hash);
+
+ if (recv != NULL)
+ {
+ char *str = ZeroMalloc(recv->Size + 1);
+ Copy(str, recv->Buf, recv->Size);
+
+ if (StartWith(str, "IP=") == false)
+ {
+ ret = ERR_PROTOCOL_ERROR;
+ }
+ else
+ {
+ StrCpy(dst, dst_size, str + 3);
+ ret = ERR_NO_ERROR;
+ }
+
+ Free(str);
+ FreeBuf(recv);
+ }
+
+ if (IsUseAlternativeHostname() == false)
+ {
+ if (ret == ERR_CONNECT_FAILED)
+ {
+ if (ipv6 && replace_v6 == NULL && use_ssl == false)
+ {
+ UINT type = DetectFletsType();
+
+ if (type & FLETS_DETECT_TYPE_EAST_BFLETS_PRIVATE && ret != ERR_NO_ERROR)
+ {
+ ret = DCGetMyIpMain(c, ipv6, dst, dst_size, use_ssl, DDNS_REPLACE_URL2_FOR_EAST_BFLETS);
+ }
+
+ if (type & FLETS_DETECT_TYPE_EAST_NGN_PRIVATE && ret != ERR_NO_ERROR)
+ {
+ ret = DCGetMyIpMain(c, ipv6, dst, dst_size, use_ssl, DDNS_REPLACE_URL2_FOR_EAST_NGN);
+ }
+
+ if (type & FLETS_DETECT_TYPE_WEST_NGN_PRIVATE && ret != ERR_NO_ERROR)
+ {
+ ret = DCGetMyIpMain(c, ipv6, dst, dst_size, use_ssl, DDNS_REPLACE_URL2_FOR_WEST_NGN);
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+// Creating a DDNS client
+DDNS_CLIENT *NewDDNSClient(CEDAR *cedar, UCHAR *key, INTERNET_SETTING *t)
+{
+ DDNS_CLIENT *c;
+ UCHAR key_hash[SHA1_SIZE];
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ c = ZeroMalloc(sizeof(DDNS_CLIENT));
+ c->Cedar = cedar;
+ AddRef(c->Cedar->ref);
+
+ c->Err_IPv4 = c->Err_IPv6 = ERR_TRYING_TO_CONNECT;
+
+ if (key == NULL)
+ {
+ // Create a new key
+ DCGenNewKey(c->Key);
+ }
+ else
+ {
+ // Set the key
+ Copy(c->Key, key, SHA1_SIZE);
+ }
+
+ HashSha1(key_hash, c->Key, sizeof(c->Key));
+
+
+ if (t != NULL)
+ {
+ Copy(&c->InternetSetting, t, sizeof(INTERNET_SETTING));
+ }
+
+ c->Lock = NewLock();
+
+ // Thread creation
+ c->Event = NewEvent();
+ c->Thread = NewThread(DCThread, c);
+
+ return c;
+}
+
+// Release of DDNS client
+void FreeDDNSClient(DDNS_CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Stop the thread
+ c->Halt = true;
+ Set(c->Event);
+
+ WaitThread(c->Thread, INFINITE);
+ ReleaseThread(c->Thread);
+
+ ReleaseEvent(c->Event);
+
+ ReleaseCedar(c->Cedar);
+ DeleteLock(c->Lock);
+
+ Free(c);
+}
+
+// Create a new key
+void DCGenNewKey(UCHAR *key)
+{
+ BUF *b;
+ UINT64 tick;
+ UCHAR hash[SHA1_SIZE];
+ UCHAR rand[SHA1_SIZE];
+ UINT i;
+ // Validate arguments
+ if (key == NULL)
+ {
+ return;
+ }
+
+ b = NewBuf();
+
+ Rand(rand, sizeof(rand));
+ WriteBuf(b, rand, sizeof(rand));
+
+ tick = TickHighres64();
+ WriteBufInt64(b, tick);
+
+ tick = Tick64();
+ WriteBufInt64(b, tick);
+
+ tick = SystemTime64();
+ WriteBufInt64(b, tick);
+
+ GetCurrentMachineIpProcessHash(hash);
+ WriteBuf(b, hash, sizeof(hash));
+
+ HashSha1(key, b->Buf, b->Size);
+ Rand(rand, sizeof(rand));
+
+ for (i = 0;i < SHA1_SIZE;i++)
+ {
+ key[i] = key[i] ^ rand[i];
+ }
+
+ FreeBuf(b);
+}
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/DDNS.h b/src/Cedar/DDNS.h
new file mode 100644
index 00000000..a2c05761
--- /dev/null
+++ b/src/Cedar/DDNS.h
@@ -0,0 +1,215 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// DDNS.h
+// Header of DDNS.c
+
+#ifndef DDNS_H
+#define DDNS_H
+
+// Certificate hash
+#define DDNS_CERT_HASH "EFAC5FA0CDD14E0F864EED58A73C35D7E33B62F3"
+
+// Destination URL
+#define DDNS_URL_V4_GLOBAL "https://x%c.x%c.x%c.x%c.servers.ddns.softether-network.net/ddns/ddns.aspx"
+#define DDNS_URL_V6_GLOBAL "https://x%c.x%c.x%c.x%c.servers-v6.ddns.softether-network.net/ddns/ddns.aspx"
+#define DDNS_URL2_V4_GLOBAL "http://get-my-ip.ddns.softether-network.net/ddns/getmyip.ashx"
+#define DDNS_URL2_V6_GLOBAL "http://get-my-ip-v6.ddns.softether-network.net/ddns/getmyip.ashx"
+
+#define DDNS_REPLACE_URL_FOR_EAST_BFLETS "https://senet-flets.v6.softether.co.jp/ddns/ddns.aspx"
+#define DDNS_REPLACE_URL_FOR_EAST_NGN "https://senet.aoi.flets-east.jp/ddns/ddns.aspx"
+#define DDNS_REPLACE_URL_FOR_WEST_NGN "https://senet.p-ns.flets-west.jp/ddns/ddns.aspx"
+
+#define DDNS_REPLACE_URL2_FOR_EAST_BFLETS "http://senet-flets.v6.softether.co.jp/ddns/getmyip.ashx"
+#define DDNS_REPLACE_URL2_FOR_EAST_NGN "http://senet.aoi.flets-east.jp/ddns/getmyip.ashx"
+#define DDNS_REPLACE_URL2_FOR_WEST_NGN "http://senet.p-ns.flets-west.jp/ddns/getmyip.ashx"
+
+// For China: Free version
+#define DDNS_URL_V4_ALT "https://x%c.x%c.x%c.x%c.servers.ddns.uxcom.jp/ddns/ddns.aspx"
+#define DDNS_URL_V6_ALT "https://x%c.x%c.x%c.x%c.servers-v6.ddns.uxcom.jp/ddns/ddns.aspx"
+#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))
+
+// Connection Timeout
+#define DDNS_CONNECT_TIMEOUT DYN32(DDNS_CONNECT_TIMEOUT, (15 * 1000))
+
+// Communication time-out
+#define DDNS_COMM_TIMEOUT DYN32(DDNS_COMM_TIMEOUT, (60 * 1000))
+
+// Maximum length of the host name
+#define DDNS_MAX_HOSTNAME 31
+
+// DDNS Version
+#define DDNS_VERSION 1
+
+// Period until the next registration in case of success
+#define DDNS_REGISTER_INTERVAL_OK_MIN DYN32(DDNS_REGISTER_INTERVAL_OK_MIN, (1 * 60 * 60 * 1000))
+#define DDNS_REGISTER_INTERVAL_OK_MAX DYN32(DDNS_REGISTER_INTERVAL_OK_MAX, (2 * 60 * 60 * 1000))
+
+// Period until the next registration in case of failure
+#define DDNS_REGISTER_INTERVAL_NG_MIN DYN32(DDNS_REGISTER_INTERVAL_NG_MIN, (1 * 60 * 1000))
+#define DDNS_REGISTER_INTERVAL_NG_MAX DYN32(DDNS_REGISTER_INTERVAL_NG_MAX, (5 * 60 * 1000))
+
+// The self IP address acquisition interval (If last trial succeeded)
+#define DDNS_GETMYIP_INTERVAL_OK_MIN DYN32(DDNS_GETMYIP_INTERVAL_OK_MIN, (10 * 60 * 1000))
+#define DDNS_GETMYIP_INTERVAL_OK_MAX DYN32(DDNS_GETMYIP_INTERVAL_OK_MAX, (20 * 60 * 1000))
+
+// The self IP address acquisition interval (If last trial failed)
+#define DDNS_GETMYIP_INTERVAL_NG_MIN DYN32(DDNS_GETMYIP_INTERVAL_NG_MIN, (1 * 60 * 1000))
+#define DDNS_GETMYIP_INTERVAL_NG_MAX DYN32(DDNS_GETMYIP_INTERVAL_NG_MAX, (5 * 60 * 1000))
+
+// Time difference to communicate with the DDNS server after a predetermined time has elapsed since the VPN Azure is disconnected
+#define DDNS_VPN_AZURE_CONNECT_ERROR_DDNS_RETRY_TIME_DIFF DYN32(DDNS_VPN_AZURE_CONNECT_ERROR_DDNS_RETRY_TIME_DIFF, (120 * 1000))
+#define DDNS_VPN_AZURE_CONNECT_ERROR_DDNS_RETRY_TIME_DIFF_MAX DYN32(DDNS_VPN_AZURE_CONNECT_ERROR_DDNS_RETRY_TIME_DIFF_MAX, (10 * 60 * 1000))
+
+// DDNS Client
+struct DDNS_CLIENT
+{
+ CEDAR *Cedar; // Cedar
+ THREAD *Thread; // Thread
+ UCHAR Key[SHA1_SIZE]; // Key
+ LOCK *Lock; // Lock
+ volatile bool Halt; // Halt flag
+ EVENT *Event; // Halt event
+ char CurrentHostName[DDNS_MAX_HOSTNAME + 1]; // Current host name
+ char CurrentFqdn[MAX_SIZE]; // Current FQDN
+ char DnsSuffix[MAX_SIZE]; // DNS suffix
+ char CurrentIPv4[MAX_SIZE]; // Current IPv4 address
+ char CurrentIPv6[MAX_SIZE]; // Current IPv6 address
+ UINT Err_IPv4, Err_IPv6; // Last error
+ UINT Err_IPv4_GetMyIp, Err_IPv6_GetMyIp; // Last error (obtaining self IP address)
+ bool KeyChanged; // Flag to indicate that the key has been changed
+ char LastMyIPv4[MAX_SIZE]; // Self IPv4 address that were acquired on last
+ char LastMyIPv6[MAX_SIZE]; // Self IPv6 address that were acquired on last
+ char CurrentAzureIp[MAX_SIZE]; // IP address of Azure Server to be used
+ UINT64 CurrentAzureTimestamp; // Time stamp to be presented to the Azure Server
+ char CurrentAzureSignature[MAX_SIZE]; // Signature to be presented to the Azure Server
+ char AzureCertHash[MAX_SIZE]; // Azure Server certificate hash
+ INTERNET_SETTING InternetSetting; // Internet connection settings
+
+ UINT64 NextRegisterTick_IPv4, NextRegisterTick_IPv6; // Next register time
+ UINT64 NextGetMyIpTick_IPv4, NextGetMyIpTick_IPv6; // Next self IP acquisition time
+};
+
+// DDNS Register Param
+struct DDNS_REGISTER_PARAM
+{
+ char NewHostname[DDNS_MAX_HOSTNAME + 1]; // Host name after the change
+};
+
+// The current status of the DDNS
+struct DDNS_CLIENT_STATUS
+{
+ UINT Err_IPv4, Err_IPv6; // Last error
+ char CurrentHostName[DDNS_MAX_HOSTNAME + 1]; // Current host name
+ char CurrentFqdn[MAX_SIZE]; // Current FQDN
+ char DnsSuffix[MAX_SIZE]; // DNS suffix
+ char CurrentIPv4[MAX_SIZE]; // Current IPv4 address
+ char CurrentIPv6[MAX_SIZE]; // Current IPv6 address
+ char CurrentAzureIp[MAX_SIZE]; // IP address of Azure Server to be used
+ UINT64 CurrentAzureTimestamp; // Time stamp to be presented to the Azure Server
+ char CurrentAzureSignature[MAX_SIZE]; // Signature to be presented to the Azure Server
+ char AzureCertHash[MAX_SIZE]; // Azure Server certificate hash
+ INTERNET_SETTING InternetSetting; // Internet settings
+};
+
+// Function prototype
+DDNS_CLIENT *NewDDNSClient(CEDAR *cedar, UCHAR *key, INTERNET_SETTING *t);
+void FreeDDNSClient(DDNS_CLIENT *c);
+void DCGenNewKey(UCHAR *key);
+void DCThread(THREAD *thread, void *param);
+UINT DCRegister(DDNS_CLIENT *c, bool ipv6, DDNS_REGISTER_PARAM *p, char *replace_v6);
+UINT DCGetMyIpMain(DDNS_CLIENT *c, bool ipv6, char *dst, UINT dst_size, bool use_ssl, char *replace_v6);
+UINT DCGetMyIp(DDNS_CLIENT *c, bool ipv6, char *dst, UINT dst_size, char *replace_v6);
+void DCUpdateNow(DDNS_CLIENT *c);
+void DCGetStatus(DDNS_CLIENT *c, DDNS_CLIENT_STATUS *st);
+UINT DCChangeHostName(DDNS_CLIENT *c, char *hostname);
+void DCSetInternetSetting(DDNS_CLIENT *c, INTERNET_SETTING *t);
+void DCGetInternetSetting(DDNS_CLIENT *c, INTERNET_SETTING *t);
+
+#endif // DDNS_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Database.c b/src/Cedar/Database.c
new file mode 100644
index 00000000..5e1b3dd1
--- /dev/null
+++ b/src/Cedar/Database.c
@@ -0,0 +1,239 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Database.c
+// License database
+
+#include "CedarPch.h"
+
+// Get the License status string
+wchar_t *LiGetLicenseStatusStr(UINT i)
+{
+ wchar_t *ret = _UU("LICENSE_STATUS_OTHERERROR");
+
+ switch (i)
+ {
+ case LICENSE_STATUS_OK:
+ ret = _UU("LICENSE_STATUS_OK");
+ break;
+
+ case LICENSE_STATUS_EXPIRED:
+ ret = _UU("LICENSE_STATUS_EXPIRED");
+ break;
+
+ case LICENSE_STATUS_ID_DIFF:
+ ret = _UU("LICENSE_STATUS_ID_DIFF");
+ break;
+
+ case LICENSE_STATUS_DUP:
+ ret = _UU("LICENSE_STATUS_DUP");
+ break;
+
+ case LICENSE_STATUS_INSUFFICIENT:
+ ret = _UU("LICENSE_STATUS_INSUFFICIENT");
+ break;
+
+ case LICENSE_STATUS_COMPETITION:
+ ret = _UU("LICENSE_STATUS_COMPETITION");
+ break;
+
+ case LICENSE_STATUS_NONSENSE:
+ ret = _UU("LICENSE_STATUS_NONSENSE");
+ break;
+
+ case LICENSE_STATUS_CPU:
+ ret = _UU("LICENSE_STATUS_CPU");
+ break;
+ }
+
+ return ret;
+}
+
+static char *li_keybit_chars = "ABCDEFGHJKLMNPQRSTUVWXYZ12345678";
+
+// Convert the string to a key bit
+bool LiStrToKeyBit(UCHAR *keybit, char *keystr)
+{
+ UINT x[36];
+ UINT i, wp;
+ char *str;
+ // Validate arguments
+ if (keybit == NULL || keystr == NULL)
+ {
+ return false;
+ }
+
+ str = CopyStr(keystr);
+ Trim(str);
+
+ wp = 0;
+ if (StrLen(str) != 41)
+ {
+ Free(str);
+ return false;
+ }
+
+ for (i = 0;i < 36;i++)
+ {
+ char c = str[wp++];
+ UINT j;
+
+ if (((i % 6) == 5) && (i != 35))
+ {
+ if (str[wp++] != '-')
+ {
+ Free(str);
+ return false;
+ }
+ }
+
+ x[i] = INFINITE;
+ for (j = 0;j < 32;j++)
+ {
+ if (ToUpper(c) == li_keybit_chars[j])
+ {
+ x[i] = j;
+ }
+ }
+
+ if (x[i] == INFINITE)
+ {
+ Free(str);
+ return false;
+ }
+ }
+
+ Zero(keybit, 23);
+
+ keybit[0] = x[0] << 1 | x[1] >> 4;
+ keybit[1] = x[1] << 4 | x[2] >> 1;
+ keybit[2] = x[2] << 7 | x[3] << 2 | x[4] >> 3;
+ keybit[3] = x[4] << 5 | x[5];
+
+ keybit[4] = x[6] << 3 | x[7] >> 2;
+ keybit[5] = x[7] << 6 | x[8] << 1 | x[9] >> 4;
+ keybit[6] = x[9] << 4 | x[10] >> 1;
+ keybit[7] = x[10] << 7 | x[11] << 2 | x[12] >> 3;
+ keybit[8] = x[12] << 5 | x[13];
+
+ keybit[9] = x[14] << 3 | x[15] >> 2;
+ keybit[10] = x[15] << 6 | x[16] << 1 | x[17] >> 4;
+ keybit[11] = x[17] << 4 | x[18] >> 1;
+ keybit[12] = x[18] << 7 | x[19] << 2 | x[20] >> 3;
+ keybit[13] = x[20] << 5 | x[21];
+
+ keybit[14] = x[22] << 3 | x[23] >> 2;
+ keybit[15] = x[23] << 6 | x[24] << 1 | x[25] >> 4;
+ keybit[16] = x[25] << 4 | x[26] >> 1;
+ keybit[17] = x[26] << 7 | x[27] << 2 | x[28] >> 3;
+ keybit[18] = x[28] << 5 | x[29];
+
+ keybit[19] = x[30] << 3 | x[31] >> 2;
+ keybit[20] = x[31] << 6 | x[32] << 1 | x[33] >> 4;
+ keybit[21] = x[33] << 4 | x[34] >> 1;
+ keybit[22] = x[34] << 7 | x[35] << 2;
+
+ Free(str);
+
+ return true;
+}
+
+// Determine whether the string is a license key
+bool LiIsLicenseKey(char *str)
+{
+ UCHAR keybit[23];
+ // Validate arguments
+ if (str == NULL)
+ {
+ return false;
+ }
+
+ if (LiStrToKeyBit(keybit, str) == false)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Database.h b/src/Cedar/Database.h
new file mode 100644
index 00000000..e62680e2
--- /dev/null
+++ b/src/Cedar/Database.h
@@ -0,0 +1,98 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Database.h
+// Header of Database.c
+
+#ifndef DATABASE_H
+#define DATABASE_H
+
+wchar_t *LiGetLicenseStatusStr(UINT i);
+bool LiIsLicenseKey(char *str);
+bool LiStrToKeyBit(UCHAR *keybit, char *keystr);
+
+
+#endif // DATABASE_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/EM.c b/src/Cedar/EM.c
new file mode 100644
index 00000000..dafcc6ea
--- /dev/null
+++ b/src/Cedar/EM.c
@@ -0,0 +1,1476 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// EM.c
+// EtherLogger Manager for Win32
+
+#include <GlobalConst.h>
+
+#ifdef WIN32
+
+#define SM_C
+#define CM_C
+#define NM_C
+#define EM_C
+
+#define _WIN32_WINNT 0x0502
+#define WINVER 0x0502
+#include <winsock2.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <wininet.h>
+#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+#include "CMInner.h"
+#include "SMInner.h"
+#include "NMInner.h"
+#include "EMInner.h"
+#include "../PenCore/resource.h"
+
+
+// License registration process
+void EmLicenseAddDlgOnOk(HWND hWnd, RPC *s)
+{
+}
+
+// Shift treatment of text input
+void EmLicenseAddDlgShiftTextItem(HWND hWnd, UINT id1, UINT id2, UINT *next_focus)
+{
+ char *s;
+ // Validate arguments
+ if (hWnd == NULL || next_focus == NULL)
+ {
+ return;
+ }
+
+ s = GetTextA(hWnd, id1);
+ if (StrLen(s) >= 6)
+ {
+ char *s2 = CopyStr(s);
+ char tmp[MAX_SIZE];
+ s2[6] = 0;
+ SetTextA(hWnd, id1, s2);
+ Free(s2);
+
+ if (id2 != 0)
+ {
+ GetTxtA(hWnd, id2, tmp, sizeof(tmp));
+
+ StrCat(tmp, sizeof(tmp), s + 6);
+ ReplaceStrEx(tmp, sizeof(tmp), tmp, "-", "", false);
+
+ SetTextA(hWnd, id2, tmp);
+
+ *next_focus = id2;
+ }
+ else
+ {
+ *next_focus = IDOK;
+ }
+ }
+
+ Free(s);
+}
+
+// Make a text from the input data
+void EmLicenseAddDlgGetText(HWND hWnd, char *str, UINT size)
+{
+ char *k1, *k2, *k3, *k4, *k5, *k6;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return;
+ }
+
+ k1 = GetTextA(hWnd, B_KEY1);
+ k2 = GetTextA(hWnd, B_KEY2);
+ k3 = GetTextA(hWnd, B_KEY3);
+ k4 = GetTextA(hWnd, B_KEY4);
+ k5 = GetTextA(hWnd, B_KEY5);
+ k6 = GetTextA(hWnd, B_KEY6);
+
+ Format(str, size, "%s-%s-%s-%s-%s-%s", k1, k2, k3, k4, k5, k6);
+
+ Free(k1);
+ Free(k2);
+ Free(k3);
+ Free(k4);
+ Free(k5);
+ Free(k6);
+}
+
+// License addition dialog update
+void EmLicenseAddDlgUpdate(HWND hWnd, RPC *s)
+{
+}
+
+// License addition dialog initialization
+void EmLicenseAddDlgInit(HWND hWnd, RPC *s)
+{
+ HFONT h;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ h = GetFont("Arial", 10, true, false, false, false);
+ SetFont(hWnd, B_KEY1, h);
+ SetFont(hWnd, B_KEY2, h);
+ SetFont(hWnd, B_KEY3, h);
+ SetFont(hWnd, B_KEY4, h);
+ SetFont(hWnd, B_KEY5, h);
+ SetFont(hWnd, B_KEY6, h);
+
+ DlgFont(hWnd, S_INFO, 10, true);
+
+ EmLicenseAddDlgUpdate(hWnd, s);
+}
+
+// License addition dialog
+UINT EmLicenseAddDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ RPC *s = (RPC *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ EmLicenseAddDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case B_KEY1:
+ case B_KEY2:
+ case B_KEY3:
+ case B_KEY4:
+ case B_KEY5:
+ case B_KEY6:
+ switch (HIWORD(wParam))
+ {
+ case EN_CHANGE:
+ EmLicenseAddDlgUpdate(hWnd, s);
+
+ switch (LOWORD(wParam))
+ {
+ case B_KEY2:
+ if (GetTextLen(hWnd, B_KEY2, true) == 0)
+ {
+ FocusEx(hWnd, B_KEY1);
+ }
+ break;
+ case B_KEY3:
+ if (GetTextLen(hWnd, B_KEY3, true) == 0)
+ {
+ FocusEx(hWnd, B_KEY2);
+ }
+ break;
+ case B_KEY4:
+ if (GetTextLen(hWnd, B_KEY4, true) == 0)
+ {
+ FocusEx(hWnd, B_KEY3);
+ }
+ break;
+ case B_KEY5:
+ if (GetTextLen(hWnd, B_KEY5, true) == 0)
+ {
+ FocusEx(hWnd, B_KEY4);
+ }
+ break;
+ case B_KEY6:
+ if (GetTextLen(hWnd, B_KEY6, true) == 0)
+ {
+ FocusEx(hWnd, B_KEY5);
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ EmLicenseAddDlgOnOk(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Add a license
+bool EmLicenseAdd(HWND hWnd, RPC *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ return Dialog(hWnd, D_EM_LICENSE_ADD, EmLicenseAddDlg, s);
+}
+
+// License dialog initialization
+void EmLicenseDlgInit(HWND hWnd, RPC *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_CERT);
+
+ DlgFont(hWnd, S_BOLD, 0, true);
+ DlgFont(hWnd, S_BOLD2, 0, true);
+
+ LvInit(hWnd, L_LIST);
+ LvSetStyle(hWnd, L_LIST, LVS_EX_GRIDLINES);
+ LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_LICENSE_COLUMN_1"), 50);
+ LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_LICENSE_COLUMN_2"), 100);
+ LvInsertColumn(hWnd, L_LIST, 2, _UU("SM_LICENSE_COLUMN_3"), 290);
+ LvInsertColumn(hWnd, L_LIST, 3, _UU("SM_LICENSE_COLUMN_4"), 150);
+ LvInsertColumn(hWnd, L_LIST, 4, _UU("SM_LICENSE_COLUMN_5"), 120);
+ LvInsertColumn(hWnd, L_LIST, 5, _UU("SM_LICENSE_COLUMN_6"), 250);
+ LvInsertColumn(hWnd, L_LIST, 6, _UU("SM_LICENSE_COLUMN_7"), 100);
+ LvInsertColumn(hWnd, L_LIST, 7, _UU("SM_LICENSE_COLUMN_8"), 100);
+ LvInsertColumn(hWnd, L_LIST, 8, _UU("SM_LICENSE_COLUMN_9"), 100);
+
+ LvInitEx(hWnd, L_STATUS, true);
+ LvInsertColumn(hWnd, L_STATUS, 0, _UU("SM_STATUS_COLUMN_1"), 100);
+ LvInsertColumn(hWnd, L_STATUS, 1, _UU("SM_STATUS_COLUMN_2"), 100);
+
+ EmLicenseDlgRefresh(hWnd, s);
+}
+
+// License dialog update
+void EmLicenseDlgRefresh(HWND hWnd, RPC *s)
+{
+ RPC_ENUM_LICENSE_KEY t;
+ RPC_EL_LICENSE_STATUS st;
+ UINT i;
+ wchar_t tmp[MAX_SIZE];
+ LVB *b;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+
+ if (CALL(hWnd, EcEnumLicenseKey(s, &t)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ b = LvInsertStart();
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ wchar_t tmp1[32], tmp2[LICENSE_KEYSTR_LEN + 1], tmp3[LICENSE_MAX_PRODUCT_NAME_LEN + 1],
+ *tmp4, tmp5[128], tmp6[LICENSE_LICENSEID_STR_LEN + 1], tmp7[64],
+ tmp8[64], tmp9[64];
+ RPC_ENUM_LICENSE_KEY_ITEM *e = &t.Items[i];
+
+ UniToStru(tmp1, e->Id);
+ StrToUni(tmp2, sizeof(tmp2), e->LicenseKey);
+ StrToUni(tmp3, sizeof(tmp3), e->LicenseName);
+ tmp4 = LiGetLicenseStatusStr(e->Status);
+ if (e->Expires == 0)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_LICENSE_NO_EXPIRES"));
+ }
+ else
+ {
+ GetDateStrEx64(tmp5, sizeof(tmp5), e->Expires, NULL);
+ }
+ StrToUni(tmp6, sizeof(tmp6), e->LicenseId);
+ UniToStru(tmp7, e->ProductId);
+ UniFormat(tmp8, sizeof(tmp8), L"%I64u", e->SystemId);
+ UniToStru(tmp9, e->SerialId);
+
+ LvInsertAdd(b,
+ e->Status == LICENSE_STATUS_OK ? ICO_PASS : ICO_DISCARD,
+ (void *)e->Id, 9,
+ tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9);
+ }
+
+ LvInsertEnd(b, hWnd, L_LIST);
+
+ FreeRpcEnumLicenseKey(&t);
+
+ Zero(&st, sizeof(st));
+
+ if (CALL(hWnd, EcGetLicenseStatus(s, &st)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ b = LvInsertStart();
+
+ if (st.Valid == false)
+ {
+ LvInsertAdd(b, 0, NULL, 2, _UU("EM_NO_LICENSE_COLUMN"), _UU("EM_NO_LICENSE"));
+ }
+ else
+ {
+ // Current system ID
+ UniFormat(tmp, sizeof(tmp), L"%I64u", st.SystemId);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_SYSTEM_ID"), tmp);
+
+ // Expiration date of the current license product
+ if (st.SystemExpires == 0)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_NO_EXPIRES"));
+ }
+ else
+ {
+ GetDateStrEx64(tmp, sizeof(tmp), st.SystemExpires, NULL);
+ }
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_EXPIRES"), tmp);
+ }
+
+ LvInsertEnd(b, hWnd, L_STATUS);
+
+ if (LvNum(hWnd, L_STATUS) >= 1)
+ {
+ LvAutoSize(hWnd, L_STATUS);
+ }
+
+ EmLicenseDlgUpdate(hWnd, s);
+}
+
+// License dialog control update
+void EmLicenseDlgUpdate(HWND hWnd, RPC *s)
+{
+ bool b = false;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ b = LvIsSingleSelected(hWnd, L_LIST);
+
+ SetEnable(hWnd, B_DEL, b);
+ SetEnable(hWnd, IDOK, b);
+}
+
+// License dialog
+UINT EmLicenseDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ RPC *s = (RPC *)param;
+ NMHDR *n;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ EmLicenseDlgInit(hWnd, s);
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ case L_STATUS:
+ EmLicenseDlgUpdate(hWnd, s);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ if (IsEnable(hWnd, IDOK))
+ {
+ UINT i = LvGetSelected(hWnd, L_LIST);
+
+ if (i != INFINITE)
+ {
+ char *s = LvGetStrA(hWnd, L_LIST, i, 5);
+ char tmp[MAX_SIZE];
+
+ Format(tmp, sizeof(tmp), _SS("LICENSE_SUPPORT_URL"), s);
+ ShellExecute(hWnd, "open", tmp, NULL, NULL, SW_SHOW);
+
+ Free(s);
+ }
+ }
+ break;
+
+ case B_OBTAIN:
+ ShellExecute(hWnd, "open", _SS("LICENSE_INFO_URL"), NULL, NULL, SW_SHOW);
+ break;
+
+ case B_ADD:
+ if (EmLicenseAdd(hWnd, s))
+ {
+ EmLicenseDlgRefresh(hWnd, s);
+ }
+ break;
+
+ case B_DEL:
+ if (IsEnable(hWnd, B_DEL))
+ {
+ UINT id = (UINT)LvGetParam(hWnd, L_LIST, LvGetSelected(hWnd, L_LIST));
+
+ if (id != 0)
+ {
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("SM_LICENSE_DELETE_MSG")) == IDYES)
+ {
+ RPC_TEST t;
+
+ Zero(&t, sizeof(t));
+ t.IntValue = id;
+
+ if (CALL(hWnd, EcDelLicenseKey(s, &t)))
+ {
+ EmLicenseDlgRefresh(hWnd, s);
+ }
+ }
+ }
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_LIST);
+
+ return 0;
+}
+
+
+
+
+
+// Change Password dialog
+UINT EmPasswordDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ RPC *r = (RPC *)param;
+ char pass1[MAX_PATH];
+ char pass2[MAX_PATH];
+ UCHAR hash[SHA1_SIZE];
+ RPC_SET_PASSWORD t;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ Focus(hWnd, E_PASSWORD1);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ GetTxtA(hWnd, E_PASSWORD1, pass1, sizeof(pass1));
+ Hash(hash, pass1, StrLen(pass1), true);
+ Zero(&t, sizeof(t));
+ Copy(t.HashedPassword, hash, SHA1_SIZE);
+ if (CALL(hWnd, EcSetPassword(r, &t)) == false)
+ {
+ break;
+ }
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_PASSWORD_SET"));
+ EndDialog(hWnd, 1);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+
+ switch (LOWORD(wParam))
+ {
+ case E_PASSWORD1:
+ case E_PASSWORD2:
+ GetTxtA(hWnd, E_PASSWORD1, pass1, sizeof(pass1));
+ GetTxtA(hWnd, E_PASSWORD2, pass2, sizeof(pass2));
+ SetEnable(hWnd, IDOK, StrCmp(pass1, pass2) == 0 ? true : false);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Copy the state of the dialog to the HUB_LOG
+void EmDlgToHubLog(HWND hWnd, HUB_LOG *g)
+{
+ // Validate arguments
+ if (hWnd == NULL || g == NULL)
+ {
+ return;
+ }
+
+ Zero(g, sizeof(HUB_LOG));
+ g->PacketLogSwitchType = CbGetSelect(hWnd, C_PACKET_SWITCH);
+ g->PacketLogConfig[0] = IsChecked(hWnd, B_PACKET_0_0) ? 0 : IsChecked(hWnd, B_PACKET_0_1) ? 1 : 2;
+ g->PacketLogConfig[1] = IsChecked(hWnd, B_PACKET_1_0) ? 0 : IsChecked(hWnd, B_PACKET_1_1) ? 1 : 2;
+ g->PacketLogConfig[2] = IsChecked(hWnd, B_PACKET_2_0) ? 0 : IsChecked(hWnd, B_PACKET_2_1) ? 1 : 2;
+ g->PacketLogConfig[3] = IsChecked(hWnd, B_PACKET_3_0) ? 0 : IsChecked(hWnd, B_PACKET_3_1) ? 1 : 2;
+ g->PacketLogConfig[4] = IsChecked(hWnd, B_PACKET_4_0) ? 0 : IsChecked(hWnd, B_PACKET_4_1) ? 1 : 2;
+ g->PacketLogConfig[5] = IsChecked(hWnd, B_PACKET_5_0) ? 0 : IsChecked(hWnd, B_PACKET_5_1) ? 1 : 2;
+ g->PacketLogConfig[6] = IsChecked(hWnd, B_PACKET_6_0) ? 0 : IsChecked(hWnd, B_PACKET_6_1) ? 1 : 2;
+ g->PacketLogConfig[7] = IsChecked(hWnd, B_PACKET_7_0) ? 0 : IsChecked(hWnd, B_PACKET_7_1) ? 1 : 2;
+}
+
+// Copy the HUB_LOG to the state of the dialog
+void EmHubLogToDlg(HWND hWnd, HUB_LOG *g)
+{
+ // Validate arguments
+ if (hWnd == NULL || g == NULL)
+ {
+ return;
+ }
+
+ CbSelect(hWnd, C_PACKET_SWITCH, g->PacketLogSwitchType);
+
+ Check(hWnd, B_PACKET_0_0, g->PacketLogConfig[0] == 0);
+ Check(hWnd, B_PACKET_0_1, g->PacketLogConfig[0] == 1);
+ Check(hWnd, B_PACKET_0_2, g->PacketLogConfig[0] == 2);
+
+ Check(hWnd, B_PACKET_1_0, g->PacketLogConfig[1] == 0);
+ Check(hWnd, B_PACKET_1_1, g->PacketLogConfig[1] == 1);
+ Check(hWnd, B_PACKET_1_2, g->PacketLogConfig[1] == 2);
+
+ Check(hWnd, B_PACKET_2_0, g->PacketLogConfig[2] == 0);
+ Check(hWnd, B_PACKET_2_1, g->PacketLogConfig[2] == 1);
+ Check(hWnd, B_PACKET_2_2, g->PacketLogConfig[2] == 2);
+
+ Check(hWnd, B_PACKET_3_0, g->PacketLogConfig[3] == 0);
+ Check(hWnd, B_PACKET_3_1, g->PacketLogConfig[3] == 1);
+ Check(hWnd, B_PACKET_3_2, g->PacketLogConfig[3] == 2);
+
+ Check(hWnd, B_PACKET_4_0, g->PacketLogConfig[4] == 0);
+ Check(hWnd, B_PACKET_4_1, g->PacketLogConfig[4] == 1);
+ Check(hWnd, B_PACKET_4_2, g->PacketLogConfig[4] == 2);
+
+ Check(hWnd, B_PACKET_5_0, g->PacketLogConfig[5] == 0);
+ Check(hWnd, B_PACKET_5_1, g->PacketLogConfig[5] == 1);
+ Check(hWnd, B_PACKET_5_2, g->PacketLogConfig[5] == 2);
+
+ Check(hWnd, B_PACKET_6_0, g->PacketLogConfig[6] == 0);
+ Check(hWnd, B_PACKET_6_1, g->PacketLogConfig[6] == 1);
+ Check(hWnd, B_PACKET_6_2, g->PacketLogConfig[6] == 2);
+
+ Check(hWnd, B_PACKET_7_0, g->PacketLogConfig[7] == 0);
+ Check(hWnd, B_PACKET_7_1, g->PacketLogConfig[7] == 1);
+ Check(hWnd, B_PACKET_7_2, g->PacketLogConfig[7] == 2);
+}
+
+// Initialize
+void EmAddInit(HWND hWnd, EM_ADD *p)
+{
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ // Initialize controls
+ CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_0"), 0);
+ CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_1"), 1);
+ CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_2"), 2);
+ CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_3"), 3);
+ CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_4"), 4);
+ CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_5"), 5);
+
+ if (p->NewMode)
+ {
+ // Newly creation mode
+ RPC_ENUM_DEVICE t;
+ HUB_LOG g;
+
+ Zero(&g, sizeof(g));
+ g.PacketLogSwitchType = LOG_SWITCH_DAY;
+ g.PacketLogConfig[PACKET_LOG_TCP_CONN] = g.PacketLogConfig[PACKET_LOG_DHCP] = 1;
+
+ EmHubLogToDlg(hWnd, &g);
+
+ Zero(&t, sizeof(t));
+ if (CALL(hWnd, EcEnumAllDevice(p->Rpc, &t)))
+ {
+ UINT i;
+ CbSetHeight(hWnd, C_DEVICE, 18);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_DEVICE_ITEM *dev = &t.Items[i];
+ wchar_t tmp[MAX_SIZE];
+
+ StrToUni(tmp, sizeof(tmp), dev->DeviceName);
+
+ CbAddStr(hWnd, C_DEVICE, tmp, 0);
+ }
+
+ FreeRpcEnumDevice(&t);
+ }
+
+ SetText(hWnd, 0, _UU("EM_ADD_NEW"));
+ }
+ else
+ {
+ // Edit mode (to obtain a configuration)
+ wchar_t tmp[MAX_PATH];
+ RPC_ADD_DEVICE t;
+ Hide(hWnd, R_PROMISCUS);
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), p->DeviceName);
+
+ if (CALL(hWnd, EcGetDevice(p->Rpc, &t)))
+ {
+ EmHubLogToDlg(hWnd, &t.LogSetting);
+ }
+ else
+ {
+ Close(hWnd);
+ }
+
+ StrToUni(tmp, sizeof(tmp), p->DeviceName);
+ CbAddStr(hWnd, C_DEVICE, tmp, 0);
+
+ Disable(hWnd, C_DEVICE);
+
+ SetText(hWnd, 0, _UU("EM_ADD_EDIT"));
+ }
+
+ EmAddUpdate(hWnd, p);
+}
+
+// [OK] button
+void EmAddOk(HWND hWnd, EM_ADD *p)
+{
+ RPC_ADD_DEVICE t;
+ wchar_t *tmp;
+ char *name;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ EmDlgToHubLog(hWnd, &t.LogSetting);
+ tmp = CbGetStr(hWnd, C_DEVICE);
+ name = CopyUniToStr(tmp);
+
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), name);
+
+ if (p->NewMode)
+ {
+ t.NoPromiscus = IsChecked(hWnd, R_PROMISCUS);
+ }
+
+ if (p->NewMode)
+ {
+ if (CALL(hWnd, EcAddDevice(p->Rpc, &t)))
+ {
+ Close(hWnd);
+ }
+ }
+ else
+ {
+ if (CALL(hWnd, EcSetDevice(p->Rpc, &t)))
+ {
+ Close(hWnd);
+ }
+ }
+
+ Free(name);
+ Free(tmp);
+}
+
+// Control update
+void EmAddUpdate(HWND hWnd, EM_ADD *p)
+{
+ wchar_t *tmp;
+ char *name;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ tmp = CbGetStr(hWnd, C_DEVICE);
+ name = CopyUniToStr(tmp);
+
+ Trim(name);
+
+ if (StrLen(name) == 0)
+ {
+ Disable(hWnd, IDOK);
+ }
+ else
+ {
+ Enable(hWnd, IDCANCEL);
+ }
+
+ Free(name);
+ Free(tmp);
+}
+
+// Device Add / Edit dialog
+UINT EmAddDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ EM_ADD *p = (EM_ADD *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ EmAddInit(hWnd, p);
+ break;
+
+ case WM_COMMAND:
+ EmAddUpdate(hWnd, p);
+ switch (wParam)
+ {
+ case IDOK:
+ EmAddOk(hWnd, p);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Add or edit
+void EmAdd(HWND hWnd, RPC *r, char *device_name)
+{
+ EM_ADD p;
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ Zero(&p, sizeof(p));
+
+ p.Rpc = r;
+
+ if (device_name != NULL)
+ {
+ StrCpy(p.DeviceName, sizeof(p.DeviceName), device_name);
+ }
+ else
+ {
+ p.NewMode = true;
+ }
+
+ Dialog(hWnd, D_EM_ADD, EmAddDlg, &p);
+}
+
+// Initialize
+void EmMainInit(HWND hWnd, RPC *r)
+{
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ LvInit(hWnd, L_LIST);
+ LvInsertColumn(hWnd, L_LIST, 0, _UU("EM_MAIN_COLUMN_1"), 300);
+ LvInsertColumn(hWnd, L_LIST, 1, _UU("EM_MAIN_COLUMN_2"), 150);
+
+ SetIcon(hWnd, 0, ICO_NIC_ONLINE);
+
+ EmMainRefresh(hWnd, r);
+
+ SetTimer(hWnd, 1, 1000, NULL);
+}
+
+// Control update
+void EmMainUpdate(HWND hWnd, RPC *r)
+{
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ SetEnable(hWnd, IDOK, LvIsMasked(hWnd, L_LIST) && LvIsMultiMasked(hWnd, L_LIST) == false);
+ SetEnable(hWnd, B_DELETE, LvIsMasked(hWnd, L_LIST) && LvIsMultiMasked(hWnd, L_LIST) == false);
+}
+
+// Update
+void EmMainRefresh(HWND hWnd, RPC *r)
+{
+ RPC_ENUM_DEVICE t;
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+
+ if (CALL(hWnd, EcEnumDevice(r, &t)))
+ {
+ UINT i;
+ LVB *b;
+
+ b = LvInsertStart();
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ wchar_t tmp[MAX_PATH];
+ RPC_ENUM_DEVICE_ITEM *dev = &t.Items[i];
+
+ StrToUni(tmp, sizeof(tmp), dev->DeviceName);
+
+ LvInsertAdd(b,
+ dev->Active ? ICO_NIC_ONLINE : ICO_NIC_OFFLINE,
+ NULL,
+ 2,
+ tmp,
+ dev->Active ? _UU("EM_MAIN_OK") : _UU("EM_MAIN_ERROR"));
+ }
+
+ LvInsertEnd(b, hWnd, L_LIST);
+
+ FreeRpcEnumDevice(&t);
+
+ SetShow(hWnd, B_LICENSE, t.IsLicenseSupported);
+ }
+ else
+ {
+ Close(hWnd);
+ }
+
+ EmMainUpdate(hWnd, r);
+}
+
+// Main dialog procedure
+UINT EmMainDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ NMHDR *n;
+ RPC *r = (RPC *)param;
+ UINT i;
+ char *name;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ EmMainInit(hWnd, r);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ // Edit
+ i = LvGetSelected(hWnd, L_LIST);
+ if (i != INFINITE)
+ {
+ wchar_t *tmp;
+ tmp = LvGetStr(hWnd, L_LIST, i, 0);
+ if (tmp != NULL)
+ {
+ name = CopyUniToStr(tmp);
+ EmAdd(hWnd, r, name);
+ Free(tmp);
+ Free(name);
+ }
+ }
+ break;
+
+ case B_PASSWORD:
+ // Admin password
+ Dialog(hWnd, D_EM_PASSWORD, EmPasswordDlg, r);
+ break;
+
+ case B_LICENSE:
+ // Admin password
+ Dialog(hWnd, D_EM_LICENSE, EmLicenseDlg, r);
+ break;
+
+ case B_ADD:
+ // Add
+ EmAdd(hWnd, r, NULL);
+ EmMainRefresh(hWnd, r);
+ break;
+
+ case B_DELETE:
+ // Delete
+ i = LvGetSelected(hWnd, L_LIST);
+ if (i != INFINITE)
+ {
+ wchar_t *tmp;
+ tmp = LvGetStr(hWnd, L_LIST, i, 0);
+ if (tmp != NULL)
+ {
+ RPC_DELETE_DEVICE t;
+ wchar_t msg[MAX_SIZE];
+ name = CopyUniToStr(tmp);
+ UniFormat(msg, sizeof(msg), _UU("EM_DELETE_CONFIRM"), name);
+ if (MsgBox(hWnd, MB_YESNO | MB_ICONEXCLAMATION | MB_DEFBUTTON2, msg) == IDYES)
+ {
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), name);
+ if (CALL(hWnd, EcDelDevice(r, &t)))
+ {
+ EmMainRefresh(hWnd, r);
+ }
+ }
+ Free(tmp);
+ Free(name);
+ }
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+ EmMainRefresh(hWnd, r);
+ SetTimer(hWnd, 1, 1000, NULL);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->code)
+ {
+ case NM_DBLCLK:
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ if (IsEnable(hWnd, IDOK))
+ {
+ Command(hWnd, IDOK);
+ }
+ break;
+ }
+ break;
+ case LVN_ITEMCHANGED:
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ EmMainUpdate(hWnd, r);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Installation of WinPcap
+void EmInstallWinPcap(HWND hWnd, RPC *r)
+{
+ wchar_t temp_name[MAX_SIZE];
+ HGLOBAL g;
+ HINSTANCE h;
+ HRSRC hr;
+ UINT size;
+ void *data;
+ IO *io;
+
+ // Ask whether the user want to start the installation
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("EM_WPCAP_INSTALL")) == IDNO)
+ {
+ return;
+ }
+
+ // Generate a temporary file name
+ UniFormat(temp_name, sizeof(temp_name), L"%s\\winpcap_installer.exe", MsGetTempDirW());
+
+ // Read from the resource
+ h = GetUiDll();
+ hr = FindResource(h, MAKEINTRESOURCE(BIN_WINPCAP), "BIN");
+ if (hr == NULL)
+ {
+RES_ERROR:
+ MsgBox(hWnd, MB_ICONSTOP, _UU("EM_RESOURCE"));
+ return;
+ }
+
+ g = LoadResource(h, hr);
+ if (g == NULL)
+ {
+ goto RES_ERROR;
+ }
+
+ size = SizeofResource(h, hr);
+ data = LockResource(g);
+
+ if (data == NULL)
+ {
+ goto RES_ERROR;
+ }
+
+ // Write to a temporary file
+ io = FileCreateW(temp_name);
+ if (io == NULL)
+ {
+ goto RES_ERROR;
+ }
+
+ FileWrite(io, data, size);
+ FileClose(io);
+
+ // Run
+ if (RunW(temp_name, NULL, false, true) == false)
+ {
+ // Failure
+ FileDeleteW(temp_name);
+ goto RES_ERROR;
+ }
+
+ FileDeleteW(temp_name);
+
+ if (r == NULL)
+ {
+ return;
+ }
+
+ // Message after the end
+ if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) == false)
+ {
+ // Need to restart the computer
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("EM_WPCAP_REBOOT1"));
+ }
+ else
+ {
+ // Need to restart the service
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("EM_WPCAP_REBOOT2")) == IDNO)
+ {
+ // Not restart
+ }
+ else
+ {
+ // Restart
+ RPC_TEST t;
+ RPC_BRIDGE_SUPPORT t2;
+ Zero(&t, sizeof(t));
+ EcRebootServer(r, &t);
+
+ SleepThread(500);
+
+ Zero(&t2, sizeof(t2));
+ CALL(hWnd, EcGetBridgeSupport(r, &t2));
+ }
+ }
+}
+
+// Main screen
+void EMMain(RPC *r)
+{
+ RPC_BRIDGE_SUPPORT t;
+
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+ // Examine the bridge support status of the server side first
+ Zero(&t, sizeof(t));
+ if (CALLEX(NULL, ScGetBridgeSupport(r, &t)) == ERR_NO_ERROR)
+ {
+ if (t.IsBridgeSupportedOs == false)
+ {
+ // OS does not support the bridge
+ MsgBox(NULL, MB_ICONEXCLAMATION, _UU("EM_UNSUPPORTED"));
+ return;
+ }
+
+ if (t.IsWinPcapNeeded)
+ {
+ if (r->Sock->RemoteIP.addr[0] != 127)
+ {
+ // WinPcap is required, but can not do anything because it is in remote management mode
+ MsgBox(NULL, MB_ICONINFORMATION, _UU("EM_WPCAP_REMOTE"));
+ return;
+ }
+ else
+ {
+ // WinPcap is required, and it's in local management mode
+ if (MsIsAdmin())
+ {
+ // Administrators
+ EmInstallWinPcap(NULL, r);
+ return;
+ }
+ else
+ {
+ // Non-Administrators
+ MsgBox(NULL, MB_ICONINFORMATION, _UU("EM_WPCAP_ROOT"));
+ return;
+ }
+ }
+ }
+ }
+
+ Dialog(NULL, D_EM_MAIN, EmMainDlg, r);
+}
+
+// Remote connection dialog procedure
+UINT EmRemoteDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ WINUI_REMOTE *r = (WINUI_REMOTE *)param;
+ CEDAR *c;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ RemoteDlgInit(hWnd, r);
+ SetTimer(hWnd, 1, 100, NULL);
+ break;
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+ RemoteDlgRefresh(hWnd, r);
+ SetTimer(hWnd, 1, 100, NULL);
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case R_LOCAL:
+ if (IsChecked(hWnd, R_LOCAL) == false)
+ {
+ SetTextA(hWnd, C_HOSTNAME, "");
+ RemoteDlgRefresh(hWnd, r);
+ FocusEx(hWnd, C_HOSTNAME);
+ }
+ else
+ {
+ SetTextA(hWnd, C_HOSTNAME, "localhost");
+ RemoteDlgRefresh(hWnd, r);
+ Focus(hWnd, IDOK);
+ }
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ case IDOK:
+ RemoteDlgOnOk(hWnd, r);
+ break;
+ case B_ABOUT:
+ c = NewCedar(NULL, NULL);
+ About(hWnd, c, _UU("PRODUCT_NAME_ELOGMGR"));
+ ReleaseCedar(c);
+ }
+ switch (LOWORD(wParam))
+ {
+ case R_LOCAL:
+ case C_HOSTNAME:
+ RemoteDlgRefresh(hWnd, r);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ FreeCandidateList(r->CandidateList);
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Remote connection dialog
+char *EmRemoteDlg()
+{
+ WINUI_REMOTE r;
+
+ Zero(&r, sizeof(r));
+ r.RegKeyName = EM_REG_KEY;
+ r.Caption = _UU("EM_TITLE");
+ r.Title = _UU("EM_REMOTE_TITLE");
+ r.Icon = ICO_USER_ADMIN;
+ r.DefaultHostname = NULL;
+
+ if (Dialog(NULL, D_EM_REMOTE, EmRemoteDlgProc, &r) == false)
+ {
+ return NULL;
+ }
+
+ return r.Hostname;
+}
+
+// Start the EtherLogger Manager
+void EMExec()
+{
+ char *host;
+ char *ret;
+ bool cancel_now = false;
+ TOKEN_LIST *t;
+ UINT port = EL_ADMIN_PORT;
+ InitWinUi(_UU("EM_TITLE"), _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+
+ while (true)
+ {
+ ret = EmRemoteDlg();
+
+ if (ret != NULL)
+ {
+ t = ParseToken(ret, ":");
+ if (t->NumTokens == 1 || t->NumTokens == 2)
+ {
+ RPC *rpc = NULL;
+ bool ok = false;
+ UINT ret;
+ host = t->Token[0];
+ if (t->NumTokens == 2)
+ {
+ port = ToInt(t->Token[1]);
+ }
+ else
+ {
+ port = EL_ADMIN_PORT;
+ }
+
+ // Try without a password first
+ ret = EcConnect(host, port, "", &rpc);
+RETRY:
+ if (ret != ERR_NO_ERROR && ret != ERR_AUTH_FAILED)
+ {
+ // Connection failed
+ CALL(NULL, ret);
+ }
+ else
+ {
+ if (ret == ERR_NO_ERROR)
+ {
+ // Successful connection
+ ok = true;
+ }
+ else
+ {
+ // Password required
+ char *pass = SmPassword(NULL, host);
+ if (pass == NULL)
+ {
+ // Cancel
+ cancel_now = true;
+ }
+ else
+ {
+ // Retry
+ ret = EcConnect(host, port, pass, &rpc);
+ Free(pass);
+ if (ret == ERR_NO_ERROR)
+ {
+ ok = true;
+ }
+ else
+ {
+ goto RETRY;
+ }
+ }
+ }
+ }
+
+ if (ok)
+ {
+ // Main screen
+ EMMain(rpc);
+
+ // Disconnect
+ EcDisconnect(rpc);
+ cancel_now = true;
+ }
+ FreeToken(t);
+ }
+ Free(ret);
+ }
+ else
+ {
+ cancel_now = true;
+ }
+
+ if (cancel_now)
+ {
+ break;
+ }
+ }
+
+ FreeWinUi();
+}
+
+#endif // WIN32
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/EM.h b/src/Cedar/EM.h
new file mode 100644
index 00000000..fd133fe9
--- /dev/null
+++ b/src/Cedar/EM.h
@@ -0,0 +1,96 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// EM.h
+// Header of EM.c
+
+#ifndef EM_H
+#define EM_H
+
+// Public function
+void EMExec();
+
+#endif // EM_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/EMInner.h b/src/Cedar/EMInner.h
new file mode 100644
index 00000000..b6aea06d
--- /dev/null
+++ b/src/Cedar/EMInner.h
@@ -0,0 +1,122 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// EMInner.h
+// Inner header of EM.c
+
+// Constants
+#define EM_REG_KEY "Software\\" GC_REG_COMPANY_NAME "\\EtherLogger\\Manager"
+
+// Innner structure
+typedef struct EM_ADD
+{
+ RPC *Rpc;
+ bool NewMode;
+ char DeviceName[MAX_SIZE];
+} EM_ADD;
+
+// Inner functions
+void EMMain(RPC *r);
+UINT EmMainDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void EmMainInit(HWND hWnd, RPC *r);
+void EmMainUpdate(HWND hWnd, RPC *r);
+void EmMainRefresh(HWND hWnd, RPC *r);
+void EmAdd(HWND hWnd, RPC *r, char *device_name);
+UINT EmAddDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void EmAddInit(HWND hWnd, EM_ADD *p);
+void EmDlgToHubLog(HWND hWnd, HUB_LOG *g);
+void EmHubLogToDlg(HWND hWnd, HUB_LOG *g);
+void EmAddOk(HWND hWnd, EM_ADD *p);
+void EmAddUpdate(HWND hWnd, EM_ADD *p);
+UINT EmPasswordDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+UINT EmLicenseDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void EmLicenseDlgInit(HWND hWnd, RPC *s);
+void EmLicenseDlgRefresh(HWND hWnd, RPC *s);
+void EmLicenseDlgUpdate(HWND hWnd, RPC *s);
+bool EmLicenseAdd(HWND hWnd, RPC *s);
+UINT EmLicenseAddDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void EmLicenseAddDlgInit(HWND hWnd, RPC *s);
+void EmLicenseAddDlgUpdate(HWND hWnd, RPC *s);
+void EmLicenseAddDlgShiftTextItem(HWND hWnd, UINT id1, UINT id2, UINT *next_focus);
+void EmLicenseAddDlgGetText(HWND hWnd, char *str, UINT size);
+void EmLicenseAddDlgOnOk(HWND hWnd, RPC *s);
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/EtherLog.c b/src/Cedar/EtherLog.c
new file mode 100644
index 00000000..c3d44955
--- /dev/null
+++ b/src/Cedar/EtherLog.c
@@ -0,0 +1,1356 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// EtherLog.c
+// EtherLogger program
+
+#include "CedarPch.h"
+
+static LOCK *el_lock = NULL;
+static EL *el = NULL;
+
+// RPC functional related macro
+#define DECLARE_RPC_EX(rpc_name, data_type, function, in_rpc, out_rpc, free_rpc) \
+ else if (StrCmpi(name, rpc_name) == 0) \
+ { \
+ data_type t; \
+ Zero(&t, sizeof(t)); \
+ in_rpc(&t, p); \
+ err = function(e, &t); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ out_rpc(ret, &t); \
+ } \
+ free_rpc(&t); \
+ ok = true; \
+ }
+#define DECLARE_RPC(rpc_name, data_type, function, in_rpc, out_rpc) \
+ else if (StrCmpi(name, rpc_name) == 0) \
+ { \
+ data_type t; \
+ Zero(&t, sizeof(t)); \
+ in_rpc(&t, p); \
+ err = function(e, &t); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ out_rpc(ret, &t); \
+ } \
+ ok = true; \
+ }
+#define DECLARE_SC_EX(rpc_name, data_type, function, in_rpc, out_rpc, free_rpc) \
+ UINT function(RPC *r, data_type *t) \
+ { \
+ PACK *p, *ret; \
+ UINT err; \
+ if (r == NULL || t == NULL) \
+ { \
+ return ERR_INTERNAL_ERROR; \
+ } \
+ p = NewPack(); \
+ out_rpc(p, t); \
+ free_rpc(t); \
+ Zero(t, sizeof(data_type)); \
+ ret = AdminCall(r, rpc_name, p); \
+ err = GetErrorFromPack(ret); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ in_rpc(t, ret); \
+ } \
+ FreePack(ret); \
+ return err; \
+ }
+#define DECLARE_SC(rpc_name, data_type, function, in_rpc, out_rpc) \
+ UINT function(RPC *r, data_type *t) \
+ { \
+ PACK *p, *ret; \
+ UINT err; \
+ if (r == NULL || t == NULL) \
+ { \
+ return ERR_INTERNAL_ERROR; \
+ } \
+ p = NewPack(); \
+ out_rpc(p, t); \
+ ret = AdminCall(r, rpc_name, p); \
+ err = GetErrorFromPack(ret); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ in_rpc(t, ret); \
+ } \
+ FreePack(ret); \
+ return err; \
+ }
+
+// RPC client disconnect
+void EcDisconnect(RPC *rpc)
+{
+ // Validate arguments
+ if (rpc == NULL)
+ {
+ return;
+ }
+
+ RpcFree(rpc);
+}
+
+// RPC client connect
+UINT EcConnect(char *host, UINT port, char *password, RPC **rpc)
+{
+ SOCK *s;
+ UCHAR password_hash[SHA1_SIZE];
+ UCHAR rand[SHA1_SIZE];
+ UCHAR response[SHA1_SIZE];
+ bool retcode;
+ // Validate arguments
+ if (host == NULL)
+ {
+ host = "localhost";
+ }
+ if (port == 0)
+ {
+ port = EL_ADMIN_PORT;
+ }
+ if (password == NULL)
+ {
+ password = "";
+ }
+ if (rpc == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ // Connect to the server
+ s = Connect(host, port);
+ if (s == NULL)
+ {
+ // Connection failure
+ return ERR_CONNECT_FAILED;
+ }
+
+ SetTimeout(s, 5000);
+
+ // Hash the password
+ Hash(password_hash, password, StrLen(password), true);
+
+ // Receive the random number
+ Zero(rand, sizeof(rand));
+ RecvAll(s, rand, sizeof(rand), false);
+ SecurePassword(response, password_hash, rand);
+
+ // Send a response
+ SendAll(s, response, sizeof(response), false);
+
+ // Receive results
+ retcode = false;
+ if (RecvAll(s, &retcode, sizeof(retcode), false) == false)
+ {
+ // Disconnect
+ ReleaseSock(s);
+ return ERR_PROTOCOL_ERROR;
+ }
+ retcode = Endian32(retcode);
+
+ if (retcode == false)
+ {
+ // Password incorrect
+ ReleaseSock(s);
+ return ERR_AUTH_FAILED;
+ }
+
+ // Successful connection
+ SetTimeout(s, INFINITE);
+
+ *rpc = StartRpcClient(s, NULL);
+
+ ReleaseSock(s);
+
+ return ERR_NO_ERROR;
+}
+
+// RPC server function
+PACK *ElRpcServer(RPC *r, char *name, PACK *p)
+{
+ EL *e = (EL *)r->Param;
+ PACK *ret;
+ UINT err;
+ bool ok;
+ // Validate arguments
+ if (r == NULL || name == NULL || p == NULL || e == NULL)
+ {
+ return NULL;
+ }
+
+ ret = NewPack();
+ err = ERR_NO_ERROR;
+ ok = false;
+
+ if (0) {}
+
+ DECLARE_RPC("AddDevice", RPC_ADD_DEVICE, EtAddDevice, InRpcAddDevice, OutRpcAddDevice)
+ DECLARE_RPC("DelDevice", RPC_DELETE_DEVICE, EtDelDevice, InRpcDeleteDevice, OutRpcDeleteDevice)
+ DECLARE_RPC("SetDevice", RPC_ADD_DEVICE, EtSetDevice, InRpcAddDevice, OutRpcAddDevice)
+ DECLARE_RPC("GetDevice", RPC_ADD_DEVICE, EtGetDevice, InRpcAddDevice, OutRpcAddDevice)
+ DECLARE_RPC_EX("EnumDevice", RPC_ENUM_DEVICE, EtEnumDevice, InRpcEnumDevice, OutRpcEnumDevice, FreeRpcEnumDevice)
+ DECLARE_RPC("SetPassword", RPC_SET_PASSWORD, EtSetPassword, InRpcSetPassword, OutRpcSetPassword)
+ DECLARE_RPC_EX("EnumAllDevice", RPC_ENUM_DEVICE, EtEnumAllDevice, InRpcEnumDevice, OutRpcEnumDevice, FreeRpcEnumDevice)
+ DECLARE_RPC("AddLicenseKey", RPC_TEST, EtAddLicenseKey, InRpcTest, OutRpcTest)
+ DECLARE_RPC("DelLicenseKey", RPC_TEST, EtDelLicenseKey, InRpcTest, OutRpcTest)
+ DECLARE_RPC_EX("EnumLicenseKey", RPC_ENUM_LICENSE_KEY, EtEnumLicenseKey, InRpcEnumLicenseKey, OutRpcEnumLicenseKey, FreeRpcEnumLicenseKey)
+ DECLARE_RPC("GetLicenseStatus", RPC_EL_LICENSE_STATUS, EtGetLicenseStatus, InRpcElLicenseStatus, OutRpcElLicenseStatus)
+ DECLARE_RPC("GetBridgeSupport", RPC_BRIDGE_SUPPORT, EtGetBridgeSupport, InRpcBridgeSupport, OutRpcBridgeSupport)
+ DECLARE_RPC("RebootServer", RPC_TEST, EtRebootServer, InRpcTest, OutRpcTest)
+
+ if (ok == false)
+ {
+ err = ERR_NOT_SUPPORTED;
+ }
+
+ PackAddInt(ret, "error", err);
+
+ return ret;
+}
+
+DECLARE_SC("AddDevice", RPC_ADD_DEVICE, EcAddDevice, InRpcAddDevice, OutRpcAddDevice)
+DECLARE_SC("DelDevice", RPC_DELETE_DEVICE, EcDelDevice, InRpcDeleteDevice, OutRpcDeleteDevice)
+DECLARE_SC("SetDevice", RPC_ADD_DEVICE, EcSetDevice, InRpcAddDevice, OutRpcAddDevice)
+DECLARE_SC("GetDevice", RPC_ADD_DEVICE, EcGetDevice, InRpcAddDevice, OutRpcAddDevice)
+DECLARE_SC_EX("EnumDevice", RPC_ENUM_DEVICE, EcEnumDevice, InRpcEnumDevice, OutRpcEnumDevice, FreeRpcEnumDevice)
+DECLARE_SC("SetPassword", RPC_SET_PASSWORD, EcSetPassword, InRpcSetPassword, OutRpcSetPassword)
+DECLARE_SC_EX("EnumAllDevice", RPC_ENUM_DEVICE, EcEnumAllDevice, InRpcEnumDevice, OutRpcEnumDevice, FreeRpcEnumDevice)
+DECLARE_SC("AddLicenseKey", RPC_TEST, EcAddLicenseKey, InRpcTest, OutRpcTest)
+DECLARE_SC("DelLicenseKey", RPC_TEST, EcDelLicenseKey, InRpcTest, OutRpcTest)
+DECLARE_SC_EX("EnumLicenseKey", RPC_ENUM_LICENSE_KEY, EcEnumLicenseKey, InRpcEnumLicenseKey, OutRpcEnumLicenseKey, FreeRpcEnumLicenseKey)
+DECLARE_SC("GetLicenseStatus", RPC_EL_LICENSE_STATUS, EcGetLicenseStatus, InRpcElLicenseStatus, OutRpcElLicenseStatus)
+DECLARE_SC("GetBridgeSupport", RPC_BRIDGE_SUPPORT, EcGetBridgeSupport, InRpcBridgeSupport, OutRpcBridgeSupport)
+DECLARE_SC("RebootServer", RPC_TEST, EcRebootServer, InRpcTest, OutRpcTest)
+
+// Thread to restart the server
+void EiRebootServerThread(THREAD *thread, void *param)
+{
+ // Validate arguments
+ if (thread == NULL)
+ {
+ return;
+ }
+
+ if (el == NULL)
+ {
+ return;
+ }
+
+ // Stopping the server
+ ElStop();
+
+ // Starting the server
+ ElStart();
+}
+
+// Restarting the server
+void EiRebootServer()
+{
+ THREAD *t;
+
+ t = NewThread(EiRebootServerThread, NULL);
+ ReleaseThread(t);
+}
+
+// RPC to restart server
+UINT EtRebootServer(EL *a, RPC_TEST *t)
+{
+
+ EiRebootServer();
+
+ return ERR_NO_ERROR;
+}
+
+// Get support information for the local bridge
+UINT EtGetBridgeSupport(EL *a, RPC_BRIDGE_SUPPORT *t)
+{
+ Zero(t, sizeof(RPC_BRIDGE_SUPPORT));
+
+ t->IsBridgeSupportedOs = IsBridgeSupported();
+ t->IsWinPcapNeeded = IsNeedWinPcap();
+
+ return ERR_NO_ERROR;
+}
+
+// Update the status by checking the all licenses
+void ElCheckLicense(EL_LICENSE_STATUS *st, LICENSE *e)
+{
+}
+
+// Save by analyzing the status of the current license
+void ElParseCurrentLicenseStatus(LICENSE_SYSTEM *s, EL_LICENSE_STATUS *st)
+{
+}
+
+// Get a license status
+UINT EtGetLicenseStatus(EL *e, RPC_EL_LICENSE_STATUS *t)
+{
+ UINT ret = ERR_NO_ERROR;
+ LICENSE_SYSTEM *ls = e->LicenseSystem;
+
+ if (ls == NULL)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ Zero(t, sizeof(RPC_EL_LICENSE_STATUS));
+
+ // Get the current license status
+ ElParseCurrentLicenseStatus(ls, e->LicenseStatus);
+
+ t->Valid = e->LicenseStatus->Valid;
+ t->SystemId = e->LicenseStatus->SystemId;
+ t->SystemExpires = e->LicenseStatus->Expires;
+
+ return ret;
+}
+
+// Enumerate the license keys
+UINT EtEnumLicenseKey(EL *el, RPC_ENUM_LICENSE_KEY *t)
+{
+ return ERR_NOT_SUPPORTED;
+}
+
+// Add a license key
+UINT EtAddLicenseKey(EL *e, RPC_TEST *t)
+{
+ return ERR_NOT_SUPPORTED;
+}
+
+// Delete the license key
+UINT EtDelLicenseKey(EL *e, RPC_TEST *t)
+{
+ return ERR_NOT_SUPPORTED;
+}
+
+// Password setting
+UINT EtSetPassword(EL *e, RPC_SET_PASSWORD *t)
+{
+ Copy(e->HashedPassword, t->HashedPassword, SHA1_SIZE);
+
+ ElSaveConfig(e);
+
+ return ERR_NO_ERROR;
+}
+
+// Add a device
+UINT EtAddDevice(EL *e, RPC_ADD_DEVICE *t)
+{
+ if (ElAddCaptureDevice(e, t->DeviceName, &t->LogSetting, t->NoPromiscus) == false)
+ {
+ return ERR_CAPTURE_DEVICE_ADD_ERROR;
+ }
+
+ ElSaveConfig(e);
+
+ return ERR_NO_ERROR;
+}
+
+// Remove the device
+UINT EtDelDevice(EL *e, RPC_DELETE_DEVICE *t)
+{
+ if (ElDeleteCaptureDevice(e, t->DeviceName) == false)
+ {
+ return ERR_CAPTURE_NOT_FOUND;
+ }
+
+ ElSaveConfig(e);
+
+ return ERR_NO_ERROR;
+}
+
+// Get the device
+UINT EtGetDevice(EL *e, RPC_ADD_DEVICE *t)
+{
+ UINT ret = ERR_CAPTURE_NOT_FOUND;
+
+ LockList(e->DeviceList);
+ {
+ EL_DEVICE *d, a;
+ Zero(&a, sizeof(a));
+ StrCpy(a.DeviceName, sizeof(a.DeviceName), t->DeviceName);
+
+ d = Search(e->DeviceList, &a);
+
+ if (d != NULL)
+ {
+ ret = ERR_NO_ERROR;
+
+ Copy(&t->LogSetting, &d->LogSetting, sizeof(HUB_LOG));
+ t->NoPromiscus = d->NoPromiscus;
+ }
+ }
+ UnlockList(e->DeviceList);
+
+ return ret;
+}
+
+// Device Setting
+UINT EtSetDevice(EL *e, RPC_ADD_DEVICE *t)
+{
+ if (ElSetCaptureDeviceLogSetting(e, t->DeviceName, &t->LogSetting) == false)
+ {
+ return ERR_CAPTURE_NOT_FOUND;
+ }
+
+ ElSaveConfig(e);
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate all devices
+UINT EtEnumAllDevice(EL *e, RPC_ENUM_DEVICE *t)
+{
+ TOKEN_LIST *eth;
+ UINT i;
+ if (IsEthSupported() == false)
+ {
+ return ERR_NOT_SUPPORTED;
+ }
+
+ FreeRpcEnumDevice(t);
+ Zero(t, sizeof(RPC_ENUM_DEVICE));
+
+ eth = GetEthList();
+
+ t->NumItem = eth->NumTokens;
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_DEVICE_ITEM) * t->NumItem);
+
+ for (i = 0;i < eth->NumTokens;i++)
+ {
+ char *name = eth->Token[i];
+ RPC_ENUM_DEVICE_ITEM *item = &t->Items[i];
+
+ StrCpy(item->DeviceName, sizeof(item->DeviceName), name);
+ }
+
+ FreeToken(eth);
+
+ return ERR_NO_ERROR;
+}
+
+// Device enumeration
+UINT EtEnumDevice(EL *e, RPC_ENUM_DEVICE *t)
+{
+ bool is_beta_expired = ElIsBetaExpired();
+
+ if (is_beta_expired)
+ {
+ // The beta version has expired
+ return ERR_BETA_EXPIRES;
+ }
+
+ FreeRpcEnumDevice(t);
+ Zero(t, sizeof(RPC_ENUM_DEVICE));
+
+ LockList(e->DeviceList);
+ {
+ UINT i;
+
+ t->NumItem = LIST_NUM(e->DeviceList);
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_DEVICE_ITEM) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_DEVICE_ITEM *d = &t->Items[i];
+ EL_DEVICE *eld = LIST_DATA(e->DeviceList, i);
+
+ StrCpy(d->DeviceName, sizeof(d->DeviceName), eld->DeviceName);
+ d->Active = eld->Active && ((ELOG_IS_BETA || e->LicenseStatus->Valid) ? true : false);
+ }
+ }
+ UnlockList(e->DeviceList);
+
+ return ERR_NO_ERROR;
+}
+
+void InRpcAddDevice(RPC_ADD_DEVICE *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ADD_DEVICE));
+ PackGetStr(p, "DeviceName", t->DeviceName, sizeof(t->DeviceName));
+ t->NoPromiscus = PackGetInt(p, "NoPromiscus");
+ t->LogSetting.PacketLogSwitchType = PackGetInt(p, "PacketLogSwitchType");
+
+ for (i = 0;i < NUM_PACKET_LOG;i++)
+ {
+ t->LogSetting.PacketLogConfig[i] = PackGetIntEx(p, "PacketLogConfig", i);
+ }
+}
+
+void OutRpcAddDevice(PACK *p, RPC_ADD_DEVICE *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "DeviceName", t->DeviceName);
+ PackAddInt(p, "NoPromiscus", t->NoPromiscus);
+ PackAddInt(p, "PacketLogSwitchType", t->LogSetting.PacketLogSwitchType);
+
+ for (i = 0;i < NUM_PACKET_LOG;i++)
+ {
+ PackAddIntEx(p, "PacketLogConfig", t->LogSetting.PacketLogConfig[i], i, NUM_PACKET_LOG);
+ }
+}
+
+void InRpcDeleteDevice(RPC_DELETE_DEVICE *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_DELETE_DEVICE));
+ PackGetStr(p, "DeviceName", t->DeviceName, sizeof(t->DeviceName));
+}
+
+void OutRpcDeleteDevice(PACK *p, RPC_DELETE_DEVICE *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "DeviceName", t->DeviceName);
+}
+
+void InRpcEnumDevice(RPC_ENUM_DEVICE *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_DEVICE));
+ t->NumItem = PackGetInt(p, "NumItem");
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_DEVICE_ITEM) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_DEVICE_ITEM *d = &t->Items[i];
+
+ PackGetStrEx(p, "DeviceName", d->DeviceName, sizeof(d->DeviceName), i);
+ d->Active = PackGetBoolEx(p, "Active", i);
+ }
+
+ t->IsLicenseSupported = PackGetBool(p, "IsLicenseSupported");
+}
+
+void OutRpcEnumDevice(PACK *p, RPC_ENUM_DEVICE *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_DEVICE_ITEM *d = &t->Items[i];
+
+ PackAddStrEx(p, "DeviceName", d->DeviceName, i, t->NumItem);
+ PackAddBoolEx(p, "Active", d->Active, i, t->NumItem);
+ }
+
+ PackAddBool(p, "IsLicenseSupported", t->IsLicenseSupported);
+}
+
+void FreeRpcEnumDevice(RPC_ENUM_DEVICE *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_LICENSE_STATUS
+void InRpcElLicenseStatus(RPC_EL_LICENSE_STATUS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_EL_LICENSE_STATUS));
+
+ t->Valid = PackGetBool(p, "Valid");
+ t->SystemId = PackGetInt64(p, "SystemId");
+ t->SystemExpires = PackGetInt64(p, "SystemExpires");
+}
+void OutRpcElLicenseStatus(PACK *p, RPC_EL_LICENSE_STATUS *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddBool(p, "Valid", t->Valid);
+ PackAddInt64(p, "SystemId", t->SystemId);
+ PackAddInt64(p, "SystemExpires", t->SystemExpires);
+}
+
+// Listener thread
+void ElListenerProc(THREAD *thread, void *param)
+{
+ TCP_ACCEPTED_PARAM *data = (TCP_ACCEPTED_PARAM *)param;
+ EL *e;
+ SOCK *s;
+ UCHAR rand[SHA1_SIZE];
+ UCHAR pass1[SHA1_SIZE], pass2[SHA1_SIZE];
+ // Validate arguments
+ if (data == NULL || thread == NULL)
+ {
+ return;
+ }
+
+ e = (EL *)data->r->ThreadParam;
+ s = data->s;
+ AddRef(s->ref);
+ SetTimeout(s, 5000);
+ LockList(e->AdminThreadList);
+ {
+ AddRef(thread->ref);
+ AddRef(s->ref);
+ Insert(e->AdminThreadList, thread);
+ Insert(e->AdminSockList, s);
+ }
+ UnlockList(e->AdminThreadList);
+ NoticeThreadInit(thread);
+
+ // Submit a challenge
+ Rand(rand, sizeof(rand));
+ SendAll(s, rand, sizeof(rand), false);
+
+ // Receive a response
+ SecurePassword(pass1, e->HashedPassword, rand);
+ Zero(pass2, sizeof(pass2));
+ RecvAll(s, pass2, sizeof(pass2), false);
+
+ if (Cmp(pass1, pass2, SHA1_SIZE) != 0)
+ {
+ // Password incorrect
+ bool code = false;
+ code = Endian32(code);
+ SendAll(s, &code, sizeof(code), false);
+ }
+ else
+ {
+ // Password match
+ bool code = true;
+ RPC *r;
+
+ code = Endian32(code);
+ SendAll(s, &code, sizeof(code), false);
+
+ SetTimeout(s, INFINITE);
+
+ // Start operation as a RPC server
+ r = StartRpcServer(s, ElRpcServer, e);
+ RpcServer(r);
+ RpcFree(r);
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+
+ LockList(e->AdminThreadList);
+ {
+ if (Delete(e->AdminThreadList, thread))
+ {
+ ReleaseThread(thread);
+ }
+ if (Delete(e->AdminSockList, s))
+ {
+ ReleaseSock(s);
+ }
+ }
+ UnlockList(e->AdminThreadList);
+}
+
+// Listener start
+void ElStartListener(EL *e)
+{
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ e->AdminThreadList = NewList(NULL);
+ e->AdminSockList = NewList(NULL);
+
+ e->Listener = NewListenerEx(e->Cedar, LISTENER_TCP, e->Port == 0 ? EL_ADMIN_PORT : e->Port,
+ ElListenerProc, e);
+}
+
+// Listener stop
+void ElStopListener(EL *e)
+{
+ UINT i;
+ THREAD **threads;
+ SOCK **socks;
+ UINT num_threads, num_socks;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ StopAllListener(e->Cedar);
+
+ LockList(e->AdminThreadList);
+ {
+ threads = ToArray(e->AdminThreadList);
+ num_threads = LIST_NUM(e->AdminThreadList);
+ DeleteAll(e->AdminThreadList);
+
+ socks = ToArray(e->AdminSockList);
+ num_socks = LIST_NUM(e->AdminSockList);
+ DeleteAll(e->AdminSockList);
+ }
+ UnlockList(e->AdminThreadList);
+
+ for (i = 0;i < num_socks;i++)
+ {
+ Disconnect(socks[i]);
+ ReleaseSock(socks[i]);
+ }
+
+ for (i = 0;i < num_threads;i++)
+ {
+ WaitThread(threads[i], INFINITE);
+ ReleaseThread(threads[i]);
+ }
+
+ Free(threads);
+ Free(socks);
+
+ ReleaseList(e->AdminSockList);
+ ReleaseList(e->AdminThreadList);
+
+ ReleaseListener(e->Listener);
+}
+
+// Update the log configuration of the capture device
+bool ElSetCaptureDeviceLogSetting(EL *e, char *name, HUB_LOG *log)
+{
+ EL_DEVICE *d;
+ bool ret = false;
+ // Validate arguments
+ if (e == NULL || log == NULL || name == NULL)
+ {
+ return false;
+ }
+
+ LockList(e->DeviceList);
+ {
+ EL_DEVICE t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), name);
+
+ d = Search(e->DeviceList, &t);
+
+ if (d != NULL)
+ {
+ Copy(&d->LogSetting, log, sizeof(HUB_LOG));
+
+ SetLogSwitchType(d->Logger, log->PacketLogSwitchType);
+
+ ret = true;
+ }
+ }
+ UnlockList(e->DeviceList);
+
+ return ret;
+}
+
+// Confirm whether the beta version has expired
+bool ElIsBetaExpired()
+{
+ SYSTEMTIME st;
+ UINT64 expires64;
+ UINT64 now64;
+ if (ELOG_IS_BETA == false)
+ {
+ return false;
+ }
+
+ Zero(&st, sizeof(st));
+
+ st.wYear = ELOG_BETA_EXPIRES_YEAR;
+ st.wMonth = ELOG_BETA_EXPIRES_MONTH;
+ st.wDay = ELOG_BETA_EXPIRES_DAY;
+
+ expires64 = SystemToUINT64(&st);
+ now64 = LocalTime64();
+
+ if (now64 >= expires64)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Capture thread
+void ElCaptureThread(THREAD *thread, void *param)
+{
+}
+
+// Delete the capture device
+bool ElDeleteCaptureDevice(EL *e, char *name)
+{
+ bool ret = false;
+ EL_DEVICE *d, t;
+ // Validate arguments
+ if (e == NULL || name == NULL)
+ {
+ return false;
+ }
+
+ LockList(e->DeviceList);
+ {
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), name);
+
+ d = Search(e->DeviceList, &t);
+
+ if (d != NULL)
+ {
+ // Stop capture
+ d->Halt = true;
+ Cancel(d->Cancel1);
+
+ // Wait for thread stop
+ WaitThread(d->Thread, INFINITE);
+ ReleaseThread(d->Thread);
+
+ // Release the memory
+ Delete(e->DeviceList, d);
+ Free(d);
+
+ ret = true;
+ }
+ }
+ UnlockList(e->DeviceList);
+
+ return ret;
+}
+
+// Add a capture device
+bool ElAddCaptureDevice(EL *e, char *name, HUB_LOG *log, bool no_promiscus)
+{
+ EL_DEVICE *d, t;
+ // Validate arguments
+ if (e == NULL || name == NULL || log == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), name);
+
+ LockList(e->DeviceList);
+ {
+ d = Search(e->DeviceList, &t);
+ if (d != NULL)
+ {
+ // Capture settings with the same name already exists
+ UnlockList(e->DeviceList);
+ return false;
+ }
+
+ // Add a device
+ d = ZeroMalloc(sizeof(EL_DEVICE));
+ StrCpy(d->DeviceName, sizeof(d->DeviceName), name);
+ Copy(&d->LogSetting, log, sizeof(HUB_LOG));
+ d->NoPromiscus = no_promiscus;
+ d->el = e;
+ Insert(e->DeviceList, d);
+
+ // Start the thread
+ d->Thread = NewThread(ElCaptureThread, d);
+ WaitThreadInit(d->Thread);
+ }
+ UnlockList(e->DeviceList);
+
+ ElSaveConfig(e);
+
+ return true;
+}
+
+// Write the license List
+void EiWriteLicenseManager(FOLDER *f, EL *s)
+{
+}
+
+// Read the license list
+void EiLoadLicenseManager(EL *s, FOLDER *f)
+{
+}
+
+// Configuration initialization
+void ElInitConfig(EL *e)
+{
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ // Device list initialization
+ e->DeviceList = NewList(ElCompareDevice);
+
+ // Read configuration file
+ ElLoadConfig(e);
+
+ // Write configuration file
+ ElSaveConfig(e);
+}
+
+// Write the configuration
+void ElSaveConfig(EL *e)
+{
+ FOLDER *root;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ root = CfgCreateFolder(NULL, TAG_ROOT);
+
+ ElSaveConfigToFolder(e, root);
+
+ SaveCfgRw(e->CfgRw, root);
+
+ CfgDeleteFolder(root);
+}
+
+// Write the configuration to the folder
+void ElSaveConfigToFolder(EL *e, FOLDER *root)
+{
+ UINT i;
+ FOLDER *devices;
+ // Validate arguments
+ if (e == NULL || root == NULL)
+ {
+ return;
+ }
+
+ CfgAddInt64(root, "AutoDeleteCheckDiskFreeSpaceMin", e->AutoDeleteCheckDiskFreeSpaceMin);
+
+ CfgAddInt(root, "AdminPort", e->Port);
+
+ CfgAddByte(root, "AdminPassword", e->HashedPassword, sizeof(e->HashedPassword));
+
+ if (ELOG_IS_BETA == false)
+ {
+ EiWriteLicenseManager(CfgCreateFolder(root, "LicenseManager"), e);
+ }
+
+ devices = CfgCreateFolder(root,"Devices");
+
+ LockList(e->DeviceList);
+ {
+ for (i = 0;i < LIST_NUM(e->DeviceList);i++)
+ {
+ FOLDER *f;
+ EL_DEVICE *d = LIST_DATA(e->DeviceList, i);
+
+ f = CfgCreateFolder(devices, d->DeviceName);
+ SiWriteHubLogCfgEx(f, &d->LogSetting, true);
+ CfgAddBool(f, "NoPromiscusMode", d->NoPromiscus);
+ }
+ }
+ UnlockList(e->DeviceList);
+}
+
+// Read the configuration from the folder
+void ElLoadConfigFromFolder(EL *e, FOLDER *root)
+{
+ UINT i;
+ TOKEN_LIST *t;
+ FOLDER *devices;
+
+ // Validate arguments
+ if (e == NULL || root == NULL)
+ {
+ return;
+ }
+
+ i = CfgGetInt(root, "AdminPort");
+ if (i >= 1 && i <= 65535)
+ {
+ e->Port = i;
+ }
+
+ e->AutoDeleteCheckDiskFreeSpaceMin = CfgGetInt64(root, "AutoDeleteCheckDiskFreeSpaceMin");
+ if (CfgIsItem(root, "AutoDeleteCheckDiskFreeSpaceMin") == false && e->AutoDeleteCheckDiskFreeSpaceMin == 0)
+ {
+ e->AutoDeleteCheckDiskFreeSpaceMin = DISK_FREE_SPACE_DEFAULT;
+ }
+
+ if (e->AutoDeleteCheckDiskFreeSpaceMin != 0)
+ {
+ if (e->AutoDeleteCheckDiskFreeSpaceMin < DISK_FREE_SPACE_MIN)
+ {
+ e->AutoDeleteCheckDiskFreeSpaceMin = DISK_FREE_SPACE_MIN;
+ }
+ }
+
+ if (CfgGetByte(root, "AdminPassword", e->HashedPassword, sizeof(e->HashedPassword)) != sizeof(e->HashedPassword))
+ {
+ Hash(e->HashedPassword, "", 0, true);
+ }
+
+ if (ELOG_IS_BETA == false)
+ {
+ EiLoadLicenseManager(e, CfgGetFolder(root, "LicenseManager"));
+ }
+
+ devices = CfgGetFolder(root, "Devices");
+ if(devices != NULL)
+ {
+ LockList(e->DeviceList);
+ {
+ t = CfgEnumFolderToTokenList(devices);
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ char *name = t->Token[i];
+ FOLDER *f = CfgGetFolder(devices, name);
+
+ if (f != NULL)
+ {
+ HUB_LOG g;
+
+ Zero(&g, sizeof(g));
+ SiLoadHubLogCfg(&g, f);
+ ElAddCaptureDevice(e, name, &g, CfgGetBool(f, "NoPromiscusMode"));
+ }
+ }
+ FreeToken(t);
+ }
+ UnlockList(e->DeviceList);
+ }
+}
+
+// Reading configuration
+bool ElLoadConfig(EL *e)
+{
+ FOLDER *root;
+ bool ret = false;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return false;
+ }
+
+ e->Port = EL_ADMIN_PORT;
+
+ e->CfgRw = NewCfgRw(&root, EL_CONFIG_FILENAME);
+
+ if (root != NULL)
+ {
+ ElLoadConfigFromFolder(e, root);
+
+ CfgDeleteFolder(root);
+ }
+ else
+ {
+ char *pass = "";
+ Hash(e->HashedPassword, pass, StrLen(pass), true);
+ e->AutoDeleteCheckDiskFreeSpaceMin = DISK_FREE_SPACE_DEFAULT;
+ }
+
+ return ret;
+}
+
+// Configuration release
+void ElFreeConfig(EL *e)
+{
+ UINT i;
+ LIST *o;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ // Write the configuration file
+ ElSaveConfig(e);
+ FreeCfgRw(e->CfgRw);
+
+ // Stop all capture
+ o = NewList(NULL);
+ LockList(e->DeviceList);
+ {
+ for (i = 0;i < LIST_NUM(e->DeviceList);i++)
+ {
+ EL_DEVICE *d = LIST_DATA(e->DeviceList, i);
+ Insert(o, CopyStr(d->DeviceName));
+ }
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ char *name = LIST_DATA(o, i);
+ ElDeleteCaptureDevice(e, name);
+ Free(name);
+ }
+ ReleaseList(o);
+ }
+ UnlockList(e->DeviceList);
+
+ ReleaseList(e->DeviceList);
+}
+
+// Comparison function of the device
+int ElCompareDevice(void *p1, void *p2)
+{
+ EL_DEVICE *d1, *d2;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ d1 = *(EL_DEVICE **)p1;
+ d2 = *(EL_DEVICE **)p2;
+ if (d1 == NULL || d2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(d1->DeviceName, d2->DeviceName);
+}
+
+// Clean-up the EL
+void CleanupEl(EL *e)
+{
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ // Stop Eraser
+ FreeEraser(e->Eraser);
+
+ // Stop Listener
+ ElStopListener(e);
+
+ // Setting release
+ ElFreeConfig(e);
+
+ // Free the license system
+ if(e->LicenseSystem != NULL)
+ {
+ }
+
+ // Free the license status
+ if(e->LicenseStatus != NULL)
+ {
+ Free(e->LicenseStatus);
+ }
+
+ // Ethernet release
+ FreeEth();
+
+ ReleaseCedar(e->Cedar);
+
+ DeleteLock(e->lock);
+
+ Free(e);
+}
+
+// Release the EL
+void ReleaseEl(EL *e)
+{
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ if (Release(e->ref) == 0)
+ {
+ CleanupEl(e);
+ }
+}
+
+// Create the EL
+EL *NewEl()
+{
+ EL *e;
+
+#ifdef OS_WIN32
+ RegistWindowsFirewallAll();
+#endif
+
+ e = ZeroMalloc(sizeof(EL));
+ e->lock = NewLock();
+ e->ref = NewRef();
+
+ e->Cedar = NewCedar(NULL, NULL);
+
+
+ // Ethernet initialization
+ InitEth();
+
+ // Setting initialization
+ ElInitConfig(e);
+
+ // Listener start
+ ElStartListener(e);
+
+ // Initialize the license status
+ ElParseCurrentLicenseStatus(e->LicenseSystem, e->LicenseStatus);
+
+ // Eraser start
+ e->Eraser = NewEraser(NULL, e->AutoDeleteCheckDiskFreeSpaceMin);
+
+ return e;
+}
+
+// EL start
+void ElStart()
+{
+ // Raise the priority
+ OSSetHighPriority();
+
+ Lock(el_lock);
+ {
+ el = NewEl();
+ }
+ Unlock(el_lock);
+}
+
+// EL stop
+void ElStop()
+{
+ Lock(el_lock);
+ {
+ ReleaseEl(el);
+ el = NULL;
+ }
+ Unlock(el_lock);
+}
+
+// EL initialization
+void ElInit()
+{
+ // Lock initialization
+ el_lock = NewLock();
+}
+
+// EL release
+void ElFree()
+{
+ // Lock release
+ DeleteLock(el_lock);
+ el_lock = NULL;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/EtherLog.h b/src/Cedar/EtherLog.h
new file mode 100644
index 00000000..499fd359
--- /dev/null
+++ b/src/Cedar/EtherLog.h
@@ -0,0 +1,255 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// EtherLog.h
+// Header of EtherLog.c
+
+#ifndef ETHERLOG_H
+#define ETHERLOG_H
+
+// Whether this is a beta version
+#define ELOG_IS_BETA true
+
+// Beta expiration date
+#define ELOG_BETA_EXPIRES_YEAR 2008
+#define ELOG_BETA_EXPIRES_MONTH 12
+#define ELOG_BETA_EXPIRES_DAY 2
+
+// Version information
+//#define EL_VER 201
+//#define EL_BUILD 1600
+//#define EL_BETA 1
+#define MAX_LOGGING_QUEUE_LEN 100000
+
+// RPC related
+struct RPC_ADD_DEVICE
+{
+ char DeviceName[MAX_SIZE]; // Device name
+ HUB_LOG LogSetting; // Log settings
+ bool NoPromiscus; // Without promiscuous mode
+};
+
+struct RPC_DELETE_DEVICE
+{
+ char DeviceName[MAX_SIZE]; // Device name
+};
+
+struct RPC_ENUM_DEVICE_ITEM
+{
+ char DeviceName[MAX_SIZE]; // Device name
+ bool Active; // Running flag
+};
+
+struct RPC_ENUM_DEVICE
+{
+ UINT NumItem; // Number of items
+ RPC_ENUM_DEVICE_ITEM *Items; // Items
+ bool IsLicenseSupported; // Whether the license system is supported
+};
+
+// License status of the service
+struct RPC_EL_LICENSE_STATUS
+{
+ BOOL Valid; // Enable flag
+ UINT64 SystemId; // System ID
+ UINT64 SystemExpires; // System expiration date
+};
+
+// Device
+struct EL_DEVICE
+{
+ EL *el; // EL
+ char DeviceName[MAX_SIZE]; // Device name
+ HUB_LOG LogSetting; // Log settings
+ THREAD *Thread; // Thread
+ CANCEL *Cancel1; // Cancel 1
+ CANCEL *Cancel2; // Cancel 2
+ volatile bool Halt; // Halting flag
+ bool Active; // Running flag
+ bool NoPromiscus; // Without promiscuous mode
+ LOG *Logger; // Logger
+};
+
+// License status
+struct EL_LICENSE_STATUS
+{
+ BOOL Valid; // Enable flag
+ UINT64 SystemId; // System ID
+ UINT64 Expires; // Expiration date
+};
+
+// EtherLogger
+struct EL
+{
+ LOCK *lock; // Lock
+ REF *ref; // Reference counter
+ CEDAR *Cedar; // Cedar
+ LIST *DeviceList; // Device list
+ CFG_RW *CfgRw; // Config R/W
+ UINT Port; // Port number
+ LISTENER *Listener; // Listener
+ UCHAR HashedPassword[SHA1_SIZE]; // Password
+ LIST *AdminThreadList; // Management thread list
+ LIST *AdminSockList; // Management socket list
+ LICENSE_SYSTEM *LicenseSystem; // License system
+ EL_LICENSE_STATUS *LicenseStatus; // License status
+ UINT64 AutoDeleteCheckDiskFreeSpaceMin; // Minimum free disk space
+ ERASER *Eraser; // Eraser
+};
+
+// Function prototype
+void ElInit();
+void ElFree();
+void ElStart();
+void ElStop();
+EL *NewEl();
+void ReleaseEl(EL *e);
+void CleanupEl(EL *e);
+void ElInitConfig(EL *e);
+void ElFreeConfig(EL *e);
+bool ElLoadConfig(EL *e);
+void ElLoadConfigFromFolder(EL *e, FOLDER *root);
+void ElSaveConfig(EL *e);
+void ElSaveConfigToFolder(EL *e, FOLDER *root);
+int ElCompareDevice(void *p1, void *p2);
+bool ElAddCaptureDevice(EL *e, char *name, HUB_LOG *log, bool no_promiscus);
+bool ElDeleteCaptureDevice(EL *e, char *name);
+bool ElSetCaptureDeviceLogSetting(EL *e, char *name, HUB_LOG *log);
+void ElCaptureThread(THREAD *thread, void *param);
+void ElStartListener(EL *e);
+void ElStopListener(EL *e);
+void ElListenerProc(THREAD *thread, void *param);
+PACK *ElRpcServer(RPC *r, char *name, PACK *p);
+void ElCheckLicense(EL_LICENSE_STATUS *st, LICENSE *e);
+void ElParseCurrentLicenseStatus(LICENSE_SYSTEM *s, EL_LICENSE_STATUS *st);
+bool ElIsBetaExpired();
+
+
+UINT EtAddDevice(EL *e, RPC_ADD_DEVICE *t);
+UINT EtDelDevice(EL *e, RPC_DELETE_DEVICE *t);
+UINT EtSetDevice(EL *e, RPC_ADD_DEVICE *t);
+UINT EtGetDevice(EL *e, RPC_ADD_DEVICE *t);
+UINT EtEnumDevice(EL *e, RPC_ENUM_DEVICE *t);
+UINT EtEnumAllDevice(EL *e, RPC_ENUM_DEVICE *t);
+UINT EtSetPassword(EL *e, RPC_SET_PASSWORD *t);
+UINT EtAddLicenseKey(EL *a, RPC_TEST *t);
+UINT EtDelLicenseKey(EL *a, RPC_TEST *t);
+UINT EtEnumLicenseKey(EL *a, RPC_ENUM_LICENSE_KEY *t);
+UINT EtGetLicenseStatus(EL *a, RPC_EL_LICENSE_STATUS *t);
+UINT EtGetBridgeSupport(EL *a, RPC_BRIDGE_SUPPORT *t);
+UINT EtRebootServer(EL *a, RPC_TEST *t);
+
+UINT EcAddDevice(RPC *r, RPC_ADD_DEVICE *t);
+UINT EcDelDevice(RPC *r, RPC_DELETE_DEVICE *t);
+UINT EcSetDevice(RPC *r, RPC_ADD_DEVICE *t);
+UINT EcGetDevice(RPC *r, RPC_ADD_DEVICE *t);
+UINT EcEnumDevice(RPC *r, RPC_ENUM_DEVICE *t);
+UINT EcEnumAllDevice(RPC *r, RPC_ENUM_DEVICE *t);
+UINT EcSetPassword(RPC *r, RPC_SET_PASSWORD *t);
+UINT EcAddLicenseKey(RPC *r, RPC_TEST *t);
+UINT EcDelLicenseKey(RPC *r, RPC_TEST *t);
+UINT EcEnumLicenseKey(RPC *r, RPC_ENUM_LICENSE_KEY *t);
+UINT EcGetLicenseStatus(RPC *r, RPC_EL_LICENSE_STATUS *t);
+UINT EcGetBridgeSupport(RPC *r, RPC_BRIDGE_SUPPORT *t);
+UINT EcRebootServer(RPC *r, RPC_TEST *t);
+
+UINT EcConnect(char *host, UINT port, char *password, RPC **rpc);
+void EcDisconnect(RPC *rpc);
+
+void InRpcAddDevice(RPC_ADD_DEVICE *t, PACK *p);
+void OutRpcAddDevice(PACK *p, RPC_ADD_DEVICE *t);
+void InRpcDeleteDevice(RPC_DELETE_DEVICE *t, PACK *p);
+void OutRpcDeleteDevice(PACK *p, RPC_DELETE_DEVICE *t);
+void InRpcEnumDevice(RPC_ENUM_DEVICE *t, PACK *p);
+void OutRpcEnumDevice(PACK *p, RPC_ENUM_DEVICE *t);
+void FreeRpcEnumDevice(RPC_ENUM_DEVICE *t);
+void InRpcEnumLicenseKey(RPC_ENUM_LICENSE_KEY *t, PACK *p);
+void OutRpcEnumLicenseKey(PACK *p, RPC_ENUM_LICENSE_KEY *t);
+void FreeRpcEnumLicenseKey(RPC_ENUM_LICENSE_KEY *t);
+void InRpcElLicenseStatus(RPC_EL_LICENSE_STATUS *t, PACK *p);
+void OutRpcElLicenseStatus(PACK *p, RPC_EL_LICENSE_STATUS *t);
+
+#endif // ETHERLOG_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Hub.c b/src/Cedar/Hub.c
new file mode 100644
index 00000000..bdd28564
--- /dev/null
+++ b/src/Cedar/Hub.c
@@ -0,0 +1,7123 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Hub.c
+// Virtual HUB module
+
+#include "CedarPch.h"
+
+static UCHAR broadcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+static char vgs_ua_str[9] = {0};
+static bool g_vgs_emb_tag = false;
+
+// A list of administration options that are currently supported and its default values
+// These names must be shorter than 64 bytes
+ADMIN_OPTION admin_options[] =
+{
+ {"allow_hub_admin_change_option", 0},
+ {"max_users", 0},
+ {"max_multilogins_per_user", 0},
+ {"max_groups", 0},
+ {"max_accesslists", 0},
+ {"max_sessions_client_bridge_apply", 0},
+ {"max_sessions", 0},
+ {"max_sessions_client", 0},
+ {"max_sessions_bridge", 0},
+ {"max_bitrates_download", 0},
+ {"max_bitrates_upload", 0},
+ {"deny_empty_password", 0},
+ {"deny_bridge", 0},
+ {"deny_routing", 0},
+ {"deny_qos", 0},
+ {"deny_change_user_password", 0},
+ {"no_change_users", 0},
+ {"no_change_groups", 0},
+ {"no_securenat", 0},
+ {"no_securenat_enablenat", 0},
+ {"no_securenat_enabledhcp", 0},
+ {"no_cascade", 0},
+ {"no_online", 0},
+ {"no_offline", 0},
+ {"no_change_log_config", 0},
+ {"no_disconnect_session", 0},
+ {"no_delete_iptable", 0},
+ {"no_delete_mactable", 0},
+ {"no_enum_session", 0},
+ {"no_query_session", 0},
+ {"no_change_admin_password", 0},
+ {"no_change_log_switch_type", 0},
+ {"no_change_access_list", 0},
+ {"no_change_access_control_list", 0},
+ {"no_change_cert_list", 0},
+ {"no_change_crl_list", 0},
+ {"no_read_log_file", 0},
+ {"deny_hub_admin_change_ext_option", 0},
+ {"no_delay_jitter_packet_loss", 0},
+ {"no_change_msg", 0},
+ {"no_access_list_include_file", 0},
+};
+
+UINT num_admin_options = sizeof(admin_options) / sizeof(ADMIN_OPTION);
+
+// Create a user list
+LIST *NewUserList()
+{
+ LIST *o = NewList(CompareUserList);
+
+ return o;
+}
+
+// Search whether the specified user matches to the user list (with cache expiration)
+bool IsUserMatchInUserListWithCacheExpires(LIST *o, char *filename, UINT64 user_hash, UINT64 lifetime)
+{
+ bool ret = false;
+ UINT64 now = Tick64();
+ // Validate arguments
+ if (o == NULL || filename == NULL || user_hash == 0)
+ {
+ return false;
+ }
+
+ LockList(o);
+ {
+ if (lifetime != 0)
+ {
+ if (o->Param1 == 0 || (now >= (o->Param1 + lifetime)))
+ {
+ DeleteAllUserListCache(o);
+
+ o->Param1 = now;
+ }
+ }
+
+ ret = IsUserMatchInUserList(o, filename, user_hash);
+ }
+ UnlockList(o);
+
+ return ret;
+}
+bool IsUserMatchInUserListWithCacheExpiresAcl(LIST *o, char *name_in_acl, UINT64 user_hash, UINT64 lifetime)
+{
+ char tmp[16];
+ bool exclude = false;
+ char filename[MAX_SIZE];
+ char filename2[MAX_SIZE];
+ bool is_full_path = false;
+ bool ret = false;
+ // Validate arguments
+ if (o == NULL || name_in_acl == NULL || user_hash == 0 || StrLen(name_in_acl) < 9)
+ {
+ return false;
+ }
+
+ StrCpy(tmp, sizeof(tmp), name_in_acl);
+ StrLower(tmp);
+
+ tmp[8] = 0;
+
+ if (Cmp(tmp, ACCESS_LIST_INCLUDED_PREFIX, 8) == 0)
+ {
+ // include
+ exclude = false;
+ }
+ else
+ {
+ // exclude
+ exclude = true;
+ }
+
+ // Extract the file name
+ StrCpy(filename, sizeof(filename), name_in_acl + 8);
+ Trim(filename);
+
+ // Identify whether the file name is an absolute path
+ if (filename[0] == '\\' || filename[0] == '/' || (filename[1] == ':' && filename[2] == '\\'))
+ {
+ is_full_path = true;
+ }
+
+ if (is_full_path == false)
+ {
+ // Prepend a '@' if the file name is a relative path
+ StrCpy(filename2, sizeof(filename2), "@");
+ StrCat(filename2, sizeof(filename2), filename);
+ StrCpy(filename, sizeof(filename), filename2);
+ }
+
+ ret = IsUserMatchInUserListWithCacheExpires(o, filename, user_hash, lifetime);
+
+ if (exclude)
+ {
+ ret = NEGATIVE_BOOL(ret);
+ }
+
+ return ret;
+}
+
+// Search whether the specified user matches to the user list
+bool IsUserMatchInUserList(LIST *o, char *filename, UINT64 user_hash)
+{
+ USERLIST *u;
+ bool ret = false;
+ // Validate arguments
+ if (o == NULL || filename == NULL || user_hash == 0)
+ {
+ return false;
+ }
+
+ LockList(o);
+ {
+ u = FindUserList(o, filename);
+ if (u == NULL)
+ {
+ u = LoadUserList(o, filename);
+ }
+
+ if (u != NULL)
+ {
+ ret = IsInt64InList(u->UserHashList, user_hash);
+ }
+ }
+ UnlockList(o);
+
+ return ret;
+}
+
+// Read the user list
+USERLIST *LoadUserList(LIST *o, char *filename)
+{
+ USERLIST *u;
+ BUF *b;
+ // Validate arguments
+ if (o == NULL || filename == NULL)
+ {
+ return NULL;
+ }
+
+ u = FindUserList(o, filename);
+
+ if (u != NULL)
+ {
+ Delete(o, u);
+
+ FreeUserListEntry(u);
+ }
+
+ u = ZeroMalloc(sizeof(USERLIST));
+
+ StrCpy(u->Filename, sizeof(u->Filename), filename);
+
+ u->UserHashList = NewInt64List(false);
+
+ b = ReadDumpWithMaxSize(filename, ACCESS_LIST_INCLUDE_FILE_MAX_SIZE);
+ if (b != NULL)
+ {
+ while (true)
+ {
+ char *line = CfgReadNextLine(b);
+ UINT64 ui;
+ if (line == NULL)
+ {
+ break;
+ }
+
+ Trim(line);
+
+ if (IsEmptyStr(line) == false)
+ {
+ if (StartWith(line, "#") == false &&
+ StartWith(line, "//") == false &&
+ StartWith(line, ";") == false)
+ {
+ ui = UsernameToInt64(line);
+
+ AddInt64Distinct(u->UserHashList, ui);
+ }
+ }
+
+ Free(line);
+ }
+
+ FreeBuf(b);
+ }
+
+ Add(o, u);
+
+ return u;
+}
+
+// Release the user list entry
+void FreeUserListEntry(USERLIST *u)
+{
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+
+ ReleaseInt64List(u->UserHashList);
+
+ Free(u);
+}
+
+// Search in user list
+USERLIST *FindUserList(LIST *o, char *filename)
+{
+ USERLIST t, *u;
+ // Validate arguments
+ if (o == NULL || filename == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Filename, sizeof(t.Filename), filename);
+
+ u = Search(o, &t);
+
+ return u;
+}
+
+// User list entry comparison function
+int CompareUserList(void *p1, void *p2)
+{
+ USERLIST *u1, *u2;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ u1 = *(USERLIST **)p1;
+ u2 = *(USERLIST **)p2;
+ if (u1 == NULL || u2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(u1->Filename, u2->Filename);
+}
+
+// Delete the cache of the all user list
+void DeleteAllUserListCache(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ LockList(o);
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ USERLIST *u = LIST_DATA(o, i);
+
+ FreeUserListEntry(u);
+ }
+
+ DeleteAll(o);
+ }
+ UnlockList(o);
+}
+
+// Release the user list
+void FreeUserList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ USERLIST *u = LIST_DATA(o, i);
+
+ FreeUserListEntry(u);
+ }
+
+ ReleaseList(o);
+}
+
+// Get whether the specified message is a URL string
+bool IsURLMsg(wchar_t *str, char *url, UINT url_size)
+{
+ UNI_TOKEN_LIST *t;
+ bool ret = false;
+ UINT i;
+ UINT n = 0;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return false;
+ }
+
+ t = UniParseToken(str, L"\r\n");
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ wchar_t *str = t->Token[i];
+
+ if (IsEmptyUniStr(str) == false)
+ {
+ n++;
+
+ UniTrim(str);
+
+ if (n == 1)
+ {
+ if (UniStartWith(str, L"http://") ||
+ UniStartWith(str, L"https://") ||
+ UniStartWith(str, L"ftp://"))
+ {
+ ret = true;
+
+ UniToStr(url, url_size, str);
+ }
+ }
+ }
+ }
+
+ if (n != 1)
+ {
+ ret = false;
+ }
+
+ UniFreeToken(t);
+
+ return ret;
+}
+
+// Get data from RPC_ADMIN_OPTION
+UINT GetHubAdminOptionData(RPC_ADMIN_OPTION *ao, char *name)
+{
+ UINT i;
+ // Validate arguments
+ if (ao == NULL || name == NULL)
+ {
+ return INFINITE;
+ }
+
+ for (i = 0;i < ao->NumItem;i++)
+ {
+ ADMIN_OPTION *a = &ao->Items[i];
+
+ if (StrCmpi(a->Name, name) == 0)
+ {
+ return a->Value;
+ }
+ }
+
+ return INFINITE;
+}
+void GetHubAdminOptionDataAndSet(RPC_ADMIN_OPTION *ao, char *name, UINT *dest)
+{
+ UINT value;
+ // Validate arguments
+ if (ao == NULL || name == NULL || dest == NULL)
+ {
+ return;
+ }
+
+ value = GetHubAdminOptionData(ao, name);
+ if (value == INFINITE)
+ {
+ return;
+ }
+
+ *dest = value;
+}
+
+// Set the contents of the HUB_OPTION based on the data
+void DataToHubOptionStruct(HUB_OPTION *o, RPC_ADMIN_OPTION *ao)
+{
+ // Validate arguments
+ if (o == NULL || ao == NULL)
+ {
+ return;
+ }
+
+ GetHubAdminOptionDataAndSet(ao, "NoAddressPollingIPv4", &o->NoArpPolling);
+ GetHubAdminOptionDataAndSet(ao, "NoAddressPollingIPv6", &o->NoIPv6AddrPolling);
+ GetHubAdminOptionDataAndSet(ao, "NoIpTable", &o->NoIpTable);
+ GetHubAdminOptionDataAndSet(ao, "NoMacAddressLog", &o->NoMacAddressLog);
+ GetHubAdminOptionDataAndSet(ao, "ManageOnlyPrivateIP", &o->ManageOnlyPrivateIP);
+ GetHubAdminOptionDataAndSet(ao, "ManageOnlyLocalUnicastIPv6", &o->ManageOnlyLocalUnicastIPv6);
+ GetHubAdminOptionDataAndSet(ao, "DisableIPParsing", &o->DisableIPParsing);
+ GetHubAdminOptionDataAndSet(ao, "YieldAfterStorePacket", &o->YieldAfterStorePacket);
+ GetHubAdminOptionDataAndSet(ao, "NoSpinLockForPacketDelay", &o->NoSpinLockForPacketDelay);
+ GetHubAdminOptionDataAndSet(ao, "BroadcastStormDetectionThreshold", &o->BroadcastStormDetectionThreshold);
+ GetHubAdminOptionDataAndSet(ao, "ClientMinimumRequiredBuild", &o->ClientMinimumRequiredBuild);
+ GetHubAdminOptionDataAndSet(ao, "FilterPPPoE", &o->FilterPPPoE);
+ GetHubAdminOptionDataAndSet(ao, "FilterOSPF", &o->FilterOSPF);
+ GetHubAdminOptionDataAndSet(ao, "FilterIPv4", &o->FilterIPv4);
+ GetHubAdminOptionDataAndSet(ao, "FilterIPv6", &o->FilterIPv6);
+ GetHubAdminOptionDataAndSet(ao, "FilterNonIP", &o->FilterNonIP);
+ GetHubAdminOptionDataAndSet(ao, "NoIPv4PacketLog", &o->NoIPv4PacketLog);
+ GetHubAdminOptionDataAndSet(ao, "NoIPv6PacketLog", &o->NoIPv6PacketLog);
+ GetHubAdminOptionDataAndSet(ao, "FilterBPDU", &o->FilterBPDU);
+ GetHubAdminOptionDataAndSet(ao, "NoIPv6DefaultRouterInRAWhenIPv6", &o->NoIPv6DefaultRouterInRAWhenIPv6);
+ GetHubAdminOptionDataAndSet(ao, "NoLookBPDUBridgeId", &o->NoLookBPDUBridgeId);
+ GetHubAdminOptionDataAndSet(ao, "NoManageVlanId", &o->NoManageVlanId);
+ GetHubAdminOptionDataAndSet(ao, "VlanTypeId", &o->VlanTypeId);
+ GetHubAdminOptionDataAndSet(ao, "FixForDLinkBPDU", &o->FixForDLinkBPDU);
+ GetHubAdminOptionDataAndSet(ao, "RequiredClientId", &o->RequiredClientId);
+ GetHubAdminOptionDataAndSet(ao, "AdjustTcpMssValue", &o->AdjustTcpMssValue);
+ GetHubAdminOptionDataAndSet(ao, "DisableAdjustTcpMss", &o->DisableAdjustTcpMss);
+ GetHubAdminOptionDataAndSet(ao, "NoDhcpPacketLogOutsideHub", &o->NoDhcpPacketLogOutsideHub);
+ GetHubAdminOptionDataAndSet(ao, "DisableHttpParsing", &o->DisableHttpParsing);
+ GetHubAdminOptionDataAndSet(ao, "DisableUdpAcceleration", &o->DisableUdpAcceleration);
+ GetHubAdminOptionDataAndSet(ao, "DisableUdpFilterForLocalBridgeNic", &o->DisableUdpFilterForLocalBridgeNic);
+ GetHubAdminOptionDataAndSet(ao, "ApplyIPv4AccessListOnArpPacket", &o->ApplyIPv4AccessListOnArpPacket);
+ GetHubAdminOptionDataAndSet(ao, "RemoveDefGwOnDhcpForLocalhost", &o->RemoveDefGwOnDhcpForLocalhost);
+ GetHubAdminOptionDataAndSet(ao, "SecureNAT_MaxTcpSessionsPerIp", &o->SecureNAT_MaxTcpSessionsPerIp);
+ GetHubAdminOptionDataAndSet(ao, "SecureNAT_MaxTcpSynSentPerIp", &o->SecureNAT_MaxTcpSynSentPerIp);
+ GetHubAdminOptionDataAndSet(ao, "SecureNAT_MaxUdpSessionsPerIp", &o->SecureNAT_MaxUdpSessionsPerIp);
+ GetHubAdminOptionDataAndSet(ao, "SecureNAT_MaxDnsSessionsPerIp", &o->SecureNAT_MaxDnsSessionsPerIp);
+ GetHubAdminOptionDataAndSet(ao, "SecureNAT_MaxIcmpSessionsPerIp", &o->SecureNAT_MaxIcmpSessionsPerIp);
+ GetHubAdminOptionDataAndSet(ao, "AccessListIncludeFileCacheLifetime", &o->AccessListIncludeFileCacheLifetime);
+ GetHubAdminOptionDataAndSet(ao, "DisableKernelModeSecureNAT", &o->DisableKernelModeSecureNAT);
+ GetHubAdminOptionDataAndSet(ao, "DisableUserModeSecureNAT", &o->DisableUserModeSecureNAT);
+ GetHubAdminOptionDataAndSet(ao, "DisableCheckMacOnLocalBridge", &o->DisableCheckMacOnLocalBridge);
+ GetHubAdminOptionDataAndSet(ao, "DisableCorrectIpOffloadChecksum", &o->DisableCorrectIpOffloadChecksum);
+ GetHubAdminOptionDataAndSet(ao, "BroadcastLimiterStrictMode", &o->BroadcastLimiterStrictMode);
+ GetHubAdminOptionDataAndSet(ao, "MaxLoggedPacketsPerMinute", &o->MaxLoggedPacketsPerMinute);
+ GetHubAdminOptionDataAndSet(ao, "DoNotSaveHeavySecurityLogs", &o->DoNotSaveHeavySecurityLogs);
+}
+
+// Convert the contents of the HUB_OPTION to data
+void HubOptionStructToData(RPC_ADMIN_OPTION *ao, HUB_OPTION *o, char *hub_name)
+{
+ LIST *aol;
+ UINT i;
+ // Validate arguments
+ if (ao == NULL || o == NULL || hub_name == NULL)
+ {
+ return;
+ }
+
+ aol = NewListFast(NULL);
+
+ Add(aol, NewAdminOption("NoAddressPollingIPv4", o->NoArpPolling));
+ Add(aol, NewAdminOption("NoAddressPollingIPv6", o->NoIPv6AddrPolling));
+ Add(aol, NewAdminOption("NoIpTable", o->NoIpTable));
+ Add(aol, NewAdminOption("NoMacAddressLog", o->NoMacAddressLog));
+ Add(aol, NewAdminOption("ManageOnlyPrivateIP", o->ManageOnlyPrivateIP));
+ Add(aol, NewAdminOption("ManageOnlyLocalUnicastIPv6", o->ManageOnlyLocalUnicastIPv6));
+ Add(aol, NewAdminOption("DisableIPParsing", o->DisableIPParsing));
+ Add(aol, NewAdminOption("YieldAfterStorePacket", o->YieldAfterStorePacket));
+ Add(aol, NewAdminOption("NoSpinLockForPacketDelay", o->NoSpinLockForPacketDelay));
+ Add(aol, NewAdminOption("BroadcastStormDetectionThreshold", o->BroadcastStormDetectionThreshold));
+ Add(aol, NewAdminOption("ClientMinimumRequiredBuild", o->ClientMinimumRequiredBuild));
+ Add(aol, NewAdminOption("FilterPPPoE", o->FilterPPPoE));
+ Add(aol, NewAdminOption("FilterOSPF", o->FilterOSPF));
+ Add(aol, NewAdminOption("FilterIPv4", o->FilterIPv4));
+ Add(aol, NewAdminOption("FilterIPv6", o->FilterIPv6));
+ Add(aol, NewAdminOption("FilterNonIP", o->FilterNonIP));
+ Add(aol, NewAdminOption("NoIPv4PacketLog", o->NoIPv4PacketLog));
+ Add(aol, NewAdminOption("NoIPv6PacketLog", o->NoIPv6PacketLog));
+ Add(aol, NewAdminOption("FilterBPDU", o->FilterBPDU));
+ Add(aol, NewAdminOption("NoIPv6DefaultRouterInRAWhenIPv6", o->NoIPv6DefaultRouterInRAWhenIPv6));
+ Add(aol, NewAdminOption("NoLookBPDUBridgeId", o->NoLookBPDUBridgeId));
+ Add(aol, NewAdminOption("NoManageVlanId", o->NoManageVlanId));
+ Add(aol, NewAdminOption("VlanTypeId", o->VlanTypeId));
+ Add(aol, NewAdminOption("FixForDLinkBPDU", o->FixForDLinkBPDU));
+ Add(aol, NewAdminOption("RequiredClientId", o->RequiredClientId));
+ Add(aol, NewAdminOption("AdjustTcpMssValue", o->AdjustTcpMssValue));
+ Add(aol, NewAdminOption("DisableAdjustTcpMss", o->DisableAdjustTcpMss));
+ Add(aol, NewAdminOption("NoDhcpPacketLogOutsideHub", o->NoDhcpPacketLogOutsideHub));
+ Add(aol, NewAdminOption("DisableHttpParsing", o->DisableHttpParsing));
+ Add(aol, NewAdminOption("DisableUdpAcceleration", o->DisableUdpAcceleration));
+ Add(aol, NewAdminOption("DisableUdpFilterForLocalBridgeNic", o->DisableUdpFilterForLocalBridgeNic));
+ Add(aol, NewAdminOption("ApplyIPv4AccessListOnArpPacket", o->ApplyIPv4AccessListOnArpPacket));
+ Add(aol, NewAdminOption("RemoveDefGwOnDhcpForLocalhost", o->RemoveDefGwOnDhcpForLocalhost));
+ Add(aol, NewAdminOption("SecureNAT_MaxTcpSessionsPerIp", o->SecureNAT_MaxTcpSessionsPerIp));
+ Add(aol, NewAdminOption("SecureNAT_MaxTcpSynSentPerIp", o->SecureNAT_MaxTcpSynSentPerIp));
+ Add(aol, NewAdminOption("SecureNAT_MaxUdpSessionsPerIp", o->SecureNAT_MaxUdpSessionsPerIp));
+ Add(aol, NewAdminOption("SecureNAT_MaxDnsSessionsPerIp", o->SecureNAT_MaxDnsSessionsPerIp));
+ Add(aol, NewAdminOption("SecureNAT_MaxIcmpSessionsPerIp", o->SecureNAT_MaxIcmpSessionsPerIp));
+ Add(aol, NewAdminOption("AccessListIncludeFileCacheLifetime", o->AccessListIncludeFileCacheLifetime));
+ Add(aol, NewAdminOption("DisableKernelModeSecureNAT", o->DisableKernelModeSecureNAT));
+ Add(aol, NewAdminOption("DisableUserModeSecureNAT", o->DisableUserModeSecureNAT));
+ Add(aol, NewAdminOption("DisableCheckMacOnLocalBridge", o->DisableCheckMacOnLocalBridge));
+ Add(aol, NewAdminOption("DisableCorrectIpOffloadChecksum", o->DisableCorrectIpOffloadChecksum));
+ Add(aol, NewAdminOption("BroadcastLimiterStrictMode", o->BroadcastLimiterStrictMode));
+ Add(aol, NewAdminOption("MaxLoggedPacketsPerMinute", o->MaxLoggedPacketsPerMinute));
+ Add(aol, NewAdminOption("DoNotSaveHeavySecurityLogs", o->DoNotSaveHeavySecurityLogs));
+
+ Zero(ao, sizeof(RPC_ADMIN_OPTION));
+
+ StrCpy(ao->HubName, sizeof(ao->HubName), hub_name);
+
+ ao->NumItem = LIST_NUM(aol);
+ ao->Items = ZeroMalloc(sizeof(ADMIN_OPTION) * ao->NumItem);
+
+ for (i = 0;i < LIST_NUM(aol);i++)
+ {
+ ADMIN_OPTION *a = LIST_DATA(aol, i);
+
+ Copy(&ao->Items[i], a, sizeof(ADMIN_OPTION));
+
+ Free(a);
+ }
+
+ ReleaseList(aol);
+}
+
+// Create a new ADMIN OPTION
+ADMIN_OPTION *NewAdminOption(char *name, UINT value)
+{
+ ADMIN_OPTION *a;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(ADMIN_OPTION));
+ StrCpy(a->Name, sizeof(a->Name), name);
+ a->Value = value;
+
+ return a;
+}
+
+// Clone the AC list
+LIST *CloneAcList(LIST *o)
+{
+ LIST *ret;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return NULL;
+ }
+
+ ret = NewAcList();
+ SetAcList(ret, o);
+
+ return ret;
+}
+
+// Set all the AC list
+void SetAcList(LIST *o, LIST *src)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL || src == NULL)
+ {
+ return;
+ }
+
+ DelAllAc(o);
+
+ for (i = 0;i < LIST_NUM(src);i++)
+ {
+ AC *ac = LIST_DATA(src, i);
+
+ AddAc(o, ac);
+ }
+}
+
+// Remove all AC from the AC list
+void DelAllAc(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ AC *ac = LIST_DATA(o, i);
+
+ Free(ac);
+ }
+
+ DeleteAll(o);
+}
+
+// Release the AC list
+void FreeAcList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ AC *ac = LIST_DATA(o, i);
+
+ Free(ac);
+ }
+
+ ReleaseList(o);
+}
+
+// Generate a string that indicates the contents of the AC
+char *GenerateAcStr(AC *ac)
+{
+ char tmp[MAX_SIZE];
+ char ip[64], mask[64];
+
+ if (ac == NULL)
+ {
+ return NULL;
+ }
+
+ IPToStr(ip, sizeof(ip), &ac->IpAddress);
+ MaskToStr(mask, sizeof(mask), &ac->SubnetMask);
+
+ if (ac->Masked == false)
+ {
+ Format(tmp, sizeof(tmp), "%s", ip);
+ }
+ else
+ {
+ Format(tmp, sizeof(tmp), "%s/%s", ip, mask);
+ }
+
+ return CopyStr(tmp);
+}
+
+// Calculate whether the specified IP address is rejected by the access list
+bool IsIpDeniedByAcList(IP *ip, LIST *o)
+{
+ return false;
+}
+
+// Calculate whether the specified IP address is masked by the AC
+bool IsIpMaskedByAc(IP *ip, AC *ac)
+{
+ return false;
+}
+
+// Set the AC
+void SetAc(LIST *o, UINT id, AC *ac)
+{
+ // Validate arguments
+ if (o == NULL || id == 0 || ac == NULL)
+ {
+ return;
+ }
+
+ if (DelAc(o, id))
+ {
+ AddAc(o, ac);
+ }
+}
+
+// Get the AC
+AC *GetAc(LIST *o, UINT id)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL || id == 0)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ AC *ac = LIST_DATA(o, i);
+
+ if (ac->Id == id)
+ {
+ return Clone(ac, sizeof(AC));
+ }
+ }
+
+ return NULL;
+}
+
+// Delete the AC
+bool DelAc(LIST *o, UINT id)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL || id == 0)
+ {
+ return false;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ AC *ac = LIST_DATA(o, i);
+
+ if (ac->Id == id)
+ {
+ if (Delete(o, ac))
+ {
+ Free(ac);
+
+ NormalizeAcList(o);
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+// Add an AC to the list
+void AddAc(LIST *o, AC *ac)
+{
+ // Validate arguments
+ if (o == NULL || ac == NULL)
+ {
+ return;
+ }
+
+ if (LIST_NUM(o) < MAX_HUB_ACS)
+ {
+ Insert(o, Clone(ac, sizeof(AC)));
+
+ NormalizeAcList(o);
+ }
+}
+
+// Normalize the AC list
+void NormalizeAcList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ AC *ac = LIST_DATA(o, i);
+
+ if (IsIP6(&ac->IpAddress))
+ {
+ ac->IpAddress.ipv6_scope_id = 0;
+ }
+
+ ac->Id = (i + 1);
+ }
+}
+
+// Create a new AC list
+LIST *NewAcList()
+{
+ return NewList(CmpAc);
+}
+
+// AC comparison
+int CmpAc(void *p1, void *p2)
+{
+ AC *a1, *a2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ a1 = *(AC **)p1;
+ a2 = *(AC **)p2;
+ if (a1 == NULL || a2 == NULL)
+ {
+ return 0;
+ }
+ if (a1->Priority > a2->Priority)
+ {
+ return 1;
+ }
+ else if (a1->Priority < a2->Priority)
+ {
+ return -1;
+ }
+ else if (a1->Deny > a2->Deny)
+ {
+ return 1;
+ }
+ else if (a1->Deny < a2->Deny)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// Copy the CRL
+CRL *CopyCrl(CRL *crl)
+{
+ CRL *ret;
+ // Validate arguments
+ if (crl == NULL)
+ {
+ return NULL;
+ }
+
+ ret = ZeroMalloc(sizeof(CRL));
+
+ if (crl->Serial != NULL)
+ {
+ ret->Serial = NewXSerial(crl->Serial->data, crl->Serial->size);
+ }
+
+ ret->Name = CopyName(crl->Name);
+
+ Copy(ret->DigestMD5, crl->DigestMD5, MD5_SIZE);
+ Copy(ret->DigestSHA1, crl->DigestSHA1, SHA1_SIZE);
+
+ return ret;
+}
+
+// Release the CRL
+void FreeCrl(CRL *crl)
+{
+ // Validate arguments
+ if (crl == NULL)
+ {
+ return;
+ }
+
+ if (crl->Serial != NULL)
+ {
+ FreeXSerial(crl->Serial);
+ }
+
+ if (crl->Name != NULL)
+ {
+ FreeName(crl->Name);
+ }
+
+ Free(crl);
+}
+
+// Check whether the certificate has been disabled by searching the CRL list of Virtual HUB
+bool IsValidCertInHub(HUB *h, X *x)
+{
+ bool ret;
+ // Validate arguments
+ if (h == NULL || x == NULL)
+ {
+ return false;
+ }
+
+ if (h->HubDb == NULL)
+ {
+ return false;
+ }
+
+ if (IsXRevoked(x))
+ {
+ // Disabled by the CRL stored in the file
+ return false;
+ }
+
+ LockList(h->HubDb->CrlList);
+ {
+ ret = IsCertMatchCrlList(x, h->HubDb->CrlList);
+ }
+ UnlockList(h->HubDb->CrlList);
+
+ if (ret)
+ {
+ // This is invalid because it was matched
+ return false;
+ }
+
+ // This is valid because it wasn't matched
+ return true;
+}
+
+// Search whether the certificate matches the CRL list
+bool IsCertMatchCrlList(X *x, LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (x == NULL || o == NULL)
+ {
+ return false;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ CRL *crl = LIST_DATA(o, i);
+
+ if (IsCertMatchCrl(x, crl))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Convert the CRL to a string
+wchar_t *GenerateCrlStr(CRL *crl)
+{
+ wchar_t tmp[2048];
+ // Validate arguments
+ if (crl == NULL)
+ {
+ return NULL;
+ }
+
+ UniStrCpy(tmp, sizeof(tmp), L"");
+
+ if (crl->Name != NULL)
+ {
+ // Name information
+ wchar_t name[MAX_SIZE];
+
+ UniStrCat(tmp, sizeof(tmp), L"Subject=\"");
+
+ GetAllNameFromName(name, sizeof(name), crl->Name);
+ UniStrCat(tmp, sizeof(tmp), name);
+ UniStrCat(tmp, sizeof(tmp), L"\", ");
+ }
+
+ if (crl->Serial != NULL)
+ {
+ // Serial information
+ char str[128];
+ wchar_t uni[128];
+
+ BinToStrEx(str, sizeof(str), crl->Serial->data, crl->Serial->size);
+ StrToUni(uni, sizeof(uni), str);
+ UniStrCat(tmp, sizeof(tmp), L"Serial=\"");
+ UniStrCat(tmp, sizeof(tmp), uni);
+ UniStrCat(tmp, sizeof(tmp), L"\", ");
+ }
+
+ if (IsZero(crl->DigestMD5, MD5_SIZE) == false)
+ {
+ // MD5
+ char str[128];
+ wchar_t uni[128];
+
+ BinToStrEx(str, sizeof(str), crl->DigestMD5, MD5_SIZE);
+ StrToUni(uni, sizeof(uni), str);
+ UniStrCat(tmp, sizeof(tmp), L"MD5=\"");
+ UniStrCat(tmp, sizeof(tmp), uni);
+ UniStrCat(tmp, sizeof(tmp), L"\", ");
+ }
+
+ if (IsZero(crl->DigestSHA1, SHA1_SIZE) == false)
+ {
+ // MD5
+ char str[128];
+ wchar_t uni[128];
+
+ BinToStrEx(str, sizeof(str), crl->DigestSHA1, SHA1_SIZE);
+ StrToUni(uni, sizeof(uni), str);
+ UniStrCat(tmp, sizeof(tmp), L"SHA1=\"");
+ UniStrCat(tmp, sizeof(tmp), uni);
+ UniStrCat(tmp, sizeof(tmp), L"\", ");
+ }
+
+ if (UniEndWith(tmp, L", "))
+ {
+ tmp[UniStrLen(tmp) - 2] = 0;
+ }
+
+ return CopyUniStr(tmp);
+}
+
+// Check whether it matches the Certificate Revocation List entry
+bool IsCertMatchCrl(X *x, CRL *crl)
+{
+ bool b = true;
+ // Validate arguments
+ if (x == NULL || crl == NULL)
+ {
+ return false;
+ }
+
+ if (crl->Serial != NULL)
+ {
+ // If a serial number is defined in the CRL
+ if (x->serial == NULL || CompareXSerial(x->serial, crl->Serial) == false)
+ {
+ // Serial number mismatch
+ b = false;
+ }
+ }
+
+ if (IsZero(crl->DigestMD5, sizeof(crl->DigestMD5)) == false)
+ {
+ UCHAR test[MD5_SIZE];
+ // If a DigestMD5 is defined in the CRL
+ GetXDigest(x, test, false);
+
+ if (Cmp(test, crl->DigestMD5, MD5_SIZE) != 0)
+ {
+ b = false;
+ }
+ }
+
+ if (IsZero(crl->DigestSHA1, sizeof(crl->DigestSHA1)) == false)
+ {
+ UCHAR test[SHA1_SIZE];
+ // If a DigestSHA1 is defined in the CRL
+ GetXDigest(x, test, true);
+
+ if (Cmp(test, crl->DigestSHA1, SHA1_SIZE) != 0)
+ {
+ b = false;
+ }
+ }
+
+ if (crl->Name != NULL)
+ {
+ // If a name is defined in the CRL
+ NAME *xn, *cn;
+ xn = x->subject_name;
+ cn = crl->Name;
+
+ if (cn->CommonName != NULL && (UniIsEmptyStr(cn->CommonName) == false))
+ {
+ if (xn->CommonName == NULL || UniSoftStrCmp(xn->CommonName, cn->CommonName) != 0)
+ {
+ // CommonName mismatch
+ b = false;
+ }
+ }
+
+ if (cn->Organization != NULL && (UniIsEmptyStr(cn->Organization) == false))
+ {
+ if (xn->Organization == NULL || UniSoftStrCmp(xn->Organization, cn->Organization) != 0)
+ {
+ // Organization mismatch
+ b = false;
+ }
+ }
+
+ if (cn->Unit != NULL && (UniIsEmptyStr(cn->Unit) == false))
+ {
+ if (xn->Unit == NULL || UniSoftStrCmp(xn->Unit, cn->Unit) != 0)
+ {
+ // Unit mismatch
+ b = false;
+ }
+ }
+
+ if (cn->Country != NULL && (UniIsEmptyStr(cn->Country) == false))
+ {
+ if (xn->Country == NULL || UniSoftStrCmp(xn->Country, cn->Country) != 0)
+ {
+ // Country mismatch
+ b = false;
+ }
+ }
+
+ if (cn->State != NULL && (UniIsEmptyStr(cn->State) == false))
+ {
+ if (xn->State == NULL || UniSoftStrCmp(xn->State, cn->State) != 0)
+ {
+ // State mismatch
+ b = false;
+ }
+ }
+
+ if (cn->Local != NULL && (UniIsEmptyStr(cn->Local) == false))
+ {
+ if (xn->Local == NULL || UniSoftStrCmp(xn->Local, cn->Local) != 0)
+ {
+ // Local mismatch
+ b = false;
+ }
+ }
+ }
+
+ return b;
+}
+
+// Get the help string of administration options
+wchar_t *GetHubAdminOptionHelpString(char *name)
+{
+ char tmp[MAX_SIZE];
+ wchar_t *ret;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return L"";
+ }
+
+ Format(tmp, sizeof(tmp), "HUB_AO_%s", name);
+
+ ret = _UU(tmp);
+ if (UniIsEmptyStr(ret))
+ {
+ ret = _UU("HUB_AO_UNKNOWN");
+ }
+
+ return ret;
+}
+
+// Add the default administration options to the Virtual HUB
+void AddHubAdminOptionsDefaults(HUB *h, bool lock)
+{
+ UINT i;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ if (lock)
+ {
+ LockList(h->AdminOptionList);
+ }
+
+ for (i = 0;i < num_admin_options;i++)
+ {
+ ADMIN_OPTION *e = &admin_options[i];
+ ADMIN_OPTION t, *r;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), e->Name);
+
+ r = Search(h->AdminOptionList, &t);
+ if (r == NULL)
+ {
+ ADMIN_OPTION *a = ZeroMalloc(sizeof(ADMIN_OPTION));
+
+ StrCpy(a->Name, sizeof(a->Name), e->Name);
+ a->Value = e->Value;
+
+ Insert(h->AdminOptionList, a);
+ }
+ }
+
+ if (lock)
+ {
+ UnlockList(h->AdminOptionList);
+ }
+}
+
+// Delete all administration options of Virtual HUB
+void DeleteAllHubAdminOption(HUB *h, bool lock)
+{
+ UINT i;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ if (lock)
+ {
+ LockList(h->AdminOptionList);
+ }
+
+ for (i = 0;i < LIST_NUM(h->AdminOptionList);i++)
+ {
+ Free(LIST_DATA(h->AdminOptionList, i));
+ }
+
+ DeleteAll(h->AdminOptionList);
+
+ if (lock)
+ {
+ UnlockList(h->AdminOptionList);
+ }
+}
+
+// Get the administration options for the virtual HUB
+UINT GetHubAdminOptionEx(HUB *h, char *name, UINT default_value)
+{
+ UINT ret = default_value;
+ // Validate arguments
+ if (h == NULL || name == NULL)
+ {
+ return 0;
+ }
+
+ LockList(h->AdminOptionList);
+ {
+ ADMIN_OPTION *a, t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), name);
+ Trim(t.Name);
+
+ a = Search(h->AdminOptionList, &t);
+
+ if (a != NULL)
+ {
+ ret = a->Value;
+ }
+ }
+ UnlockList(h->AdminOptionList);
+
+ return ret;
+}
+UINT GetHubAdminOption(HUB *h, char *name)
+{
+ return GetHubAdminOptionEx(h, name, 0);
+}
+
+// Administration options
+int CompareAdminOption(void *p1, void *p2)
+{
+ ADMIN_OPTION *a1, *a2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ a1 = *(ADMIN_OPTION **)p1;
+ a2 = *(ADMIN_OPTION **)p2;
+ if (a1 == NULL || a2 == NULL)
+ {
+ return 0;
+ }
+ return StrCmpi(a1->Name, a2->Name);
+}
+
+// Start the watchdog
+void StartHubWatchDog(HUB *h)
+{
+ THREAD *t;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ h->HaltWatchDog = false;
+ h->WatchDogEvent = NewEvent();
+
+ t = NewThread(HubWatchDogThread, h);
+ WaitThreadInit(t);
+ ReleaseThread(t);
+}
+
+// Stop the watchdog
+void StopHubWatchDog(HUB *h)
+{
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ h->HaltWatchDog = true;
+ Set(h->WatchDogEvent);
+
+ WaitThread(h->WatchDogThread, INFINITE);
+ ReleaseThread(h->WatchDogThread);
+ h->WatchDogThread = NULL;
+ h->HaltWatchDog = false;
+
+ ReleaseEvent(h->WatchDogEvent);
+ h->WatchDogEvent = NULL;
+}
+
+// Watchdog thread
+void HubWatchDogThread(THREAD *t, void *param)
+{
+ UINT num_packets_v4 = 0;
+ UINT num_packets_v6 = 0;
+ HUB *hub;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ hub = (HUB *)param;
+
+ hub->WatchDogThread = t;
+ AddRef(t->ref);
+
+ NoticeThreadInit(t);
+
+ while (true)
+ {
+ LIST *o;
+ LIST *o2;
+ UINT i, num;
+ UINT interval;
+ UINT wait_time = 100;
+ if (hub->HaltWatchDog)
+ {
+ break;
+ }
+
+ o = NewListFast(NULL);
+ o2 = NewListFast(NULL);
+
+ // Send an ARP packet
+ LockList(hub->IpTable);
+ {
+ num = LIST_NUM(hub->IpTable);
+ for (i = 0;i < LIST_NUM(hub->IpTable);i++)
+ {
+ IP_TABLE_ENTRY *e = LIST_DATA(hub->IpTable, i);
+
+ if ((e->UpdatedTime + (UINT64)(IP_TABLE_EXPIRE_TIME)) > Tick64())
+ {
+ if (e->MacAddress[0] != 0xff || e->MacAddress[1] != 0xff || e->MacAddress[2] != 0xff ||
+ e->MacAddress[3] != 0xff || e->MacAddress[4] != 0xff || e->MacAddress[5] != 0xff)
+ {
+ if (hub->Option != NULL && hub->Option->NoArpPolling == false)
+ {
+ if (IsIP4(&e->Ip))
+ {
+ // IPv4
+ MAC_HEADER *mac = ZeroMalloc(sizeof(MAC_HEADER) + sizeof(ARPV4_HEADER));
+ ARPV4_HEADER *p = (ARPV4_HEADER *)(((UCHAR *)mac) + sizeof(MAC_HEADER));
+
+ Copy(mac->DestAddress, e->MacAddress, 6);
+ Copy(mac->SrcAddress, hub->HubMacAddr, 6);
+ mac->Protocol = Endian16(MAC_PROTO_ARPV4);
+
+ p->HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+ p->ProtocolType = Endian16(MAC_PROTO_IPV4);
+ p->HardwareSize = 6;
+ p->ProtocolSize = 4;
+ p->Operation = Endian16(ARP_OPERATION_REQUEST);
+ Copy(p->SrcAddress, hub->HubMacAddr, 6);
+ p->SrcIP = IPToUINT(&hub->HubIp);
+ p->TargetAddress[0] =
+ p->TargetAddress[1] =
+ p->TargetAddress[2] =
+ p->TargetAddress[3] =
+ p->TargetAddress[4] =
+ p->TargetAddress[5] = 0x00;
+ p->TargetIP = IPToUINT(&e->Ip);
+ Insert(o, mac);
+ }
+ }
+
+ if (hub->Option != NULL && hub->Option->NoIPv6AddrPolling == false)
+ {
+ if (IsIP6(&e->Ip))
+ {
+ // IPv6
+ BUF *buf;
+ IPV6_ADDR ip6addr;
+
+ if (IPToIPv6Addr(&ip6addr, &e->Ip))
+ {
+ buf = BuildICMPv6NeighborSoliciation(&hub->HubIpV6,
+ &ip6addr,
+ hub->HubMacAddr, ++hub->HubIP6Id);
+
+ if (buf != NULL)
+ {
+ BUF *buf2 = NewBuf();
+ MAC_HEADER mac;
+
+ Zero(&mac, sizeof(mac));
+
+ Copy(mac.DestAddress, e->MacAddress, 6);
+ Copy(mac.SrcAddress, hub->HubMacAddr, 6);
+ mac.Protocol = Endian16(MAC_PROTO_IPV6);
+
+ WriteBuf(buf2, &mac, sizeof(MAC_HEADER));
+
+ WriteBuf(buf2, buf->Buf, buf->Size);
+
+ FreeBuf(buf);
+
+ Insert(o2, buf2);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ UnlockList(hub->IpTable);
+
+ if ((LIST_NUM(o) + LIST_NUM(o2)) != 0)
+ {
+ interval = HUB_ARP_SEND_INTERVAL / (LIST_NUM(o) + LIST_NUM(o2));
+ }
+ else
+ {
+ interval = HUB_ARP_SEND_INTERVAL;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ PKT *packet;
+ void *p = LIST_DATA(o, i);
+
+ Wait(hub->WatchDogEvent, interval);
+ if (hub->HaltWatchDog)
+ {
+ for (;i < LIST_NUM(o);i++)
+ {
+ Free(LIST_DATA(o, i));
+ }
+ ReleaseList(o);
+
+ for (i = 0;i < LIST_NUM(o2);i++)
+ {
+ FreeBuf(LIST_DATA(o2, i));
+ }
+ ReleaseList(o2);
+ goto ESCAPE;
+ }
+
+ packet = ParsePacket((UCHAR *)p, sizeof(MAC_HEADER) + sizeof(ARPV4_HEADER));
+ if (packet != NULL)
+ {
+ StorePacket(hub, NULL, packet);
+ num_packets_v4++;
+ }
+ else
+ {
+ Free(p);
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o2);i++)
+ {
+ PKT *packet;
+ BUF *buf = LIST_DATA(o2, i);
+
+ Wait(hub->WatchDogEvent, interval);
+ if (hub->HaltWatchDog)
+ {
+ ReleaseList(o);
+
+ for (;i < LIST_NUM(o2);i++)
+ {
+ FreeBuf(LIST_DATA(o2, i));
+ }
+ ReleaseList(o2);
+ goto ESCAPE;
+ }
+
+ packet = ParsePacket(buf->Buf, buf->Size);
+ if (packet != NULL)
+ {
+ StorePacket(hub, NULL, packet);
+ num_packets_v6++;
+ }
+ else
+ {
+ Free(buf->Buf);
+ }
+
+ Free(buf);
+ }
+
+ ReleaseList(o);
+ ReleaseList(o2);
+
+ if (num == 0)
+ {
+ wait_time = HUB_ARP_SEND_INTERVAL;
+ }
+
+ Wait(hub->WatchDogEvent, wait_time);
+ }
+ESCAPE:
+ return;
+}
+
+// Eable / disable the SecureNAT
+void EnableSecureNAT(HUB *h, bool enable)
+{
+ EnableSecureNATEx(h, enable, false);
+}
+void EnableSecureNATEx(HUB *h, bool enable, bool no_change)
+{
+ bool for_cluster = false;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ if (h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ if (h->Type == HUB_TYPE_FARM_DYNAMIC)
+ {
+ for_cluster = true;
+ }
+ }
+
+ Lock(h->lock_online);
+ {
+ if (no_change == false)
+ {
+ h->EnableSecureNAT = enable;
+ }
+
+ if (h->EnableSecureNAT == false)
+ {
+STOP:
+ // Stop if it's already started
+ if (h->SecureNAT != NULL)
+ {
+ SnFreeSecureNAT(h->SecureNAT);
+ h->SecureNAT = NULL;
+ }
+ }
+ else
+ {
+ if (for_cluster)
+ {
+ if ((h->SecureNAT != NULL && LIST_NUM(h->SessionList) <= 1) ||
+ (h->SecureNAT == NULL && LIST_NUM(h->SessionList) == 0))
+ {
+ // It is in a start mode, but stop when there is no other sessions
+ // in the case of dynamic Virtual HUB
+ goto STOP;
+ }
+ }
+
+ // Start if the HUB is online and not started
+ if (h->SecureNAT == NULL && h->Offline == false)
+ {
+ h->SecureNAT = SnNewSecureNAT(h, h->SecureNATOption);
+ }
+ }
+ }
+ Unlock(h->lock_online);
+}
+
+// Convert an access list to a string
+void GetAccessListStr(char *str, UINT size, ACCESS *a)
+{
+ char tmp[MAX_SIZE];
+ char tmp1[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ bool l3 = false;
+ bool asterisk = false;
+ // Validate arguments
+ if (str == NULL || a == NULL)
+ {
+ return;
+ }
+
+ StrCpy(str, size, "");
+
+ if (a->IsIPv6 == false)
+ {
+ if (a->SrcIpAddress != 0 || a->SrcSubnetMask != 0)
+ {
+ IPToStr32(tmp1, sizeof(tmp1), a->SrcIpAddress);
+ MaskToStr32(tmp2, sizeof(tmp2), a->SrcSubnetMask);
+ Format(tmp, sizeof(tmp), "SrcIPv4=%s/%s, ", tmp1, tmp2);
+ StrCat(str, size, tmp);
+
+ l3 = true;
+ }
+
+ if (a->DestIpAddress != 0 || a->DestSubnetMask != 0)
+ {
+ IPToStr32(tmp1, sizeof(tmp1), a->DestIpAddress);
+ MaskToStr32(tmp2, sizeof(tmp2), a->DestSubnetMask);
+ Format(tmp, sizeof(tmp), "DstIPv4=%s/%s, ", tmp1, tmp2);
+ StrCat(str, size, tmp);
+
+ l3 = true;
+ }
+ }
+ else
+ {
+ if (IsZeroIP6Addr(&a->SrcIpAddress6) == false || IsZeroIP6Addr(&a->SrcSubnetMask6) == false)
+ {
+ IP6AddrToStr(tmp1, sizeof(tmp1), &a->SrcIpAddress6);
+ Mask6AddrToStr(tmp2, sizeof(tmp2), &a->SrcSubnetMask6);
+ Format(tmp, sizeof(tmp), "SrcIPv6=%s/%s, ", tmp1, tmp2);
+ StrCat(str, size, tmp);
+
+ l3 = true;
+ }
+
+ if (IsZeroIP6Addr(&a->DestIpAddress6) == false || IsZeroIP6Addr(&a->DestSubnetMask6) == false)
+ {
+ IP6AddrToStr(tmp1, sizeof(tmp1), &a->DestIpAddress6);
+ Mask6AddrToStr(tmp2, sizeof(tmp2), &a->DestSubnetMask6);
+ Format(tmp, sizeof(tmp), "DstIPv6=%s/%s, ", tmp1, tmp2);
+ StrCat(str, size, tmp);
+
+ l3 = true;
+ }
+ }
+
+ if (a->Protocol != 0)
+ {
+ StrCpy(tmp1, sizeof(tmp1), "");
+ switch (a->Protocol)
+ {
+ case 1:
+ StrCpy(tmp1, sizeof(tmp1), "ICMPv4");
+ break;
+ case 3:
+ StrCpy(tmp1, sizeof(tmp1), "GGP");
+ break;
+ case 6:
+ StrCpy(tmp1, sizeof(tmp1), "TCP");
+ break;
+ case 8:
+ StrCpy(tmp1, sizeof(tmp1), "EGP");
+ break;
+ case 12:
+ StrCpy(tmp1, sizeof(tmp1), "PUP");
+ break;
+ case 17:
+ StrCpy(tmp1, sizeof(tmp1), "UDP");
+ break;
+ case 20:
+ StrCpy(tmp1, sizeof(tmp1), "HMP");
+ break;
+ case 22:
+ StrCpy(tmp1, sizeof(tmp1), "XNS-IDP");
+ break;
+ case 27:
+ StrCpy(tmp1, sizeof(tmp1), "RDP");
+ break;
+ case 58:
+ StrCpy(tmp1, sizeof(tmp1), "ICMPv6");
+ break;
+ case 66:
+ StrCpy(tmp1, sizeof(tmp1), "RVD");
+ break;
+ }
+
+ if (IsEmptyStr(tmp1))
+ {
+ Format(tmp, sizeof(tmp), "Protocol=%s(%u), ", tmp1, a->Protocol);
+ }
+ else
+ {
+ Format(tmp, sizeof(tmp), "Protocol=%s, ", tmp1);
+ }
+
+ StrCat(str, size, tmp);
+
+ l3 = true;
+ }
+
+ if (a->SrcPortStart != 0)
+ {
+ if (a->SrcPortEnd == a->SrcPortStart)
+ {
+ Format(tmp, sizeof(tmp), "SrcPort=%u, ", a->SrcPortStart);
+ StrCat(str, size, tmp);
+ }
+ else
+ {
+ Format(tmp, sizeof(tmp), "SrcPort=%u-%u, ", a->SrcPortStart, a->SrcPortEnd);
+ StrCat(str, size, tmp);
+ }
+
+ l3 = true;
+ }
+
+ if (a->DestPortStart != 0)
+ {
+ if (a->DestPortEnd == a->DestPortStart)
+ {
+ Format(tmp, sizeof(tmp), "DstPort=%u, ", a->DestPortStart);
+ StrCat(str, size, tmp);
+ }
+ else
+ {
+ Format(tmp, sizeof(tmp), "DstPort=%u-%u, ", a->DestPortStart, a->DestPortEnd);
+ StrCat(str, size, tmp);
+ }
+
+ l3 = true;
+ }
+
+ if (StrLen(a->SrcUsername) != 0)
+ {
+ Format(tmp, sizeof(tmp), "SrcUser=%s, ", a->SrcUsername);
+ StrCat(str, size, tmp);
+ }
+
+ if (StrLen(a->DestUsername) != 0)
+ {
+ Format(tmp, sizeof(tmp), "DstUser=%s, ", a->DestUsername);
+ StrCat(str, size, tmp);
+ }
+
+ if (a->CheckSrcMac != false)
+ {
+ char mac[MAX_SIZE], mask[MAX_SIZE];
+ MacToStr(mac, sizeof(mac), a->SrcMacAddress);
+ MacToStr(mask, sizeof(mask), a->SrcMacMask);
+ Format(tmp, sizeof(tmp), "SrcMac=%s/%s, ", mac, mask);
+ StrCat(str, size, tmp);
+ }
+ if (a->CheckDstMac != false)
+ {
+ char mac[MAX_SIZE], mask[MAX_SIZE];
+ MacToStr(mac, sizeof(mac), a->DstMacAddress);
+ MacToStr(mask, sizeof(mask), a->DstMacMask);
+ Format(tmp, sizeof(tmp), "DstMac=%s/%s, ", mac, mask);
+ StrCat(str, size, tmp);
+ }
+
+ if (a->CheckTcpState)
+ {
+ if(a->Established)
+ {
+ StrCat(str, size, "Established, ");
+ }
+ else
+ {
+ StrCat(str, size, "Unestablished, ");
+ }
+
+ l3 = true;
+ }
+
+ if (a->Discard == false)
+ {
+ if (a->Delay >= 1)
+ {
+ Format(tmp, sizeof(tmp), "Delay=%u, ", a->Delay);
+ StrCat(str, size, tmp);
+ }
+
+ if (a->Jitter >= 1)
+ {
+ Format(tmp, sizeof(tmp), "Jitter=%u, ", a->Jitter);
+ StrCat(str, size, tmp);
+ }
+
+ if (a->Loss >= 1)
+ {
+ Format(tmp, sizeof(tmp), "Loss=%u, " , a->Loss);
+ StrCat(str, size, tmp);
+ }
+ }
+
+ if (IsEmptyStr(a->RedirectUrl) == false)
+ {
+ Format(tmp, sizeof(tmp), "RedirectUrl=%s, ", a->RedirectUrl);
+ StrCat(str, size, tmp);
+ }
+
+ if (StrLen(str) == 0)
+ {
+ asterisk = true;
+ }
+
+ if (l3)
+ {
+ if (a->IsIPv6)
+ {
+ StrCatLeft(str, size, "(ipv6) ");
+ }
+ else
+ {
+ StrCatLeft(str, size, "(ipv4) ");
+ }
+ }
+ else
+ {
+ StrCatLeft(str, size, "(ether) ");
+ }
+
+ if (EndWith(str, ", "))
+ {
+ str[StrLen(str) - 2] = 0;
+ }
+
+ if (asterisk)
+ {
+ StrCat(str, size, "*");
+ }
+}
+
+// Determine whether the access list can mask the packet
+bool IsPacketMaskedByAccessList(SESSION *s, PKT *p, ACCESS *a, UINT64 dest_username, UINT64 dest_groupname, SESSION *dest_session)
+{
+ UINT64 src_username;
+ UINT64 src_username_simple;
+ UINT64 src_groupname;
+ HUB_PA *pa;
+ IPV4_HEADER *ip = NULL;
+ IPV6_HEADER *ip6 = NULL;
+ bool is_ipv4_packet = false;
+ bool is_ipv6_packet = false;
+ // Validate arguments
+ if (s == NULL || p == NULL || a == NULL)
+ {
+ return false;
+ }
+ if (a->Active == false)
+ {
+ // Access list is inactive
+ return false;
+ }
+
+ pa = (HUB_PA *)s->PacketAdapter->Param;
+
+ // Hash of the source user name
+ src_username = pa->UsernameHash;
+ src_username_simple = pa->UsernameHashSimple;
+ src_groupname = pa->GroupnameHash;
+
+ // Determine the source and destination MAC address
+ if (a->CheckSrcMac != false)
+ {
+ UINT i;
+ for (i = 0; i < 6; i++)
+ {
+ if((a->SrcMacAddress[i] & a->SrcMacMask[i]) != (a->SrcMacMask[i] & p->MacAddressSrc[i]))
+ {
+ return false;
+ }
+ }
+ }
+
+ if (a->CheckDstMac != false)
+ {
+ UINT i;
+ for (i = 0; i < 6; i++)
+ {
+ if ((a->DstMacAddress[i] & a->DstMacMask[i]) != (a->DstMacMask[i] & p->MacAddressDest[i]))
+ {
+ return false;
+ }
+ }
+ }
+
+ // Check the source user name / group name
+ if (a->SrcUsernameHash != 0)
+ {
+ if (a->IsSrcUsernameIncludeOrExclude == false)
+ {
+ // It is specified as a regular user name
+ if ((a->SrcUsernameHash != src_username) && (a->SrcUsernameHash != src_groupname))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // It is specified in the form of a exclude:FILENAME or include:FILENAME
+ HUB *hub = s->Hub;
+
+ if (hub != NULL)
+ {
+ LIST *o = hub->UserList;
+
+ if (s->NormalClient == false)
+ {
+ // The internal session don't become target for format exclude: or include:
+ return false;
+ }
+
+ if (IsUserMatchInUserListWithCacheExpiresAcl(o, a->SrcUsername, src_username,
+ hub->Option->AccessListIncludeFileCacheLifetime * 1000) == false)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ // Check the destination user name / group name
+ if (a->DestUsernameHash != 0)
+ {
+ if (a->IsDestUsernameIncludeOrExclude == false)
+ {
+ // It is specified as a regular user name
+ if ((a->DestUsernameHash != dest_username) && (a->DestUsernameHash != dest_groupname))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ // It is specified in the form of a exclude:FILENAME or include:FILENAME
+ HUB *hub = s->Hub;
+
+ if (hub != NULL)
+ {
+ LIST *o = hub->UserList;
+
+ if (dest_session != NULL && dest_session->NormalClient == false)
+ {
+ // The internal session don't become target for format exclude: or include:
+ return false;
+ }
+
+ if (IsUserMatchInUserListWithCacheExpiresAcl(o, a->DestUsername, dest_username,
+ hub->Option->AccessListIncludeFileCacheLifetime * 1000) == false)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ // Determine of the IP packet
+ if (p->TypeL3 != L3_IPV4)
+ {
+ is_ipv4_packet = false;
+ }
+ else
+ {
+ is_ipv4_packet = true;
+ }
+
+ if (p->TypeL3 != L3_IPV6)
+ {
+ is_ipv6_packet = false;
+ }
+ else
+ {
+ is_ipv6_packet = true;
+ }
+
+ if (is_ipv4_packet)
+ {
+ ip = p->L3.IPv4Header;
+ }
+
+ if (is_ipv6_packet)
+ {
+ ip6 = p->L3.IPv6Header;
+ }
+
+ if (a->IsIPv6 == false)
+ {
+ // IPv4
+
+ // Check the source IP address
+ if (a->SrcIpAddress != 0 || a->SrcSubnetMask != 0)
+ {
+ if (is_ipv4_packet == false)
+ {
+ if (p->TypeL3 == L3_ARPV4)
+ {
+ bool arp_match = false;
+ if (p->L3.ARPv4Header->HardwareSize == 6 &&
+ Endian16(p->L3.ARPv4Header->HardwareType) == ARP_HARDWARE_TYPE_ETHERNET &&
+ p->L3.ARPv4Header->ProtocolSize == 4 &&
+ Endian16(p->L3.ARPv4Header->ProtocolType) == 0x0800)
+ {
+ UINT uint_ip = p->L3.ARPv4Header->SrcIP;
+
+ if (uint_ip != 0 && uint_ip != 0xffffffff && !(IsHubIpAddress32(uint_ip) && IsHubMacAddress(p->MacAddressSrc)))
+ {
+ if ((uint_ip & a->SrcSubnetMask) != (a->SrcIpAddress & a->SrcSubnetMask))
+ {
+ }
+ else
+ {
+ arp_match = true;
+ }
+ }
+ }
+
+ if (arp_match == false)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if ((ip->SrcIP & a->SrcSubnetMask) != (a->SrcIpAddress & a->SrcSubnetMask))
+ {
+ return false;
+ }
+ }
+ }
+
+ // Check the destination IP address
+ if (a->DestIpAddress != 0 || a->DestSubnetMask != 0)
+ {
+ if (is_ipv4_packet == false)
+ {
+ if (p->TypeL3 == L3_ARPV4)
+ {
+ bool arp_match = false;
+ if (p->L3.ARPv4Header->HardwareSize == 6 &&
+ Endian16(p->L3.ARPv4Header->HardwareType) == ARP_HARDWARE_TYPE_ETHERNET &&
+ p->L3.ARPv4Header->ProtocolSize == 4 &&
+ Endian16(p->L3.ARPv4Header->ProtocolType) == 0x0800)
+ {
+ UINT uint_ip = p->L3.ARPv4Header->TargetIP;
+
+ if (uint_ip != 0 && uint_ip != 0xffffffff && !(IsHubIpAddress32(uint_ip) && IsHubMacAddress(p->MacAddressSrc)))
+ {
+ if ((uint_ip & a->DestSubnetMask) != (a->DestIpAddress & a->DestSubnetMask))
+ {
+ }
+ else
+ {
+ arp_match = true;
+ }
+ }
+ }
+
+ if (arp_match == false)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if ((ip->DstIP & a->DestSubnetMask) != (a->DestIpAddress & a->DestSubnetMask))
+ {
+ return false;
+ }
+ }
+ }
+ }
+ else
+ {
+ // IPv6
+
+ // Check the source IP address
+ if (IsZeroIP6Addr(&a->SrcIpAddress6) == false ||
+ IsZeroIP6Addr(&a->SrcSubnetMask6) == false)
+ {
+ if (is_ipv6_packet == false)
+ {
+ return false;
+ }
+ else
+ {
+ IP a_ip, a_subnet, p_ip;
+ IP and1, and2;
+
+ IPv6AddrToIP(&a_ip, &a->SrcIpAddress6);
+ IPv6AddrToIP(&a_subnet, &a->SrcSubnetMask6);
+ IPv6AddrToIP(&p_ip, &ip6->SrcAddress);
+
+ IPAnd6(&and1, &a_ip, &a_subnet);
+ IPAnd6(&and2, &p_ip, &a_subnet);
+
+ if (CmpIpAddr(&and1, &and2) != 0)
+ {
+ return false;
+ }
+ }
+ }
+
+ // Check the destination IP address
+ if (IsZeroIP6Addr(&a->DestIpAddress6) == false ||
+ IsZeroIP6Addr(&a->DestSubnetMask6) == false)
+ {
+ if (is_ipv6_packet == false)
+ {
+ return false;
+ }
+ else
+ {
+ IP a_ip, a_subnet, p_ip;
+ IP and1, and2;
+
+ IPv6AddrToIP(&a_ip, &a->DestIpAddress6);
+ IPv6AddrToIP(&a_subnet, &a->DestSubnetMask6);
+ IPv6AddrToIP(&p_ip, &ip6->DestAddress);
+
+ IPAnd6(&and1, &a_ip, &a_subnet);
+ IPAnd6(&and2, &p_ip, &a_subnet);
+
+ if (CmpIpAddr(&and1, &and2) != 0)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ // Don't match the packet of non-IPv4 and non-IPv6
+ if (is_ipv4_packet == false && is_ipv6_packet==false)
+ {
+ if (s->Hub != NULL && s->Hub->Option != NULL && s->Hub->Option->ApplyIPv4AccessListOnArpPacket)
+ {
+ // Match the ARP only if ApplyIPv4AccessListOnArpPacket option is enabled
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ // Check the protocol number
+ if (a->Protocol != 0)
+ {
+ if (a->IsIPv6 == false)
+ {
+ if (is_ipv4_packet == false)
+ {
+ return false;
+ }
+ else
+ {
+ if (ip->Protocol != a->Protocol)
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ if (is_ipv6_packet == false)
+ {
+ return false;
+ }
+ else
+ {
+ if (p->IPv6HeaderPacketInfo.Protocol != a->Protocol)
+ {
+ return false;
+ }
+ }
+ }
+ }
+
+ // Check the port number
+ if (a->SrcPortStart != 0 || a->DestPortStart != 0 ||
+ a->SrcPortEnd != 0 || a->DestPortEnd != 0)
+ {
+ if ((a->IsIPv6 == false && is_ipv4_packet == false) ||
+ (a->IsIPv6 && is_ipv6_packet == false))
+ {
+ return false;
+ }
+ else
+ {
+ if (p->TypeL4 == L4_TCP)
+ {
+ TCP_HEADER *tcp = p->L4.TCPHeader;
+ // Check the source port
+ if (a->SrcPortStart != 0 || a->SrcPortEnd != 0)
+ {
+ UINT src_port = Endian16(tcp->SrcPort);
+ if (src_port < a->SrcPortStart || src_port > a->SrcPortEnd)
+ {
+ return false;
+ }
+ }
+
+ // Check the destination port number
+ if (a->DestPortStart != 0 || a->DestPortEnd != 0)
+ {
+ UINT dest_port = Endian16(tcp->DstPort);
+ if (dest_port < a->DestPortStart || dest_port > a->DestPortEnd)
+ {
+ return false;
+ }
+ }
+ }
+ else if (p->TypeL4 == L4_UDP)
+ {
+ UDP_HEADER *udp = p->L4.UDPHeader;
+ // Check the source port
+ if (a->SrcPortStart != 0 || a->SrcPortEnd != 0)
+ {
+ UINT src_port = Endian16(udp->SrcPort);
+ if (src_port < a->SrcPortStart || src_port > a->SrcPortEnd)
+ {
+ return false;
+ }
+ }
+
+ // Check the destination port number
+ if (a->DestPortStart != 0 || a->DestPortEnd != 0)
+ {
+ UINT dest_port = Endian16(udp->DstPort);
+ if (dest_port < a->DestPortStart || dest_port > a->DestPortEnd)
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ // When the port number is specified in the access list,
+ // The rule is applied only for UDP or TCP packets
+ return false;
+ }
+ }
+ }
+
+ // Check the status of the TCP connection
+ if (a->CheckTcpState != false)
+ {
+ if ((a->IsIPv6 == false && is_ipv4_packet == false) ||
+ (a->IsIPv6 && is_ipv6_packet == false))
+ {
+ return false;
+ }
+ else
+ {
+ if(p->TypeL4 == L4_TCP)
+ {
+ // by shimizu
+ TCP_HEADER *tcp = p->L4.TCPHeader;
+ bool est = true;
+
+ if ((tcp->Flag & TCP_SYN) && (!(tcp->Flag & TCP_ACK)))
+ {
+ est = false;
+ }
+
+ if((MAKEBOOL(a->Established) ^ MAKEBOOL(est)))
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+// Apply the access list for packets to forward
+bool ApplyAccessListToForwardPacket(HUB *hub, SESSION *src_session, SESSION *dest_session, PKT *p)
+{
+ UINT i;
+ bool pass = true; // Pass by default
+ bool skip = true;
+ // Validate arguments
+ if (hub == NULL || src_session == NULL || p == NULL || dest_session == NULL)
+ {
+ return false;
+ }
+
+ // The access list is not re-applied for packets that have been already checked
+ if (p->AccessChecked)
+ {
+ return true;
+ }
+
+ LockList(hub->AccessList);
+ {
+ for (i = 0;i < LIST_NUM(hub->AccessList);i++)
+ {
+ ACCESS *a = LIST_DATA(hub->AccessList, i);
+
+ // Scan the entry only after the destination user name is specified.
+ if (a->DestUsernameHash != 0)
+ {
+ skip = false;
+ }
+
+ if (skip == false)
+ {
+ if (IsPacketMaskedByAccessList(src_session, p, a,
+ ((HUB_PA *)dest_session->PacketAdapter->Param)->UsernameHash,
+ ((HUB_PA *)dest_session->PacketAdapter->Param)->GroupnameHash,
+ dest_session))
+ {
+ // Determine the pass or discard the packet
+ pass = a->Discard ? false : true;
+
+ // Complete the scanning of the list here
+ break;
+ }
+ }
+ }
+ }
+ UnlockList(hub->AccessList);
+
+ return pass;
+}
+
+// Generate a HTTP payload for redirect
+BUF *BuildRedirectToUrlPayload(HUB *hub, SESSION *s, char *redirect_url)
+{
+ char html[MAX_REDIRECT_URL_LEN * 2 + 1 + MAX_SIZE];
+ char header[MAX_REDIRECT_URL_LEN * 2 + 1 + MAX_SIZE];
+ char redirect_url2[MAX_REDIRECT_URL_LEN * 2];
+ BUF *b;
+ // Validate arguments
+ if (hub == NULL || s == NULL || redirect_url == NULL)
+ {
+ return NULL;
+ }
+
+ StrCpy(redirect_url2, sizeof(redirect_url2), redirect_url);
+ Trim(redirect_url2);
+
+ if (InStr(redirect_url2, ACCESS_LIST_URL_INFO_TAG))
+ {
+ // Get the secret key string
+ char secret[MAX_SIZE];
+ char tmp[MAX_SIZE];
+ SYSTEMTIME st;
+ UINT i, len, isp;
+
+ isp = INFINITE;
+
+ SystemTime(&st);
+ ClearStr(secret, sizeof(secret));
+
+ len = StrLen(redirect_url2);
+
+ for (i = 0;i < len;i++)
+ {
+ char c = redirect_url2[i];
+ if (c == '|')
+ {
+ isp = i;
+ }
+ }
+
+ if (isp != INFINITE)
+ {
+ StrCpy(secret, sizeof(secret), redirect_url2 + isp + 1);
+ redirect_url2[isp] = 0;
+ }
+
+ Format(tmp, sizeof(tmp), "%s|%s|%r|%04u%02u%02u%02u%02u%02u%s",
+ s->Username, s->Name, &s->Connection->ClientIp,
+ st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, (IsEmptyStr(secret) ? "" : "|"));
+
+ if (IsEmptyStr(secret) == false)
+ {
+ // Calculate the hash
+ UCHAR hash[SHA1_SIZE];
+ char hash_str[MAX_SIZE];
+ BUF *b2 = NewBuf();
+
+ WriteBuf(b2, tmp, StrLen(tmp));
+ WriteBuf(b2, secret, StrLen(secret));
+
+ HashSha1(hash, b2->Buf, b2->Size);
+
+ BinToStr(hash_str, sizeof(hash_str), hash, sizeof(hash));
+
+ FreeBuf(b2);
+
+ StrCat(tmp, sizeof(tmp), hash_str);
+
+ // Replace
+ ReplaceStrEx(redirect_url2, sizeof(redirect_url2), redirect_url2,
+ ACCESS_LIST_URL_INFO_TAG, tmp, false);
+ }
+ }
+
+ Format(html, sizeof(html),
+ "<html><head><title>Object moved</title></head><body>\r\n<h2>Object moved to <a href=\"%s\">here</a>.</h2>\r\n</body></html>\r\n\r\n",
+ redirect_url2);
+
+ Format(header, sizeof(header),
+ "HTTP/1.1 302 Found\r\nLocation: %s\r\nCache-Control: private\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: %u\r\n\r\n",
+ redirect_url2, StrLen(redirect_url2));
+
+ b = NewBuf();
+
+ WriteBuf(b, header, StrLen(header));
+ WriteBuf(b, html, StrLen(html));
+
+ return b;
+}
+
+// Rpely a TCP response packet to redirect forcibly to the specified URL
+void ForceRedirectToUrl(HUB *hub, SESSION *src_session, PKT *p, char *redirect_url)
+{
+ BUF *payload;
+ UINT tcp_size;
+ TCP_HEADER *tcp_data;
+ TCP_HEADER *src_tcp;
+ BUF *b;
+ // Validate arguments
+ if (hub == NULL || src_session == NULL || p == NULL || redirect_url == NULL)
+ {
+ return;
+ }
+ if (p->TypeL3 != L3_IPV4 && p->TypeL3 != L3_IPV6)
+ {
+ return;
+ }
+ if (p->TypeL4 != L4_TCP)
+ {
+ return;
+ }
+
+ src_tcp = p->L4.TCPHeader;
+ if (src_tcp == NULL)
+ {
+ return;
+ }
+
+ // Generate a payload to be sent
+ payload = BuildRedirectToUrlPayload(hub, src_session, redirect_url);
+ if (payload == NULL)
+ {
+ return;
+ }
+
+ // Generate a TCP packet
+ tcp_size = sizeof(TCP_HEADER) + payload->Size;
+ tcp_data = (TCP_HEADER *)ZeroMalloc(tcp_size);
+ tcp_data->SrcPort = src_tcp->DstPort;
+ tcp_data->DstPort = src_tcp->SrcPort;
+ tcp_data->SeqNumber = src_tcp->AckNumber;
+ tcp_data->AckNumber = Endian32(Endian32(src_tcp->SeqNumber) + p->PayloadSize);
+ TCP_SET_HEADER_SIZE(tcp_data, 5);
+ tcp_data->Flag = TCP_ACK | TCP_PSH;
+ tcp_data->WindowSize = Endian16(0xFFFF);
+ Copy(((UCHAR *)tcp_data) + sizeof(TCP_HEADER), payload->Buf, payload->Size);
+
+ // Calculate the TCP checksum
+ if (p->TypeL3 == L3_IPV4)
+ {
+ // IPv4
+ tcp_data->Checksum = CalcChecksumForIPv4(p->L3.IPv4Header->DstIP, p->L3.IPv4Header->SrcIP, IP_PROTO_TCP,
+ tcp_data, tcp_size, 0);
+ }
+ else
+ {
+ // IPv6
+ tcp_data->Checksum = CalcChecksumForIPv6(&p->IPv6HeaderPacketInfo.IPv6Header->DestAddress,
+ &p->IPv6HeaderPacketInfo.IPv6Header->SrcAddress, IP_PROTO_TCP, tcp_data, tcp_size, 0);
+ }
+
+ // Generate the Ethernet and IP packet
+ b = NewBuf();
+
+ // Destination MAC address
+ WriteBuf(b, p->MacHeader->SrcAddress, 6);
+ WriteBuf(b, p->MacHeader->DestAddress, 6);
+ WriteBuf(b, &p->MacHeader->Protocol, 2);
+
+ if (p->TypeL3 == L3_IPV4)
+ {
+ // IPv4
+ IPV4_HEADER v4;
+
+ Zero(&v4, sizeof(v4));
+
+ IPV4_SET_VERSION(&v4, 4);
+ IPV4_SET_HEADER_LEN(&v4, 5);
+ v4.TotalLength = Endian16((USHORT)(sizeof(IPV4_HEADER) + tcp_size));
+ v4.Identification = Endian16(Rand16());
+ IPV4_SET_FLAGS(&v4, 0x02);
+ v4.TimeToLive = 128;
+ v4.Protocol = IP_PROTO_TCP;
+ v4.SrcIP = p->L3.IPv4Header->DstIP;
+ v4.DstIP = p->L3.IPv4Header->SrcIP;
+ v4.Checksum = IpChecksum(&v4, sizeof(v4));
+
+ WriteBuf(b, &v4, sizeof(v4));
+ }
+ else
+ {
+ // IPv6
+ IPV6_HEADER v6;
+
+ Zero(&v6, sizeof(v6));
+
+ IPV6_SET_VERSION(&v6, 6);
+ v6.PayloadLength = Endian16(tcp_size);
+ v6.NextHeader = IP_PROTO_TCP;
+ v6.HopLimit = 64;
+
+ Copy(&v6.SrcAddress, &p->IPv6HeaderPacketInfo.IPv6Header->DestAddress, sizeof(IPV6_ADDR));
+ Copy(&v6.DestAddress, &p->IPv6HeaderPacketInfo.IPv6Header->SrcAddress, sizeof(IPV6_ADDR));
+
+ WriteBuf(b, &v6, sizeof(v6));
+ }
+
+ WriteBuf(b, tcp_data, tcp_size);
+
+ // Reply packet
+ StorePacketToHubPa((HUB_PA *)src_session->PacketAdapter->Param,
+ NULL, b->Buf, b->Size, NULL);
+
+ // Release the memory
+ Free(tcp_data);
+ FreeBuf(payload);
+ Free(b);
+}
+
+// Apply the access list for packets stored
+bool ApplyAccessListToStoredPacket(HUB *hub, SESSION *s, PKT *p)
+{
+ UINT i;
+ bool pass = true; // Pass by default
+ bool use_redirect_url = false;
+ char redirect_url[MAX_REDIRECT_URL_LEN + 1];
+ // Validate arguments
+ if (hub == NULL || s == NULL || p == NULL)
+ {
+ return false;
+ }
+
+ if (hub->Option != NULL && hub->Option->FilterPPPoE)
+ {
+ if (p->MacHeader != NULL)
+ {
+ USHORT proto = Endian16(p->MacHeader->Protocol);
+ if (proto == 0x8863 || proto == 0x8864)
+ {
+ // PPPoE Filter
+ return false;
+ }
+ }
+ }
+
+ if (hub->Option != NULL && hub->Option->FilterOSPF)
+ {
+ if (p->TypeL3 == L3_IPV4)
+ {
+ if (p->L3.IPv4Header != NULL)
+ {
+ if (p->L3.IPv4Header->Protocol == 89)
+ {
+ // OSPF Filter
+ return false;
+ }
+ }
+ }
+ }
+
+ if (hub->Option != NULL && hub->Option->FilterIPv4)
+ {
+ if (p->MacHeader != NULL)
+ {
+ USHORT proto = Endian16(p->MacHeader->Protocol);
+ if (proto == 0x0800 || proto == 0x0806)
+ {
+ // IPv4 Filter
+ return false;
+ }
+ }
+ }
+
+ if (hub->Option != NULL && hub->Option->FilterIPv6)
+ {
+ if (p->MacHeader != NULL)
+ {
+ USHORT proto = Endian16(p->MacHeader->Protocol);
+ if (proto == 0x86dd)
+ {
+ // IPv6 Filter
+ return false;
+ }
+ }
+ }
+
+ if (hub->Option != NULL && hub->Option->FilterNonIP)
+ {
+ if (p->MacHeader != NULL)
+ {
+ USHORT proto = Endian16(p->MacHeader->Protocol);
+ if (!(proto == 0x86dd || proto == 0x0800 || proto == 0x0806))
+ {
+ // Non-IP Filter
+ return false;
+ }
+ }
+ }
+
+ if (hub->Option != NULL && hub->Option->FilterBPDU)
+ {
+ if (p->MacHeader != NULL)
+ {
+ if (p->TypeL3 == L3_BPDU)
+ {
+ // BPDU Filter
+ return false;
+ }
+ }
+ }
+
+ LockList(hub->AccessList);
+ {
+ for (i = 0;i < LIST_NUM(hub->AccessList);i++)
+ {
+ ACCESS *a = LIST_DATA(hub->AccessList, i);
+
+ if (a->DestUsernameHash != 0)
+ {
+ // If a destination user name is specified, suspend the scanning of the list.
+ break;
+ }
+
+ if (IsPacketMaskedByAccessList(s, p, a, 0, 0, NULL))
+ {
+ // Determine the pass or discard the packet
+ pass = a->Discard ? false : true;
+
+ // Packets determined processing here is not scanned when leaving the HUB.
+ p->AccessChecked = true;
+
+ // Copy of the parameters of the delay jitter packet loss
+ p->Delay = a->Delay;
+ p->Jitter = a->Jitter;
+ p->Loss = a->Loss;
+
+ if (a->RedirectUrl[0] != 0)
+ {
+ // There is a setting of URL redirection in the access list
+ if ((p->TypeL3 == L3_IPV4 || p->TypeL3 == L3_IPV6) &&
+ p->TypeL4 == L4_TCP)
+ {
+ TCP_HEADER *tcp = p->L4.TCPHeader;
+
+ // Examine whether this packet is a TCP data packet
+ if (tcp != NULL)
+ {
+ if (tcp->Flag & TCP_ACK)
+ {
+ if ((tcp->Flag & TCP_SYN) == 0 &&
+ (tcp->Flag & TCP_RST) == 0 &&
+ (tcp->Flag & TCP_URG) == 0)
+ {
+ if (p->PayloadSize != 0)
+ {
+ // Do URL redirection
+ use_redirect_url = true;
+ StrCpy(redirect_url, sizeof(redirect_url), a->RedirectUrl);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Complete the scanning of the list here
+ break;
+ }
+ }
+ }
+ UnlockList(hub->AccessList);
+
+ if (pass)
+ {
+ if (s != NULL && s->FirstTimeHttpRedirect && s->FirstTimeHttpAccessCheckIp != 0)
+ {
+ if ((p->TypeL3 == L3_IPV4 || p->TypeL3 == L3_IPV6) &&
+ p->TypeL4 == L4_TCP)
+ {
+ TCP_HEADER *tcp = p->L4.TCPHeader;
+
+ // Examine whether this packet is a TCP data packet
+ if (tcp != NULL)
+ {
+ if (tcp->DstPort == Endian16(80))
+ {
+ if (p->L3.IPv4Header->DstIP == s->FirstTimeHttpAccessCheckIp)
+ {
+ s->FirstTimeHttpRedirect = false;
+ }
+ else if (tcp->Flag & TCP_ACK)
+ {
+ if ((tcp->Flag & TCP_SYN) == 0 &&
+ (tcp->Flag & TCP_RST) == 0 &&
+ (tcp->Flag & TCP_URG) == 0)
+ {
+ if (p->PayloadSize != 0)
+ {
+ if (IsTcpPacketNcsiHttpAccess(p) == false)
+ {
+/* char tmp[4000];
+ Zero(tmp, sizeof(tmp));
+ Copy(tmp, p->Payload, p->PayloadSize);
+ Debug("HTTP: %s\n", tmp);*/
+ if (IsEmptyStr(s->FirstTimeHttpRedirectUrl) == false)
+ {
+ use_redirect_url = true;
+ StrCpy(redirect_url, sizeof(redirect_url), s->FirstTimeHttpRedirectUrl);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (use_redirect_url)
+ {
+ if (s->NormalClient)
+ {
+ // In the case of a normal VPN client (Not a local bridge, a SecureNAT, and not a virtual L3 switch),
+ // process URL redirection and discard the packet
+ ForceRedirectToUrl(hub, s, p, redirect_url);
+ }
+ else
+ {
+ // Discard packets that is sent from the sessions such as local bridge,
+ // SecureNAT, virtual L3 switch
+ }
+
+ pass = false;
+ }
+
+ return pass;
+}
+
+// Check whether the TCP packet is NCSI accessing
+bool IsTcpPacketNcsiHttpAccess(PKT *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return false;
+ }
+
+ if (p->TypeL4 != L4_TCP)
+ {
+ return false;
+ }
+
+ if (p->Payload == NULL || p->PayloadSize == 0)
+ {
+ return false;
+ }
+
+ if (SearchBin(p->Payload, 0, p->PayloadSize, "NCSI", 4) != INFINITE)
+ {
+ return true;
+ }
+
+ if (SearchBin(p->Payload, 0, p->PayloadSize, ".jpeg", 5) != INFINITE)
+ {
+ return true;
+ }
+
+ if (SearchBin(p->Payload, 0, p->PayloadSize, ".jpg", 4) != INFINITE)
+ {
+ return true;
+ }
+
+ if (SearchBin(p->Payload, 0, p->PayloadSize, ".gif", 4) != INFINITE)
+ {
+ return true;
+ }
+
+ if (SearchBin(p->Payload, 0, p->PayloadSize, ".css", 4) != INFINITE)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Set the URL to which to redirect first
+bool SetSessionFirstRedirectHttpUrl(SESSION *s, char *url)
+{
+ URL_DATA d;
+ IP ip;
+ // Validate arguments
+ if (s == NULL || url == NULL || IsEmptyStr(url))
+ {
+ return false;
+ }
+
+ if (ParseUrl(&d, url, false, NULL) == false)
+ {
+ return false;
+ }
+
+ if (StrToIP(&ip, d.HostName) == false)
+ {
+ return false;
+ }
+
+ if (IsIP4(&ip) == false)
+ {
+ return false;
+ }
+
+ s->FirstTimeHttpAccessCheckIp = IPToUINT(&ip);
+ StrCpy(s->FirstTimeHttpRedirectUrl, sizeof(s->FirstTimeHttpRedirectUrl), url);
+ s->FirstTimeHttpRedirect = true;
+
+ return true;
+}
+
+// Adding Access List
+void AddAccessList(HUB *hub, ACCESS *a)
+{
+ AddAccessListEx(hub, a, false, false);
+}
+void AddAccessListEx(HUB *hub, ACCESS *a, bool no_sort, bool no_reassign_id)
+{
+ // Validate arguments
+ if (hub == NULL || a == NULL)
+ {
+ return;
+ }
+
+ LockList(hub->AccessList);
+ {
+ ACCESS *access;
+ UINT i;
+
+ // Check the number of items
+ if (LIST_NUM(hub->AccessList) >= MAX_ACCESSLISTS)
+ {
+ UnlockList(hub->AccessList);
+ return;
+ }
+
+ access = Malloc(sizeof(ACCESS));
+ Copy(access, a, sizeof(ACCESS));
+
+ access->IsSrcUsernameIncludeOrExclude = false;
+ access->IsDestUsernameIncludeOrExclude = false;
+
+ // User name correction
+ if (IsEmptyStr(access->SrcUsername) == false)
+ {
+ if (StartWith(access->SrcUsername, ACCESS_LIST_INCLUDED_PREFIX) == false && StartWith(access->SrcUsername, ACCESS_LIST_EXCLUDED_PREFIX) == false)
+ {
+ MakeSimpleUsernameRemoveNtDomain(access->SrcUsername, sizeof(access->SrcUsername), access->SrcUsername);
+ }
+ else
+ {
+ access->IsSrcUsernameIncludeOrExclude = true;
+ }
+ }
+ if (IsEmptyStr(access->DestUsername) == false)
+ {
+ if (StartWith(access->DestUsername, ACCESS_LIST_INCLUDED_PREFIX) == false && StartWith(access->DestUsername, ACCESS_LIST_EXCLUDED_PREFIX) == false)
+ {
+ MakeSimpleUsernameRemoveNtDomain(access->DestUsername, sizeof(access->DestUsername), access->DestUsername);
+ }
+ else
+ {
+ access->IsDestUsernameIncludeOrExclude = true;
+ }
+ }
+
+ access->SrcUsernameHash = UsernameToInt64(access->SrcUsername);
+ access->DestUsernameHash = UsernameToInt64(access->DestUsername);
+
+ // Port number correction
+ if (access->SrcPortStart != 0)
+ {
+ access->SrcPortEnd = MAX(access->SrcPortEnd, access->SrcPortStart);
+ }
+ if (access->DestPortStart != 0)
+ {
+ access->DestPortEnd = MAX(access->DestPortEnd, access->DestPortStart);
+ }
+
+ // Correct delay, jitter, and packet loss
+ access->Delay = MAKESURE(access->Delay, 0, HUB_ACCESSLIST_DELAY_MAX);
+ access->Jitter = MAKESURE(access->Jitter, 0, HUB_ACCESSLIST_JITTER_MAX);
+ access->Loss = MAKESURE(access->Loss, 0, HUB_ACCESSLIST_LOSS_MAX);
+
+ if (no_sort == false)
+ {
+ Insert(hub->AccessList, access);
+ }
+ else
+ {
+ Add(hub->AccessList, access);
+ }
+
+ // Reassign the ID
+ if (no_reassign_id == false)
+ {
+ for (i = 0;i < LIST_NUM(hub->AccessList);i++)
+ {
+ ACCESS *a = LIST_DATA(hub->AccessList, i);
+ a->Id = (i + 1);
+ }
+ }
+ }
+ UnlockList(hub->AccessList);
+}
+
+// Initialize the access list
+void InitAccessList(HUB *hub)
+{
+ // Validate arguments
+ if (hub == NULL)
+ {
+ return;
+ }
+
+ hub->AccessList = NewList(CmpAccessList);
+}
+
+// Release the access list
+void FreeAccessList(HUB *hub)
+{
+ UINT i;
+ // Validate arguments
+ if (hub == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(hub->AccessList);i++)
+ {
+ ACCESS *a = LIST_DATA(hub->AccessList, i);
+ Free(a);
+ }
+
+ ReleaseList(hub->AccessList);
+ hub->AccessList = NULL;
+}
+
+// Comparison of the access list entry
+int CmpAccessList(void *p1, void *p2)
+{
+ ACCESS *a1, *a2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ a1 = *(ACCESS **)p1;
+ a2 = *(ACCESS **)p2;
+ if (a1 == NULL || a2 == NULL)
+ {
+ return 0;
+ }
+ // Sort by priority
+ if (a1->Priority > a2->Priority)
+ {
+ return 1;
+ }
+ else if (a1->Priority < a2->Priority)
+ {
+ return -1;
+ }
+ else if (a1->Discard > a2->Discard)
+ {
+ return 1;
+ }
+ else if (a1->Discard < a2->Discard)
+ {
+ return -1;
+ }
+ else
+ {
+ UINT64 size64 = ((UINT64)(&a1->UniqueId) - (UINT64)(&a1->Active));
+ UINT size32 = (UINT)size64;
+
+ return Cmp(&a1->Active, &a2->Active, size32);
+ }
+}
+
+// Generate a user name without domain name of the Windows NT
+void MakeSimpleUsernameRemoveNtDomain(char *dst, UINT dst_size, char *src)
+{
+ char tmp1[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ // Validate arguments
+ if (dst == NULL || src == NULL)
+ {
+ return;
+ }
+
+ ParseNtUsername(src, tmp1, sizeof(tmp1), tmp2, sizeof(tmp2), false);
+
+ StrCpy(dst, dst_size, tmp1);
+}
+
+// Convert the user name to UINT
+UINT64 UsernameToInt64(char *name)
+{
+ UCHAR hash[SHA1_SIZE];
+ UINT64 ret;
+ char tmp[MAX_USERNAME_LEN + 1];
+ // Validate arguments
+ if (name == 0 || IsEmptyStr(name))
+ {
+ return 0;
+ }
+
+ if (StartWith(name, ACCESS_LIST_INCLUDED_PREFIX) || StartWith(name, ACCESS_LIST_EXCLUDED_PREFIX))
+ {
+ return Rand64();
+ }
+
+ MakeSimpleUsernameRemoveNtDomain(tmp, sizeof(tmp), name);
+ Trim(tmp);
+ StrUpper(tmp);
+
+ if (StrLen(tmp) == 0)
+ {
+ return 0;
+ }
+
+ Hash(hash, tmp, StrLen(tmp), true);
+ Copy(&ret, hash, sizeof(ret));
+
+ return ret;
+}
+
+// Search the session from the session pointer
+SESSION *GetSessionByPtr(HUB *hub, void *ptr)
+{
+ // Validate arguments
+ if (hub == NULL || ptr == NULL)
+ {
+ return NULL;
+ }
+
+ LockList(hub->SessionList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(hub->SessionList);i++)
+ {
+ SESSION *s = LIST_DATA(hub->SessionList, i);
+ if (s == (SESSION *)ptr)
+ {
+ // Found
+ AddRef(s->ref);
+ UnlockList(hub->SessionList);
+ return s;
+ }
+ }
+ }
+ UnlockList(hub->SessionList);
+
+ return NULL;
+}
+
+// Search the session from the session name
+SESSION *GetSessionByName(HUB *hub, char *name)
+{
+ // Validate arguments
+ if (hub == NULL || name == NULL)
+ {
+ return NULL;
+ }
+
+ LockList(hub->SessionList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(hub->SessionList);i++)
+ {
+ SESSION *s = LIST_DATA(hub->SessionList, i);
+ if (StrCmpi(s->Name, name) == 0)
+ {
+ // Found
+ AddRef(s->ref);
+ UnlockList(hub->SessionList);
+ return s;
+ }
+ }
+ }
+ UnlockList(hub->SessionList);
+
+ return NULL;
+}
+
+// Sort of the STORM list
+int CompareStormList(void *p1, void *p2)
+{
+ STORM *s1, *s2;
+ UINT r;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ s1 = *(STORM **)p1;
+ s2 = *(STORM **)p2;
+ if (s1 == NULL || s2 == NULL)
+ {
+ return 0;
+ }
+ if (s1->StrictMode == false && s2->StrictMode == false)
+ {
+ // Normal mode
+ r = CmpIpAddr(&s1->DestIp, &s2->DestIp);
+ if (r != 0)
+ {
+ return r;
+ }
+ r = CmpIpAddr(&s1->SrcIp, &s2->SrcIp);
+ if (r != 0)
+ {
+ return r;
+ }
+ }
+ else
+ {
+ // Strict mode
+ int r1, r2;
+ r1 = CmpIpAddr(&s1->DestIp, &s2->DestIp);
+ r2 = CmpIpAddr(&s1->SrcIp, &s2->SrcIp);
+ if (r1 == 0 || r2 == 0)
+ {
+ // Either the source IP, and destination IP match
+ }
+ else
+ {
+ // Mismatch
+ if (r1 != 0)
+ {
+ return r1;
+ }
+
+ if (r2 != 0)
+ {
+ return r2;
+ }
+ }
+ }
+ r = Cmp(s1->MacAddress, s2->MacAddress, 6);
+ return r;
+}
+
+// Packet adapter initialization
+bool HubPaInit(SESSION *s)
+{
+ // Initialize the packet adapter information
+ HUB_PA *pa = ZeroMalloc(sizeof(HUB_PA));
+ pa->Cancel = NewCancel();
+ pa->PacketQueue = NewQueue();
+ pa->Now = Tick64();
+ pa->Session = s;
+ pa->StormList = NewList(CompareStormList);
+ pa->UsernameHash = UsernameToInt64(s->Username);
+ pa->GroupnameHash = UsernameToInt64(s->GroupName);
+
+ s->PacketAdapter->Param = pa;
+
+ if (s->Policy->MonitorPort)
+ {
+ // Mark this port as monitoring port
+ pa->MonitorPort = true;
+
+ // Add this session to the list of monitoring port of the HUB
+ LockList(s->Hub->MonitorList);
+ {
+ Insert(s->Hub->MonitorList, s);
+ }
+ UnlockList(s->Hub->MonitorList);
+ }
+
+ return true;
+}
+
+// Release the Packet adapter
+void HubPaFree(SESSION *s)
+{
+ HUB_PA *pa = (HUB_PA *)s->PacketAdapter->Param;
+ HUB *hub = s->Hub;
+
+ if (pa->MonitorPort)
+ {
+ // Remove the session from the list of monitor port of the HUB
+ LockList(s->Hub->MonitorList);
+ {
+ Delete(s->Hub->MonitorList, s);
+ }
+ UnlockList(s->Hub->MonitorList);
+ }
+
+ // Erase MAC address table entries that is associated with this session
+ LockList(hub->MacTable);
+ {
+ UINT i, num = LIST_NUM(hub->MacTable);
+ LIST *o = NewListFast(NULL);
+ for (i = 0;i < num;i++)
+ {
+ MAC_TABLE_ENTRY *e = (MAC_TABLE_ENTRY *)LIST_DATA(hub->MacTable, i);
+ if (e->Session == s)
+ {
+ Add(o, e);
+ }
+ }
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ MAC_TABLE_ENTRY *e = (MAC_TABLE_ENTRY *)LIST_DATA(o, i);
+ Delete(hub->MacTable, e);
+ Free(e);
+ }
+ ReleaseList(o);
+ }
+ {
+ UINT i, num = LIST_NUM(hub->IpTable);
+ LIST *o = NewListFast(NULL);
+ for (i = 0;i < num;i++)
+ {
+ IP_TABLE_ENTRY *e = LIST_DATA(hub->IpTable, i);
+ if (e->Session == s)
+ {
+ Add(o, e);
+ }
+ }
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IP_TABLE_ENTRY *e = LIST_DATA(o, i);
+ Delete(hub->IpTable, e);
+ Free(e);
+ }
+ ReleaseList(o);
+ }
+ UnlockList(hub->MacTable);
+
+ // Release the STORM list
+ LockList(pa->StormList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(pa->StormList);i++)
+ {
+ STORM *s = (STORM *)LIST_DATA(pa->StormList, i);
+ Free(s);
+ }
+ DeleteAll(pa->StormList);
+ }
+ UnlockList(pa->StormList);
+
+ ReleaseList(pa->StormList);
+
+ // Release the packets remaining in the queue
+ LockQueue(pa->PacketQueue);
+ {
+ BLOCK *b;
+
+ while (b = GetNext(pa->PacketQueue))
+ {
+ // Release the block
+ FreeBlock(b);
+ }
+ }
+ UnlockQueue(pa->PacketQueue);
+
+ // Release the queue
+ ReleaseQueue(pa->PacketQueue);
+
+ // Release the cancel object
+ ReleaseCancel(pa->Cancel);
+
+ // Release the packet adapter information
+ Free(pa);
+ s->PacketAdapter->Param = NULL;
+}
+
+// Get the cancel object
+CANCEL *HubPaGetCancel(SESSION *s)
+{
+ HUB_PA *pa = (HUB_PA *)s->PacketAdapter->Param;
+
+ AddRef(pa->Cancel->ref);
+ return pa->Cancel;
+}
+
+// Get the packet to be transmitted next
+UINT HubPaGetNextPacket(SESSION *s, void **data)
+{
+ UINT ret = 0;
+ HUB_PA *pa = (HUB_PA *)s->PacketAdapter->Param;
+
+ // Get one from the head of the queue
+ LockQueue(pa->PacketQueue);
+ {
+ BLOCK *block = GetNext(pa->PacketQueue);
+ if (block == NULL)
+ {
+ // No queue
+ ret = 0;
+ }
+ else
+ {
+ // Found
+ *data = block->Buf;
+ ret = block->Size;
+ // Release the memory of the structure of the block
+ Free(block);
+ }
+ }
+ UnlockQueue(pa->PacketQueue);
+
+ return ret;
+}
+
+// Receive a packet
+bool HubPaPutPacket(SESSION *s, void *data, UINT size)
+{
+ PKT *packet;
+ HUB_PA *pa = (HUB_PA *)s->PacketAdapter->Param;
+ bool b = false;
+ HUB *hub;
+ bool no_l3 = false;
+ bool no_http = false;
+ LIST *o = NULL;
+ UINT i;
+ UINT vlan_type_id = 0;
+ bool no_look_bpdu_bridge_id = false;
+ bool no_parse_dhcp = false;
+ bool no_correct_checksum = false;
+
+ hub = s->Hub;
+
+ pa->Now = Tick64();
+
+ // Processing of Adjust TCP MSS
+ if (hub->Option != NULL && hub->Option->DisableAdjustTcpMss == false && s != NULL)
+ {
+ UINT target_mss = (hub->Option->AdjustTcpMssValue == 0 ? INFINITE : hub->Option->AdjustTcpMssValue);
+ UINT session_mss = (s->AdjustMss == 0 ? INFINITE : s->AdjustMss);
+
+ target_mss = MIN(target_mss, session_mss);
+
+ if (s->IsUsingUdpAcceleration && s->UdpAccelMss != 0)
+ {
+ // If the link is established with UDP acceleration function, use optimum value of the UDP acceleration function
+ target_mss = MIN(target_mss, s->UdpAccelMss);
+ }
+ else if (s->IsRUDPSession && s->RUdpMss != 0)
+ {
+ // If the link with UDP acceleration is not established, use the optimum value for R-UDP in the case of using R-UDP connection
+ target_mss = MIN(target_mss, s->RUdpMss);
+ }
+
+ if (target_mss != INFINITE)
+ {
+ AdjustTcpMssL2(data, size, target_mss, hub->Option->VlanTypeId);
+ }
+ }
+
+ if (data == NULL)
+ {
+ // Check the delayed packet
+ o = NULL;
+ LockList(s->DelayedPacketList);
+ {
+ UINT i;
+ if (LIST_NUM(s->DelayedPacketList) >= 1)
+ {
+ UINT64 now = TickHighres64();
+ for (i = 0;i < LIST_NUM(s->DelayedPacketList);i++)
+ {
+ PKT *p = LIST_DATA(s->DelayedPacketList, i);
+
+ if (now >= p->DelayedForwardTick)
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Add(o, p);
+ }
+ }
+ }
+
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ PKT *p = LIST_DATA(o, i);
+
+ Delete(s->DelayedPacketList, p);
+ }
+ }
+ }
+ UnlockList(s->DelayedPacketList);
+
+ // If there is a delayed packet, store it
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ PKT *p = LIST_DATA(o, i);
+
+ StorePacket(s->Hub, s, p);
+ }
+
+ ReleaseList(o);
+ }
+
+ // Reception of all packets from this session is complete
+ CancelList(s->CancelList);
+
+ // Yield
+ if (hub->Option != NULL && hub->Option->YieldAfterStorePacket)
+ {
+ YieldCpu();
+ }
+
+ return true;
+ }
+
+ if (hub != NULL && hub->Option != NULL)
+ {
+ no_l3 = hub->Option->DisableIPParsing;
+ no_http = hub->Option->DisableHttpParsing;
+ vlan_type_id = hub->Option->VlanTypeId;
+ no_look_bpdu_bridge_id = hub->Option->NoLookBPDUBridgeId;
+ no_correct_checksum = hub->Option->DisableCorrectIpOffloadChecksum;
+ }
+
+ // Insert a VLAN tag
+ if (s->VLanId != 0)
+ {
+ VLanInsertTag(&data, &size, s->VLanId, vlan_type_id);
+ }
+
+LABEL_TRY_AGAIN:
+ // Parse the packet
+ packet = ParsePacketEx4(data, size, no_l3, vlan_type_id, !no_look_bpdu_bridge_id, no_http, !no_correct_checksum);
+
+ if (packet != NULL)
+ {
+ if (packet->InvalidSourcePacket)
+ {
+ // Packet which have illegal source
+ FreePacket(packet);
+ packet = NULL;
+ }
+ }
+
+
+ if (packet != NULL)
+ {
+ if (packet->TypeL7 == L7_DHCPV4)
+ {
+ if (packet->TypeL3 == L3_IPV4 && packet->TypeL4 == L4_UDP)
+ {
+ if (packet->L7.DHCPv4Header != NULL)
+ {
+ DHCPV4_HEADER *dhcp = packet->L7.DHCPv4Header;
+
+ if (dhcp->OpCode == 1)
+ {
+ if (NsIsMacAddressOnLocalhost(dhcp->ClientMacAddress))
+ {
+ // Filter DHCP requests sent from local kernel-mode virtual NAT
+ // not to re-enter it to the virtual HUB along the local bridge
+ FreePacket(packet);
+ packet = NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (no_parse_dhcp == false && packet != NULL)
+ {
+ if (hub->Option != NULL && hub->Option->RemoveDefGwOnDhcpForLocalhost)
+ {
+ // Remove the designation of the DHCP server from the DHCP response packet addressed to localhost
+ if (packet->TypeL7 == L7_DHCPV4)
+ {
+ if (packet->TypeL3 == L3_IPV4)
+ {
+ if (packet->TypeL4 == L4_UDP)
+ {
+ if (packet->L7.DHCPv4Header != NULL)
+ {
+ DHCPV4_HEADER *dhcp = packet->L7.DHCPv4Header;
+
+ if (dhcp->OpCode == 2)
+ {
+ if (IsMacAddressLocalFast(dhcp->ClientMacAddress))
+ {
+ BUF *new_buf;
+ DHCP_MODIFY_OPTION m;
+ WHERE;
+
+ Zero(&m, sizeof(m));
+ m.RemoveDefaultGatewayOnReply = true;
+
+ new_buf = DhcpModifyIPv4(&m, data, size);
+
+ if (new_buf != NULL)
+ {
+ Free(data);
+
+ data = new_buf->Buf;
+ size = new_buf->Size;
+
+ Free(new_buf);
+
+ no_parse_dhcp = true;
+
+ FreePacket(packet);
+
+ goto LABEL_TRY_AGAIN;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (packet != NULL)
+ {
+ // Store packet
+ StorePacket(s->Hub, s, packet);
+ }
+ else
+ {
+ // Release the packet data because it is a bad packet (not a correct MAC frame)
+ Free(data);
+ }
+
+ return true;
+}
+
+// VGS: Setting for embedding UA tag
+void VgsSetEmbTag(bool b)
+{
+ g_vgs_emb_tag = b;
+}
+
+// VGS: Setting for the User-Agent value
+void VgsSetUserAgentValue(char *str)
+{
+ // Validate arguments
+ if (str == NULL || StrLen(str) != 8)
+ {
+ Zero(vgs_ua_str, sizeof(vgs_ua_str));
+ }
+ else
+ {
+ StrCpy(vgs_ua_str, sizeof(vgs_ua_str), str);
+ }
+}
+
+// Checking algorithm to prevent broadcast-storm
+// If broadcast from a specific endpoint came frequently, filter it
+bool CheckBroadcastStorm(HUB *hub, SESSION *s, PKT *p)
+{
+ IP src_ip, dest_ip;
+ HUB_PA *pa;
+ UINT64 now = Tick64();
+ UINT limit_start_count;
+ SESSION *sess = s;
+ bool ret = true;
+ bool strict = false;
+ bool no_heavy = false;
+ // Validate arguments
+ if (s == NULL || p == NULL || hub == NULL)
+ {
+ return false;
+ }
+
+ if (s->Policy->NoBroadcastLimiter)
+ {
+ // Unlimited the number of broadcasts
+ return true;
+ }
+
+ if (hub != NULL && hub->Option != NULL)
+ {
+ strict = hub->Option->BroadcastLimiterStrictMode;
+ no_heavy = hub->Option->DoNotSaveHeavySecurityLogs;
+ }
+
+ pa = (HUB_PA *)s->PacketAdapter->Param;
+
+ Zero(&src_ip, sizeof(IP));
+ Zero(&dest_ip, sizeof(IP));
+
+ if (p->TypeL3 == L3_IPV4)
+ {
+ UINTToIP(&src_ip, p->L3.IPv4Header->SrcIP);
+ UINTToIP(&dest_ip, p->L3.IPv4Header->DstIP);
+ }
+ else if (p->TypeL3 == L3_ARPV4)
+ {
+ UINTToIP(&src_ip, p->L3.ARPv4Header->SrcIP);
+ Zero(&dest_ip, sizeof(IP));
+ }
+ else if (p->TypeL3 == L3_IPV6)
+ {
+ IPv6AddrToIP(&src_ip, &p->L3.IPv6Header->SrcAddress);
+ IPv6AddrToIP(&dest_ip, &p->L3.IPv6Header->DestAddress);
+ }
+
+ // Number of broadcast to start limitation for a single interval
+ limit_start_count = 32;
+
+ if (s->Hub != NULL && s->Hub->Option->BroadcastStormDetectionThreshold != 0)
+ {
+ limit_start_count = s->Hub->Option->BroadcastStormDetectionThreshold;
+ }
+
+ LockList(pa->StormList);
+ {
+ STORM *s;
+ UINT num;
+ s = SearchStormList(pa, p->MacAddressSrc, &src_ip, &dest_ip, strict);
+ if (s == NULL)
+ {
+ s = AddStormList(pa, p->MacAddressSrc, &src_ip, &dest_ip, strict);
+ }
+
+ s->CurrentBroadcastNum++;
+
+ if ((s->CheckStartTick + STORM_CHECK_SPAN) < now ||
+ s->CheckStartTick == 0 || s->CheckStartTick > now)
+ {
+ // Measure the number of broadcast periodically
+ UINT64 diff_time;
+ if (s->CheckStartTick < now)
+ {
+ diff_time = now - s->CheckStartTick;
+ }
+ else
+ {
+ diff_time = 0;
+ }
+ s->CheckStartTick = now;
+ num = (UINT)((UINT64)s->CurrentBroadcastNum * (UINT64)1000 / (UINT64)STORM_CHECK_SPAN);
+ s->CurrentBroadcastNum = 0;
+ if (num >= limit_start_count)
+ {
+ char ip1[64];
+ char ip2[64];
+ char mac[MAX_SIZE];
+ IPToStr(ip1, sizeof(ip1), &src_ip);
+ IPToStr(ip2, sizeof(ip2), &dest_ip);
+ ret = false;
+ if (s->DiscardValue < STORM_DISCARD_VALUE_END)
+ {
+ s->DiscardValue = MAX(s->DiscardValue, 1) * 2;
+ }
+ Debug("s->DiscardValue: %u (%u)\n", s->DiscardValue, num);
+
+ MacToStr(mac, sizeof(mac), p->MacAddressSrc);
+
+ if (no_heavy == false)
+ {
+ HLog(sess->Hub, "LH_BCAST_STORM", sess->Name, mac, ip1, ip2, num);
+ }
+ }
+ else
+ {
+ if (s->DiscardValue >= 1)
+ {
+ s->DiscardValue = (UINT)((UINT64)s->DiscardValue / MAX((UINT64)2, (UINT64)diff_time / (UINT64)STORM_CHECK_SPAN));
+ }
+ }
+ }
+
+ if (s->DiscardValue >= STORM_DISCARD_VALUE_START)
+ {
+ if (s->DiscardValue >= 128)
+ {
+ ret = false;
+ }
+ else if ((rand() % s->DiscardValue) != 0)
+ {
+ ret = false;
+ }
+ }
+
+ }
+ UnlockList(pa->StormList);
+
+ return ret;
+}
+
+// Store packet
+void StorePacket(HUB *hub, SESSION *s, PKT *packet)
+{
+ MAC_TABLE_ENTRY *entry = NULL;
+ MAC_TABLE_ENTRY t;
+ void *data;
+ UINT size;
+ bool broadcast_mode;
+ HUB_PA *dest_pa;
+ SESSION *dest_session;
+ TRAFFIC traffic;
+ UINT64 now = Tick64();
+ bool no_heavy = false;
+ // Validate arguments
+ if (hub == NULL || packet == NULL)
+ {
+ return;
+ }
+
+ if (s != NULL)
+ {
+ if (((HUB_PA *)s->PacketAdapter->Param)->MonitorPort)
+ {
+ // Not to forward packets received from the monitor port
+ Free(packet->PacketData);
+ FreePacket(packet);
+ return;
+ }
+ }
+
+ if (hub->Option != NULL)
+ {
+ no_heavy = hub->Option->DoNotSaveHeavySecurityLogs;
+ }
+
+ // Lock the entire MAC address table
+ LockList(hub->MacTable);
+ {
+ // Filtering
+ if (s != NULL && (packet->DelayedForwardTick == 0 && StorePacketFilter(s, packet) == false))
+ {
+DISCARD_PACKET:
+ // Release a packet since passing has been disallowed
+ Free(packet->PacketData);
+ FreePacket(packet);
+ }
+ else // Passing is allowed
+ {
+ bool forward_now = true;
+
+ if (packet->Loss >= 1)
+ {
+ // Cause packet loss
+ UINT r = rand() % 100;
+ if ((packet->Loss >= 100) || (r < packet->Loss))
+ {
+ // Packet loss
+ goto DISCARD_PACKET;
+ }
+ }
+
+ if (packet->Delay >= 1)
+ {
+ float delay = (float)packet->Delay;
+ float jitter;
+ UINT delay_uint;
+ bool f = Rand1();
+ if (packet->Jitter == 0)
+ {
+ jitter = 0;
+ }
+ else
+ {
+ jitter = (float)(Rand32() % (int)((float)packet->Jitter * delay / 100.0f));
+ }
+
+ delay += jitter * (f ? 1 : -1);
+ delay_uint = (UINT)delay;
+
+ if (delay_uint >= 1)
+ {
+ // Cause delay
+ forward_now = false;
+ packet->Loss = packet->Jitter = packet->Delay = 0;
+ packet->DelayedForwardTick = TickHighres64() + (UINT64)delay_uint;
+ packet->DelayedSrcSession = s;
+
+ LockList(s->DelayedPacketList);
+ {
+ Add(s->DelayedPacketList, packet);
+ }
+ UnlockList(s->DelayedPacketList);
+ }
+ }
+
+ if (forward_now)
+ {
+ if (Cmp(packet->MacAddressSrc, hub->HubMacAddr, 6) == 0)
+ {
+ if (s != NULL)
+ {
+ // Packets that this HUB itself sent is input from the outside
+ goto DISCARD_PACKET;
+ }
+ }
+ if (s != NULL && (Cmp(packet->MacAddressSrc, hub->HubMacAddr, 6) != 0))
+ {
+ // Check whether the source MAC address is registered in the table
+ Copy(t.MacAddress, packet->MacAddressSrc, 6);
+ if (hub->Option->NoManageVlanId == false)
+ {
+ t.VlanId = packet->VlanId;
+ }
+ else
+ {
+ t.VlanId = 0;
+ }
+ entry = Search(hub->MacTable, &t);
+
+ if (entry == NULL)
+ {
+ // Remove old entries
+ DeleteExpiredMacTableEntry(hub->MacTable);
+
+ // Register since it is not registered
+ if ((s->Policy->MaxMac != 0 || s->Policy->NoBridge) && (s->IsOpenVPNL3Session == false))
+ {
+ UINT i, num_mac_for_me = 0;
+ UINT limited_count;
+
+ // Examine a number of MAC addresses that are registered in this current session
+ for (i = 0;i < LIST_NUM(hub->MacTable);i++)
+ {
+ MAC_TABLE_ENTRY *e = LIST_DATA(hub->MacTable, i);
+ if (e->Session == s)
+ {
+ num_mac_for_me++;
+ }
+ }
+
+ limited_count = 0xffffffff;
+ if (s->Policy->NoBridge)
+ {
+ limited_count = MIN(limited_count, MAC_MIN_LIMIT_COUNT);
+ }
+ if (s->Policy->MaxMac != 0)
+ {
+ limited_count = MIN(limited_count, s->Policy->MaxMac);
+ }
+ limited_count = MAX(limited_count, MAC_MIN_LIMIT_COUNT);
+
+ if (num_mac_for_me >= limited_count)
+ {
+ // Number of MAC addresses that are registered already exceeds the upper limit
+ char mac_str[64];
+
+ if (s != NULL)
+ {
+ MacToStr(mac_str, sizeof(mac_str), packet->MacAddressSrc);
+ if (s->Policy->NoBridge)
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_BRIDGE_LIMIT", s->Name, mac_str, num_mac_for_me, limited_count);
+ }
+ }
+ else
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_MAC_LIMIT", s->Name, mac_str, num_mac_for_me, limited_count);
+ }
+ }
+ }
+
+ goto DISCARD_PACKET; // Drop the packet
+ }
+ }
+
+ if (LIST_NUM(hub->MacTable) >= MAX_MAC_TABLES)
+ {
+ // Delete the oldest entry because the MAC table database is
+ // exceeded the maximum number of entries
+ UINT i;
+ UINT64 old_time = 0xffffffffffffffffULL;
+ MAC_TABLE_ENTRY *old_entry = NULL;
+ for (i = 0;i < LIST_NUM(hub->MacTable);i++)
+ {
+ MAC_TABLE_ENTRY *e = LIST_DATA(hub->MacTable, i);
+ if (e->UpdatedTime <= old_time)
+ {
+ old_time = e->UpdatedTime;
+ old_entry = e;
+ }
+ }
+ if (old_entry != NULL)
+ {
+ Delete(hub->MacTable, old_entry);
+ Free(old_entry);
+ }
+ }
+
+ entry = ZeroMalloc(sizeof(MAC_TABLE_ENTRY));
+ entry->HubPa = (HUB_PA *)s->PacketAdapter->Param;
+ Copy(entry->MacAddress, packet->MacAddressSrc, 6);
+ if (hub->Option->NoManageVlanId == false)
+ {
+ entry->VlanId = packet->VlanId;
+ }
+ else
+ {
+ entry->VlanId = 0;
+ }
+ entry->Session = s;
+ entry->UpdatedTime = entry->CreatedTime = now;
+
+ Insert(hub->MacTable, entry);
+
+ if (hub->Option->NoMacAddressLog == false)
+ {
+ // Debug display
+ char mac_address[32];
+
+ if (s != NULL)
+ {
+ MacToStr(mac_address, sizeof(mac_address), packet->MacAddressSrc);
+// Debug("Register MAC Address %s to Session %X.\n", mac_address, s);
+
+ if (packet->VlanId == 0)
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_MAC_REGIST", s->Name, mac_address);
+ }
+ }
+ else
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_MAC_REGIST_VLAN", s->Name, mac_address, packet->VlanId);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (entry->Session == s)
+ {
+ // Do not do anything because it is already registered
+ entry->UpdatedTime = now;
+ }
+ else
+ {
+ // Read the value of the policy CheckMac
+ bool check_mac = s->Policy->CheckMac;
+
+ if (check_mac == false)
+ {
+ if (s->BridgeMode)
+ {
+ // Enable the CheckMac policy for the local bridge session forcibly
+ check_mac = true;
+
+ if (hub->Option != NULL && hub->Option->DisableCheckMacOnLocalBridge)
+ {
+ // Disable if DisableCheckMacOnLocalBridge option is set
+ check_mac = false;
+ }
+ }
+ }
+
+ // It's already registered and it's in another session
+ if (check_mac && (Cmp(packet->MacAddressSrc, hub->HubMacAddr, 6) != 0) &&
+ ((entry->UpdatedTime + MAC_TABLE_EXCLUSIVE_TIME) >= now))
+ {
+ UCHAR *mac = packet->MacAddressSrc;
+ if (hub->Option != NULL && hub->Option->FixForDLinkBPDU &&
+ (mac[0] == 0x00 && mac[1] == 0x80 && mac[2] == 0xc8 && mac[3] == 0x00 && mac[4] == 0x00 && mac[5] == 0x00) ||
+ (mac[0] == 0x00 && mac[1] == 0x0d && mac[2] == 0x88 && mac[3] == 0x00 && mac[4] == 0x00 && mac[5] == 0x00))
+ {
+ // Measures for D-Link. Spanning tree packet of D-Link is sent from the above address.
+ //CheckMac options for the local bridge may cause an adverse effect. So process this exceptionally.
+ UCHAR hash[MD5_SIZE];
+ UINT64 tick_diff = Tick64() - s->LastDLinkSTPPacketSendTick;
+
+ Hash(hash, packet->PacketData, packet->PacketSize, false);
+
+ if ((s->LastDLinkSTPPacketSendTick != 0) &&
+ (tick_diff < 750ULL) &&
+ (Cmp(hash, s->LastDLinkSTPPacketDataHash, MD5_SIZE) == 0))
+ {
+ // Discard if the same packet sent before 750ms ago
+ Debug("D-Link Discard %u\n", (UINT)tick_diff);
+ goto DISCARD_PACKET; // Drop the packet
+ }
+ else
+ {
+ goto UPDATE_FDB;
+ }
+ }
+ else
+ {
+ if (0)
+ {
+ // If the CheckMac policy-enabled, owning same
+ // MAC address by other sessions are prohibited
+ // (If the second byte is 0xAE, don't perform this check)
+ char mac_address[32];
+ BinToStr(mac_address, sizeof(mac_address), packet->MacAddressSrc, 6);
+ }
+ }
+
+ goto DISCARD_PACKET; // Drop the packet
+ }
+ else
+ {
+ // Rewrite the session of MAC address table and the HUB_PA
+ char mac_address[32];
+UPDATE_FDB:
+ BinToStr(mac_address, sizeof(mac_address), packet->MacAddressSrc, 6);
+
+ entry->Session = s;
+ entry->HubPa = (HUB_PA *)s->PacketAdapter->Param;
+ entry->UpdatedTime = entry->CreatedTime = now;
+
+ if (1)
+ {
+ // Debug display
+ char mac_address[32];
+
+ if (s != NULL)
+ {
+ MacToStr(mac_address, sizeof(mac_address), packet->MacHeader->SrcAddress);
+ Debug("Register MAC Address %s to Session %X.\n", mac_address, s);
+ if (packet->VlanId == 0)
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_MAC_REGIST", s->Name, mac_address);
+ }
+ }
+ else
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_MAC_REGIST_VLAN", s->Name, mac_address, packet->VlanId);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ broadcast_mode = false;
+ dest_pa = NULL;
+ dest_session = NULL;
+
+ if (packet->BroadcastPacket)
+ {
+ // Broadcast packet
+ broadcast_mode = true;
+ }
+ else
+ {
+ // Examine whether the destination MAC address is registered in the table
+ Copy(t.MacAddress, packet->MacAddressDest, 6);
+ if (hub->Option->NoManageVlanId == false)
+ {
+ t.VlanId = packet->VlanId;
+ }
+ else
+ {
+ t.VlanId = 0;
+ }
+ entry = Search(hub->MacTable, &t);
+
+ if (entry == NULL)
+ {
+ // Broadcast because the destination isn't found
+ broadcast_mode = true;
+ }
+ else
+ {
+ if (entry->Session != s)
+ {
+ // Destination is found
+ dest_pa = entry->HubPa;
+ dest_session = entry->Session;
+ }
+ else
+ {
+ // Bad packet whose destination is its own
+ goto DISCARD_PACKET;
+ }
+ }
+ }
+
+ if (s != NULL && hub->Option->NoIpTable == false)
+ {
+ if (packet->TypeL3 == L3_IPV6)
+ {
+ // IPv6 packet
+ IP ip;
+ bool b = true;
+ UINT ip_type;
+ bool dhcp_or_ra = false;
+
+ IPv6AddrToIP(&ip, &packet->L3.IPv6Header->SrcAddress);
+ ip_type = GetIPv6AddrType(&packet->L3.IPv6Header->SrcAddress);
+
+ if (!(ip_type & IPV6_ADDR_UNICAST))
+ {
+ // Multicast address
+ b = false;
+ }
+ else if ((ip_type & IPV6_ADDR_LOOPBACK) || (ip_type & IPV6_ADDR_ZERO))
+ {
+ // Loop-back address or all-zero address
+ b = false;
+ }
+
+ if (packet->TypeL4 == L4_ICMPV6)
+ {
+ if (packet->ICMPv6HeaderPacketInfo.Type == 133 ||
+ packet->ICMPv6HeaderPacketInfo.Type == 134)
+ {
+ // ICMPv6 RS/RA
+ dhcp_or_ra = true;
+ }
+ }
+ else if (packet->TypeL4 == L4_UDP)
+ {
+ if (Endian16(packet->L4.UDPHeader->DstPort) == 546 ||
+ Endian16(packet->L4.UDPHeader->DstPort) == 547)
+ {
+ // DHCPv6
+ dhcp_or_ra = true;
+ }
+ }
+
+ if (IsHubMacAddress(packet->MacAddressSrc) &&
+ IsHubIpAddress64(&packet->L3.IPv6Header->SrcAddress))
+ {
+ // The source address of the Virtual HUB for polling
+ b = false;
+ }
+
+ if (b)
+ {
+ // Other than ICMPv6 RS/RA nor DHCPv6 packet
+ IP_TABLE_ENTRY t, *e;
+
+ Copy(&t.Ip, &ip, sizeof(IP));
+
+ // Check whether it is registered to an existing table
+ e = Search(hub->IpTable, &t);
+
+ if (e == NULL)
+ {
+ // Register since it is not registered
+ if (s->Policy->NoRoutingV6 || s->Policy->MaxIPv6 != 0)
+ {
+ UINT i, num_ip_for_me = 0;
+ UINT limited_count = 0xffffffff;
+
+ for (i = 0;i < LIST_NUM(hub->IpTable);i++)
+ {
+ IP_TABLE_ENTRY *e = LIST_DATA(hub->IpTable, i);
+
+ if (e->Session == s)
+ {
+ if (IsIP6(&e->Ip))
+ {
+ num_ip_for_me++;
+ }
+ }
+ }
+
+ if (s->Policy->NoRoutingV6)
+ {
+ limited_count = MIN(limited_count, IP_LIMIT_WHEN_NO_ROUTING_V6);
+ }
+ if (s->Policy->MaxIPv6 != 0)
+ {
+ limited_count = MIN(limited_count, s->Policy->MaxIPv6);
+ }
+ limited_count = MAX(limited_count, IP_MIN_LIMIT_COUNT_V6);
+
+ if (dhcp_or_ra)
+ {
+ limited_count = 0xffffffff;
+ }
+
+ if (num_ip_for_me >= limited_count)
+ {
+ // Discard the packet because it exceeded the
+ // upper limit of the IP address that can be used
+ char tmp[64];
+ IPToStr(tmp, sizeof(tmp), &ip);
+ if (s->Policy->NoRoutingV6 == false)
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_IP_LIMIT", s->Name, tmp, num_ip_for_me, limited_count);
+ }
+ }
+ else
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_ROUTING_LIMIT", s->Name, tmp, num_ip_for_me, limited_count);
+ }
+ }
+ goto DISCARD_PACKET;
+ }
+ }
+
+ if (IsIPManagementTargetForHUB(&ip, hub))
+ {
+ // Create a entry
+ e = ZeroMalloc(sizeof(IP_TABLE_ENTRY));
+ e->CreatedTime = e->UpdatedTime = now;
+ e->DhcpAllocated = false;
+ Copy(&e->Ip, &ip, sizeof(IP));
+ Copy(e->MacAddress, packet->MacAddressSrc, 6);
+ e->Session = s;
+
+ DeleteExpiredIpTableEntry(hub->IpTable);
+
+ if (LIST_NUM(hub->IpTable) >= MAX_IP_TABLES)
+ {
+ // Delete old IP table entries
+ DeleteOldIpTableEntry(hub->IpTable);
+ }
+
+ Insert(hub->IpTable, e);
+
+ if (0)
+ {
+ char ip_address[64];
+ IPToStr(ip_address, sizeof(ip_address), &ip);
+ Debug("Registered IP Address %s to Session %X.\n",
+ ip_address, s);
+ }
+ }
+ }
+ else
+ {
+ if (e->Session == s)
+ {
+ // Do not do anything because it is self session
+ // Renew updated time
+ e->UpdatedTime = now;
+ Copy(e->MacAddress, packet->MacAddressSrc, 6);
+ }
+ else
+ {
+ // Another session was using this IP address before
+ if ((s->Policy->CheckIPv6) &&
+ ((e->UpdatedTime + IP_TABLE_EXCLUSIVE_TIME) >= now))
+ {
+ // Discard the packet because another session uses this IP address
+ char ip_address[32];
+ char mac_str[48];
+ IPToStr(ip_address, sizeof(ip_address), &ip);
+
+ Debug("IP Address %s is Already used by Session %X.\n",
+ ip_address, s);
+
+ MacToStr(mac_str, sizeof(mac_str), e->MacAddress);
+
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_IP_CONFLICT", s->Name, ip_address, e->Session->Name, mac_str,
+ e->CreatedTime, e->UpdatedTime, e->DhcpAllocated, now);
+ }
+
+ goto DISCARD_PACKET;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (
+ (s != NULL) &&
+ (hub->Option->NoIpTable == false) &&
+ (
+ (packet->TypeL3 == L3_IPV4 ||
+ (packet->TypeL3 == L3_ARPV4 && packet->L3.ARPv4Header->HardwareSize == 6 &&
+ Endian16(packet->L3.ARPv4Header->HardwareType) == ARP_HARDWARE_TYPE_ETHERNET &&
+ packet->L3.ARPv4Header->ProtocolSize == 4 &&
+ Endian16(packet->L3.ARPv4Header->ProtocolType) == 0x0800)
+ ) &&
+ (packet->TypeL7 != L7_DHCPV4)
+ )
+ ) // Other than DHCP packets
+ {
+ // In the case of the ARP response packet or the IP packet, search in the IP address table
+ IP_TABLE_ENTRY t, *e;
+ IP ip;
+ UINT uint_ip = 0;
+
+ if (packet->TypeL3 == L3_IPV4)
+ {
+ uint_ip = packet->L3.IPv4Header->SrcIP;
+ }
+ else if (packet->TypeL3 == L3_ARPV4)
+ {
+ uint_ip = packet->L3.ARPv4Header->SrcIP;
+ }
+
+ if (uint_ip != 0 && uint_ip != 0xffffffff && !(IsHubIpAddress32(uint_ip) && IsHubMacAddress(packet->MacAddressSrc)))
+ {
+ UINTToIP(&ip, uint_ip);
+ Copy(&t.Ip, &ip, sizeof(IP));
+
+ // Check whether it is registered to an existing table
+ e = Search(hub->IpTable, &t);
+
+ if (e == NULL)
+ {
+ // Register since it is not registered
+ if (s->Policy->DHCPForce)
+ {
+ char ipstr[MAX_SIZE];
+
+ // Discard the packet because this IP address isn't
+ // assigned by the DHCP server
+ IPToStr32(ipstr, sizeof(ipstr), uint_ip);
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_DHCP_FORCE", s->Name, ipstr);
+ }
+ goto DISCARD_PACKET;
+ }
+
+ // if (packet->TypeL3 == L3_ARPV4)
+ {
+ // Examine the number that are registered in this session already
+ if (s->Policy->NoRouting || s->Policy->MaxIP != 0)
+ {
+ UINT i, num_ip_for_me = 0;
+ UINT limited_count = 0xffffffff;
+
+ for (i = 0;i < LIST_NUM(hub->IpTable);i++)
+ {
+ IP_TABLE_ENTRY *e = LIST_DATA(hub->IpTable, i);
+
+ if (e->Session == s)
+ {
+ if (IsIP4(&e->Ip))
+ {
+ num_ip_for_me++;
+ }
+ }
+ }
+
+ if (s->Policy->NoRouting)
+ {
+ limited_count = MIN(limited_count, IP_MIN_LIMIT_COUNT);
+ }
+ if (s->Policy->MaxIP != 0)
+ {
+ limited_count = MIN(limited_count, s->Policy->MaxIP);
+ }
+ limited_count = MAX(limited_count, IP_MIN_LIMIT_COUNT);
+
+ if (num_ip_for_me >= limited_count)
+ {
+ // Discard the packet because it exceeded the
+ // upper limit of the IP address that can be used
+ char tmp[64];
+ IPToStr32(tmp, sizeof(tmp), uint_ip);
+ if (s->Policy->NoRouting == false)
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_IP_LIMIT", s->Name, tmp, num_ip_for_me, limited_count);
+ }
+ }
+ else
+ {
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_ROUTING_LIMIT", s->Name, tmp, num_ip_for_me, limited_count);
+ }
+ }
+ goto DISCARD_PACKET;
+ }
+ }
+
+ if (IsIPManagementTargetForHUB(&ip, hub))
+ {
+ // Create a entry
+ e = ZeroMalloc(sizeof(IP_TABLE_ENTRY));
+ e->CreatedTime = e->UpdatedTime = now;
+ e->DhcpAllocated = false;
+ Copy(&e->Ip, &ip, sizeof(IP));
+ Copy(e->MacAddress, packet->MacAddressSrc, 6);
+ e->Session = s;
+
+ DeleteExpiredIpTableEntry(hub->IpTable);
+
+ if (LIST_NUM(hub->IpTable) >= MAX_IP_TABLES)
+ {
+ // Delete old IP table entries
+ DeleteOldIpTableEntry(hub->IpTable);
+ }
+
+ Insert(hub->IpTable, e);
+
+ if (0)
+ {
+ char ip_address[64];
+ IPToStr(ip_address, sizeof(ip_address), &ip);
+ Debug("Registered IP Address %s to Session %X.\n",
+ ip_address, s);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (e->Session == s)
+ {
+ // Do not do anything because it is self session
+ // Renew update time
+ e->UpdatedTime = now;
+ Copy(e->MacAddress, packet->MacAddressSrc, 6);
+ }
+ else
+ {
+ // Another session was using this IP address before
+ if ((s->Policy->CheckIP || s->Policy->DHCPForce) &&
+ ((e->UpdatedTime + IP_TABLE_EXCLUSIVE_TIME) >= now))
+ {
+ // Discard the packet because another session uses
+ // this IP address
+ char ip_address[32];
+ char mac_str[48];
+ IPToStr(ip_address, sizeof(ip_address), &ip);
+
+ Debug("IP Address %s is Already used by Session %X.\n",
+ ip_address, s);
+
+ MacToStr(mac_str, sizeof(mac_str), e->MacAddress);
+
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_IP_CONFLICT", s->Name, ip_address, e->Session->Name, mac_str,
+ e->CreatedTime, e->UpdatedTime, e->DhcpAllocated, now);
+ }
+
+ goto DISCARD_PACKET;
+ }
+
+ if (s->Policy->DHCPForce)
+ {
+ if (e->DhcpAllocated == false)
+ {
+ char ipstr[MAX_SIZE];
+
+ // Discard the packet because this IP address
+ // isn't assigned by the DHCP server
+ IPToStr32(ipstr, sizeof(ipstr), uint_ip);
+ if (no_heavy == false)
+ {
+ HLog(hub, "LH_DHCP_FORCE", s->Name, ipstr);
+ }
+ goto DISCARD_PACKET;
+ }
+ }
+
+ // Overwrite the entry
+ e->Session = s;
+ e->UpdatedTime = now;
+ Copy(e->MacAddress, packet->MacAddressSrc, 6);
+ }
+ }
+ }
+ }
+
+ if (s != NULL && broadcast_mode)
+ {
+ // Calling Broadcast Storm avoidance algorithm
+ // in order to prevent occurrence of a broadcast packet loop
+ // or a large number of broadcast
+ if (CheckBroadcastStorm(hub, s, packet) == false)
+ {
+ goto DISCARD_PACKET;
+ }
+ }
+
+ // Adding traffic
+ Zero(&traffic, sizeof(traffic));
+ if (packet->BroadcastPacket)
+ {
+ // Broadcast
+ traffic.Send.BroadcastBytes = packet->PacketSize;
+ traffic.Send.BroadcastCount = 1;
+ }
+ else
+ {
+ // Unicast
+ traffic.Send.UnicastBytes = packet->PacketSize;
+ traffic.Send.UnicastCount = 1;
+ }
+
+ if (s != NULL)
+ {
+ AddTrafficForSession(s, &traffic);
+ }
+
+ // Invert the Recv and Send of traffic information
+ Copy(&traffic.Recv, &traffic.Send, sizeof(TRAFFIC_ENTRY));
+ Zero(&traffic.Send, sizeof(TRAFFIC_ENTRY));
+
+ // Broadcast this packet to the monitor port of the HUB
+ if (hub->MonitorList->num_item != 0)
+ {
+ LockList(hub->MonitorList);
+ {
+ UINT i;
+ void *data;
+ UINT size = packet->PacketSize;
+ for (i = 0;i < LIST_NUM(hub->MonitorList);i++)
+ {
+ SESSION *monitor_session = (SESSION *)LIST_DATA(hub->MonitorList, i);
+
+ // Flood the packet
+ if (monitor_session->PacketAdapter->Param != NULL)
+ {
+ data = MallocFast(size);
+ Copy(data, packet->PacketData, size);
+ StorePacketToHubPa((HUB_PA *)monitor_session->PacketAdapter->Param,
+ s, data, size, packet);
+ }
+ }
+ }
+ UnlockList(hub->MonitorList);
+ }
+
+ if (broadcast_mode == false)
+ {
+ if (dest_pa != NULL)
+ {
+ if (dest_session->Policy->NoIPv6DefaultRouterInRA ||
+ (dest_session->Policy->NoIPv6DefaultRouterInRAWhenIPv6 && dest_session->IPv6Session) ||
+ (hub->Option->NoIPv6DefaultRouterInRAWhenIPv6 && dest_session->IPv6Session))
+ {
+ DeleteIPv6DefaultRouterInRA(packet);
+ }
+ if (dest_session->Policy->RSandRAFilter)
+ {
+ if (packet->TypeL3 == L3_IPV6 &&
+ packet->TypeL4 == L4_ICMPV6 &&
+ (packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_SOLICIATION ||
+ packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
+ {
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+ if (dest_session->Policy->DHCPFilter)
+ {
+ if (packet->TypeL3 == L3_IPV4 &&
+ packet->TypeL4 == L4_UDP &&
+ packet->TypeL7 == L7_DHCPV4)
+ {
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+ if (dest_session->Policy->DHCPv6Filter)
+ {
+ if (packet->TypeL3 == L3_IPV6 &&
+ packet->TypeL4 == L4_UDP &&
+ (Endian16(packet->L4.UDPHeader->DstPort) == 546 || Endian16(packet->L4.UDPHeader->DstPort) == 547))
+ {
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+ if (dest_session->Policy->ArpDhcpOnly)
+ {
+ if (packet->BroadcastPacket)
+ {
+ bool b = true;
+
+ if (packet->TypeL3 == L3_IPV4 &&
+ packet->TypeL4 == L4_UDP &&
+ packet->TypeL7 == L7_DHCPV4)
+ {
+ b = false;
+ }
+ else if (packet->TypeL3 == L3_ARPV4)
+ {
+ b = false;
+ }
+ else if (packet->TypeL3 == L3_IPV6 &&
+ packet->TypeL4 == L4_UDP &&
+ (Endian16(packet->L4.UDPHeader->DstPort) == 546 || Endian16(packet->L4.UDPHeader->DstPort) == 547))
+ {
+ b = false;
+ }
+ else if (packet->TypeL3 == L3_IPV6 &&
+ packet->TypeL4 == L4_ICMPV6)
+ {
+ b = false;
+ }
+
+ if (b)
+ {
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+ }
+ if (dest_session->Policy->FilterIPv4)
+ {
+ if (packet->TypeL3 == L3_IPV4 || packet->TypeL3 == L3_ARPV4)
+ {
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+ if (dest_session->Policy->FilterIPv6)
+ {
+ if (packet->TypeL3 == L3_IPV6)
+ {
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+ if (dest_session->Policy->FilterNonIP)
+ {
+ if (packet->TypeL3 != L3_IPV4 && packet->TypeL3 != L3_ARPV4 && packet->TypeL3 != L3_IPV6)
+ {
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+
+ if (s != NULL &&
+ (packet->BroadcastPacket == false &&
+ s->Policy->PrivacyFilter &&
+ dest_session->Policy->PrivacyFilter)
+ )
+ {
+ // Privacy filter
+ if (packet->TypeL3 != L3_ARPV4)
+ {
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+
+ if (s != NULL)
+ {
+ if (Cmp(packet->MacAddressSrc, s->Hub->HubMacAddr, 6) == 0 ||
+ Cmp(packet->MacAddressDest, s->Hub->HubMacAddr, 6) == 0)
+ {
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+
+ // Take a packet log
+ if (s != NULL)
+ {
+ if (PacketLog(s->Hub, s, dest_session, packet, now) == false)
+ {
+ // The packet drops because it have exceeded the allowable amount
+ goto DISCARD_UNICAST_PACKET;
+ }
+ }
+
+ // Store to the destination HUB_PA
+ StorePacketToHubPa(dest_pa, s, packet->PacketData, packet->PacketSize, packet);
+
+ // Adding traffic
+ AddTrafficForSession(dest_session, &traffic);
+ }
+ else
+ {
+DISCARD_UNICAST_PACKET:
+ Free(packet->PacketData);
+ }
+ }
+ else
+ {
+ // Take a packet log
+ if (s != NULL)
+ {
+ if (PacketLog(s->Hub, s, NULL, packet, now) == false)
+ {
+ // The packet drops because It have exceeded the allowable amount
+ goto DISCARD_BROADCAST_PACKET;
+ }
+ }
+
+ // Store for all sessions
+ LockList(hub->SessionList);
+ {
+ UINT i, num = LIST_NUM(hub->SessionList);
+ for (i = 0;i < num;i++)
+ {
+ SESSION *dest_session = LIST_DATA(hub->SessionList, i);
+ HUB_PA *dest_pa = (HUB_PA *)dest_session->PacketAdapter->Param;
+ bool discard = false;
+
+ if (dest_session != s)
+ {
+ bool delete_default_router_in_ra = false;
+
+ if (dest_session->IsMonitorMode)
+ {
+ discard = true;
+ }
+
+ if (dest_session->VLanId != 0 && packet->TypeL3 == L3_TAGVLAN &&
+ packet->VlanId != dest_session->VLanId)
+ {
+ discard = true;
+ }
+
+ if (dest_session->Policy->NoIPv6DefaultRouterInRA ||
+ (dest_session->Policy->NoIPv6DefaultRouterInRAWhenIPv6 && dest_session->IPv6Session) ||
+ (hub->Option->NoIPv6DefaultRouterInRAWhenIPv6 && dest_session->IPv6Session))
+ {
+ if (packet->TypeL3 == L3_IPV6 && packet->TypeL4 == L4_ICMPV6 &&
+ (packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
+ {
+ if (packet->ICMPv6HeaderPacketInfo.Headers.RouterAdvertisementHeader->Lifetime != 0)
+ {
+ delete_default_router_in_ra = true;
+ }
+ }
+ }
+ if (dest_session->Policy->RSandRAFilter)
+ {
+ if (packet->TypeL3 == L3_IPV6 &&
+ packet->TypeL4 == L4_ICMPV6 &&
+ (packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_SOLICIATION ||
+ packet->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
+ {
+ discard = true;
+ }
+ }
+
+ if (dest_session->Policy->DHCPFilter)
+ {
+ if (packet->TypeL3 == L3_IPV4 &&
+ packet->TypeL4 == L4_UDP &&
+ packet->TypeL7 == L7_DHCPV4)
+ {
+ discard = true;
+ }
+ }
+
+ if (dest_session->Policy->DHCPv6Filter)
+ {
+ if (packet->TypeL3 == L3_IPV6 &&
+ packet->TypeL4 == L4_UDP &&
+ (Endian16(packet->L4.UDPHeader->DstPort) == 546 || Endian16(packet->L4.UDPHeader->DstPort) == 547))
+ {
+ discard = true;
+ }
+ }
+
+ if (dest_session->Policy->ArpDhcpOnly)
+ {
+ if (packet->BroadcastPacket)
+ {
+ bool b = true;
+
+ if (packet->TypeL3 == L3_IPV4 &&
+ packet->TypeL4 == L4_UDP &&
+ packet->TypeL7 == L7_DHCPV4)
+ {
+ b = false;
+ }
+ else if (packet->TypeL3 == L3_ARPV4)
+ {
+ b = false;
+ }
+ else if (packet->TypeL3 == L3_IPV6 &&
+ packet->TypeL4 == L4_UDP &&
+ (Endian16(packet->L4.UDPHeader->DstPort) == 546 || Endian16(packet->L4.UDPHeader->DstPort) == 547))
+ {
+ b = false;
+ }
+ else if (packet->TypeL3 == L3_IPV6 &&
+ packet->TypeL4 == L4_ICMPV6)
+ {
+ b = false;
+ }
+
+ if (discard == false)
+ {
+ discard = b;
+ }
+ }
+ }
+
+ if (dest_session->Policy->FilterIPv4)
+ {
+ if (packet->TypeL3 == L3_IPV4 || packet->TypeL3 == L3_ARPV4)
+ {
+ discard = true;
+ }
+ }
+ if (dest_session->Policy->FilterIPv6)
+ {
+ if (packet->TypeL3 == L3_IPV6)
+ {
+ discard = true;
+ }
+ }
+ if (dest_session->Policy->FilterNonIP)
+ {
+ if (packet->TypeL3 != L3_IPV4 && packet->TypeL3 != L3_ARPV4 && packet->TypeL3 != L3_IPV6)
+ {
+ discard = true;
+ }
+ }
+
+ if (s != NULL &&
+ (packet->BroadcastPacket == false &&
+ s->Policy->PrivacyFilter &&
+ dest_session->Policy->PrivacyFilter)
+ )
+ {
+ // Privacy filter
+ if (packet->TypeL3 != L3_ARPV4)
+ {
+ discard = true;
+ }
+ }
+
+ if (s != NULL)
+ {
+ if (Cmp(packet->MacAddressSrc, s->Hub->HubMacAddr, 6) == 0 ||
+ Cmp(packet->MacAddressDest, s->Hub->HubMacAddr, 6) == 0)
+ {
+ discard = true;
+ }
+ }
+
+ if (discard == false && dest_pa != NULL)
+ {
+ // Store in session other than its own
+ data = MallocFast(packet->PacketSize);
+ Copy(data, packet->PacketData, packet->PacketSize);
+ size = packet->PacketSize;
+
+ if (delete_default_router_in_ra)
+ {
+ PKT *pkt2 = ParsePacket(data, size);
+
+ DeleteIPv6DefaultRouterInRA(pkt2);
+
+ FreePacket(pkt2);
+ }
+
+ StorePacketToHubPa(dest_pa, s, data, size, packet);
+
+ // Adding traffic
+ AddTrafficForSession(dest_session, &traffic);
+ }
+ }
+ }
+ }
+ UnlockList(hub->SessionList);
+
+DISCARD_BROADCAST_PACKET:
+ Free(packet->PacketData);
+ }
+ FreePacket(packet);
+ }
+ }
+ }
+ UnlockList(hub->MacTable);
+}
+
+// Examine the maximum number of logging target packets per minute
+bool CheckMaxLoggedPacketsPerMinute(SESSION *s, UINT max_packets, UINT64 now)
+{
+ UINT64 minute = 60 * 1000;
+ // Validate arguments
+ if (s == NULL || max_packets == 0)
+ {
+ return true;
+ }
+
+ if ((s->Policy != NULL && s->Policy->NoBroadcastLimiter) ||
+ s->SecureNATMode || s->BridgeMode || s->LinkModeServer || s->LinkModeClient ||
+ s->L3SwitchMode)
+ {
+ return true;
+ }
+
+ if (s->MaxLoggedPacketsPerMinuteStartTick == 0 ||
+ ((s->MaxLoggedPacketsPerMinuteStartTick + minute) <= now))
+ {
+ s->MaxLoggedPacketsPerMinuteStartTick = now;
+ s->CurrentNumPackets = 0;
+ }
+
+ s->CurrentNumPackets++;
+ if (s->CurrentNumPackets > max_packets)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Confirm whether the specified IP address is managed by Virtual HUB
+bool IsIPManagementTargetForHUB(IP *ip, HUB *hub)
+{
+ // Validate arguments
+ if (ip == NULL || hub == NULL)
+ {
+ return false;
+ }
+
+ if (hub->Option == NULL)
+ {
+ return true;
+ }
+
+ if (IsIP4(ip))
+ {
+ if (hub->Option->ManageOnlyPrivateIP)
+ {
+ if (IsIPPrivate(ip) == false)
+ {
+ return false;
+ }
+ }
+ }
+ else
+ {
+ if (hub->Option->ManageOnlyLocalUnicastIPv6)
+ {
+ UINT ip_type = GetIPAddrType6(ip);
+
+ if (!(ip_type & IPV6_ADDR_LOCAL_UNICAST))
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+// Delete old IP table entries
+void DeleteOldIpTableEntry(LIST *o)
+{
+ UINT i;
+ UINT64 oldest_time = 0xffffffffffffffffULL;
+ IP_TABLE_ENTRY *old = NULL;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IP_TABLE_ENTRY *e = LIST_DATA(o, i);
+
+ if (e->UpdatedTime <= oldest_time)
+ {
+ old = e;
+ }
+ }
+
+ if (old != NULL)
+ {
+ Delete(o, old);
+ Free(old);
+ }
+}
+
+
+// Add to Storm list
+STORM *AddStormList(HUB_PA *pa, UCHAR *mac_address, IP *src_ip, IP *dest_ip, bool strict)
+{
+ STORM *s;
+ // Validate arguments
+ if (pa == NULL || mac_address == NULL)
+ {
+ return NULL;
+ }
+
+ s = ZeroMalloc(sizeof(STORM));
+ if (src_ip != NULL)
+ {
+ Copy(&s->SrcIp, src_ip, sizeof(IP));
+ }
+ if (dest_ip != NULL)
+ {
+ Copy(&s->DestIp, dest_ip, sizeof(IP));
+ }
+ Copy(s->MacAddress, mac_address, 6);
+ s->StrictMode = strict;
+
+ Insert(pa->StormList, s);
+
+ return s;
+}
+
+// Search in Storm list
+STORM *SearchStormList(HUB_PA *pa, UCHAR *mac_address, IP *src_ip, IP *dest_ip, bool strict)
+{
+ STORM t, *s;
+ // Validate arguments
+ if (pa == NULL || mac_address == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&t, sizeof(t));
+ if (src_ip != NULL)
+ {
+ Copy(&t.SrcIp, src_ip, sizeof(IP));
+ }
+ if (dest_ip != NULL)
+ {
+ Copy(&t.DestIp, dest_ip, sizeof(IP));
+ }
+ Copy(t.MacAddress, mac_address, 6);
+
+ t.StrictMode = strict;
+
+ s = Search(pa->StormList, &t);
+
+ return s;
+}
+
+// Store the packet to destination HUB_PA
+void StorePacketToHubPa(HUB_PA *dest, SESSION *src, void *data, UINT size, PKT *packet)
+{
+ BLOCK *b;
+ // Validate arguments
+ if (dest == NULL || data == NULL)
+ {
+ return;
+ }
+
+ if (size < 14)
+ {
+ Free(data);
+ return;
+ }
+
+ if (src != NULL)
+ {
+ // Apply the access list for forwarding
+ if (ApplyAccessListToForwardPacket(src->Hub, src, dest->Session, packet) == false)
+ {
+ Free(data);
+ return;
+ }
+ }
+
+ if (src != NULL)
+ {
+ if (dest->Session->Policy->MaxDownload != 0)
+ {
+ // Traffic limit
+ if (packet != NULL && IsMostHighestPriorityPacket(dest->Session, packet) == false)
+ {
+ TRAFFIC_LIMITER *tr = &dest->DownloadLimiter;
+ IntoTrafficLimiter(tr, packet);
+
+ if ((tr->Value * (UINT64)1000 / (UINT64)LIMITER_SAMPLING_SPAN) > dest->Session->Policy->MaxDownload)
+ {
+ // Limit
+ Free(data);
+ return;
+ }
+ }
+ }
+ }
+
+ if (src != NULL && src->Hub != NULL && src->Hub->Option != NULL && src->Hub->Option->FixForDLinkBPDU)
+ {
+ // Measures for D-Link bug
+ UCHAR *mac = packet->MacAddressSrc;
+ if ((mac[0] == 0x00 && mac[1] == 0x80 && mac[2] == 0xc8 && mac[3] == 0x00 && mac[4] == 0x00 && mac[5] == 0x00) ||
+ (mac[0] == 0x00 && mac[1] == 0x0d && mac[2] == 0x88 && mac[3] == 0x00 && mac[4] == 0x00 && mac[5] == 0x00))
+ {
+ SESSION *session = dest->Session;
+
+ if (session != NULL)
+ {
+ if (session->Policy != NULL && session->Policy->CheckMac)
+ {
+ UCHAR hash[MD5_SIZE];
+ Hash(hash, packet->PacketData, packet->PacketSize, false);
+
+ Copy(session->LastDLinkSTPPacketDataHash, hash, MD5_SIZE);
+ session->LastDLinkSTPPacketSendTick = Tick64();
+ }
+ }
+ }
+ }
+
+ // Remove the VLAN tag
+ if (dest->Session != NULL && dest->Session->VLanId != 0)
+ {
+ UINT vlan_tpid = 0;
+ if (src != NULL && src->Hub != NULL && src->Hub->Option != NULL)
+ {
+ vlan_tpid = src->Hub->Option->VlanTypeId;
+ }
+ if (VLanRemoveTag(&data, &size, dest->Session->VLanId, vlan_tpid) == false)
+ {
+ Free(data);
+ return;
+ }
+ }
+
+ if (dest != NULL && src != NULL && dest->Session != NULL && src->Hub != NULL && src->Hub->Option != NULL)
+ {
+ if (dest->Session->AdjustMss != 0 ||
+ (dest->Session->IsUsingUdpAcceleration && dest->Session->UdpAccelMss != 0) ||
+ (dest->Session->IsRUDPSession && dest->Session->RUdpMss != 0))
+ {
+ if (src->Hub->Option->DisableAdjustTcpMss == false)
+ {
+ UINT target_mss = INFINITE;
+
+ if (dest->Session->AdjustMss != 0)
+ {
+ target_mss = MIN(target_mss, dest->Session->AdjustMss);
+ }
+
+ if (dest->Session->IsUsingUdpAcceleration && dest->Session->UdpAccelMss != 0)
+ {
+ target_mss = MIN(target_mss, dest->Session->UdpAccelMss);
+ }
+ else if (dest->Session->IsRUDPSession && dest->Session->RUdpMss != 0)
+ {
+ target_mss = MIN(target_mss, dest->Session->RUdpMss);
+ }
+
+ // Processing of Adjust TCP MSS
+ if (target_mss != INFINITE)
+ {
+ AdjustTcpMssL2(data, size, target_mss, src->Hub->Option->VlanTypeId);
+ }
+ }
+ }
+ }
+
+ // Create a block
+ b = NewBlock(data, size, 0);
+
+ LockQueue(dest->PacketQueue);
+ {
+ // Measure the length of queue
+ if ((dest->PacketQueue->num_item < MAX_STORED_QUEUE_NUM) ||
+ (((UCHAR *)data)[12] == 'S' && ((UCHAR *)data)[13] == 'E'))
+ {
+ // Store
+ InsertQueue(dest->PacketQueue, b);
+ }
+ else
+ {
+ // Drop the packet
+ FreeBlock(b);
+ }
+ }
+ UnlockQueue(dest->PacketQueue);
+
+ // Issue of cancellation
+ if (src != NULL)
+ {
+ AddCancelList(src->CancelList, dest->Cancel);
+ }
+ else
+ {
+ Cancel(dest->Cancel);
+ }
+}
+
+// Remove the default router specification from the IPv6 router advertisement
+bool DeleteIPv6DefaultRouterInRA(PKT *p)
+{
+ if (p->TypeL3 == L3_IPV6 && p->TypeL4 == L4_ICMPV6 &&
+ (p->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
+ {
+ if (p->ICMPv6HeaderPacketInfo.Headers.RouterAdvertisementHeader->Lifetime != 0)
+ {
+ p->ICMPv6HeaderPacketInfo.Headers.RouterAdvertisementHeader->Lifetime = 0;
+
+ p->L4.ICMPHeader->Checksum = 0;
+ p->L4.ICMPHeader->Checksum =
+ CalcChecksumForIPv6(&p->L3.IPv6Header->SrcAddress,
+ &p->L3.IPv6Header->DestAddress, IP_PROTO_ICMPV6,
+ p->L4.ICMPHeader, p->IPv6HeaderPacketInfo.PayloadSize, 0);
+ }
+ }
+
+ return false;
+}
+
+// Packet filter by policy
+bool StorePacketFilterByPolicy(SESSION *s, PKT *p)
+{
+ POLICY *pol;
+ HUB *hub;
+ bool no_heavy = false;
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return false;
+ }
+
+ hub = s->Hub;
+
+ if (hub->Option != NULL)
+ {
+ no_heavy = hub->Option->DoNotSaveHeavySecurityLogs;
+ }
+
+ // Policy
+ pol = s->Policy;
+
+ // To prohibit the operation as a server
+ if (pol->NoServer)
+ {
+ if (p->TypeL3 == L3_IPV4)
+ {
+ if (p->TypeL4 == L4_TCP)
+ {
+ UCHAR flag = p->L4.TCPHeader->Flag;
+ if ((flag & TCP_SYN) && (flag & TCP_ACK))
+ {
+ char ip1[64], ip2[64];
+ // Not to send a SYN + ACK packet
+ Debug("pol->NoServer: Discard SYN+ACK Packet.\n");
+
+ IPToStr32(ip1, sizeof(ip1), p->L3.IPv4Header->SrcIP);
+ IPToStr32(ip2, sizeof(ip2), p->L3.IPv4Header->DstIP);
+
+ if (no_heavy == false)
+ {
+ HLog(s->Hub, "LH_NO_SERVER", s->Name, ip2, p->L4.TCPHeader->DstPort,
+ ip1, p->L4.TCPHeader->SrcPort);
+ }
+
+ return false;
+ }
+ }
+ }
+ }
+
+ // Prohibit the operation as a server (IPv6)
+ if (pol->NoServerV6)
+ {
+ if (p->TypeL3 == L3_IPV6)
+ {
+ if (p->TypeL4 == L4_TCP)
+ {
+ UCHAR flag = p->L4.TCPHeader->Flag;
+ if ((flag & TCP_SYN) && (flag & TCP_ACK))
+ {
+ char ip1[128], ip2[128];
+ // Not to send a SYN + ACK packet
+ Debug("pol->NoServerV6: Discard SYN+ACK Packet.\n");
+
+ IP6AddrToStr(ip1, sizeof(ip1), &p->IPv6HeaderPacketInfo.IPv6Header->SrcAddress);
+ IP6AddrToStr(ip2, sizeof(ip2), &p->IPv6HeaderPacketInfo.IPv6Header->DestAddress);
+
+ if (no_heavy == false)
+ {
+ HLog(s->Hub, "LH_NO_SERVER", s->Name, ip2, p->L4.TCPHeader->DstPort,
+ ip1, p->L4.TCPHeader->SrcPort);
+ }
+
+ return false;
+ }
+ }
+ }
+ }
+
+ // Allow broadcast only DHCP and ARP
+ if (pol->ArpDhcpOnly && p->BroadcastPacket)
+ {
+ bool ok = false;
+
+ if (p->TypeL3 == L3_ARPV4)
+ {
+ ok = true;
+ }
+ if (p->TypeL3 == L3_IPV4)
+ {
+ if (p->TypeL4 == L4_UDP)
+ {
+ if (p->TypeL7 == L7_DHCPV4)
+ {
+ ok = true;
+ }
+ }
+ }
+ if (p->TypeL3 == L3_IPV6)
+ {
+ if (p->TypeL4 == L4_ICMPV6)
+ {
+ ok = true;
+ }
+ }
+
+ if (p->TypeL3 == L3_IPV6 &&
+ p->TypeL4 == L4_UDP &&
+ (Endian16(p->L4.UDPHeader->DstPort) == 546 || Endian16(p->L4.UDPHeader->DstPort) == 547))
+ {
+ ok = true;
+ }
+
+ if (ok == false)
+ {
+ return false;
+ }
+ }
+
+ // Filter IPv4 packets
+ if (pol->FilterIPv4)
+ {
+ if (p->MacHeader != NULL)
+ {
+ USHORT proto = Endian16(p->MacHeader->Protocol);
+ if (proto == 0x0800 || proto == 0x0806)
+ {
+ return false;
+ }
+ }
+ }
+
+ // Filter IPv6 packets
+ if (pol->FilterIPv6)
+ {
+ if (p->MacHeader != NULL)
+ {
+ USHORT proto = Endian16(p->MacHeader->Protocol);
+ if (proto == 0x86dd)
+ {
+ return false;
+ }
+ }
+ }
+
+ // Filter non-IP packets
+ if (pol->FilterNonIP)
+ {
+ if (p->MacHeader != NULL)
+ {
+ USHORT proto = Endian16(p->MacHeader->Protocol);
+ if (!(proto == 0x86dd || proto == 0x0800 || proto == 0x0806))
+ {
+ return false;
+ }
+ }
+ }
+
+ // Filter DHCP packets
+ if (pol->DHCPFilter)
+ {
+ if (p->TypeL3 == L3_IPV4 &&
+ p->TypeL4 == L4_UDP &&
+ p->TypeL7 == L7_DHCPV4)
+ {
+ // Discard the DHCP packet
+ Debug("pol->DHCPFilter: Discard DHCP Packet.\n");
+
+ return false;
+ }
+ }
+
+ // DHCPv6 packet filtering
+ if (pol->DHCPv6Filter)
+ {
+ if (p->TypeL3 == L3_IPV6 &&
+ p->TypeL4 == L4_UDP)
+ {
+ if (Endian16(p->L4.UDPHeader->DstPort) == 546 ||
+ Endian16(p->L4.UDPHeader->DstPort) == 547)
+ {
+ // Discard the DHCPv6 packet
+ Debug("pol->DHCPv6Filter: Discard DHCPv6 Packet.\n");
+
+ return false;
+ }
+ }
+ }
+
+ // The behavior as a DHCP server is prohibited
+ if (pol->DHCPNoServer)
+ {
+ if (p->TypeL3 == L3_IPV4 &&
+ p->TypeL4 == L4_UDP &&
+ p->TypeL7 == L7_DHCPV4)
+ {
+ DHCPV4_HEADER *h = p->L7.DHCPv4Header;
+ if (h->OpCode == 2)
+ {
+ char ip1[64], ip2[64];
+
+ // Discard the DHCP packet
+ IPToStr32(ip1, sizeof(ip1), p->L3.IPv4Header->SrcIP);
+ IPToStr32(ip2, sizeof(ip2), p->L3.IPv4Header->DstIP);
+
+ if (no_heavy == false)
+ {
+ HLog(s->Hub, "LH_NO_DHCP", s->Name, ip1, ip2);
+ }
+
+ // Discard the DHCP response packet
+ Debug("pol->DHCPNoServer: Discard DHCP Response Packet.\n");
+ return false;
+ }
+ }
+ }
+
+ // The behavior as a DHCPv6 server is prohibited
+ if (pol->DHCPv6NoServer)
+ {
+ if (p->TypeL3 == L3_IPV6 &&
+ p->TypeL4 == L4_UDP &&
+ (Endian16(p->L4.UDPHeader->DstPort) == 546 || Endian16(p->L4.UDPHeader->SrcPort) == 547))
+ {
+ char ip1[128], ip2[128];
+
+ // Discard the DHCP packet
+ IP6AddrToStr(ip1, sizeof(ip1), &p->L3.IPv6Header->SrcAddress);
+ IP6AddrToStr(ip2, sizeof(ip2), &p->L3.IPv6Header->DestAddress);
+
+ if (no_heavy == false)
+ {
+ HLog(s->Hub, "LH_NO_DHCP", s->Name, ip1, ip2);
+ }
+
+ // Discard the DHCP response packet
+ Debug("pol->DHCPv6NoServer: Discard DHCPv6 Response Packet.\n");
+ return false;
+ }
+ }
+
+ // Filter the Router Solicitation / Advertising packet (IPv6)
+ if (pol->RSandRAFilter)
+ {
+ if (p->TypeL3 == L3_IPV6 && p->TypeL4 == L4_ICMPV6 &&
+ (p->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_SOLICIATION ||
+ p->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT))
+ {
+ return false;
+ }
+ }
+
+ // Filter the router advertisement packet (IPv6)
+ if (pol->RAFilter)
+ {
+ if (p->TypeL3 == L3_IPV6 && p->TypeL4 == L4_ICMPV6 &&
+ p->ICMPv6HeaderPacketInfo.Type == ICMPV6_TYPE_ROUTER_ADVERTISEMENT)
+ {
+ return false;
+ }
+ }
+
+ // Register to the IP table by recording the DHCP response packet
+ if (p->TypeL3 == L3_IPV4 &&
+ p->TypeL4 == L4_UDP &&
+ p->TypeL7 == L7_DHCPV4 &&
+ (s->Hub != NULL && s->Hub->Option->NoIpTable == false))
+ {
+ DHCPV4_HEADER *h = p->L7.DHCPv4Header;
+ if (h->OpCode == 2 && p->DhcpOpCode == DHCP_ACK)
+ {
+ // Register to the IP table by peeking the contents of the DHCP response packet
+ if (h->HardwareType == ARP_HARDWARE_TYPE_ETHERNET)
+ {
+ if (h->HardwareAddressSize == 6)
+ {
+ if (h->YourIP != 0 && h->YourIP != 0xffffffff)
+ {
+ UINT ip_uint = h->YourIP;
+ IP ip;
+ IP_TABLE_ENTRY *e, t;
+ MAC_TABLE_ENTRY *mac_table, mt;
+ mt.VlanId = 0;
+ Copy(&mt.MacAddress, &h->ClientMacAddress, 6);
+ mac_table = Search(hub->MacTable, &mt);
+
+ if (mac_table != NULL)
+ {
+ bool new_entry = true;
+ UINTToIP(&ip, ip_uint);
+ Copy(&t.Ip, &ip, sizeof(IP));
+
+ e = Search(hub->IpTable, &t);
+ if (e == NULL)
+ {
+ // Register as a new item
+ e = ZeroMalloc(sizeof(IP_TABLE_ENTRY));
+UPDATE_DHCP_ALLOC_ENTRY:
+ e->CreatedTime = e->UpdatedTime = Tick64();
+ e->DhcpAllocated = true;
+ Copy(&e->Ip, &ip, sizeof(IP));
+ e->Session = mac_table->Session;
+ Copy(e->MacAddress, p->MacAddressDest, 6);
+
+ if (new_entry)
+ {
+ // Delete the expired IP table entries
+ DeleteExpiredIpTableEntry(hub->IpTable);
+ if (LIST_NUM(hub->IpTable) >= MAX_IP_TABLES)
+ {
+ // Remove old entries
+ DeleteOldIpTableEntry(hub->IpTable);
+ }
+ Insert(hub->IpTable, e);
+ }
+
+ if (new_entry)
+ {
+ if ((hub->Option != NULL && hub->Option->NoDhcpPacketLogOutsideHub == false) || mac_table->Session != s)
+ {
+ char dhcp_mac_addr[64];
+ char dest_mac_addr[64];
+ char dest_ip_addr[64];
+ char server_ip_addr[64];
+ MacToStr(dhcp_mac_addr, sizeof(dhcp_mac_addr), p->MacAddressSrc);
+ MacToStr(dest_mac_addr, sizeof(dest_mac_addr), h->ClientMacAddress);
+ IPToStr(dest_ip_addr, sizeof(dest_ip_addr), &ip);
+ IPToStr32(server_ip_addr, sizeof(server_ip_addr), p->L3.IPv4Header->SrcIP);
+ Debug("DHCP Allocated; dhcp server: %s, client: %s, new_ip: %s\n",
+ dhcp_mac_addr, dest_mac_addr, dest_ip_addr);
+
+ if (no_heavy == false)
+ {
+ HLog(s->Hub, "LH_REGIST_DHCP", s->Name, dhcp_mac_addr, server_ip_addr,
+ mac_table->Session->Name, dest_mac_addr, dest_ip_addr);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Update
+ new_entry = false;
+ goto UPDATE_DHCP_ALLOC_ENTRY;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+// Delete the expired MAC table entries
+void DeleteExpiredMacTableEntry(LIST *o)
+{
+ LIST *o2;
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ o2 = NewListFast(NULL);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ MAC_TABLE_ENTRY *e = LIST_DATA(o, i);
+ if ((e->UpdatedTime + (UINT64)MAC_TABLE_EXPIRE_TIME) <= Tick64())
+ {
+ Add(o2, e);
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o2);i++)
+ {
+ MAC_TABLE_ENTRY *e = LIST_DATA(o2, i);
+ Delete(o, e);
+ Free(e);
+ }
+
+ ReleaseList(o2);
+}
+
+// Delete the expired IP table entries
+void DeleteExpiredIpTableEntry(LIST *o)
+{
+ LIST *o2;
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ o2 = NewListFast(NULL);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IP_TABLE_ENTRY *e = LIST_DATA(o, i);
+ if ((e->UpdatedTime + (UINT64)(e->DhcpAllocated ? IP_TABLE_EXPIRE_TIME_DHCP : IP_TABLE_EXPIRE_TIME)) <= Tick64())
+ {
+ Add(o2, e);
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o2);i++)
+ {
+ IP_TABLE_ENTRY *e = LIST_DATA(o2, i);
+ Delete(o, e);
+ Free(e);
+ }
+
+ ReleaseList(o2);
+}
+
+// Determine whether the packet to be handled with priority
+bool IsMostHighestPriorityPacket(SESSION *s, PKT *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return false;
+ }
+
+ if (p->TypeL3 == L3_ARPV4)
+ {
+ // ARP packets
+ return true;
+ }
+
+ if (p->TypeL3 == L3_IPV4)
+ {
+ if (p->TypeL4 == L4_ICMPV4)
+ {
+ // ICMP packets
+ return true;
+ }
+
+ if (p->TypeL4 == L4_TCP)
+ {
+ if ((p->L4.TCPHeader->Flag & TCP_SYN) || (p->L4.TCPHeader->Flag & TCP_FIN)
+ || (p->L4.TCPHeader->Flag & TCP_RST))
+ {
+ // SYN, FIN, RST packet
+ return true;
+ }
+ }
+
+ if (p->TypeL4 == L4_UDP)
+ {
+ if (p->TypeL7 == L7_DHCPV4)
+ {
+ // DHCP packets
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+// Add a packet to traffic limiter
+void IntoTrafficLimiter(TRAFFIC_LIMITER *tr, PKT *p)
+{
+ UINT64 now = Tick64();
+ // Validate arguments
+ if (tr == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (tr->LastTime == 0 || tr->LastTime > now ||
+ (tr->LastTime + LIMITER_SAMPLING_SPAN) < now)
+ {
+ // Sampling initialization
+ tr->Value = 0;
+ tr->LastTime = now;
+ }
+
+ // Value increase
+ tr->Value += (UINT64)(p->PacketSize * 8);
+}
+
+// The bandwidth reduction by traffic limiter
+bool StorePacketFilterByTrafficLimiter(SESSION *s, PKT *p)
+{
+ HUB_PA *pa;
+ TRAFFIC_LIMITER *tr;
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return false;
+ }
+
+ if (s->Policy->MaxUpload == 0)
+ {
+ // Unlimited
+ return true;
+ }
+
+ pa = (HUB_PA *)s->PacketAdapter->Param;
+ tr = &pa->UploadLimiter;
+
+ // Restrictions are not applied for priority packets
+ if (IsMostHighestPriorityPacket(s, p))
+ {
+ return true;
+ }
+
+ // Input packets to the limiter
+ IntoTrafficLimiter(tr, p);
+
+ // Compare the current bandwidth and limit value
+ if ((tr->Value * (UINT64)1000 / (UINT64)LIMITER_SAMPLING_SPAN) > s->Policy->MaxUpload)
+ {
+ // Discard the packet
+ return false;
+ }
+
+ return true;
+}
+
+// Filtering of packets to store
+bool StorePacketFilter(SESSION *s, PKT *packet)
+{
+ // Validate arguments
+ if (s == NULL || packet == NULL)
+ {
+ return false;
+ }
+
+ // The bandwidth reduction by traffic limiter
+ if (StorePacketFilterByTrafficLimiter(s, packet) == false)
+ {
+ return false;
+ }
+
+ // Packet filter by policy
+ if (StorePacketFilterByPolicy(s, packet) == false)
+ {
+ return false;
+ }
+
+ // The packet filter with Access Lists
+ if (ApplyAccessListToStoredPacket(s->Hub, s, packet) == false)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Get the packet adapter for the HUB
+PACKET_ADAPTER *GetHubPacketAdapter()
+{
+ // Hand over by creating a function list
+ PACKET_ADAPTER *pa = NewPacketAdapter(HubPaInit,
+ HubPaGetCancel, HubPaGetNextPacket, HubPaPutPacket, HubPaFree);
+
+ return pa;
+}
+
+// Stop all the SESSION of the HUB
+void StopAllSession(HUB *h)
+{
+ SESSION **s;
+ UINT i, num;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ LockList(h->SessionList);
+ {
+ num = LIST_NUM(h->SessionList);
+ s = ToArray(h->SessionList);
+ DeleteAll(h->SessionList);
+ }
+ UnlockList(h->SessionList);
+
+ for (i = 0;i < num;i++)
+ {
+ StopSession(s[i]);
+ ReleaseSession(s[i]);
+ }
+
+ Free(s);
+}
+
+// Remove the SESSION from HUB
+void DelSession(HUB *h, SESSION *s)
+{
+ // Validate arguments
+ if (h == NULL || s == NULL)
+ {
+ return;
+ }
+
+ LockList(h->SessionList);
+ {
+ if (Delete(h->SessionList, s))
+ {
+ Debug("Session %s was Deleted from %s.\n", s->Name, h->Name);
+ ReleaseSession(s);
+ }
+ }
+ UnlockList(h->SessionList);
+}
+
+// Add a SESSION to the HUB
+void AddSession(HUB *h, SESSION *s)
+{
+ // Validate arguments
+ if (h == NULL || s == NULL)
+ {
+ return;
+ }
+
+ LockList(h->SessionList);
+ {
+ Insert(h->SessionList, s);
+ AddRef(s->ref);
+ Debug("Session %s Inserted to %s.\n", s->Name, h->Name);
+
+ if (s->InProcMode)
+ {
+ s->UniqueId = GetNewUniqueId(h);
+ }
+ }
+ UnlockList(h->SessionList);
+}
+
+// Create a new unique ID of the HUB
+UINT GetNewUniqueId(HUB *h)
+{
+ UINT id;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return 0;
+ }
+
+ for (id = 1;;id++)
+ {
+ if (SearchSessionByUniqueId(h, id) == NULL)
+ {
+ return id;
+ }
+ }
+}
+
+// Search for a session by the unique session ID
+SESSION *SearchSessionByUniqueId(HUB *h, UINT id)
+{
+ UINT i;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(h->SessionList);i++)
+ {
+ SESSION *s = LIST_DATA(h->SessionList, i);
+
+ if (s->UniqueId == id)
+ {
+ return s;
+ }
+ }
+
+ return NULL;
+}
+
+// Stop the operation of the HUB
+void StopHub(HUB *h)
+{
+ bool old_status = false;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ old_status = h->Offline;
+ h->HubIsOnlineButHalting = true;
+
+ SetHubOffline(h);
+
+ if (h->Halt == false)
+ {
+ SLog(h->Cedar, "LS_HUB_STOP", h->Name);
+ h->Halt = true;
+ }
+
+ h->Offline = old_status;
+ h->HubIsOnlineButHalting = false;
+}
+
+// Online the Virtual HUB
+void SetHubOnline(HUB *h)
+{
+ bool for_cluster = false;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ if (h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ if (h->Type == HUB_TYPE_FARM_DYNAMIC)
+ {
+ for_cluster = true;
+ }
+ }
+
+ Lock(h->lock_online);
+ {
+ if (h->Offline == false)
+ {
+ Unlock(h->lock_online);
+ return;
+ }
+ HLog(h, "LH_ONLINE");
+
+ // Start all links
+ StartAllLink(h);
+
+ // Start the SecureNAT
+ if (h->EnableSecureNAT)
+ {
+ if (h->SecureNAT == NULL)
+ {
+ if (for_cluster == false)
+ {
+ h->SecureNAT = SnNewSecureNAT(h, h->SecureNATOption);
+ }
+ }
+ }
+
+ // Start all of the local bridges that is associated with this HUB
+ if (h->Type != HUB_TYPE_FARM_DYNAMIC)
+ {
+ LockList(h->Cedar->LocalBridgeList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(h->Cedar->LocalBridgeList);i++)
+ {
+ LOCALBRIDGE *br = LIST_DATA(h->Cedar->LocalBridgeList, i);
+
+ if (StrCmpi(br->HubName, h->Name) == 0)
+ {
+ if (br->Bridge == NULL)
+ {
+ br->Bridge = BrNewBridge(h, br->DeviceName, NULL, br->Local, br->Monitor,
+ br->TapMode, br->TapMacAddress, br->LimitBroadcast, br);
+ }
+ }
+ }
+ }
+ UnlockList(h->Cedar->LocalBridgeList);
+ }
+
+ h->Offline = false;
+ }
+ Unlock(h->lock_online);
+
+ if (h->Cedar->Server != NULL)
+ {
+ SiHubOnlineProc(h);
+ }
+}
+
+// Offline the Virtual HUB
+void SetHubOffline(HUB *h)
+{
+ UINT i;
+ bool for_cluster = false;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ if (h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ if (h->Type == HUB_TYPE_FARM_DYNAMIC)
+ {
+ for_cluster = true;
+ }
+ }
+
+ h->BeingOffline = true;
+
+ Lock(h->lock_online);
+ {
+ if (h->Offline || h->Halt)
+ {
+ Unlock(h->lock_online);
+ h->BeingOffline = false;
+ return;
+ }
+
+ HLog(h, "LH_OFFLINE");
+
+ // Stop all links
+ StopAllLink(h);
+
+ // Stop the SecureNAT
+ SnFreeSecureNAT(h->SecureNAT);
+ h->SecureNAT = NULL;
+
+ // Stop all the local bridges that is associated with this HUB
+ LockList(h->Cedar->LocalBridgeList);
+ {
+ for (i = 0;i < LIST_NUM(h->Cedar->LocalBridgeList);i++)
+ {
+ LOCALBRIDGE *br = LIST_DATA(h->Cedar->LocalBridgeList, i);
+
+ if (StrCmpi(br->HubName, h->Name) == 0)
+ {
+ BrFreeBridge(br->Bridge);
+ br->Bridge = NULL;
+ }
+ }
+ }
+ UnlockList(h->Cedar->LocalBridgeList);
+
+ // Offline
+ h->Offline = true;
+
+ // Disconnect all sessions
+ StopAllSession(h);
+ }
+ Unlock(h->lock_online);
+
+ h->BeingOffline = false;
+
+ if (h->Cedar->Server != NULL)
+ {
+ SiHubOfflineProc(h);
+ }
+}
+
+// Get whether a HUB which have the specified name exists
+bool IsHub(CEDAR *cedar, char *name)
+{
+ HUB *h;
+ // Validate arguments
+ if (cedar == NULL || name == NULL)
+ {
+ return false;
+ }
+
+ h = GetHub(cedar, name);
+ if (h == NULL)
+ {
+ return false;
+ }
+
+ ReleaseHub(h);
+
+ return true;
+}
+
+// Get the HUB
+HUB *GetHub(CEDAR *cedar, char *name)
+{
+ HUB *h, t;
+ // Validate arguments
+ if (cedar == NULL || name == NULL)
+ {
+ return NULL;
+ }
+
+ LockHubList(cedar);
+
+ t.Name = name;
+ h = Search(cedar->HubList, &t);
+ if (h == NULL)
+ {
+ UnlockHubList(cedar);
+ return NULL;
+ }
+
+ AddRef(h->ref);
+
+ UnlockHubList(cedar);
+
+ return h;
+}
+
+// Lock the HUB list
+void LockHubList(CEDAR *cedar)
+{
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return;
+ }
+
+ LockList(cedar->HubList);
+}
+
+// Unlock the HUB list
+void UnlockHubList(CEDAR *cedar)
+{
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return;
+ }
+
+ UnlockList(cedar->HubList);
+}
+
+// Release the HUB
+void ReleaseHub(HUB *h)
+{
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ if (Release(h->ref) == 0)
+ {
+ CleanupHub(h);
+ }
+}
+
+// Get the Radius server information
+bool GetRadiusServer(HUB *hub, char *name, UINT size, UINT *port, char *secret, UINT secret_size)
+{
+ UINT interval;
+ return GetRadiusServerEx(hub, name, size, port, secret, secret_size, &interval);
+}
+bool GetRadiusServerEx(HUB *hub, char *name, UINT size, UINT *port, char *secret, UINT secret_size, UINT *interval)
+{
+ return GetRadiusServerEx2(hub, name, size, port, secret, secret_size, interval, NULL, 0);
+}
+bool GetRadiusServerEx2(HUB *hub, char *name, UINT size, UINT *port, char *secret, UINT secret_size, UINT *interval, char *suffix_filter, UINT suffix_filter_size)
+{
+ bool ret = false;
+ // Validate arguments
+ if (hub == NULL || name == NULL || port == NULL || secret == NULL || interval == NULL)
+ {
+ return false;
+ }
+
+ Lock(hub->RadiusOptionLock);
+ {
+ if (hub->RadiusServerName != NULL)
+ {
+ char *tmp;
+ UINT tmp_size;
+ StrCpy(name, size, hub->RadiusServerName);
+ *port = hub->RadiusServerPort;
+ *interval = hub->RadiusRetryInterval;
+
+ tmp_size = hub->RadiusSecret->Size + 1;
+ tmp = ZeroMalloc(tmp_size);
+ Copy(tmp, hub->RadiusSecret->Buf, hub->RadiusSecret->Size);
+ StrCpy(secret, secret_size, tmp);
+ Free(tmp);
+
+ if (suffix_filter != NULL)
+ {
+ StrCpy(suffix_filter, suffix_filter_size, hub->RadiusSuffixFilter);
+ }
+
+ ret = true;
+ }
+ }
+ Unlock(hub->RadiusOptionLock);
+
+ return ret;
+}
+
+// Set the Radius server information
+void SetRadiusServer(HUB *hub, char *name, UINT port, char *secret)
+{
+ SetRadiusServerEx(hub, name, port, secret, RADIUS_RETRY_INTERVAL);
+}
+void SetRadiusServerEx(HUB *hub, char *name, UINT port, char *secret, UINT interval)
+{
+ // Validate arguments
+ if (hub == NULL)
+ {
+ return;
+ }
+
+ Lock(hub->RadiusOptionLock);
+ {
+ if (hub->RadiusServerName != NULL)
+ {
+ Free(hub->RadiusServerName);
+ }
+
+ if (name == NULL)
+ {
+ hub->RadiusServerName = NULL;
+ hub->RadiusServerPort = 0;
+ hub->RadiusRetryInterval = RADIUS_RETRY_INTERVAL;
+ FreeBuf(hub->RadiusSecret);
+ }
+ else
+ {
+ hub->RadiusServerName = CopyStr(name);
+ hub->RadiusServerPort = port;
+ if (interval == 0)
+ {
+ hub->RadiusRetryInterval = RADIUS_RETRY_INTERVAL;
+ }
+ else if (interval > RADIUS_RETRY_TIMEOUT)
+ {
+ hub->RadiusRetryInterval = RADIUS_RETRY_TIMEOUT;
+ }
+ else
+ {
+ hub->RadiusRetryInterval = interval;
+ }
+ FreeBuf(hub->RadiusSecret);
+
+ if (secret == NULL)
+ {
+ hub->RadiusSecret = NewBuf();
+ }
+ else
+ {
+ hub->RadiusSecret = NewBuf();
+ WriteBuf(hub->RadiusSecret, secret, StrLen(secret));
+ SeekBuf(hub->RadiusSecret, 0, 0);
+ }
+ }
+ }
+ Unlock(hub->RadiusOptionLock);
+}
+
+// Get the difference between the traffic data
+void CalcTrafficEntryDiff(TRAFFIC_ENTRY *diff, TRAFFIC_ENTRY *old, TRAFFIC_ENTRY *current)
+{
+ // Validate arguments
+ Zero(diff, sizeof(TRAFFIC_ENTRY));
+ if (old == NULL || current == NULL || diff == NULL)
+ {
+ return;
+ }
+
+ if (current->BroadcastCount >= old->BroadcastCount)
+ {
+ diff->BroadcastCount = current->BroadcastCount - old->BroadcastCount;
+ }
+ if (current->BroadcastBytes >= old->BroadcastBytes)
+ {
+ diff->BroadcastBytes = current->BroadcastBytes - old->BroadcastBytes;
+ }
+ if (current->UnicastCount >= old->UnicastCount)
+ {
+ diff->UnicastCount = current->UnicastCount - old->UnicastCount;
+ }
+ if (current->UnicastBytes >= old->UnicastBytes)
+ {
+ diff->UnicastBytes = current->UnicastBytes - old->UnicastBytes;
+ }
+}
+void CalcTrafficDiff(TRAFFIC *diff, TRAFFIC *old, TRAFFIC *current)
+{
+ Zero(diff, sizeof(TRAFFIC));
+ if (old == NULL || current == NULL || diff == NULL)
+ {
+ return;
+ }
+
+ CalcTrafficEntryDiff(&diff->Send, &old->Send, &current->Send);
+ CalcTrafficEntryDiff(&diff->Recv, &old->Recv, &current->Recv);
+}
+
+// Add the traffic information for Virtual HUB
+void IncrementHubTraffic(HUB *h)
+{
+ TRAFFIC t;
+ // Validate arguments
+ if (h == NULL || h->FarmMember == false)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+
+ Lock(h->TrafficLock);
+ {
+ t.Send.BroadcastBytes =
+ h->Traffic->Send.BroadcastBytes - h->OldTraffic->Send.BroadcastBytes;
+ t.Send.BroadcastCount =
+ h->Traffic->Send.BroadcastCount - h->OldTraffic->Send.BroadcastCount;
+ t.Send.UnicastBytes =
+ h->Traffic->Send.UnicastBytes - h->OldTraffic->Send.UnicastBytes;
+ t.Send.UnicastCount =
+ h->Traffic->Send.UnicastCount - h->OldTraffic->Send.UnicastCount;
+ t.Recv.BroadcastBytes =
+ h->Traffic->Recv.BroadcastBytes - h->OldTraffic->Recv.BroadcastBytes;
+ t.Recv.BroadcastCount =
+ h->Traffic->Recv.BroadcastCount - h->OldTraffic->Recv.BroadcastCount;
+ t.Recv.UnicastBytes =
+ h->Traffic->Recv.UnicastBytes - h->OldTraffic->Recv.UnicastBytes;
+ t.Recv.UnicastCount =
+ h->Traffic->Recv.UnicastCount - h->OldTraffic->Recv.UnicastCount;
+ Copy(h->OldTraffic, h->Traffic, sizeof(TRAFFIC));
+ }
+ Unlock(h->TrafficLock);
+
+ if (IsZero(&t, sizeof(TRAFFIC)))
+ {
+ return;
+ }
+
+ AddTrafficDiff(h, h->Name, TRAFFIC_DIFF_HUB, &t);
+}
+
+// Adding Traffic information
+void AddTrafficDiff(HUB *h, char *name, UINT type, TRAFFIC *traffic)
+{
+ TRAFFIC_DIFF *d;
+ // Validate arguments
+ if (h == NULL || h->FarmMember == false || name == NULL || traffic == NULL)
+ {
+ return;
+ }
+
+ if (LIST_NUM(h->Cedar->TrafficDiffList) > MAX_TRAFFIC_DIFF)
+ {
+ return;
+ }
+
+ d = ZeroMallocFast(sizeof(TRAFFIC_DIFF));
+ d->HubName = CopyStr(h->Name);
+ d->Name = CopyStr(name);
+ d->Type = type;
+ Copy(&d->Traffic, traffic, sizeof(TRAFFIC));
+
+ LockList(h->Cedar->TrafficDiffList);
+ {
+ Insert(h->Cedar->TrafficDiffList, d);
+ }
+ UnlockList(h->Cedar->TrafficDiffList);
+}
+
+// Cleanup of HUB
+void CleanupHub(HUB *h)
+{
+ UINT i;
+ char name[MAX_SIZE];
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ StrCpy(name, sizeof(name), h->Name);
+
+ if (h->WatchDogStarted)
+ {
+ StopHubWatchDog(h);
+ }
+
+ FreeAccessList(h);
+
+ if (h->RadiusServerName != NULL)
+ {
+ Free(h->RadiusServerName);
+ FreeBuf(h->RadiusSecret);
+ }
+ ReleaseAllLink(h);
+ DeleteHubDb(h->HubDb);
+ ReleaseCedar(h->Cedar);
+ DeleteLock(h->lock);
+ DeleteLock(h->lock_online);
+ Free(h->Name);
+ ReleaseList(h->SessionList);
+ ReleaseList(h->MacTable);
+ ReleaseList(h->IpTable);
+ ReleaseList(h->MonitorList);
+ ReleaseList(h->LinkList);
+ DeleteCounter(h->NumSessions);
+ DeleteCounter(h->NumSessionsClient);
+ DeleteCounter(h->NumSessionsBridge);
+ DeleteCounter(h->SessionCounter);
+ FreeTraffic(h->Traffic);
+ FreeTraffic(h->OldTraffic);
+ Free(h->Option);
+
+ Free(h->SecureNATOption);
+
+ DeleteLock(h->TrafficLock);
+
+ for (i = 0;i < LIST_NUM(h->TicketList);i++)
+ {
+ Free(LIST_DATA(h->TicketList, i));
+ }
+
+ ReleaseList(h->TicketList);
+
+ DeleteLock(h->RadiusOptionLock);
+
+ FreeLog(h->PacketLogger);
+ FreeLog(h->SecurityLogger);
+
+ for (i = 0;i < LIST_NUM(h->AdminOptionList);i++)
+ {
+ Free(LIST_DATA(h->AdminOptionList, i));
+ }
+ ReleaseList(h->AdminOptionList);
+
+ if (h->Msg != NULL)
+ {
+ Free(h->Msg);
+ }
+
+ FreeUserList(h->UserList);
+
+ Free(h);
+}
+
+// Comparison function of IP table entries
+int CompareIpTable(void *p1, void *p2)
+{
+ IP_TABLE_ENTRY *e1, *e2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ e1 = *(IP_TABLE_ENTRY **)p1;
+ e2 = *(IP_TABLE_ENTRY **)p2;
+ if (e1 == NULL || e2 == NULL)
+ {
+ return 0;
+ }
+ return CmpIpAddr(&e1->Ip, &e2->Ip);
+}
+
+// Comparison function of the MAC table entries
+int CompareMacTable(void *p1, void *p2)
+{
+ int r;
+ MAC_TABLE_ENTRY *e1, *e2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ e1 = *(MAC_TABLE_ENTRY **)p1;
+ e2 = *(MAC_TABLE_ENTRY **)p2;
+ if (e1 == NULL || e2 == NULL)
+ {
+ return 0;
+ }
+ r = Cmp(e1->MacAddress, e2->MacAddress, 6);
+ if (r != 0)
+ {
+ return r;
+ }
+ if (e1->VlanId > e2->VlanId)
+ {
+ return 1;
+ }
+ else if (e1->VlanId < e2->VlanId)
+ {
+ return -1;
+ }
+ return 0;
+}
+
+// Comparison function of HUB
+int CompareHub(void *p1, void *p2)
+{
+ HUB *h1, *h2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ h1 = *(HUB **)p1;
+ h2 = *(HUB **)p2;
+ if (h1 == NULL || h2 == NULL)
+ {
+ return 0;
+ }
+ return StrCmpi(h1->Name, h2->Name);
+}
+
+// Examine whether the MAC address is for the ARP polling of the Virtual HUB
+bool IsHubMacAddress(UCHAR *mac)
+{
+ // Validate arguments
+ if (mac == NULL)
+ {
+ return false;
+ }
+
+ if (mac[0] == 0x00 && mac[1] == SE_HUB_MAC_ADDR_SIGN)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Examine whether the IP address is for the ARP polling of the Virtual HUB
+bool IsHubIpAddress32(UINT ip32)
+{
+ IP ip;
+
+ UINTToIP(&ip, ip32);
+
+ return IsHubIpAddress(&ip);
+}
+bool IsHubIpAddress(IP *ip)
+{
+ // Validate arguments
+ if (ip == NULL)
+ {
+ return false;
+ }
+
+ if (ip->addr[0] == 172 && ip->addr[1] == 31)
+ {
+ if (ip->addr[2] >= 1 && ip->addr[2] <= 254)
+ {
+ if (ip->addr[3] >= 1 && ip->addr[3] <= 254)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+bool IsHubIpAddress64(IPV6_ADDR *addr)
+{
+ // Validate arguments
+ if (addr == NULL)
+ {
+ return false;
+ }
+
+ if (addr->Value[0] == 0xfe && addr->Value[1] == 0x80 &&
+ addr->Value[2] == 0 &&
+ addr->Value[3] == 0 &&
+ addr->Value[4] == 0 &&
+ addr->Value[5] == 0 &&
+ addr->Value[6] == 0 &&
+ addr->Value[7] == 0 &&
+ addr->Value[8] == 0x02 && addr->Value[9] == 0xae &&
+ addr->Value[11] == 0xff && addr->Value[12] == 0xfe)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Generate an IP address for the Virtual HUB
+void GenHubIpAddress(IP *ip, char *name)
+{
+ char tmp1[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ UCHAR hash[SHA1_SIZE];
+ // Validate arguments
+ if (ip == NULL || name == NULL)
+ {
+ return;
+ }
+
+ StrCpy(tmp1, sizeof(tmp1), name);
+ Trim(tmp1);
+ GenerateMachineUniqueHash(hash);
+ BinToStr(tmp2, sizeof(tmp2), hash, sizeof(hash));
+ StrCat(tmp2, sizeof(tmp2), tmp1);
+ StrUpper(tmp2);
+
+ Hash(hash, tmp2, StrLen(tmp2), true);
+
+ Zero(ip, sizeof(IP));
+ ip->addr[0] = 172;
+ ip->addr[1] = 31;
+ ip->addr[2] = hash[0] % 254 + 1;
+ ip->addr[3] = hash[1] % 254 + 1;
+}
+
+// Generate a MAC address for the Virtual HUB
+void GenHubMacAddress(UCHAR *mac, char *name)
+{
+ char tmp1[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ UCHAR hash[SHA1_SIZE];
+ // Validate arguments
+ if (mac == NULL || name == NULL)
+ {
+ return;
+ }
+
+ StrCpy(tmp1, sizeof(tmp1), name);
+ Trim(tmp1);
+ GenerateMachineUniqueHash(hash);
+ BinToStr(tmp2, sizeof(tmp2), hash, sizeof(hash));
+ StrCat(tmp2, sizeof(tmp2), tmp1);
+ StrUpper(tmp2);
+
+ Hash(hash, tmp2, StrLen(tmp2), true);
+
+ mac[0] = 0x00;
+ mac[1] = SE_HUB_MAC_ADDR_SIGN;
+ mac[2] = hash[0];
+ mac[3] = hash[1];
+ mac[4] = hash[2];
+ mac[5] = hash[3];
+}
+
+// Get a message from HUB
+wchar_t *GetHubMsg(HUB *h)
+{
+ wchar_t *ret = NULL;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return NULL;
+ }
+
+ Lock(h->lock);
+ {
+ if (h->Msg != NULL)
+ {
+ ret = CopyUniStr(h->Msg);
+ }
+ }
+ Unlock(h->lock);
+
+ return ret;
+}
+
+// Set a message to the HUB
+void SetHubMsg(HUB *h, wchar_t *msg)
+{
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ Lock(h->lock);
+ {
+ if (h->Msg != NULL)
+ {
+ Free(h->Msg);
+ h->Msg = NULL;
+ }
+
+ if (UniIsEmptyStr(msg) == false)
+ {
+ h->Msg = UniCopyStr(msg);
+ }
+ }
+ Unlock(h->lock);
+}
+
+// Creating a new HUB
+HUB *NewHub(CEDAR *cedar, char *HubName, HUB_OPTION *option)
+{
+ HUB *h;
+ char packet_logger_name[MAX_SIZE];
+ char tmp[MAX_SIZE];
+ char safe_hub_name[MAX_HUBNAME_LEN + 1];
+ UCHAR hash[SHA1_SIZE];
+ IP ip6;
+ // Validate arguments
+ if (cedar == NULL || option == NULL || HubName == NULL)
+ {
+ return NULL;
+ }
+
+ h = ZeroMalloc(sizeof(HUB));
+ Hash(h->HashedPassword, "", 0, true);
+ HashPassword(h->SecurePassword, ADMINISTRATOR_USERNAME, "");
+ h->lock = NewLock();
+ h->lock_online = NewLock();
+ h->ref = NewRef();
+ h->Cedar = cedar;
+ AddRef(h->Cedar->ref);
+ h->Type = HUB_TYPE_STANDALONE;
+
+ ConvertSafeFileName(safe_hub_name, sizeof(safe_hub_name), HubName);
+ h->Name = CopyStr(safe_hub_name);
+
+
+ h->AdminOptionList = NewList(CompareAdminOption);
+ AddHubAdminOptionsDefaults(h, true);
+
+ h->LastCommTime = SystemTime64();
+ h->LastLoginTime = SystemTime64();
+ h->NumLogin = 0;
+
+ h->TrafficLock = NewLock();
+
+ h->HubDb = NewHubDb();
+
+ h->SessionList = NewList(NULL);
+ h->SessionCounter = NewCounter();
+ h->NumSessions = NewCounter();
+ h->NumSessionsClient = NewCounter();
+ h->NumSessionsBridge = NewCounter();
+ h->MacTable = NewList(CompareMacTable);
+ h->IpTable = NewList(CompareIpTable);
+ h->MonitorList = NewList(NULL);
+ h->LinkList = NewList(NULL);
+
+ h->Traffic = NewTraffic();
+ h->OldTraffic = NewTraffic();
+
+ h->Option = ZeroMalloc(sizeof(HUB_OPTION));
+ Copy(h->Option, option, sizeof(HUB_OPTION));
+
+ if (h->Option->VlanTypeId == 0)
+ {
+ h->Option->VlanTypeId = MAC_PROTO_TAGVLAN;
+ }
+
+ Rand(h->HubSignature, sizeof(h->HubSignature));
+
+ // SecureNAT related
+ h->EnableSecureNAT = false;
+ h->SecureNAT = NULL;
+ h->SecureNATOption = ZeroMalloc(sizeof(VH_OPTION));
+ NiSetDefaultVhOption(NULL, h->SecureNATOption);
+
+ if (h->Cedar != NULL && h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ NiClearUnsupportedVhOptionForDynamicHub(h->SecureNATOption, true);
+ }
+
+ // Generate a temporary MAC address for the HUB
+ GenerateMachineUniqueHash(hash);
+ GenHubMacAddress(h->HubMacAddr, h->Name);
+ GenHubIpAddress(&h->HubIp, h->Name);
+
+ // IPv6 address for the HUB
+ GenerateEui64LocalAddress(&ip6, h->HubMacAddr);
+ IPToIPv6Addr(&h->HubIpV6, &ip6);
+
+ h->RadiusOptionLock = NewLock();
+ h->RadiusServerPort = RADIUS_DEFAULT_PORT;
+
+ h->TicketList = NewList(NULL);
+
+ InitAccessList(h);
+
+ // Create a user list
+ h->UserList = NewUserList();
+
+ // Default logging settings
+ h->LogSetting.SavePacketLog = h->LogSetting.SaveSecurityLog = true;
+ h->LogSetting.PacketLogConfig[PACKET_LOG_TCP_CONN] =
+ h->LogSetting.PacketLogConfig[PACKET_LOG_DHCP] = PACKET_LOG_HEADER;
+ h->LogSetting.SecurityLogSwitchType = LOG_SWITCH_DAY;
+ h->LogSetting.PacketLogSwitchType = LOG_SWITCH_DAY;
+
+ MakeDir(HUB_SECURITY_LOG_DIR_NAME);
+ MakeDir(HUB_PACKET_LOG_DIR_NAME);
+
+ // Start the packet logger
+ Format(packet_logger_name, sizeof(packet_logger_name), HUB_PACKET_LOG_FILE_NAME, h->Name);
+ h->PacketLogger = NewLog(packet_logger_name, HUB_PACKET_LOG_PREFIX, h->LogSetting.PacketLogSwitchType);
+
+ // Start the security logger
+ Format(tmp, sizeof(tmp), HUB_SECURITY_LOG_FILE_NAME, h->Name);
+ h->SecurityLogger = NewLog(tmp, HUB_SECURITY_LOG_PREFIX, h->LogSetting.SecurityLogSwitchType);
+
+ if (h->Cedar->Server != NULL && h->Cedar->Server->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ h->FarmMember = true;
+ }
+
+ // Start the HUB
+ SetHubOnline(h);
+
+ if (h->Cedar->Bridge)
+ {
+ h->Option->NoArpPolling = true;
+ }
+
+ if (h->Option->NoArpPolling == false && h->Option->NoIpTable == false)
+ {
+ StartHubWatchDog(h);
+ h->WatchDogStarted = true;
+ }
+
+ SLog(h->Cedar, "LS_HUB_START", h->Name);
+
+ MacToStr(tmp, sizeof(tmp), h->HubMacAddr);
+ SLog(h->Cedar, "LS_HUB_MAC", h->Name, tmp);
+
+ return h;
+}
+
+// Delete the HUBDB
+void DeleteHubDb(HUBDB *d)
+{
+ // Validate arguments
+ if (d == NULL)
+ {
+ return;
+ }
+
+ LockList(d->UserList);
+ {
+ LockList(d->GroupList);
+ {
+ // Release all users and groups
+ UINT i;
+ USER **users;
+ USERGROUP **groups;
+
+ users = ToArray(d->UserList);
+ groups = ToArray(d->GroupList);
+
+ for (i = 0;i < LIST_NUM(d->UserList);i++)
+ {
+ ReleaseUser(users[i]);
+ }
+ for (i = 0;i < LIST_NUM(d->GroupList);i++)
+ {
+ ReleaseGroup(groups[i]);
+ }
+
+ Free(users);
+ Free(groups);
+ }
+ UnlockList(d->GroupList);
+ }
+ UnlockList(d->UserList);
+
+ // Release the root certificate list
+ LockList(d->RootCertList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(d->RootCertList);i++)
+ {
+ X *x = LIST_DATA(d->RootCertList, i);
+ FreeX(x);
+ }
+ }
+ UnlockList(d->RootCertList);
+
+ // Release the CRL
+ LockList(d->CrlList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(d->CrlList);i++)
+ {
+ CRL *crl = LIST_DATA(d->CrlList, i);
+ FreeCrl(crl);
+ }
+ }
+ UnlockList(d->CrlList);
+
+ // Release the AC list
+ FreeAcList(d->AcList);
+
+ ReleaseList(d->GroupList);
+ ReleaseList(d->UserList);
+ ReleaseList(d->RootCertList);
+ ReleaseList(d->CrlList);
+ Free(d);
+}
+
+// Get a log setting of the HUB
+void GetHubLogSetting(HUB *h, HUB_LOG *setting)
+{
+ // Validate arguments
+ if (setting == NULL || h == NULL)
+ {
+ return;
+ }
+
+ Copy(setting, &h->LogSetting, sizeof(HUB_LOG));
+}
+
+// Update the log settings of the HUB
+void SetHubLogSettingEx(HUB *h, HUB_LOG *setting, bool no_change_switch_type)
+{
+ UINT i1, i2;
+ // Validate arguments
+ if (setting == NULL || h == NULL)
+ {
+ return;
+ }
+
+ i1 = h->LogSetting.PacketLogSwitchType;
+ i2 = h->LogSetting.SecurityLogSwitchType;
+
+ Copy(&h->LogSetting, setting, sizeof(HUB_LOG));
+
+ if (no_change_switch_type)
+ {
+ h->LogSetting.PacketLogSwitchType = i1;
+ h->LogSetting.SecurityLogSwitchType = i2;
+ }
+
+ // Packet logger configuration
+ SetLogSwitchType(h->PacketLogger, setting->PacketLogSwitchType);
+ SetLogSwitchType(h->SecurityLogger, setting->SecurityLogSwitchType);
+}
+void SetHubLogSetting(HUB *h, HUB_LOG *setting)
+{
+ SetHubLogSettingEx(h, setting, false);
+}
+
+// Add the trusted root certificate to the HUB
+void AddRootCert(HUB *hub, X *x)
+{
+ HUBDB *db;
+ // Validate arguments
+ if (hub == NULL || x == NULL)
+ {
+ return;
+ }
+
+ db = hub->HubDb;
+ if (db != NULL)
+ {
+ LockList(db->RootCertList);
+ {
+ if (LIST_NUM(db->RootCertList) < MAX_HUB_CERTS)
+ {
+ UINT i;
+ bool ok = true;
+
+ for (i = 0;i < LIST_NUM(db->RootCertList);i++)
+ {
+ X *exist_x = LIST_DATA(db->RootCertList, i);
+ if (CompareX(exist_x, x))
+ {
+ ok = false;
+ break;
+ }
+ }
+
+ if (ok)
+ {
+ Insert(db->RootCertList, CloneX(x));
+ }
+ }
+ }
+ UnlockList(db->RootCertList);
+ }
+}
+
+// Compare the list of certificates
+int CompareCert(void *p1, void *p2)
+{
+ X *x1, *x2;
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ x1 = *(X **)p1;
+ x2 = *(X **)p2;
+ if (x1 == NULL || x2 == NULL)
+ {
+ return 0;
+ }
+
+ GetPrintNameFromX(tmp1, sizeof(tmp1), x1);
+ GetPrintNameFromX(tmp2, sizeof(tmp2), x2);
+
+ return UniStrCmpi(tmp1, tmp2);
+}
+
+// Creating a new HUBDB
+HUBDB *NewHubDb()
+{
+ HUBDB *d = ZeroMalloc(sizeof(HUBDB));
+
+ d->GroupList = NewList(CompareGroupName);
+ d->UserList = NewList(CompareUserName);
+ d->RootCertList = NewList(CompareCert);
+ d->CrlList = NewList(NULL);
+ d->AcList = NewAcList();
+
+ return d;
+}
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Hub.h b/src/Cedar/Hub.h
new file mode 100644
index 00000000..ae671d89
--- /dev/null
+++ b/src/Cedar/Hub.h
@@ -0,0 +1,598 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Hub.h
+// Header of Hub.c
+
+#ifndef HUB_H
+#define HUB_H
+
+
+// Prefix in the access list for investigating whether the user name which is contained in a particular file
+#define ACCESS_LIST_INCLUDED_PREFIX "include:" // Included
+#define ACCESS_LIST_EXCLUDED_PREFIX "exclude:" // Not included
+
+// The default value for the cache expiration of the user name reference file of the access list (in seconds)
+#define ACCESS_LIST_INCLUDE_FILE_CACHE_LIFETIME 30
+
+// The maximum length of the include file in the access list
+#define ACCESS_LIST_INCLUDE_FILE_MAX_SIZE (1024 * 1024)
+
+// <INFO> tags of the URL in the access list
+#define ACCESS_LIST_URL_INFO_TAG "<INFO>"
+
+
+// SoftEther link control packet
+struct SE_LINK
+{
+ UCHAR DestMacAddress[6]; // Destination MAC address
+ UCHAR SrcMacAddress[6]; // Source MAC address
+ UCHAR SignatureS; // 'S'
+ UCHAR SignatureE; // 'E'
+ UCHAR Padding[2]; // Padding
+ UINT Type; // Type
+ UCHAR HubSignature[16]; // HUB signature
+ UINT TransactionId; // Transaction ID
+ UINT Data; // Data
+ UCHAR Dummy[20]; // Dummy
+ UCHAR Checksum[SHA1_SIZE]; // Checksum
+};
+
+
+// Test packet reception record
+struct TEST_HISTORY
+{
+ SESSION *s1;
+ SESSION *s2;
+};
+
+// State machine for link test
+struct SE_TEST
+{
+ LOCK *lock; // Lock
+ UINT64 LastTestPacketSentTime; // Time that sent the test packet at the last
+ UINT NextTestPacketSendInterval; // Next test packet transmission interval
+ bool CurrentTesting; // Test by sending a test packet currently
+ UINT TransactionId; // Transaction ID
+ LIST *TestHistory; // Reception history
+};
+
+// Macro
+#define NO_ACCOUNT_DB(h) ((h)->FarmMember)
+
+// Database in the case of a stand-alone or a farm master HUB
+struct HUBDB
+{
+ LIST *UserList; // User List
+ LIST *GroupList; // Group List
+ LIST *RootCertList; // Certificate list to trust
+ LIST *CrlList; // CRL list
+ LIST *AcList; // AC List
+};
+
+// Traffic limiter
+struct TRAFFIC_LIMITER
+{
+ UINT64 LastTime; // Time of last measured
+ UINT64 Value; // The current value
+};
+
+// Record the number of broadcast of each endpoint
+struct STORM
+{
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2]; // Padding
+ IP SrcIp; // Source IP address
+ IP DestIp; // Destination IP address
+ UINT64 CheckStartTick; // Time that checking is started
+ UINT CurrentBroadcastNum; // The current number of broadcasts
+ UINT DiscardValue; // Ratio to discard the broadcast packet
+ bool StrictMode; // Strict mode
+};
+
+// Packet adapter information structure for HUB
+struct HUB_PA
+{
+ CANCEL *Cancel; // Cancel object
+ QUEUE *PacketQueue; // Packet queue
+ bool MonitorPort; // Monitor port
+ UINT64 Now; // Current time
+ TRAFFIC_LIMITER UploadLimiter; // Upload bandwidth limit
+ TRAFFIC_LIMITER DownloadLimiter; // Download bandwidth limitation
+ SESSION *Session; // Session
+ LIST *StormList; // Broadcast storm recording list
+ UINT64 UsernameHash; // User name hash
+ UINT64 UsernameHashSimple; // User name hash (simple)
+ UINT64 GroupnameHash; // Group name hash
+};
+
+// HUB options
+struct HUB_OPTION
+{
+ // Standard options
+ UINT MaxSession; // Maximum number of simultaneous connections
+ bool NoEnum; // Excluded from the enumeration
+ // Advanced options
+ bool NoArpPolling; // No ARP polling
+ bool NoIPv6AddrPolling; // No IPv6 address polling
+ bool NoIpTable; // Do not generate an IP address table
+ bool NoMacAddressLog; // Not to write the registration log of the MAC address
+ bool ManageOnlyPrivateIP; // Manage only private IP
+ bool ManageOnlyLocalUnicastIPv6; // Manage only local unicast IPv6 addresses
+ bool DisableIPParsing; // Disable the IP interpretation
+ bool YieldAfterStorePacket; // Yield after the packet is stored
+ bool NoSpinLockForPacketDelay; // Do not use the spin lock
+ UINT BroadcastStormDetectionThreshold; // Broadcast number limit threshold
+ bool FilterPPPoE; // Filtering the PPPoE (0x8863, 0x8864)
+ bool FilterOSPF; // Filtering the OSPF (ip_proto = 89)
+ bool FilterIPv4; // Filter IPv4 packets
+ bool FilterIPv6; // Filter IPv6 packets
+ bool FilterNonIP; // Filter all non-IP packets
+ bool FilterBPDU; // Filter the BPDU packets
+ UINT ClientMinimumRequiredBuild; // If the build number of the client is lower than a certain value, deny it
+ bool NoIPv6DefaultRouterInRAWhenIPv6; // Delete the default router specification from the IPv6 router advertisement (only in the case of IPv6 physical connection)
+ bool NoIPv4PacketLog; // Do not save the packet log for the IPv4 packet
+ bool NoIPv6PacketLog; // Do not save the packet log of IPv6 packets
+ bool NoLookBPDUBridgeId; // Don't look the BPDU bridge ID for switching
+ bool NoManageVlanId; // Don't manage the VLAN ID
+ UINT VlanTypeId; // Type ID of VLAN packets (usually 0x8100)
+ bool FixForDLinkBPDU; // Apply the fix for the BPDU of the strange behavior of the D-Link
+ UINT RequiredClientId; // Client ID
+ UINT AdjustTcpMssValue; // TCP MSS adjustment value
+ bool DisableAdjustTcpMss; // Completely disable the TCP MSS adjustment function
+ bool NoDhcpPacketLogOutsideHub; // Suppress DHCP unrelated log
+ bool DisableHttpParsing; // Prohibit the HTTP interpretation
+ bool DisableUdpAcceleration; // Prohibit the UDP acceleration function
+ bool DisableUdpFilterForLocalBridgeNic; // Not to perform filtering DHCP packets associated with local bridge NIC
+ bool ApplyIPv4AccessListOnArpPacket; // Apply an IPv4 access list to the ARP packet
+ bool RemoveDefGwOnDhcpForLocalhost; // Remove the designation of the DHCP server from the DHCP response packet addressed to localhost
+ UINT SecureNAT_MaxTcpSessionsPerIp; // Maximum number of TCP sessions per IP address
+ UINT SecureNAT_MaxTcpSynSentPerIp; // Maximum number of TCP sessions of SYN_SENT state per IP address
+ UINT SecureNAT_MaxUdpSessionsPerIp; // Maximum number of UDP sessions per IP address
+ UINT SecureNAT_MaxDnsSessionsPerIp; // Maximum number of DNS sessions per IP address
+ UINT SecureNAT_MaxIcmpSessionsPerIp; // Maximum number of ICMP sessions per IP address
+ UINT AccessListIncludeFileCacheLifetime; // Expiration of the access list external file (in seconds)
+ bool DisableKernelModeSecureNAT; // Disable the kernel mode NAT
+ bool DisableUserModeSecureNAT; // Disable the user mode NAT
+ bool DisableCheckMacOnLocalBridge; // Disable the MAC address verification in local bridge
+ bool DisableCorrectIpOffloadChecksum; // Disable the correction of checksum that is IP-Offloaded
+ bool BroadcastLimiterStrictMode; // Strictly broadcast packets limiting mode
+ UINT MaxLoggedPacketsPerMinute; // Maximum number of logging target packets per minute
+ bool DoNotSaveHeavySecurityLogs; // Do not take heavy security log
+};
+
+// MAC table entry
+struct MAC_TABLE_ENTRY
+{
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2];
+ UINT VlanId; // VLAN ID
+ SESSION *Session; // Session
+ HUB_PA *HubPa; // HUB packet adapter
+ UINT64 CreatedTime; // Creation date and time
+ UINT64 UpdatedTime; // Updating date
+};
+
+// IP table entry
+struct IP_TABLE_ENTRY
+{
+ IP Ip; // IP address
+ SESSION *Session; // Session
+ bool DhcpAllocated; // Assigned by DHCP
+ UINT64 CreatedTime; // Creation date and time
+ UINT64 UpdatedTime; // Updating date
+ UCHAR MacAddress[6]; // MAC address
+};
+
+// Loop List
+struct LOOP_LIST
+{
+ UINT NumSessions;
+ SESSION **Session;
+};
+
+// Access list
+struct ACCESS
+{
+ // IPv4
+ UINT Id; // ID
+ wchar_t Note[MAX_ACCESSLIST_NOTE_LEN + 1]; // Note
+
+ // --- Please add items to the bottom of here for enhancements ---
+ bool Active; // Enable flag
+ UINT Priority; // Priority
+ bool Discard; // Discard flag
+ UINT SrcIpAddress; // Source IP address
+ UINT SrcSubnetMask; // Source subnet mask
+ UINT DestIpAddress; // Destination IP address
+ UINT DestSubnetMask; // Destination subnet mask
+ UINT Protocol; // Protocol
+ UINT SrcPortStart; // Source port number starting point
+ UINT SrcPortEnd; // Source port number end point
+ UINT DestPortStart; // Destination port number starting point
+ UINT DestPortEnd; // Destination port number end point
+ UINT64 SrcUsernameHash; // Source user name hash
+ bool IsSrcUsernameIncludeOrExclude; // The source user name is formed as the "include:" or "exclude:"
+ char SrcUsername[MAX_USERNAME_LEN + 1];
+ bool IsDestUsernameIncludeOrExclude; // The destination user name is formed as "include:" or "exclude:"
+ UINT64 DestUsernameHash; // Destination user name hash
+ char DestUsername[MAX_USERNAME_LEN + 1];
+ bool CheckSrcMac; // Presence of a source MAC address setting
+ UCHAR SrcMacAddress[6]; // Source MAC address
+ UCHAR SrcMacMask[6]; // Source MAC address mask
+ bool CheckDstMac; // Whether the setting of the destination MAC address exists
+ UCHAR DstMacAddress[6]; // Destination MAC address
+ UCHAR DstMacMask[6]; // Destination MAC address mask
+ bool CheckTcpState; // The state of the TCP connection
+ bool Established; // Establieshed(TCP)
+ UINT Delay; // Delay
+ UINT Jitter; // Jitter
+ UINT Loss; // Packet loss
+ char RedirectUrl[MAX_REDIRECT_URL_LEN + 1]; // URL to redirect to
+
+ // IPv6
+ bool IsIPv6; // Whether it's an IPv6
+ IPV6_ADDR SrcIpAddress6; // The source IP address (IPv6)
+ IPV6_ADDR SrcSubnetMask6; // Source subnet mask (IPv6)
+ IPV6_ADDR DestIpAddress6; // Destination IP address (IPv6)
+ IPV6_ADDR DestSubnetMask6; // Destination subnet mask (IPv6)
+
+ // --- Please add items to the above of here for enhancements ---
+
+ // For management
+ UINT UniqueId; // Unique ID
+};
+
+// Ticket
+struct TICKET
+{
+ UINT64 CreatedTick; // Creation date and time
+ UCHAR Ticket[SHA1_SIZE]; // Ticket
+ char Username[MAX_USERNAME_LEN + 1]; // User name
+ char UsernameReal[MAX_USERNAME_LEN + 1]; // Real user name
+ char GroupName[MAX_USERNAME_LEN + 1]; // Group name
+ char SessionName[MAX_SESSION_NAME_LEN + 1]; // Session name
+ POLICY Policy; // Policy
+};
+
+// Traffic difference
+struct TRAFFIC_DIFF
+{
+ UINT Type; // Type
+ TRAFFIC Traffic; // Traffic
+ char *HubName; // HUB name
+ char *Name; // Name
+};
+
+// Administration options
+struct ADMIN_OPTION
+{
+ char Name[MAX_ADMIN_OPTION_NAME_LEN + 1]; // Name
+ UINT Value; // Data
+};
+
+// Certificate Revocation List entry
+struct CRL
+{
+ X_SERIAL *Serial; // Serial number
+ NAME *Name; // Name information
+ UCHAR DigestMD5[MD5_SIZE]; // MD5 hash
+ UCHAR DigestSHA1[SHA1_SIZE]; // SHA-1 hash
+};
+
+// Access control
+struct AC
+{
+ UINT Id; // ID
+ UINT Priority; // Priority
+ bool Deny; // Deny access
+ bool Masked; // Is masked
+ IP IpAddress; // IP address
+ IP SubnetMask; // Subnet mask
+};
+
+// User List
+struct USERLIST
+{
+ char Filename[MAX_PATH]; // File name
+ LIST *UserHashList; // Hash list of user names
+};
+
+// HUB structure
+struct HUB
+{
+ LOCK *lock; // Lock
+ LOCK *lock_online; // Lock for Online
+ REF *ref; // Reference counter
+ CEDAR *Cedar; // Cedar
+ UINT Type; // Type
+ HUBDB *HubDb; // Database
+ char *Name; // The name of the HUB
+ LOCK *RadiusOptionLock; // Lock for Radius option
+ char *RadiusServerName; // Radius server name
+ UINT RadiusServerPort; // Radius server port number
+ UINT RadiusRetryInterval; // Radius retry interval
+ BUF *RadiusSecret; // Radius shared key
+ char RadiusSuffixFilter[MAX_SIZE]; // Radius suffix filter
+ volatile bool Halt; // Halting flag
+ bool Offline; // Offline
+ bool BeingOffline; // Be Doing Offline
+ LIST *SessionList; // Session list
+ COUNTER *SessionCounter; // Session number generation counter
+ TRAFFIC *Traffic; // Traffic information
+ TRAFFIC *OldTraffic; // Old traffic information
+ LOCK *TrafficLock; // Traffic lock
+ COUNTER *NumSessions; // The current number of sessions
+ COUNTER *NumSessionsClient; // The current number of sessions (client)
+ COUNTER *NumSessionsBridge; // The current number of sessions (bridge)
+ HUB_OPTION *Option; // HUB options
+ LIST *MacTable; // MAC address table
+ LIST *IpTable; // IP address table
+ LIST *MonitorList; // Monitor port session list
+ LIST *LinkList; // Linked list
+ UCHAR HubSignature[16]; // HUB signature
+ UCHAR HubMacAddr[6]; // MAC address of the HUB
+ IP HubIp; // IP address of the HUB (IPv4)
+ IPV6_ADDR HubIpV6; // IP address of the HUB (IPv6)
+ UINT HubIP6Id; // IPv6 packet ID of the HUB
+ UCHAR Padding[2]; // Padding
+ LOCK *LoopListLock; // Lock for the loop list
+ UINT NumLoopList; // Number of loop lists
+ LOOP_LIST **LoopLists; // Loop List
+ LIST *AccessList; // Access list
+ HUB_LOG LogSetting; // Log Settings
+ LOG *PacketLogger; // Packet logger
+ LOG *SecurityLogger; // Security logger
+ UCHAR HashedPassword[SHA1_SIZE]; // Password
+ UCHAR SecurePassword[SHA1_SIZE]; // Secure password
+ LIST *TicketList; // Ticket list
+ bool FarmMember; // Farm member
+ UINT64 LastIncrementTraffic; // Traffic reporting time
+ UINT64 LastSendArpTick; // ARP transmission time of the last
+ SNAT *SecureNAT; // SecureNAT
+ bool EnableSecureNAT; // SecureNAT enable / disable flag
+ VH_OPTION *SecureNATOption; // SecureNAT Option
+ THREAD *WatchDogThread; // Watchdog thread
+ EVENT *WatchDogEvent; // Watchdog event
+ bool WatchDogStarted; // Whether the watchdog thread is used
+ volatile bool HaltWatchDog; // Stop the watchdog thread
+ LIST *AdminOptionList; // Administration options list
+ UINT64 CreatedTime; // Creation date and time
+ UINT64 LastCommTime; // Last communication date and time
+ UINT64 LastLoginTime; // Last login date and time
+ UINT NumLogin; // Number of logins
+ bool HubIsOnlineButHalting; // Virtual HUB is really online, but it is in offline state to stop
+ UINT FarmMember_MaxSessionClient; // Maximum client connection sessions for cluster members
+ UINT FarmMember_MaxSessionBridge; // Maximum bridge connection sessions for cluster members
+ bool FarmMember_MaxSessionClientBridgeApply; // Apply the FarmMember_MaxSession*
+ UINT CurrentVersion; // The current version
+ UINT LastVersion; // Version of when the update notification is issued at the last
+ wchar_t *Msg; // Message to be displayed when the client is connected
+ LIST *UserList; // Cache of the user list file
+ bool IsVgsHub; // Whether it's a VGS Virtual HUB
+};
+
+
+// Global variable
+extern ADMIN_OPTION admin_options[];
+extern UINT num_admin_options;
+
+
+// Function prototype
+HUBDB *NewHubDb();
+void DeleteHubDb(HUBDB *d);
+HUB *NewHub(CEDAR *cedar, char *HubName, HUB_OPTION *option);
+void SetHubMsg(HUB *h, wchar_t *msg);
+wchar_t *GetHubMsg(HUB *h);
+void GenHubMacAddress(UCHAR *mac, char *name);
+void GenHubIpAddress(IP *ip, char *name);
+bool IsHubIpAddress(IP *ip);
+bool IsHubIpAddress32(UINT ip32);
+bool IsHubIpAddress64(IPV6_ADDR *addr);
+bool IsHubMacAddress(UCHAR *mac);
+void ReleaseHub(HUB *h);
+void CleanupHub(HUB *h);
+int CompareHub(void *p1, void *p2);
+void LockHubList(CEDAR *cedar);
+void UnlockHubList(CEDAR *cedar);
+HUB *GetHub(CEDAR *cedar, char *name);
+bool IsHub(CEDAR *cedar, char *name);
+void StopHub(HUB *h);
+void AddSession(HUB *h, SESSION *s);
+void DelSession(HUB *h, SESSION *s);
+SESSION *SearchSessionByUniqueId(HUB *h, UINT id);
+UINT GetNewUniqueId(HUB *h);
+void StopAllSession(HUB *h);
+bool HubPaInit(SESSION *s);
+void HubPaFree(SESSION *s);
+CANCEL *HubPaGetCancel(SESSION *s);
+UINT HubPaGetNextPacket(SESSION *s, void **data);
+bool HubPaPutPacket(SESSION *s, void *data, UINT size);
+PACKET_ADAPTER *GetHubPacketAdapter();
+int CompareMacTable(void *p1, void *p2);
+void StorePacket(HUB *hub, SESSION *s, PKT *packet);
+bool StorePacketFilter(SESSION *s, PKT *packet);
+void StorePacketToHubPa(HUB_PA *dest, SESSION *src, void *data, UINT size, PKT *packet);
+void SetHubOnline(HUB *h);
+void SetHubOffline(HUB *h);
+SESSION *GetSessionByPtr(HUB *hub, void *ptr);
+SESSION *GetSessionByName(HUB *hub, char *name);
+int CompareIpTable(void *p1, void *p2);
+bool StorePacketFilterByPolicy(SESSION *s, PKT *p);
+bool DeleteIPv6DefaultRouterInRA(PKT *p);
+bool StorePacketFilterByTrafficLimiter(SESSION *s, PKT *p);
+void IntoTrafficLimiter(TRAFFIC_LIMITER *tr, PKT *p);
+bool IsMostHighestPriorityPacket(SESSION *s, PKT *p);
+bool IsPriorityPacketForQoS(PKT *p);
+int CompareStormList(void *p1, void *p2);
+STORM *SearchStormList(HUB_PA *pa, UCHAR *mac_address, IP *src_ip, IP *dest_ip, bool strict);
+STORM *AddStormList(HUB_PA *pa, UCHAR *mac_address, IP *src_ip, IP *dest_ip, bool strict);
+bool CheckBroadcastStorm(HUB *hub, SESSION *s, PKT *p);
+void AddRootCert(HUB *hub, X *x);
+int CmpAccessList(void *p1, void *p2);
+void InitAccessList(HUB *hub);
+void FreeAccessList(HUB *hub);
+void AddAccessList(HUB *hub, ACCESS *a);
+void AddAccessListEx(HUB *hub, ACCESS *a, bool no_sort, bool no_reassign_id);
+bool SetSessionFirstRedirectHttpUrl(SESSION *s, char *url);
+bool IsTcpPacketNcsiHttpAccess(PKT *p);
+UINT64 UsernameToInt64(char *name);
+void MakeSimpleUsernameRemoveNtDomain(char *dst, UINT dst_size, char *src);
+bool ApplyAccessListToStoredPacket(HUB *hub, SESSION *s, PKT *p);
+void ForceRedirectToUrl(HUB *hub, SESSION *src_session, PKT *p, char *redirect_url);
+BUF *BuildRedirectToUrlPayload(HUB *hub, SESSION *s, char *redirect_url);
+bool ApplyAccessListToForwardPacket(HUB *hub, SESSION *src_session, SESSION *dest_session, PKT *p);
+bool IsPacketMaskedByAccessList(SESSION *s, PKT *p, ACCESS *a, UINT64 dest_username, UINT64 dest_groupname, SESSION *dest_session);
+void GetAccessListStr(char *str, UINT size, ACCESS *a);
+void DeleteOldIpTableEntry(LIST *o);
+void SetRadiusServer(HUB *hub, char *name, UINT port, char *secret);
+void SetRadiusServerEx(HUB *hub, char *name, UINT port, char *secret, UINT interval);
+bool GetRadiusServer(HUB *hub, char *name, UINT size, UINT *port, char *secret, UINT secret_size);
+bool GetRadiusServerEx(HUB *hub, char *name, UINT size, UINT *port, char *secret, UINT secret_size, UINT *interval);
+bool GetRadiusServerEx2(HUB *hub, char *name, UINT size, UINT *port, char *secret, UINT secret_size, UINT *interval, char *suffix_filter, UINT suffix_filter_size);
+int CompareCert(void *p1, void *p2);
+void GetHubLogSetting(HUB *h, HUB_LOG *setting);
+void SetHubLogSetting(HUB *h, HUB_LOG *setting);
+void SetHubLogSettingEx(HUB *h, HUB_LOG *setting, bool no_change_switch_type);
+void DeleteExpiredIpTableEntry(LIST *o);
+void DeleteExpiredMacTableEntry(LIST *o);
+void AddTrafficDiff(HUB *h, char *name, UINT type, TRAFFIC *traffic);
+void IncrementHubTraffic(HUB *h);
+void EnableSecureNAT(HUB *h, bool enable);
+void EnableSecureNATEx(HUB *h, bool enable, bool no_change);
+void StartHubWatchDog(HUB *h);
+void StopHubWatchDog(HUB *h);
+void HubWatchDogThread(THREAD *t, void *param);
+int CompareAdminOption(void *p1, void *p2);
+UINT GetHubAdminOptionEx(HUB *h, char *name, UINT default_value);
+UINT GetHubAdminOption(HUB *h, char *name);
+void DeleteAllHubAdminOption(HUB *h, bool lock);
+void AddHubAdminOptionsDefaults(HUB *h, bool lock);
+bool IsCertMatchCrl(X *x, CRL *crl);
+bool IsCertMatchCrlList(X *x, LIST *o);
+wchar_t *GenerateCrlStr(CRL *crl);
+bool IsValidCertInHub(HUB *h, X *x);
+void FreeCrl(CRL *crl);
+CRL *CopyCrl(CRL *crl);
+int CmpAc(void *p1, void *p2);
+LIST *NewAcList();
+void AddAc(LIST *o, AC *ac);
+bool DelAc(LIST *o, UINT id);
+AC *GetAc(LIST *o, UINT id);
+void SetAc(LIST *o, UINT id, AC *ac);
+void DelAllAc(LIST *o);
+void SetAcList(LIST *o, LIST *src);
+void NormalizeAcList(LIST *o);
+bool IsIpMaskedByAc(IP *ip, AC *ac);
+bool IsIpDeniedByAcList(IP *ip, LIST *o);
+char *GenerateAcStr(AC *ac);
+void FreeAcList(LIST *o);
+LIST *CloneAcList(LIST *o);
+bool IsIPManagementTargetForHUB(IP *ip, HUB *hub);
+wchar_t *GetHubAdminOptionHelpString(char *name);
+void HubOptionStructToData(RPC_ADMIN_OPTION *ao, HUB_OPTION *o, char *hub_name);
+ADMIN_OPTION *NewAdminOption(char *name, UINT value);
+void DataToHubOptionStruct(HUB_OPTION *o, RPC_ADMIN_OPTION *ao);
+UINT GetHubAdminOptionData(RPC_ADMIN_OPTION *ao, char *name);
+void GetHubAdminOptionDataAndSet(RPC_ADMIN_OPTION *ao, char *name, UINT *dest);
+bool IsURLMsg(wchar_t *str, char *url, UINT url_size);
+LIST *NewUserList();
+void DeleteAllUserListCache(LIST *o);
+void FreeUserList(LIST *o);
+void FreeUserListEntry(USERLIST *u);
+int CompareUserList(void *p1, void *p2);
+USERLIST *LoadUserList(LIST *o, char *filename);
+USERLIST *FindUserList(LIST *o, char *filename);
+bool IsUserMatchInUserList(LIST *o, char *filename, UINT64 user_hash);
+bool IsUserMatchInUserListWithCacheExpires(LIST *o, char *filename, UINT64 user_hash, UINT64 lifetime);
+bool IsUserMatchInUserListWithCacheExpiresAcl(LIST *o, char *name_in_acl, UINT64 user_hash, UINT64 lifetime);
+void CalcTrafficEntryDiff(TRAFFIC_ENTRY *diff, TRAFFIC_ENTRY *old, TRAFFIC_ENTRY *current);
+void CalcTrafficDiff(TRAFFIC *diff, TRAFFIC *old, TRAFFIC *current);
+bool CheckMaxLoggedPacketsPerMinute(SESSION *s, UINT max_packets, UINT64 now);
+void VgsSetUserAgentValue(char *str);
+void VgsSetEmbTag(bool b);
+
+#endif // HUB_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec.c b/src/Cedar/IPsec.c
new file mode 100644
index 00000000..7288e0b5
--- /dev/null
+++ b/src/Cedar/IPsec.c
@@ -0,0 +1,767 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec.c
+// IPsec module
+
+#include "CedarPch.h"
+
+
+static bool ipsec_disable = false;
+
+// Disabling whole IPsec
+void IPSecSetDisable(bool b)
+{
+ ipsec_disable = b;
+}
+
+
+// Monitor the IPsec service of the OS, and stop it if it will conflict
+void IPsecOsServiceCheckThread(THREAD *t, void *p)
+{
+ UINT interval = IPSEC_CHECK_OS_SERVICE_INTERVAL_INITIAL;
+ IPSEC_SERVER *s = (IPSEC_SERVER *)p;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ s->HostIPAddressListChanged = true;
+ s->OsServiceStoped = false;
+
+ while (s->Halt == false)
+ {
+ if (IPsecCheckOsService(s))
+ {
+ interval = IPSEC_CHECK_OS_SERVICE_INTERVAL_INITIAL;
+ }
+
+ if (Wait(s->OsServiceCheckThreadEvent, interval) == false)
+ {
+ interval = MIN(interval * 2, IPSEC_CHECK_OS_SERVICE_INTERVAL_MAX);
+ }
+ else
+ {
+ interval = IPSEC_CHECK_OS_SERVICE_INTERVAL_INITIAL;
+ }
+ }
+
+ IPsecCheckOsService(s);
+}
+
+// Monitoring process main
+bool IPsecCheckOsService(IPSEC_SERVER *s)
+{
+ bool b_ipsec;
+ IPSEC_SERVICES sl;
+ bool ret = false;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ IPsecServerGetServices(s, &sl);
+
+ b_ipsec = (sl.EtherIP_IPsec || sl.L2TP_IPsec);
+
+ if (b_ipsec != s->Check_LastEnabledStatus)
+ {
+ s->Check_LastEnabledStatus = b_ipsec;
+
+ if (b_ipsec)
+ {
+ // Use of IPsec has been started
+#ifdef OS_WIN32
+ if (s->Win7 == NULL)
+ {
+ s->Win7 = IPsecWin7Init();
+ s->HostIPAddressListChanged = true;
+ }
+
+ s->OsServiceStoped = false;
+#else // OS_WIN32
+#endif // OS_WIN32
+ }
+ else
+ {
+ // Use of IPsec is stopped
+#ifdef OS_WIN32
+ if (s->Win7 != NULL)
+ {
+ IPsecWin7Free(s->Win7);
+ s->Win7 = NULL;
+ }
+
+ if (s->OsServiceStoped)
+ {
+ MsStartIPsecService();
+ s->OsServiceStoped = false;
+ }
+#else // OS_WIN32
+ UnixSetEnableKernelEspProcessing(true);
+#endif // OS_WIN32
+ }
+ }
+
+ if (b_ipsec)
+ {
+#ifdef OS_WIN32
+ if (MsStopIPsecService())
+ {
+ s->OsServiceStoped = true;
+ ret = true;
+ }
+#else // OS_WIN32
+ UnixSetEnableKernelEspProcessing(false);
+#endif // OS_WIN32
+ }
+
+#ifdef OS_WIN32
+ if (s->Win7 != NULL)
+ {
+ IPsecWin7UpdateHostIPAddressList(s->Win7);
+ s->HostIPAddressListChanged = false;
+ }
+#endif // OS_WIN32
+
+ return ret;
+}
+
+// Processing of UDP packets (one by one)
+void IPsecProcPacket(IPSEC_SERVER *s, UDPPACKET *p)
+{
+ L2TP_SERVER *l2tp;
+ IKE_SERVER *ike;
+ void *old_data_ptr;
+ UINT old_data_size;
+ bool proc_this_packet = true;
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ old_data_ptr = p->Data;
+ old_data_size = p->Size;
+
+ l2tp = s->L2TP;
+ ike = s->Ike;
+
+ // UDP decapsulation process
+ if (p->DestPort == IPSEC_PORT_IPSEC_ESP_UDP)
+ {
+#ifdef OS_WIN32
+ if (p->Size >= 12 && IsZero(p->Data, 4))
+ {
+ if (((*((UINT *)(((UCHAR *)p->Data) + sizeof(UINT) * 1))) == WFP_ESP_PACKET_TAG_1) &&
+ ((*((UINT *)(((UCHAR *)p->Data) + sizeof(UINT) * 2))) == WFP_ESP_PACKET_TAG_2))
+ {
+ // Truncate the head because the packet was modified by WFP
+ p->Data = ((UCHAR *)p->Data) + 12;
+ p->Size -= 12;
+ }
+ }
+#endif // OS_WIN32
+
+ if (p->Size >= 4 && IsZero(p->Data, 4))
+ {
+ // Truncate the Non-ESP Marker
+ p->Data = ((UCHAR *)p->Data) + 4;
+ p->Size -= 4;
+
+ p->Type = IKE_UDP_TYPE_ISAKMP;
+ }
+ else
+ {
+ p->Type = IKE_UDP_TYPE_ESP;
+ }
+ }
+ else if (p->DestPort == IPSEC_PORT_IPSEC_ISAKMP)
+ {
+ if (p->Size >= 8 && IsZero(p->Data, 8))
+ {
+ // Truncate the Non-IKE Maker
+ p->Data = ((UCHAR *)p->Data) + 8;
+ p->Size -= 8;
+
+ p->Type = IKE_UDP_TYPE_ESP;
+ }
+ else
+ {
+ p->Type = IKE_UDP_TYPE_ISAKMP;
+ }
+ }
+ else if (p->DestPort == IPSEC_PORT_IPSEC_ESP_RAW)
+ {
+ // Raw ESP
+ p->Type = IKE_UDP_TYPE_ESP;
+ }
+
+
+ if (proc_this_packet)
+ {
+ switch (p->DestPort)
+ {
+ case IPSEC_PORT_L2TP:
+ // L2TP
+ ProcL2TPPacketRecv(l2tp, p);
+ break;
+
+ case IPSEC_PORT_IPSEC_ISAKMP:
+ case IPSEC_PORT_IPSEC_ESP_UDP:
+ case IPSEC_PORT_IPSEC_ESP_RAW:
+ // IPsec
+ ProcIKEPacketRecv(ike, p);
+ break;
+ }
+ }
+
+ p->Data = old_data_ptr;
+ p->Size = old_data_size;
+}
+
+// Packet reception procedure of UDP listener
+void IPsecServerUdpPacketRecvProc(UDPLISTENER *u, LIST *packet_list)
+{
+ UINT i;
+ IPSEC_SERVER *s;
+ L2TP_SERVER *l2tp;
+ IKE_SERVER *ike;
+ UINT64 now;
+ static UCHAR zero8[8] = {0, 0, 0, 0, 0, 0, 0, 0, };
+ // Validate arguments
+ if (u == NULL || packet_list == NULL)
+ {
+ return;
+ }
+ s = (IPSEC_SERVER *)u->Param;
+ if (s == NULL)
+ {
+ return;
+ }
+
+ if (u->HostIPAddressListChanged)
+ {
+ u->HostIPAddressListChanged = false;
+
+ s->HostIPAddressListChanged = true;
+
+ Set(s->OsServiceCheckThreadEvent);
+ }
+
+ now = Tick64();
+
+ // Adjustment about L2TP server timing
+ l2tp = s->L2TP;
+
+ if (l2tp->Interrupts == NULL)
+ {
+ l2tp->Interrupts = u->Interrupts;
+ }
+
+ if (l2tp->SockEvent == NULL)
+ {
+ SetL2TPServerSockEvent(l2tp, u->Event);
+ }
+
+ l2tp->Now = now;
+
+ // Adjustment about IKE server timing
+ ike = s->Ike;
+
+ if (ike->Interrupts == NULL)
+ {
+ ike->Interrupts = u->Interrupts;
+ }
+
+ if (ike->SockEvent == NULL)
+ {
+ SetIKEServerSockEvent(ike, u->Event);
+ }
+
+ ike->Now = now;
+
+ if (ipsec_disable == false)
+ {
+ // Process the received packet
+ for (i = 0;i < LIST_NUM(packet_list);i++)
+ {
+ UDPPACKET *p = LIST_DATA(packet_list, i);
+
+ IPsecProcPacket(s, p);
+ }
+ }
+
+ // Interrupt processing of L2TP server
+ L2TPProcessInterrupts(l2tp);
+
+ // L2TP packet transmission processing
+ UdpListenerSendPackets(u, l2tp->SendPacketList);
+ DeleteAll(l2tp->SendPacketList);
+
+ // Interrupt processing of IKE server
+ ProcessIKEInterrupts(ike);
+
+ // UDP encapsulation process of IKE server packet scheduled for transmission
+ for (i = 0;i < LIST_NUM(ike->SendPacketList);i++)
+ {
+ UDPPACKET *p = LIST_DATA(ike->SendPacketList, i);
+
+ if (p->Type == IKE_UDP_TYPE_ISAKMP && p->SrcPort == IPSEC_PORT_IPSEC_ESP_UDP)
+ {
+ // Add the Non-ESP Marker
+ void *old_data = p->Data;
+
+ p->Data = AddHead(p->Data, p->Size, zero8, 4);
+ p->Size += 4;
+
+ Free(old_data);
+ }
+ else if (p->Type == IKE_UDP_TYPE_ESP && p->SrcPort == IPSEC_PORT_IPSEC_ISAKMP)
+ {
+ // Add the Non-IKE Marker
+ void *old_data = p->Data;
+
+ p->Data = AddHead(p->Data, p->Size, zero8, 8);
+ p->Size += 8;
+
+ Free(old_data);
+ }
+ }
+
+ // IKE server packet transmission processing
+ UdpListenerSendPackets(u, ike->SendPacketList);
+ DeleteAll(ike->SendPacketList);
+}
+
+// Get the service list
+void IPsecServerGetServices(IPSEC_SERVER *s, IPSEC_SERVICES *sl)
+{
+ // Validate arguments
+ if (s == NULL || sl == NULL)
+ {
+ return;
+ }
+
+ Lock(s->LockSettings);
+ {
+ IPsecNormalizeServiceSetting(s);
+
+ Copy(sl, &s->Services, sizeof(IPSEC_SERVICES));
+ }
+ Unlock(s->LockSettings);
+}
+
+// Normalize the IPsec service setttings
+void IPsecNormalizeServiceSetting(IPSEC_SERVER *s)
+{
+ CEDAR *c;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ c = s->Cedar;
+
+ Lock(s->LockSettings);
+ {
+ bool reset_hub_setting = false;
+
+ if (IsEmptyStr(s->Services.IPsec_Secret))
+ {
+ // If the secret is not set, set the default one
+ StrCpy(s->Services.IPsec_Secret, sizeof(s->Services.IPsec_Secret), IPSEC_DEFAULT_SECRET);
+ }
+
+ LockList(c->HubList);
+ {
+ if (IsEmptyStr(s->Services.L2TP_DefaultHub))
+ {
+ reset_hub_setting = true;
+ }
+ else
+ {
+ if (IsHub(c, s->Services.L2TP_DefaultHub) == false)
+ {
+ reset_hub_setting = true;
+ }
+ }
+
+ if (reset_hub_setting)
+ {
+ // Select the first Virtual HUB if there is no HUB
+ HUB *h = NULL;
+
+ if (LIST_NUM(c->HubList) >= 1)
+ {
+ h = LIST_DATA(c->HubList, 0);
+ }
+
+ if (h != NULL)
+ {
+ StrCpy(s->Services.L2TP_DefaultHub, sizeof(s->Services.L2TP_DefaultHub), h->Name);
+ }
+ else
+ {
+ StrCpy(s->Services.L2TP_DefaultHub, sizeof(s->Services.L2TP_DefaultHub), "");
+ }
+ }
+ }
+ UnlockList(c->HubList);
+ }
+ Unlock(s->LockSettings);
+}
+
+// Set the service list
+void IPsecServerSetServices(IPSEC_SERVER *s, IPSEC_SERVICES *sl)
+{
+ // Validate arguments
+ if (s == NULL || sl == NULL)
+ {
+ return;
+ }
+
+ if (IsZero(sl, sizeof(IPSEC_SERVICES)) == false)
+ {
+ if (s->NoMoreChangeSettings)
+ {
+ return;
+ }
+ }
+
+ Lock(s->LockSettings);
+ {
+ Copy(&s->Services, sl, sizeof(IPSEC_SERVICES));
+
+ if (sl->L2TP_Raw)
+ {
+ AddPortToUdpListener(s->UdpListener, IPSEC_PORT_L2TP);
+ }
+ else
+ {
+ DeletePortFromUdpListener(s->UdpListener, IPSEC_PORT_L2TP);
+ }
+
+ if (sl->L2TP_IPsec || sl->EtherIP_IPsec)
+ {
+ AddPortToUdpListener(s->UdpListener, IPSEC_PORT_IPSEC_ISAKMP);
+ AddPortToUdpListener(s->UdpListener, IPSEC_PORT_IPSEC_ESP_UDP);
+ AddPortToUdpListener(s->UdpListener, IPSEC_PORT_IPSEC_ESP_RAW);
+ AddPortToUdpListener(s->UdpListener, IPSEC_PORT_IPSEC_ESP_RAW_WPF);
+ }
+ else
+ {
+ DeletePortFromUdpListener(s->UdpListener, IPSEC_PORT_IPSEC_ISAKMP);
+ DeletePortFromUdpListener(s->UdpListener, IPSEC_PORT_IPSEC_ESP_UDP);
+ DeletePortFromUdpListener(s->UdpListener, IPSEC_PORT_IPSEC_ESP_RAW);
+ DeletePortFromUdpListener(s->UdpListener, IPSEC_PORT_IPSEC_ESP_RAW_WPF);
+ }
+
+ if (IsEmptyStr(sl->IPsec_Secret) == false)
+ {
+ StrCpy(s->Ike->Secret, sizeof(s->Ike->Secret), sl->IPsec_Secret);
+ }
+
+ IPsecNormalizeServiceSetting(s);
+ }
+ Unlock(s->LockSettings);
+
+ Set(s->OsServiceCheckThreadEvent);
+}
+
+// Add the EtherIP key
+void AddEtherIPId(IPSEC_SERVER *s, ETHERIP_ID *id)
+{
+ // Validate arguments
+ if (s == NULL || id == NULL)
+ {
+ return;
+ }
+
+ Lock(s->LockSettings);
+ {
+ // If there is the same key, remove them
+ ETHERIP_ID t, *k;
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Id, sizeof(t.Id), id->Id);
+
+ k = Search(s->EtherIPIdList, &t);
+
+ if (k != NULL)
+ {
+ Delete(s->EtherIPIdList, k);
+
+ Free(k);
+ }
+
+ // Add
+ k = Clone(id, sizeof(ETHERIP_ID));
+
+ Insert(s->EtherIPIdList, k);
+
+ s->EtherIPIdListSettingVerNo++;
+ }
+ Unlock(s->LockSettings);
+}
+
+// Delete the EtherIP key
+bool DeleteEtherIPId(IPSEC_SERVER *s, char *id_str)
+{
+ bool ret = false;
+ // Validate arguments
+ if (s == NULL || id_str == NULL)
+ {
+ return false;
+ }
+
+ Lock(s->LockSettings);
+ {
+ // If there is the same key, remove them
+ ETHERIP_ID t, *k;
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Id, sizeof(t.Id), id_str);
+
+ k = Search(s->EtherIPIdList, &t);
+
+ if (k != NULL)
+ {
+ Delete(s->EtherIPIdList, k);
+
+ Free(k);
+
+ ret = true;
+
+ s->EtherIPIdListSettingVerNo++;
+ }
+ }
+ Unlock(s->LockSettings);
+
+ return ret;
+}
+
+// Search the EtherIP key
+bool SearchEtherIPId(IPSEC_SERVER *s, ETHERIP_ID *id, char *id_str)
+{
+ bool ret = false;
+ // Validate arguments
+ if (s == NULL || id == NULL || id_str == NULL)
+ {
+ return false;
+ }
+
+ Lock(s->LockSettings);
+ {
+ ETHERIP_ID t, *k;
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.Id, sizeof(t.Id), id_str);
+
+ k = Search(s->EtherIPIdList, &t);
+
+ if (k != NULL)
+ {
+ Copy(id, k, sizeof(ETHERIP_ID));
+
+ ret = true;
+ }
+ }
+ Unlock(s->LockSettings);
+
+ return ret;
+}
+
+// Comparison of key EtherIP list entries
+int CmpEtherIPId(void *p1, void *p2)
+{
+ ETHERIP_ID *k1, *k2;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ k1 = *(ETHERIP_ID **)p1;
+ k2 = *(ETHERIP_ID **)p2;
+ if (k1 == NULL || k2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(k1->Id, k2->Id);
+}
+
+// Release and stop the IPsec server
+void FreeIPsecServer(IPSEC_SERVER *s)
+{
+ UINT i;
+ IPSEC_SERVICES sl;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ s->NoMoreChangeSettings = true;
+
+ // Stopp the L2TP server
+ StopL2TPServer(s->L2TP, false);
+
+ // Stop the IKE server
+ StopIKEServer(s->Ike);
+
+ // Stop all the services explicitly
+ Zero(&sl, sizeof(sl));
+ IPsecServerSetServices(s, &sl);
+
+ // Releasing process
+ FreeUdpListener(s->UdpListener);
+
+ ReleaseCedar(s->Cedar);
+
+ FreeL2TPServer(s->L2TP);
+
+ FreeIKEServer(s->Ike);
+
+ for (i = 0;i < LIST_NUM(s->EtherIPIdList);i++)
+ {
+ ETHERIP_ID *k = LIST_DATA(s->EtherIPIdList, i);
+
+ Free(k);
+ }
+
+ ReleaseList(s->EtherIPIdList);
+
+ // Stop the OS monitoring thread
+ s->Halt = true;
+ Set(s->OsServiceCheckThreadEvent);
+ WaitThread(s->OsServiceCheckThread, INFINITE);
+ ReleaseThread(s->OsServiceCheckThread);
+ ReleaseEvent(s->OsServiceCheckThreadEvent);
+
+ DeleteLock(s->LockSettings);
+
+ Free(s);
+}
+
+// Initialize the IPsec server
+IPSEC_SERVER *NewIPsecServer(CEDAR *cedar)
+{
+ IPSEC_SERVER *s;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ s = ZeroMalloc(sizeof(IPSEC_SERVER));
+
+ s->LockSettings = NewLock();
+
+ s->Cedar = cedar;
+
+ AddRef(s->Cedar->ref);
+
+ s->L2TP = NewL2TPServer(cedar);
+
+ s->Ike = NewIKEServer(cedar, s);
+ StrCpy(s->Ike->Secret, sizeof(s->Ike->Secret), IPSEC_DEFAULT_SECRET);
+
+ s->UdpListener = NewUdpListener(IPsecServerUdpPacketRecvProc, s);
+
+ s->EtherIPIdList = NewList(CmpEtherIPId);
+
+ // Start an OS service monitoring thread
+ s->OsServiceCheckThreadEvent = NewEvent();
+ s->OsServiceCheckThread = NewThread(IPsecOsServiceCheckThread, s);
+
+ return s;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec.h b/src/Cedar/IPsec.h
new file mode 100644
index 00000000..48b297c8
--- /dev/null
+++ b/src/Cedar/IPsec.h
@@ -0,0 +1,179 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec.h
+// Header of IPsec.c
+
+#ifndef IPSEC_H
+#define IPSEC_H
+
+//// Constants
+
+// UDP port number
+#define IPSEC_PORT_L2TP 1701 // L2TP
+#define IPSEC_PORT_IPSEC_ISAKMP 500 // ISAKMP
+#define IPSEC_PORT_IPSEC_ESP_UDP 4500 // IPsec ESP over UDP
+#define IPSEC_PORT_IPSEC_ESP_RAW MAKE_SPECIAL_PORT(50) // Raw mode ESP Protocol No: 50
+#define IPSEC_PORT_IPSEC_ESP_RAW_WPF MAKE_SPECIAL_PORT(52) // Raw mode ESP Protocol No: 52 (WPF)
+#define IPSEC_PORT_L2TPV3_VIRTUAL 1000001 // L2TPv3 virtual port
+
+// IP protocol number
+#define IPSEC_IP_PROTO_ETHERIP IP_PROTO_ETHERIP // EtherIP
+#define IPSEC_IP_PROTO_L2TPV3 IP_PROTO_L2TPV3 // L2TPv3
+
+// WFP tag
+#define WFP_ESP_PACKET_TAG_1 0x19841117
+#define WFP_ESP_PACKET_TAG_2 0x1accafe1
+
+// Monitoring interval of OS service
+#define IPSEC_CHECK_OS_SERVICE_INTERVAL_INITIAL 1024
+#define IPSEC_CHECK_OS_SERVICE_INTERVAL_MAX (5 * 60 * 1000)
+
+// Default IPsec pre-shared key
+#define IPSEC_DEFAULT_SECRET "vpn"
+
+
+//// Type
+
+// List of services provided by IPsec server
+struct IPSEC_SERVICES
+{
+ bool L2TP_Raw; // Raw L2TP
+ bool L2TP_IPsec; // L2TP over IPsec
+ bool EtherIP_IPsec; // EtherIP over IPsec
+
+ char IPsec_Secret[MAX_SIZE]; // IPsec pre-shared key
+ char L2TP_DefaultHub[MAX_SIZE]; // Default Virtual HUB name for L2TP connection
+};
+
+// EtherIP key list entry
+struct ETHERIP_ID
+{
+ char Id[MAX_SIZE]; // ID
+ char HubName[MAX_HUBNAME_LEN + 1]; // Virtual HUB name
+ char UserName[MAX_USERNAME_LEN + 1]; // User name
+ char Password[MAX_USERNAME_LEN + 1]; // Password
+};
+
+// IPsec server
+struct IPSEC_SERVER
+{
+ CEDAR *Cedar;
+ UDPLISTENER *UdpListener;
+ bool Halt;
+ bool NoMoreChangeSettings;
+ LOCK *LockSettings;
+ IPSEC_SERVICES Services;
+ L2TP_SERVER *L2TP; // L2TP server
+ IKE_SERVER *Ike; // IKE server
+ LIST *EtherIPIdList; // EtherIP setting list
+ UINT EtherIPIdListSettingVerNo; // EtherIP setting list version number
+ THREAD *OsServiceCheckThread; // OS Service monitoring thread
+ EVENT *OsServiceCheckThreadEvent; // Event for OS Service monitoring thread
+ IPSEC_WIN7 *Win7; // Helper module for Windows Vista / 7
+ bool Check_LastEnabledStatus;
+ bool HostIPAddressListChanged;
+ bool OsServiceStoped;
+};
+
+
+//// Function prototype
+IPSEC_SERVER *NewIPsecServer(CEDAR *cedar);
+void FreeIPsecServer(IPSEC_SERVER *s);
+void IPsecServerUdpPacketRecvProc(UDPLISTENER *u, LIST *packet_list);
+void IPsecServerSetServices(IPSEC_SERVER *s, IPSEC_SERVICES *sl);
+void IPsecNormalizeServiceSetting(IPSEC_SERVER *s);
+void IPsecServerGetServices(IPSEC_SERVER *s, IPSEC_SERVICES *sl);
+void IPsecProcPacket(IPSEC_SERVER *s, UDPPACKET *p);
+int CmpEtherIPId(void *p1, void *p2);
+bool SearchEtherIPId(IPSEC_SERVER *s, ETHERIP_ID *id, char *id_str);
+void AddEtherIPId(IPSEC_SERVER *s, ETHERIP_ID *id);
+bool DeleteEtherIPId(IPSEC_SERVER *s, char *id_str);
+void IPsecOsServiceCheckThread(THREAD *t, void *p);
+bool IPsecCheckOsService(IPSEC_SERVER *s);
+void IPSecSetDisable(bool b);
+
+
+#endif // IPSEC_H
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_EtherIP.c b/src/Cedar/IPsec_EtherIP.c
new file mode 100644
index 00000000..632df40b
--- /dev/null
+++ b/src/Cedar/IPsec_EtherIP.c
@@ -0,0 +1,539 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_EtherIP.c
+// EtherIP protocol stack
+
+#include "CedarPch.h"
+
+// IPC connection processing thread
+void EtherIPIpcConnectThread(THREAD *t, void *p)
+{
+ ETHERIP_SERVER *s;
+ IPC *ipc = NULL;
+ UINT error_code = 0;
+ char tmp[MAX_SIZE];
+ ETHERIP_ID id;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ s = (ETHERIP_SERVER *)p;
+
+ GetHostName(tmp, sizeof(tmp), &s->ClientIP);
+
+ // Get the setting of the virtual HUB to be connected based on the client ID presented
+ if (SearchEtherIPId(s->Ike->IPsec, &id, s->ClientId) == false &&
+ SearchEtherIPId(s->Ike->IPsec, &id, "*") == false)
+ {
+ // Failed to get the settings for the virtual HUB
+ Debug("Not Found: EtherIP Settings for Client ID \"%s\".\n", s->ClientId);
+
+ EtherIPLog(s, "LE_NO_SETTING", s->ClientId);
+ }
+ else
+ {
+ UINT mss = CalcEtherIPTcpMss(s);
+ char client_name[MAX_SIZE];
+
+ if (s->L2TPv3 == false)
+ {
+ StrCpy(client_name, sizeof(client_name), ETHERIP_CLIENT_NAME);
+ }
+ else
+ {
+ if (IsEmptyStr(s->VendorName))
+ {
+ StrCpy(client_name, sizeof(client_name), ETHERIP_L2TPV3_CLIENT_NAME);
+ }
+ else
+ {
+ Format(client_name, sizeof(client_name), ETHERIP_L2TPV3_CLIENT_NAME_EX, s->VendorName);
+ }
+ }
+
+ // Execution of IPC connection process
+ EtherIPLog(s, "LE_START_IPC", id.HubName, id.UserName, mss);
+ ipc = NewIPC(s->Cedar, client_name,
+ (s->L2TPv3 ? ETHERIP_L2TPV3_POSTFIX : ETHERIP_POSTFIX),
+ id.HubName, id.UserName, id.Password,
+ &error_code,
+ &s->ClientIP, s->ClientPort,
+ &s->ServerIP, s->ServerPort,
+ tmp,
+ s->CryptName, true, mss);
+
+ if (ipc != NULL)
+ {
+ Copy(&s->CurrentEtherIPIdSetting, &id, sizeof(ETHERIP_ID));
+ EtherIPLog(s, "LE_IPC_CONNECT_OK", id.HubName);
+ }
+ else
+ {
+ EtherIPLog(s, "LE_IPC_CONNECT_ERROR", id.HubName, error_code, _E(error_code));
+ }
+ }
+
+ Lock(s->Lock);
+ {
+ // Set the results
+ ReleaseThread(s->IpcConnectThread);
+ s->IpcConnectThread = NULL;
+
+ s->Ipc = ipc;
+
+ s->LastConnectFailedTick = Tick64();
+ }
+ Unlock(s->Lock);
+
+ // Hit the event to cause interrupt
+ SetSockEvent(s->SockEvent);
+
+ // Release the EtherIP object that is hold by this thread
+ ReleaseEtherIPServer(s);
+}
+
+// Processing of the interrupt
+void EtherIPProcInterrupts(ETHERIP_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ // If EtherIP settings have been changed, and the change may effect to this connection, disconnect
+ if (s->Ipc != NULL)
+ {
+ if (s->Ike->IPsec->EtherIPIdListSettingVerNo != s->LastEtherIPSettingVerNo)
+ {
+ ETHERIP_ID id;
+ bool ok = true;
+
+ s->LastEtherIPSettingVerNo = s->Ike->IPsec->EtherIPIdListSettingVerNo;
+
+ if (SearchEtherIPId(s->IPsec, &id, s->ClientId) == false &&
+ SearchEtherIPId(s->IPsec, &id, "*") == false)
+ {
+ ok = false;
+ }
+ else
+ {
+ if (StrCmpi(s->CurrentEtherIPIdSetting.HubName, id.HubName) != 0 ||
+ StrCmpi(s->CurrentEtherIPIdSetting.UserName, id.UserName) != 0 ||
+ StrCmp(s->CurrentEtherIPIdSetting.Password, id.Password) != 0)
+ {
+ ok = false;
+ }
+ }
+
+ if (ok == false)
+ {
+ // Disconnect immediately since setting of EtherIP seems to have been changed
+ FreeIPC(s->Ipc);
+ s->Ipc = NULL;
+
+ EtherIPLog(s, "LE_RECONNECT");
+ }
+ }
+ }
+
+ // Connect if IPC connection is not completed
+ Lock(s->Lock);
+ {
+ if (s->Ipc == NULL)
+ {
+ if (s->IpcConnectThread == NULL)
+ {
+ if ((s->LastConnectFailedTick == 0) || ((s->LastConnectFailedTick + (UINT64)ETHERIP_VPN_CONNECT_RETRY_INTERVAL) <= s->Now))
+ {
+ Lock(s->IPsec->LockSettings);
+ {
+ Copy(&s->CurrentIPSecServiceSetting, &s->IPsec->Services, sizeof(IPSEC_SERVICES));
+ }
+ Unlock(s->IPsec->LockSettings);
+
+ s->IpcConnectThread = NewThread(EtherIPIpcConnectThread, s);
+ AddThreadToThreadList(s->Ike->ThreadList, s->IpcConnectThread);
+ AddRef(s->Ref);
+ }
+ }
+ }
+ }
+ Unlock(s->Lock);
+
+ if (s->Ipc != NULL)
+ {
+ // Set to get hit the SockEvent when a packet arrives via the IPC
+ IPCSetSockEventWhenRecvL2Packet(s->Ipc, s->SockEvent);
+
+ // IPC interrupt processing
+ IPCProcessInterrupts(s->Ipc);
+
+ // Receive the MAC frame which arrived via the IPC
+ while (true)
+ {
+ BLOCK *b = IPCRecvL2(s->Ipc);
+ UCHAR *dst;
+ UINT dst_size;
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ if (b->Size >= 14)
+ {
+ BLOCK *block;
+
+ // Store the arrived MAC frame by adding an EtherIP header to the reception packet queue
+
+ if (s->L2TPv3 == false)
+ {
+ dst_size = b->Size + 2;
+ dst = Malloc(dst_size);
+
+ dst[0] = 0x30;
+ dst[1] = 0x00;
+
+ Copy(dst + 2, b->Buf, b->Size);
+ }
+ else
+ {
+ dst = Clone(b->Buf, b->Size);
+ dst_size = b->Size;
+ }
+
+ block = NewBlock(dst, dst_size, 0);
+
+ Add(s->SendPacketList, block);
+ }
+
+ FreeBlock(b);
+ }
+
+ if (IsIPCConnected(s->Ipc) == false)
+ {
+ // IPC connection is disconnected
+ FreeIPC(s->Ipc);
+ s->Ipc = NULL;
+ }
+ }
+}
+
+// Process the received packet
+void EtherIPProcRecvPackets(ETHERIP_SERVER *s, BLOCK *b)
+{
+ UCHAR *src;
+ UINT src_size;
+ // Validate arguments
+ if (s == NULL || b == NULL)
+ {
+ return;
+ }
+
+ if (s->Ipc == NULL)
+ {
+ // Not connected to the Virtual HUB
+ return;
+ }
+
+ src = b->Buf;
+ src_size = b->Size;
+
+ if (s->L2TPv3 == false)
+ {
+ // EtherIP header confirmation
+ if (src_size < 2)
+ {
+ return;
+ }
+
+ if ((src[0] & 0xf0) != 0x30)
+ {
+ return;
+ }
+
+ src += 2;
+ src_size -= 2;
+ }
+
+ if (src_size < 14)
+ {
+ // The size of the MAC frame is less than 14 bytes
+ return;
+ }
+
+ // Send by IPC since a MAC frame has been received
+ IPCSendL2(s->Ipc, src, src_size);
+}
+
+// Create a new EtherIP server
+ETHERIP_SERVER *NewEtherIPServer(CEDAR *cedar, IPSEC_SERVER *ipsec, IKE_SERVER *ike,
+ IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, char *crypt_name,
+ bool is_tunnel_mode, UINT crypt_block_size,
+ char *client_id, UINT id)
+{
+ ETHERIP_SERVER *s;
+ // Validate arguments
+ if (cedar == NULL || ipsec == NULL || ike == NULL || client_ip == NULL || server_ip == NULL || client_id == NULL)
+ {
+ return NULL;
+ }
+
+ s = ZeroMalloc(sizeof(ETHERIP_SERVER));
+
+ s->Ref = NewRef();
+
+ s->Id = id;
+
+ s->Cedar = cedar;
+ AddRef(s->Cedar->ref);
+ s->IPsec = ipsec;
+ s->Ike = ike;
+ s->IsTunnelMode = is_tunnel_mode;
+
+ StrCpy(s->ClientId, sizeof(s->ClientId), client_id);
+
+ s->SendPacketList = NewList(NULL);
+
+ s->Now = Tick64();
+
+ s->Lock = NewLock();
+
+ Copy(&s->ClientIP, client_ip, sizeof(IP));
+ s->ClientPort = client_port;
+
+ Copy(&s->ServerIP, server_ip, sizeof(IP));
+ s->ServerPort = server_port;
+
+ StrCpy(s->CryptName, sizeof(s->CryptName), crypt_name);
+ s->CryptBlockSize = crypt_block_size;
+
+ EtherIPLog(s, "LE_START_MODULE");
+
+ return s;
+}
+
+// Release the EtherIP server
+void ReleaseEtherIPServer(ETHERIP_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ if (Release(s->Ref) == 0)
+ {
+ CleanupEtherIPServer(s);
+ }
+}
+void CleanupEtherIPServer(ETHERIP_SERVER *s)
+{
+ UINT i;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ EtherIPLog(s, "LE_STOP");
+
+ if (s->IpcConnectThread != NULL)
+ {
+ ReleaseThread(s->IpcConnectThread);
+ }
+
+ if (s->Ipc != NULL)
+ {
+ FreeIPC(s->Ipc);
+ }
+
+ for (i = 0;i < LIST_NUM(s->SendPacketList);i++)
+ {
+ BLOCK *b = LIST_DATA(s->SendPacketList, i);
+
+ FreeBlock(b);
+ }
+
+ ReleaseList(s->SendPacketList);
+
+ ReleaseSockEvent(s->SockEvent);
+
+ ReleaseCedar(s->Cedar);
+
+ DeleteLock(s->Lock);
+
+ Free(s);
+}
+
+
+// Set SockEvent to EtherIP server
+void SetEtherIPServerSockEvent(ETHERIP_SERVER *s, SOCK_EVENT *e)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ if (e != NULL)
+ {
+ AddRef(e->ref);
+ }
+
+ if (s->SockEvent != NULL)
+ {
+ ReleaseSockEvent(s->SockEvent);
+ s->SockEvent = NULL;
+ }
+
+ s->SockEvent = e;
+}
+
+// Calculate the proper TCP MSS in EtherIP communication
+UINT CalcEtherIPTcpMss(ETHERIP_SERVER *s)
+{
+ UINT ret = MTU_FOR_PPPOE;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return 0;
+ }
+
+ // IPv4 / IPv6
+ if (IsIP4(&s->ClientIP))
+ {
+ ret -= 20;
+ }
+ else
+ {
+ ret -= 40;
+ }
+
+ // IPsec UDP
+ ret -= 8;
+
+ // IPsec ESP
+ ret -= 20;
+ ret -= s->CryptBlockSize * 2;
+
+ // IPsec Tunnel Mode IPv4 / IPv6 Header
+ if (s->IsTunnelMode)
+ {
+ if (IsIP4(&s->ClientIP))
+ {
+ ret -= 20;
+ }
+ else
+ {
+ ret -= 40;
+ }
+ }
+
+ if (s->L2TPv3 == false)
+ {
+ // EtherIP
+ ret -= 2;
+ }
+ else
+ {
+ // L2TPv3
+ ret -= 2;
+ }
+
+ // Ethernet
+ ret -= 14;
+
+ // IPv4
+ ret -= 20;
+
+ // TCP
+ ret -= 20;
+
+ return ret;
+}
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_EtherIP.h b/src/Cedar/IPsec_EtherIP.h
new file mode 100644
index 00000000..a0be2bf5
--- /dev/null
+++ b/src/Cedar/IPsec_EtherIP.h
@@ -0,0 +1,150 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_EtherIP.h
+// Header of IPsec_EtherIP.c
+
+#ifndef IPSEC_ETHERIP_H
+#define IPSEC_ETHERIP_H
+
+//// Macro
+
+
+//// Constants
+#define ETHERIP_VPN_CONNECT_RETRY_INTERVAL (15 * 1000) // VPN connection retry interval
+#define ETHERIP_CLIENT_NAME "EtherIP Client"
+#define ETHERIP_POSTFIX "ETHERIP"
+#define ETHERIP_L2TPV3_CLIENT_NAME "L2TPv3 Client"
+#define ETHERIP_L2TPV3_CLIENT_NAME_EX "L2TPv3 Client - %s"
+#define ETHERIP_L2TPV3_POSTFIX "L2TPV3"
+
+//// Type
+
+// EtherIP server
+struct ETHERIP_SERVER
+{
+ REF *Ref;
+ CEDAR *Cedar;
+ IPSEC_SERVER *IPsec;
+ LOCK *Lock;
+ UINT Id;
+ IKE_SERVER *Ike;
+ UINT64 Now; // Current time
+ INTERRUPT_MANAGER *Interrupts; // Interrupt manager
+ SOCK_EVENT *SockEvent; // SockEvent
+ char CryptName[MAX_SIZE]; // Cipher algorithm name
+ LIST *SendPacketList; // Transmission packet list
+ UINT64 LastConnectFailedTick; // Time that it fails to connect at the last
+ IPC *Ipc; // IPC
+ THREAD *IpcConnectThread; // IPC connection thread
+ IPSEC_SERVICES CurrentIPSecServiceSetting; // Copy of the current IPsec service settings
+ IP ClientIP, ServerIP;
+ UINT ClientPort, ServerPort;
+ bool IsTunnelMode; // Whether the IPsec is in the tunnel mode
+ UINT CryptBlockSize; // Encryption block size of IPsec
+ char ClientId[MAX_SIZE]; // Client ID has been presented by the IPsec connection
+ UINT LastEtherIPSettingVerNo; // Version number of EtherIP settings last checked
+ ETHERIP_ID CurrentEtherIPIdSetting; // Current EtherIP ID settings
+ bool L2TPv3; // L2TPv3 mode
+ char VendorName[MAX_SIZE]; // Vendor name
+};
+
+
+//// Function prototype
+ETHERIP_SERVER *NewEtherIPServer(CEDAR *cedar, IPSEC_SERVER *ipsec, IKE_SERVER *ike,
+ IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, char *crypt_name,
+ bool is_tunnel_mode, UINT crypt_block_size,
+ char *client_id, UINT id);
+void ReleaseEtherIPServer(ETHERIP_SERVER *s);
+void CleanupEtherIPServer(ETHERIP_SERVER *s);
+void SetEtherIPServerSockEvent(ETHERIP_SERVER *s, SOCK_EVENT *e);
+void EtherIPProcInterrupts(ETHERIP_SERVER *s);
+void EtherIPProcRecvPackets(ETHERIP_SERVER *s, BLOCK *b);
+void EtherIPIpcConnectThread(THREAD *t, void *p);
+UINT CalcEtherIPTcpMss(ETHERIP_SERVER *s);
+
+
+#endif // IPSEC_ETHERIP_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_IKE.c b/src/Cedar/IPsec_IKE.c
new file mode 100644
index 00000000..7156b735
--- /dev/null
+++ b/src/Cedar/IPsec_IKE.c
@@ -0,0 +1,5947 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_IKE.c
+// IKE (ISAKMP) and ESP protocol stack
+
+#include "CedarPch.h"
+
+
+// Processing of IKE received packet
+void ProcIKEPacketRecv(IKE_SERVER *ike, UDPPACKET *p)
+{
+ // Validate arguments
+ if (ike == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (p->Type == IKE_UDP_TYPE_ISAKMP)
+ {
+ // ISAKMP (IKE) packet
+ IKE_PACKET *header;
+
+ header = ParseIKEPacketHeader(p);
+ if (header == NULL)
+ {
+ return;
+ }
+
+ //Debug("InitiatorCookie: %I64u, ResponderCookie: %I64u\n", header->InitiatorCookie, header->ResponderCookie);
+
+ switch (header->ExchangeType)
+ {
+ case IKE_EXCHANGE_TYPE_MAIN: // Main mode
+ ProcIkeMainModePacketRecv(ike, p, header);
+ break;
+
+ case IKE_EXCHANGE_TYPE_AGGRESSIVE: // Aggressive mode
+ ProcIkeAggressiveModePacketRecv(ike, p, header);
+ break;
+
+ case IKE_EXCHANGE_TYPE_QUICK: // Quick mode
+ ProcIkeQuickModePacketRecv(ike, p, header);
+ break;
+
+ case IKE_EXCHANGE_TYPE_INFORMATION: // Information exchange
+ ProcIkeInformationalExchangePacketRecv(ike, p, header);
+ break;
+ }
+
+ IkeFree(header);
+ }
+ else if (p->Type == IKE_UDP_TYPE_ESP)
+ {
+ // ESP packet
+ ProcIPsecEspPacketRecv(ike, p);
+ }
+}
+
+// Send a packet via IPsec
+void IPsecSendPacketByIPsecSa(IKE_SERVER *ike, IPSECSA *sa, UCHAR *data, UINT data_size, UCHAR protocol_id)
+{
+ bool is_tunnel_mode;
+ IKE_CLIENT *c;
+ // Validate arguments
+ if (ike == NULL || sa == NULL || data == NULL || data_size == 0)
+ {
+ return;
+ }
+
+ is_tunnel_mode = IsIPsecSaTunnelMode(sa);
+
+ c = sa->IkeClient;
+
+ if (c == NULL)
+ {
+ return;
+ }
+
+ if (is_tunnel_mode)
+ {
+ // Add an IPv4 / IPv6 header in the case of tunnel mode
+ if (IsZeroIP(&c->TunnelModeClientIP) == false || IsZeroIP(&c->TunnelModeServerIP) == false)
+ {
+ BUF *b;
+ UCHAR esp_proto_id;
+
+ b = NewBuf();
+
+ if (IsIP4(&c->TunnelModeClientIP))
+ {
+ // IPv4 header
+ IPV4_HEADER h;
+
+ h.VersionAndHeaderLength = 0;
+ h.TypeOfService = 0;
+ IPV4_SET_VERSION(&h, 4);
+ IPV4_SET_HEADER_LEN(&h, sizeof(IPV4_HEADER) / 4);
+ h.TotalLength = Endian16((USHORT)(data_size + sizeof(IPV4_HEADER)));
+ h.Identification = Endian16(c->TunnelSendIpId++);
+ h.FlagsAndFlagmentOffset[0] = h.FlagsAndFlagmentOffset[1] = 0;
+ h.TimeToLive = DEFAULT_IP_TTL;
+ h.Protocol = protocol_id;
+ h.SrcIP = IPToUINT(&c->TunnelModeServerIP);
+ h.DstIP = IPToUINT(&c->TunnelModeClientIP);
+ h.Checksum = 0;
+ h.Checksum = IpChecksum(&h, sizeof(IPV4_HEADER));
+
+ WriteBuf(b, &h, sizeof(IPV4_HEADER));
+
+ esp_proto_id = IKE_PROTOCOL_ID_IPV4;
+ }
+ else
+ {
+ // IPv6 header
+ IPV6_HEADER h;
+
+ Zero(&h, sizeof(h));
+ h.VersionAndTrafficClass1 = 0;
+ IPV6_SET_VERSION(&h, 6);
+ h.TrafficClass2AndFlowLabel1 = 0;
+ h.FlowLabel2 = h.FlowLabel3 = 0;
+ h.PayloadLength = Endian16(data_size);
+ h.NextHeader = protocol_id;
+ h.HopLimit = 64;
+ Copy(h.SrcAddress.Value, c->TunnelModeServerIP.ipv6_addr, 16);
+ Copy(h.DestAddress.Value, c->TunnelModeClientIP.ipv6_addr, 16);
+
+ WriteBuf(b, &h, sizeof(IPV6_HEADER));
+
+ esp_proto_id = IKE_PROTOCOL_ID_IPV6;
+ }
+
+ WriteBuf(b, data, data_size);
+
+ IPsecSendPacketByIPsecSaInner(ike, sa, b->Buf, b->Size, esp_proto_id);
+
+ FreeBuf(b);
+ }
+ }
+ else
+ {
+ // Send as it is in the case of transport mode
+ IPsecSendPacketByIPsecSaInner(ike, sa, data, data_size, protocol_id);
+ }
+}
+void IPsecSendPacketByIPsecSaInner(IKE_SERVER *ike, IPSECSA *sa, UCHAR *data, UINT data_size, UCHAR protocol_id)
+{
+ UINT esp_size;
+ UINT encrypted_payload_size;
+ UCHAR *esp;
+ UINT i;
+ UINT size_of_padding;
+ IKE_CRYPTO_PARAM cp;
+ BUF *enc;
+ IKE_CLIENT *c;
+ // Validate arguments
+ if (ike == NULL || sa == NULL || data == NULL || data_size == 0)
+ {
+ return;
+ }
+
+ c = sa->IkeClient;
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Calculate the payload size after encryption
+ encrypted_payload_size = data_size + 2;
+ if ((encrypted_payload_size % sa->TransformSetting.Crypto->BlockSize) != 0)
+ {
+ encrypted_payload_size = ((encrypted_payload_size / sa->TransformSetting.Crypto->BlockSize) + 1) * sa->TransformSetting.Crypto->BlockSize;
+ }
+ size_of_padding = encrypted_payload_size - data_size - 2;
+
+ // Calculate the size of the ESP packet
+ esp_size = sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize + encrypted_payload_size + IKE_ESP_HASH_SIZE;
+
+ // Build the ESP packet
+ esp = Malloc(esp_size + IKE_MAX_HASH_SIZE);
+
+ // SPI
+ WRITE_UINT(esp, sa->Spi);
+
+ // Sequence number
+ sa->CurrentSeqNo++;
+ WRITE_UINT(esp + sizeof(UINT), sa->CurrentSeqNo);
+
+ // IV
+ Copy(esp + sizeof(UINT) * 2, sa->EspIv, sa->TransformSetting.Crypto->BlockSize);
+
+ // Payload data
+ Copy(esp + sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize, data, data_size);
+
+ // Padding
+ for (i = 0;i < size_of_padding;i++)
+ {
+ esp[sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize + data_size + i] = (UCHAR)(i + 1);
+ }
+
+ // Padding length
+ esp[sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize + data_size + size_of_padding] = (UCHAR)size_of_padding;
+
+ // Next header number
+ esp[sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize + data_size + size_of_padding + 1] = protocol_id;
+
+ // Encryption
+ Copy(cp.Iv, sa->EspIv, sa->TransformSetting.Crypto->BlockSize);
+ cp.Key = sa->CryptoKey;
+
+ enc = IkeEncrypt(esp + sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize, encrypted_payload_size, &cp);
+ if (enc != NULL)
+ {
+ bool start_qm = false;
+ UINT server_port = c->ServerPort;
+ UINT client_port = c->ClientPort;
+
+ // Overwrite the encrypted result
+ Copy(esp + sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize, enc->Buf, encrypted_payload_size);
+
+ FreeBuf(enc);
+
+ // Calculate the HMAC
+ IkeHMac(sa->TransformSetting.Hash,
+ esp + sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize + encrypted_payload_size,
+ sa->HashKey,
+ sa->TransformSetting.Hash->HashSize,
+ esp,
+ sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize + encrypted_payload_size);
+
+ //*(UCHAR *)(esp + sizeof(UINT) * 2 + sa->TransformSetting.Crypto->BlockSize + encrypted_payload_size) = 0xff;
+
+ if (sa->TransformSetting.CapsuleMode == IKE_P2_CAPSULE_TRANSPORT ||
+ sa->TransformSetting.CapsuleMode == IKE_P2_CAPSULE_TUNNEL)
+ {
+ server_port = client_port = IPSEC_PORT_IPSEC_ESP_RAW;
+ }
+
+ // Add the completed packet to the transmission list
+ IkeSendUdpPacket(ike, IKE_UDP_TYPE_ESP, &c->ServerIP, server_port, &c->ClientIP, client_port,
+ esp, esp_size);
+
+ // Feedback the IV
+ Copy(sa->EspIv, cp.NextIv, sa->TransformSetting.Crypto->BlockSize);
+
+ sa->TotalSize += esp_size;
+
+ if (sa->CurrentSeqNo >= 0xf0000000)
+ {
+ start_qm = true;
+ }
+
+ if (sa->TransformSetting.LifeKilobytes != 0)
+ {
+ UINT64 hard_size = (UINT64)sa->TransformSetting.LifeKilobytes * (UINT64)1000;
+ UINT64 soft_size = hard_size * (UINT64)2 / (UINT64)3;
+
+ if (sa->TotalSize >= soft_size)
+ {
+ start_qm = true;
+ }
+ }
+
+ if (start_qm)
+ {
+ if (sa->StartQM_FlagSet == false)
+ {
+ sa->StartQM_FlagSet = true;
+ c->StartQuickModeAsSoon = true;
+ }
+ }
+ }
+ else
+ {
+ // Encryption failure
+ Free(esp);
+ }
+}
+void IPsecSendPacketByIkeClient(IKE_SERVER *ike, IKE_CLIENT *c, UCHAR *data, UINT data_size, UCHAR protocol_id)
+{
+ // Validate arguments
+ if (ike == NULL || c == NULL || data == NULL || data_size == 0)
+ {
+ return;
+ }
+
+ if (c->CurrentIpSecSaSend == NULL)
+ {
+ return;
+ }
+
+ IPsecSendPacketByIPsecSa(ike, c->CurrentIpSecSaSend, data, data_size, protocol_id);
+}
+
+// Send an UDP packet via IPsec
+void IPsecSendUdpPacket(IKE_SERVER *ike, IKE_CLIENT *c, UINT src_port, UINT dst_port, UCHAR *data, UINT data_size)
+{
+ UCHAR *udp;
+ UINT udp_size;
+ UDP_HEADER *u;
+ UCHAR tmp1600[1600];
+ bool no_free = false;
+ // Validate arguments
+ if (ike == NULL || c == NULL || data == NULL || data_size == 0)
+ {
+ return;
+ }
+
+ // Build an UDP packet
+ udp_size = sizeof(UDP_HEADER) + data_size;
+
+ if (udp_size > sizeof(tmp1600))
+ {
+ udp = Malloc(udp_size);
+ }
+ else
+ {
+ udp = tmp1600;
+ no_free = true;
+ }
+
+ // UDP header
+ u = (UDP_HEADER *)udp;
+ u->SrcPort = Endian16(src_port);
+ u->DstPort = Endian16(dst_port);
+ u->PacketLength = Endian16(udp_size);
+ u->Checksum = 0;
+
+ //Debug("IPsec UDP Send: %u -> %u %u\n", src_port, dst_port, data_size);
+#ifdef RAW_DEBUG
+ IPsecIkeSendUdpForDebug(IPSEC_PORT_L2TP, 1, data, data_size);
+#endif // RAW_DEBUG
+
+ // Payload
+ Copy(udp + sizeof(UDP_HEADER), data, data_size);
+
+ if (IsIP6(&c->ClientIP))
+ {
+ if (IsIPsecSaTunnelMode(c->CurrentIpSecSaSend) == false)
+ {
+ u->Checksum = CalcChecksumForIPv6((IPV6_ADDR *)c->TransportModeServerIP.ipv6_addr,
+ (IPV6_ADDR *)c->TransportModeClientIP.ipv6_addr,
+ IP_PROTO_UDP,
+ u,
+ udp_size, 0);
+ }
+ else
+ {
+ u->Checksum = CalcChecksumForIPv6((IPV6_ADDR *)c->TunnelModeServerIP.ipv6_addr,
+ (IPV6_ADDR *)c->TunnelModeClientIP.ipv6_addr,
+ IP_PROTO_UDP,
+ u,
+ udp_size, 0);
+ }
+ }
+
+ IPsecSendPacketByIkeClient(ike, c, udp, udp_size, IP_PROTO_UDP);
+
+ if (no_free == false)
+ {
+ Free(udp);
+ }
+}
+
+// Get whether the specified IPsec SA is in tunnel mode
+bool IsIPsecSaTunnelMode(IPSECSA *sa)
+{
+ // Validate arguments
+ if (sa == NULL)
+ {
+ return false;
+ }
+
+ if (sa->TransformSetting.CapsuleMode == IKE_P2_CAPSULE_TUNNEL ||
+ sa->TransformSetting.CapsuleMode == IKE_P2_CAPSULE_NAT_TUNNEL_1 ||
+ sa->TransformSetting.CapsuleMode == IKE_P2_CAPSULE_NAT_TUNNEL_2)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Reception process of ESP packet
+void ProcIPsecEspPacketRecv(IKE_SERVER *ike, UDPPACKET *p)
+{
+ UCHAR *src;
+ UINT src_size;
+ UINT spi;
+ UINT seq;
+ IPSECSA *ipsec_sa;
+ IKE_CLIENT *c;
+ UINT block_size;
+ UINT hash_size;
+ bool update_status = false;
+ UCHAR *iv;
+ UCHAR *hash;
+ UCHAR *encrypted_payload_data;
+ UINT size_of_payload_data;
+ IKE_CRYPTO_PARAM cp;
+ BUF *dec;
+ UCHAR calced_hash[IKE_MAX_HASH_SIZE];
+ bool is_tunnel_mode = false;
+ // Validate arguments
+ if (ike == NULL || p == NULL)
+ {
+ return;
+ }
+
+ src = (UCHAR *)p->Data;
+ src_size = p->Size;
+
+ if (p->DestPort == IPSEC_PORT_IPSEC_ESP_RAW)
+ {
+ if (IsIP4(&p->DstIP))
+ {
+ // Skip the IP header when received in Raw mode (only in the case of IPv4)
+ UINT ip_header_size = GetIpHeaderSize(src, src_size);
+
+ src += ip_header_size;
+ src_size -= ip_header_size;
+ }
+ }
+
+ // Get the SPI
+ if (src_size < sizeof(UINT))
+ {
+ return;
+ }
+
+ spi = READ_UINT(src + 0);
+ if (spi == 0)
+ {
+ return;
+ }
+
+ // Get the sequence number
+ if (src_size < (sizeof(UINT) * 2))
+ {
+ return;
+ }
+ seq = READ_UINT(src + sizeof(UINT));
+
+ // Search and retrieve the IPsec SA from SPI
+ ipsec_sa = SearchClientToServerIPsecSaBySpi(ike, spi);
+ if (ipsec_sa == NULL)
+ {
+ // Invalid SPI
+ UINT64 init_cookie = Rand64();
+ UINT64 resp_cookie = 0;
+ IKE_CLIENT *c = NULL;
+ IKE_CLIENT t;
+
+
+ Copy(&t.ClientIP, &p->SrcIP, sizeof(IP));
+ t.ClientPort = p->SrcPort;
+ Copy(&t.ServerIP, &p->DstIP, sizeof(IP));
+ t.ServerPort = p->DestPort;
+ t.CurrentIkeSa = NULL;
+
+ if (p->DestPort == IPSEC_PORT_IPSEC_ESP_RAW)
+ {
+ t.ClientPort = t.ServerPort = IPSEC_PORT_IPSEC_ISAKMP;
+ }
+
+ c = Search(ike->ClientList, &t);
+
+ if (c != NULL && c->CurrentIkeSa != NULL)
+ {
+ init_cookie = c->CurrentIkeSa->InitiatorCookie;
+ resp_cookie = c->CurrentIkeSa->ResponderCookie;
+ }
+
+ SendInformationalExchangePacketEx(ike, (c == NULL ? &t : c), IkeNewNoticeErrorInvalidSpiPayload(spi), false,
+ init_cookie, resp_cookie);
+
+ SendDeleteIPsecSaPacket(ike, (c == NULL ? &t : c), spi);
+ return;
+ }
+
+ is_tunnel_mode = IsIPsecSaTunnelMode(ipsec_sa);
+
+ c = ipsec_sa->IkeClient;
+ if (c == NULL)
+ {
+ return;
+ }
+
+ block_size = ipsec_sa->TransformSetting.Crypto->BlockSize;
+ hash_size = IKE_ESP_HASH_SIZE;
+
+ // Get the IV
+ if (src_size < (sizeof(UINT) * 2 + block_size + hash_size + block_size))
+ {
+ return;
+ }
+ iv = src + sizeof(UINT) * 2;
+
+ // Get the hash
+ hash = src + src_size - hash_size;
+
+ // Inspect the HMAC
+ IkeHMac(ipsec_sa->TransformSetting.Hash, calced_hash, ipsec_sa->HashKey,
+ ipsec_sa->TransformSetting.Hash->HashSize, src, src_size - hash_size);
+
+ if (Cmp(calced_hash, hash, hash_size) != 0)
+ {
+ //Debug("IPsec SA 0x%X: Invalid HMAC Value.\n", ipsec_sa->Spi);
+ return;
+ }
+
+ // Get the payload data
+ encrypted_payload_data = src + sizeof(UINT) * 2 + block_size;
+ size_of_payload_data = src_size - hash_size - block_size - sizeof(UINT) * 2;
+ if (size_of_payload_data == 0 || (size_of_payload_data % block_size) != 0)
+ {
+ // Payload data don't exist or is not a multiple of block size
+ return;
+ }
+
+ // Decrypt the payload data
+ cp.Key = ipsec_sa->CryptoKey;
+ Copy(&cp.Iv, iv, block_size);
+
+ dec = IkeDecrypt(encrypted_payload_data, size_of_payload_data, &cp);
+ if (dec != NULL)
+ {
+ UCHAR *dec_data = dec->Buf;
+ UINT dec_size = dec->Size;
+ UCHAR size_of_padding = dec_data[dec_size - 2];
+ UCHAR next_header = dec_data[dec_size - 1];
+ if ((dec_size - 2) >= size_of_padding)
+ {
+ UINT orig_size = dec_size - 2 - size_of_padding;
+
+ ipsec_sa->TotalSize += dec_size;
+
+ if (is_tunnel_mode)
+ {
+ // Tunnel Mode
+ if (next_header == IKE_PROTOCOL_ID_IPV4 || next_header == IKE_PROTOCOL_ID_IPV6)
+ {
+ // Check the contents by parsing the IPv4 / IPv6 header in the case of tunnel mode
+ BUF *b = NewBuf();
+ static UCHAR src_mac_dummy[6] = {0, 0, 0, 0, 0, 0, };
+ static UCHAR dst_mac_dummy[6] = {0, 0, 0, 0, 0, 0, };
+ USHORT tpid = Endian16(next_header == IKE_PROTOCOL_ID_IPV4 ? MAC_PROTO_IPV4 : MAC_PROTO_IPV6);
+ PKT *pkt;
+
+ WriteBuf(b, src_mac_dummy, sizeof(src_mac_dummy));
+ WriteBuf(b, dst_mac_dummy, sizeof(dst_mac_dummy));
+ WriteBuf(b, &tpid, sizeof(tpid));
+
+ WriteBuf(b, dec_data, dec_size);
+
+ // Parse
+ pkt = ParsePacket(b->Buf, b->Size);
+
+#ifdef RAW_DEBUG
+ IPsecIkeSendUdpForDebug(IPSEC_PORT_L2TP, 1, b->Buf, b->Size);
+#endif // RAW_DEBUG
+
+ if (pkt == NULL)
+ {
+ // Parsing failure
+ dec_data = NULL;
+ dec_size = 0;
+ }
+ else
+ {
+ // Parsing success
+ switch (pkt->TypeL3)
+ {
+ case L3_IPV4:
+ // Save the internal IP address information
+ UINTToIP(&c->TunnelModeServerIP, pkt->L3.IPv4Header->DstIP);
+ UINTToIP(&c->TunnelModeClientIP, pkt->L3.IPv4Header->SrcIP);
+
+ if (IPV4_GET_OFFSET(pkt->L3.IPv4Header) == 0)
+ {
+ if ((IPV4_GET_FLAGS(pkt->L3.IPv4Header) & 0x01) == 0)
+ {
+ if (pkt->L3.IPv4Header->Protocol == IPSEC_IP_PROTO_ETHERIP)
+ {
+ // EtherIP
+ if (ike->IPsec->Services.EtherIP_IPsec)
+ {
+ // An EtherIP packet has been received
+ ProcIPsecEtherIPPacketRecv(ike, c, pkt->IPv4PayloadData, pkt->IPv4PayloadSize, true);
+ }
+ }
+ else if (pkt->L3.IPv4Header->Protocol == IPSEC_IP_PROTO_L2TPV3)
+ {
+ // L2TPv3
+ if (ike->IPsec->Services.EtherIP_IPsec)
+ {
+ // A L2TPv3 packet has been received
+ ProcL2TPv3PacketRecv(ike, c, pkt->IPv4PayloadData, pkt->IPv4PayloadSize, true);
+ }
+ }
+ }
+ }
+ break;
+
+ case L3_IPV6:
+ // Save the internal IP address information
+ SetIP6(&c->TunnelModeServerIP, pkt->IPv6HeaderPacketInfo.IPv6Header->DestAddress.Value);
+ SetIP6(&c->TunnelModeClientIP, pkt->IPv6HeaderPacketInfo.IPv6Header->SrcAddress.Value);
+
+ if (pkt->IPv6HeaderPacketInfo.IsFragment == false)
+ {
+ if (pkt->IPv6HeaderPacketInfo.FragmentHeader == NULL || (IPV6_GET_FLAGS(pkt->IPv6HeaderPacketInfo.FragmentHeader) & IPV6_FRAGMENT_HEADER_FLAG_MORE_FRAGMENTS) == 0)
+ {
+ if (pkt->IPv6HeaderPacketInfo.Protocol == IPSEC_IP_PROTO_ETHERIP)
+ {
+ // EtherIP
+ if (ike->IPsec->Services.EtherIP_IPsec)
+ {
+ // An EtherIP packet has been received
+ ProcIPsecEtherIPPacketRecv(ike, c, pkt->IPv6HeaderPacketInfo.Payload, pkt->IPv6HeaderPacketInfo.PayloadSize, true);
+ }
+ }
+ else if (pkt->IPv6HeaderPacketInfo.Protocol == IPSEC_IP_PROTO_L2TPV3)
+ {
+ // L2TPv3
+ if (ike->IPsec->Services.EtherIP_IPsec)
+ {
+ // A L2TPv3 packet has been received
+ ProcL2TPv3PacketRecv(ike, c, pkt->IPv6HeaderPacketInfo.Payload, pkt->IPv6HeaderPacketInfo.PayloadSize, true);
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ FreePacket(pkt);
+ }
+
+ FreeBuf(b);
+ }
+ }
+ else
+ {
+ // Transport mode
+ if (next_header == IP_PROTO_UDP)
+ {
+ if (ike->IPsec->Services.L2TP_IPsec)
+ {
+ // An UDP packet has been received
+ ProcIPsecUdpPacketRecv(ike, c, dec_data, dec_size);
+ }
+ }
+ else if (next_header == IPSEC_IP_PROTO_ETHERIP)
+ {
+ if (ike->IPsec->Services.EtherIP_IPsec)
+ {
+ // An EtherIP packet has been received
+ ProcIPsecEtherIPPacketRecv(ike, c, dec_data, dec_size, false);
+ }
+ }
+ else if (next_header == IPSEC_IP_PROTO_L2TPV3)
+ {
+ if (ike->IPsec->Services.EtherIP_IPsec)
+ {
+ // A L2TPv3 packet has been received
+ ProcL2TPv3PacketRecv(ike, c, dec_data, dec_size, false);
+ }
+ }
+ }
+
+ update_status = true;
+ }
+
+ FreeBuf(dec);
+ }
+
+ if (update_status)
+ {
+ bool start_qm = false;
+ // Update the status of the client
+ c->CurrentIpSecSaRecv = ipsec_sa;
+ if (ipsec_sa->PairIPsecSa != NULL)
+ {
+ c->CurrentIpSecSaSend = ipsec_sa->PairIPsecSa;
+ }
+ c->LastCommTick = ike->Now;
+ ipsec_sa->LastCommTick = ike->Now;
+ if (ipsec_sa->PairIPsecSa != NULL)
+ {
+ ipsec_sa->PairIPsecSa->LastCommTick = ike->Now;
+ }
+
+ SetIkeClientEndpoint(ike, c, &p->SrcIP, p->SrcPort, &p->DstIP, p->DestPort);
+
+ if (seq >= 0xf0000000)
+ {
+ // Execute a QuickMode forcibly since sequence number is going to exhaust
+ start_qm = true;
+ }
+
+ if (ipsec_sa->TransformSetting.LifeKilobytes != 0)
+ {
+ UINT64 hard_size = (UINT64)ipsec_sa->TransformSetting.LifeKilobytes * (UINT64)1000;
+ UINT64 soft_size = hard_size * (UINT64)2 / (UINT64)3;
+
+ if (ipsec_sa->TotalSize >= soft_size)
+ {
+ // Execute a QuickMode forcibly because the capacity limit is going to exceed
+ start_qm = true;
+ }
+ }
+
+ if (start_qm)
+ {
+ if (ipsec_sa->StartQM_FlagSet == false)
+ {
+ c->StartQuickModeAsSoon = true;
+ ipsec_sa->StartQM_FlagSet = true;
+ }
+ }
+ }
+}
+
+// Received the L2TPv3 packet via the IPsec tunnel
+void ProcL2TPv3PacketRecv(IKE_SERVER *ike, IKE_CLIENT *c, UCHAR *data, UINT data_size, bool is_tunnel_mode)
+{
+ UDPPACKET p;
+ // Validate arguments
+ if (ike == NULL || c == NULL || data == NULL || data_size == 0)
+ {
+ return;
+ }
+
+ c->IsL2TPOnIPsecTunnelMode = is_tunnel_mode;
+
+ IPsecIkeClientManageL2TPServer(ike, c);
+
+ // Pass the received packet to the L2TP server
+ p.Type = 0;
+ p.Data = data;
+ p.DestPort = IPSEC_PORT_L2TPV3_VIRTUAL;
+ p.Size = data_size;
+
+ if (is_tunnel_mode)
+ {
+ Copy(&p.DstIP, &c->TunnelModeServerIP, sizeof(IP));
+ Copy(&p.SrcIP, &c->TunnelModeClientIP, sizeof(IP));
+ }
+ else
+ {
+ Copy(&p.DstIP, &c->L2TPServerIP, sizeof(IP));
+ Copy(&p.SrcIP, &c->L2TPClientIP, sizeof(IP));
+ }
+ p.SrcPort = IPSEC_PORT_L2TPV3_VIRTUAL;
+
+#ifdef RAW_DEBUG
+ IPsecIkeSendUdpForDebug(IPSEC_PORT_L2TP, 1, ((UCHAR *)p.Data) + 4, p.Size - 4);
+#endif // RAW_DEBUG
+
+ ProcL2TPPacketRecv(c->L2TP, &p);
+}
+
+// An EtherIP packet has been received via an IPsec tunnel
+void ProcIPsecEtherIPPacketRecv(IKE_SERVER *ike, IKE_CLIENT *c, UCHAR *data, UINT data_size, bool is_tunnel_mode)
+{
+ BLOCK *b;
+ // Validate arguments
+ if (ike == NULL || c == NULL || data == NULL || data_size == 0)
+ {
+ return;
+ }
+
+ c->IsEtherIPOnIPsecTunnelMode = is_tunnel_mode;
+
+ IPsecIkeClientManageEtherIPServer(ike, c);
+
+ b = NewBlock(data, data_size, 0);
+
+ EtherIPProcRecvPackets(c->EtherIP, b);
+
+ Free(b);
+}
+
+// An UDP packet has been received via the IPsec tunnel
+void ProcIPsecUdpPacketRecv(IKE_SERVER *ike, IKE_CLIENT *c, UCHAR *data, UINT data_size)
+{
+ UDP_HEADER *u;
+ UINT payload_size;
+ UINT src_port, dst_port;
+ UINT packet_length;
+ // Validate arguments
+ if (ike == NULL || c == NULL || data == NULL || data_size == 0)
+ {
+ return;
+ }
+
+ if (data_size <= sizeof(UDP_HEADER))
+ {
+ // There is no UDP header or the data is 0 bytes
+ return;
+ }
+
+ // UDP header
+ u = (UDP_HEADER *)data;
+
+ packet_length = Endian16(u->PacketLength);
+
+ if (packet_length <= sizeof(UDP_HEADER))
+ {
+ return;
+ }
+
+ payload_size = packet_length - sizeof(UDP_HEADER);
+
+ if (payload_size == 0)
+ {
+ // No data
+ return;
+ }
+
+ if (data_size < (sizeof(UDP_HEADER) + payload_size))
+ {
+ // Data is not followed
+ return;
+ }
+
+ src_port = Endian16(u->SrcPort);
+ dst_port = Endian16(u->DstPort);
+
+ if (dst_port == IPSEC_PORT_L2TP)
+ {
+ UDPPACKET p;
+ // A L2TP packet has been received
+ IPsecIkeClientManageL2TPServer(ike, c);
+
+ // Update Port number
+ c->L2TPClientPort = src_port;
+
+ // Pass the received packet to the L2TP server
+ p.Type = 0;
+ p.Data = data + sizeof(UDP_HEADER);
+ p.DestPort = IPSEC_PORT_L2TP;
+ Copy(&p.DstIP, &c->L2TPServerIP, sizeof(IP));
+ p.Size = payload_size;
+ Copy(&p.SrcIP, &c->L2TPClientIP, sizeof(IP));
+ p.SrcPort = IPSEC_PORT_L2TP;
+
+ ProcL2TPPacketRecv(c->L2TP, &p);
+
+ //Debug("IPsec UDP Recv: %u <= %u %u\n", dst_port, src_port, p.Size);
+
+#ifdef RAW_DEBUG
+ IPsecIkeSendUdpForDebug(IPSEC_PORT_L2TP, 1, p.Data, p.Size);
+#endif // RAW_DEBUG
+ }
+}
+
+// Send a raw packet for debugging
+void IPsecIkeSendUdpForDebug(UINT dst_port, UINT dst_ip, void *data, UINT size)
+{
+ SOCK *s = NewUDP(0);
+ IP d;
+
+ SetIP(&d, dst_ip, dst_ip, dst_ip, dst_ip);
+
+ SendTo(s, &d, dst_port, data, size);
+
+ ReleaseSock(s);
+}
+
+// L2TP packet transmission (via IPsec SA tunnel)
+void IPsecIkeClientSendL2TPPackets(IKE_SERVER *ike, IKE_CLIENT *c, L2TP_SERVER *l2tp)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL || c == NULL || l2tp == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(l2tp->SendPacketList);i++)
+ {
+ UDPPACKET *u = LIST_DATA(l2tp->SendPacketList, i);
+
+ if (u->SrcPort != IPSEC_PORT_L2TPV3_VIRTUAL)
+ {
+ // L2TP UDP packet transmission
+ IPsecSendUdpPacket(ike, c, IPSEC_PORT_L2TP, c->L2TPClientPort,
+ u->Data, u->Size);
+ }
+ else
+ {
+ // L2TPv3 special IP packet transmission
+ IPsecSendPacketByIkeClient(ike, c, u->Data, u->Size, IPSEC_IP_PROTO_L2TPV3);
+
+#ifdef RAW_DEBUG
+ IPsecIkeSendUdpForDebug(IPSEC_PORT_L2TP, 1, ((UCHAR *)u->Data) + 4, u->Size - 4);
+#endif // RAW_DEBUG
+ }
+
+ FreeUdpPacket(u);
+ }
+
+ DeleteAll(l2tp->SendPacketList);
+}
+
+// Manage the L2TP server that is associated with the IKE_CLIENT
+void IPsecIkeClientManageL2TPServer(IKE_SERVER *ike, IKE_CLIENT *c)
+{
+ L2TP_SERVER *l2tp;
+ // Validate arguments
+ if (ike == NULL || c == NULL)
+ {
+ return;
+ }
+
+ if (c->L2TP == NULL)
+ {
+ UINT crypt_block_size = IKE_MAX_BLOCK_SIZE;
+
+ if (c->CurrentIpSecSaRecv != NULL)
+ {
+ crypt_block_size = c->CurrentIpSecSaRecv->TransformSetting.Crypto->BlockSize;
+ }
+
+ c->L2TP = NewL2TPServerEx(ike->Cedar, ike, IsIP6(&c->ClientIP), crypt_block_size);
+ c->L2TP->IkeClient = c;
+
+ Copy(&c->L2TPServerIP, &c->ServerIP, sizeof(IP));
+ Copy(&c->L2TPClientIP, &c->ClientIP, sizeof(IP));
+
+ if (c->CurrentIpSecSaRecv != NULL)
+ {
+ Format(c->L2TP->CryptName, sizeof(c->L2TP->CryptName),
+ "IPsec - %s (%u bits)",
+ c->CurrentIpSecSaRecv->TransformSetting.Crypto->Name,
+ c->CurrentIpSecSaRecv->TransformSetting.CryptoKeySize * 8);
+ }
+
+ Debug("IKE_CLIENT 0x%X: L2TP Server Started.\n", c);
+
+ IPsecLog(ike, c, NULL, NULL, "LI_L2TP_SERVER_STARTED");
+ }
+
+ l2tp = c->L2TP;
+
+ if (l2tp->Interrupts == NULL)
+ {
+ l2tp->Interrupts = ike->Interrupts;
+ }
+
+ if (l2tp->SockEvent == NULL)
+ {
+ SetL2TPServerSockEvent(l2tp, ike->SockEvent);
+ }
+
+ l2tp->Now = ike->Now;
+}
+
+// Manage the EtherIP server that is associated with the IKE_CLIENT
+void IPsecIkeClientManageEtherIPServer(IKE_SERVER *ike, IKE_CLIENT *c)
+{
+ ETHERIP_SERVER *s;
+ // Validate arguments
+ if (ike == NULL || c == NULL)
+ {
+ return;
+ }
+
+ if (c->EtherIP == NULL)
+ {
+ char crypt_name[MAX_SIZE];
+ UINT crypt_block_size = IKE_MAX_BLOCK_SIZE;
+
+ Zero(crypt_name, sizeof(crypt_name));
+
+ if (c->CurrentIpSecSaRecv != NULL)
+ {
+ Format(crypt_name, sizeof(crypt_name),
+ "IPsec - %s (%u bits)",
+ c->CurrentIpSecSaRecv->TransformSetting.Crypto->Name,
+ c->CurrentIpSecSaRecv->TransformSetting.CryptoKeySize * 8);
+
+ crypt_block_size = c->CurrentIpSecSaRecv->TransformSetting.Crypto->BlockSize;
+ }
+
+ c->EtherIP = NewEtherIPServer(ike->Cedar, ike->IPsec, ike,
+ &c->ClientIP, c->ClientPort,
+ &c->ServerIP, c->ServerPort, crypt_name,
+ c->IsEtherIPOnIPsecTunnelMode, crypt_block_size, c->ClientId,
+ ++ike->CurrentEtherId);
+
+ Debug("IKE_CLIENT 0x%X: EtherIP Server Started.\n", c);
+
+ IPsecLog(ike, c, NULL, NULL, NULL, "LI_ETHERIP_SERVER_STARTED", ike->CurrentEtherId);
+ }
+ else
+ {
+ StrCpy(c->EtherIP->ClientId, sizeof(c->EtherIP->ClientId), c->ClientId);
+ }
+
+ s = c->EtherIP;
+
+ if (s->Interrupts == NULL)
+ {
+ s->Interrupts = ike->Interrupts;
+ }
+
+ if (s->SockEvent == NULL)
+ {
+ SetEtherIPServerSockEvent(s, ike->SockEvent);
+ }
+
+ s->Now = ike->Now;
+}
+
+// EtherIP packet transmission (via IPsec SA tunnel)
+void IPsecIkeClientSendEtherIPPackets(IKE_SERVER *ike, IKE_CLIENT *c, ETHERIP_SERVER *s)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL || c == NULL || s == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(s->SendPacketList);i++)
+ {
+ BLOCK *b = LIST_DATA(s->SendPacketList, i);
+
+ // Packet transmission
+ IPsecSendPacketByIkeClient(ike, c, b->Buf, b->Size, IPSEC_IP_PROTO_ETHERIP);
+
+ FreeBlock(b);
+ }
+
+ DeleteAll(s->SendPacketList);
+}
+
+// Handle the deletion payload
+void ProcDeletePayload(IKE_SERVER *ike, IKE_CLIENT *c, IKE_PACKET_DELETE_PAYLOAD *d)
+{
+ // Validate arguments
+ if (ike == NULL || c == NULL || d == NULL)
+ {
+ return;
+ }
+
+ if (d->ProtocolId == IKE_PROTOCOL_ID_IPSEC_ESP)
+ {
+ UINT i;
+ // Remove the IPsec SA
+ for (i = 0;i < LIST_NUM(d->SpiList);i++)
+ {
+ BUF *b = LIST_DATA(d->SpiList, i);
+
+ if (b->Size == 4)
+ {
+ UINT spi = READ_UINT(b->Buf);
+ MarkIPsecSaAsDeleted(ike, SearchIPsecSaBySpi(ike, c, spi));
+ }
+ }
+ }
+ else if (d->ProtocolId == IKE_PROTOCOL_ID_IKE)
+ {
+ UINT i;
+ // Remove the IKE SA
+ for (i = 0;i < LIST_NUM(d->SpiList);i++)
+ {
+ BUF *b = LIST_DATA(d->SpiList, i);
+
+ if (b->Size == 16)
+ {
+ UINT64 v1 = READ_UINT64(((UCHAR *)b->Buf) + 0);
+ UINT64 v2 = READ_UINT64(((UCHAR *)b->Buf) + 8);
+
+ IKE_SA *sa = FindIkeSaByResponderCookie(ike, v2);
+
+ if (sa != NULL && sa->IkeClient == c)
+ {
+ MarkIkeSaAsDeleted(ike, sa);
+ }
+ }
+ }
+ }
+}
+
+// Mark the IKE_CLIENT for deletion
+void MarkIkeClientAsDeleted(IKE_SERVER *ike, IKE_CLIENT *c)
+{
+ char client_ip_str[MAX_SIZE];
+ char server_ip_str[MAX_SIZE];
+ // Validate arguments
+ if (ike == NULL || c == NULL)
+ {
+ return;
+ }
+
+ if (c->Deleting)
+ {
+ return;
+ }
+
+ ike->StateHasChanged = true;
+
+ c->Deleting = true;
+
+ IPToStr(client_ip_str, sizeof(client_ip_str), &c->ClientIP);
+ IPToStr(server_ip_str, sizeof(server_ip_str), &c->ServerIP);
+
+ Debug("Deleting IKE_CLIENT: %p: %s:%u -> %s:%u\n", c, client_ip_str, c->ClientPort, server_ip_str, c->ServerPort);
+
+ IPsecLog(ike, c, NULL, NULL, "LI_DELETE_IKE_CLIENT");
+}
+
+// Mark the IKE SA for deletion
+void MarkIkeSaAsDeleted(IKE_SERVER *ike, IKE_SA *sa)
+{
+ // Validate arguments
+ if (ike == NULL || sa == NULL)
+ {
+ return;
+ }
+
+ if (sa->Deleting)
+ {
+ return;
+ }
+
+ ike->StateHasChanged = true;
+
+ sa->Deleting = true;
+
+ Debug("IKE SA %I64u - %I64u has been marked as being deleted.\n", sa->InitiatorCookie, sa->ResponderCookie);
+
+ SendDeleteIkeSaPacket(ike, sa->IkeClient, sa->InitiatorCookie, sa->ResponderCookie);
+
+ IPsecLog(ike, NULL, sa, NULL, "LI_DELETE_IKE_SA");
+}
+
+// Mark the IPsec SA for deletion
+void MarkIPsecSaAsDeleted(IKE_SERVER *ike, IPSECSA *sa)
+{
+ // Validate arguments
+ if (ike == NULL || sa == NULL)
+ {
+ return;
+ }
+
+ if (sa->Deleting)
+ {
+ return;
+ }
+
+ ike->StateHasChanged = true;
+
+ sa->Deleting = true;
+
+ Debug("IPsec SA 0x%X has been marked as being deleted.\n", sa->Spi);
+
+ SendDeleteIPsecSaPacket(ike, sa->IkeClient, sa->Spi);
+
+ IPsecLog(ike, NULL, NULL, sa, "LI_DELETE_IPSEC_SA");
+}
+
+// IPsec SA Deletion packet transmission process
+void SendDeleteIPsecSaPacket(IKE_SERVER *ike, IKE_CLIENT *c, UINT spi)
+{
+ IKE_PACKET_PAYLOAD *payload;
+ BUF *buf;
+ // Validate arguments
+ if (ike == NULL || c == NULL || spi == 0)
+ {
+ return;
+ }
+
+ buf = NewBuf();
+ WriteBufInt(buf, spi);
+
+ payload = IkeNewDeletePayload(IKE_PROTOCOL_ID_IPSEC_ESP, NewListSingle(buf));
+
+ SendInformationalExchangePacket(ike, c, payload);
+}
+
+// IKE SA deletion packet transmission process
+void SendDeleteIkeSaPacket(IKE_SERVER *ike, IKE_CLIENT *c, UINT64 init_cookie, UINT64 resp_cookie)
+{
+ IKE_PACKET_PAYLOAD *payload;
+ BUF *buf;
+ // Validate arguments
+ if (ike == NULL || c == NULL)
+ {
+ return;
+ }
+
+ buf = NewBuf();
+ WriteBufInt64(buf, init_cookie);
+ WriteBufInt64(buf, resp_cookie);
+
+ payload = IkeNewDeletePayload(IKE_PROTOCOL_ID_IKE, NewListSingle(buf));
+
+ SendInformationalExchangePacket(ike, c, payload);
+}
+
+// Information exchange packet transmission process
+void SendInformationalExchangePacket(IKE_SERVER *ike, IKE_CLIENT *c, IKE_PACKET_PAYLOAD *payload)
+{
+ SendInformationalExchangePacketEx(ike, c, payload, false, 0, 0);
+}
+void SendInformationalExchangePacketEx(IKE_SERVER *ike, IKE_CLIENT *c, IKE_PACKET_PAYLOAD *payload, bool force_plain, UINT64 init_cookie, UINT64 resp_cookie)
+{
+ IKE_SA *sa;
+ IKE_PACKET *ps;
+ LIST *payload_list;
+ UCHAR dummy_hash_data[IKE_MAX_HASH_SIZE];
+ IKE_PACKET_PAYLOAD *hash_payload;
+ BUF *ps_buf;
+ UINT after_hash_offset, after_hash_size;
+ BUF *ps_buf_after_hash;
+ BUF *tmp_buf;
+ UCHAR hash[IKE_MAX_HASH_SIZE];
+ IKE_CRYPTO_PARAM cp;
+ bool plain = false;
+ // Validate arguments
+ if (ike == NULL || c == NULL || payload == NULL)
+ {
+ IkeFreePayload(payload);
+ return;
+ }
+
+ sa = c->CurrentIkeSa;
+ if (sa == NULL)
+ {
+ plain = true;
+ }
+
+ if (force_plain)
+ {
+ plain = true;
+ }
+
+ if (plain && (init_cookie == 0 && resp_cookie == 0))
+ {
+ init_cookie = Rand64();
+ resp_cookie = 0;
+ }
+
+ payload_list = NewListFast(NULL);
+
+ Zero(dummy_hash_data, sizeof(dummy_hash_data));
+
+ // Hash payload
+ if (plain == false)
+ {
+ hash_payload = IkeNewDataPayload(IKE_PAYLOAD_HASH, dummy_hash_data, sa->HashSize);
+ Add(payload_list, hash_payload);
+ }
+
+ // Body
+ Add(payload_list, payload);
+
+ // Packet creation
+ ps = IkeNew((plain ? init_cookie : sa->InitiatorCookie), (plain ? resp_cookie : sa->ResponderCookie),
+ IKE_EXCHANGE_TYPE_INFORMATION, false, false, false,
+ GenerateNewMessageId(ike), payload_list);
+
+ if (plain == false)
+ {
+ // Build a temporary packet
+ ps_buf = IkeBuild(ps, NULL);
+
+ // Get the payload after the hash part
+ after_hash_offset = sizeof(IKE_HEADER) + hash_payload->BitArray->Size + sizeof(IKE_COMMON_HEADER);
+ after_hash_size = ((ps_buf->Size > after_hash_offset) ? (ps_buf->Size - after_hash_offset) : 0);
+
+ ps_buf_after_hash = MemToBuf(((UCHAR *)ps_buf->Buf) + after_hash_offset, after_hash_size);
+ FreeBuf(ps_buf);
+
+ // Calculate the hash
+ tmp_buf = NewBuf();
+ WriteBufInt(tmp_buf, ps->MessageId);
+ WriteBufBuf(tmp_buf, ps_buf_after_hash);
+ IkeHMac(sa->TransformSetting.Hash, hash, sa->SKEYID_a, sa->HashSize, tmp_buf->Buf, tmp_buf->Size);
+ FreeBuf(tmp_buf);
+
+ // Overwrite the hash
+ Copy(hash_payload->Payload.Hash.Data->Buf, hash, sa->HashSize);
+
+ ps->FlagEncrypted = true;
+ FreeBuf(ps_buf_after_hash);
+ }
+
+ // Packet reply
+ Zero(&cp, sizeof(cp));
+
+ if (plain == false)
+ {
+ cp.Key = sa->CryptoKey;
+ IkeCalcPhase2InitialIv(cp.Iv, sa, ps->MessageId);
+ }
+
+ ps_buf = IkeBuild(ps, &cp);
+
+ IkeSendUdpPacket(ike, IKE_UDP_TYPE_ISAKMP, &c->ServerIP, c->ServerPort,
+ &c->ClientIP, c->ClientPort,
+ ps_buf->Buf, ps_buf->Size);
+
+#ifdef RAW_DEBUG
+ IkeDebugUdpSendRawPacket(ps);
+#endif // RAW_DEBUG
+
+ Free(ps_buf);
+
+ IkeFree(ps);
+}
+
+// Information exchange packet reception process
+void ProcIkeInformationalExchangePacketRecv(IKE_SERVER *ike, UDPPACKET *p, IKE_PACKET *header)
+{
+ IKE_CLIENT *c;
+ IKE_SA *ike_sa;
+ // Validate arguments
+ if (ike == NULL || p == NULL || header == NULL || header->InitiatorCookie == 0 || header->ResponderCookie == 0
+ || header->MessageId == 0 || header->FlagEncrypted == false)
+ {
+ return;
+ }
+
+ c = SearchOrCreateNewIkeClientForIkePacket(ike, &p->SrcIP, p->SrcPort, &p->DstIP, p->DestPort, header);
+
+ if (c == NULL)
+ {
+ return;
+ }
+
+ ike_sa = FindIkeSaByResponderCookieAndClient(ike, header->ResponderCookie, c);
+
+ if (ike_sa != NULL && ike_sa->Established)
+ {
+ IKE_PACKET *pr;
+ IKE_CRYPTO_PARAM cp;
+
+ // Packet decoding
+ Zero(&cp, sizeof(cp));
+ cp.Key = ike_sa->CryptoKey;
+ IkeCalcPhase2InitialIv(cp.Iv, ike_sa, header->MessageId);
+
+ pr = IkeParse(p->Data, p->Size, &cp);
+#ifdef RAW_DEBUG
+ IkeDebugUdpSendRawPacket(pr);
+#endif // RAW_DEBUG
+ if (pr != NULL)
+ {
+ // Get the hash payload
+ IKE_PACKET_PAYLOAD *hash_payload;
+
+ hash_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_HASH, 0);
+ if (hash_payload != NULL)
+ {
+ // Get the payload after the hash
+ UINT header_and_hash_size = sizeof(IKE_COMMON_HEADER) + hash_payload->BitArray->Size;
+ void *after_hash_data = ((UCHAR *)pr->DecryptedPayload->Buf) + header_and_hash_size;
+ if (pr->DecryptedPayload->Size > header_and_hash_size)
+ {
+ UINT after_hash_size = pr->DecryptedPayload->Size - header_and_hash_size;
+ UCHAR hash1[IKE_MAX_HASH_SIZE];
+ BUF *hash1_buf;
+
+ hash1_buf = NewBuf();
+ WriteBufInt(hash1_buf, header->MessageId);
+ WriteBuf(hash1_buf, after_hash_data, after_hash_size);
+
+ IkeHMac(ike_sa->TransformSetting.Hash, hash1, ike_sa->SKEYID_a, ike_sa->HashSize,
+ hash1_buf->Buf, hash1_buf->Size);
+
+ // Compare the hash value
+ if (IkeCompareHash(hash_payload, hash1, ike_sa->HashSize))
+ {
+ UINT i, num;
+ // Handle the deletion payload
+ num = IkeGetPayloadNum(pr->PayloadList, IKE_PAYLOAD_DELETE);
+ for (i = 0;i < num;i++)
+ {
+ IKE_PACKET_PAYLOAD *payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_DELETE, i);
+ IKE_PACKET_DELETE_PAYLOAD *del = &payload->Payload.Delete;
+
+ ProcDeletePayload(ike, c, del);
+ }
+ num = IkeGetPayloadNum(pr->PayloadList, IKE_PAYLOAD_NOTICE);
+ // Handle the notification payload
+ for (i = 0;i < num;i++)
+ {
+ IKE_PACKET_PAYLOAD *payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NOTICE, i);
+ IKE_PACKET_NOTICE_PAYLOAD *n = &payload->Payload.Notice;
+
+ if (n->MessageType == IKE_NOTICE_DPD_REQUEST || n->MessageType == IKE_NOTICE_DPD_RESPONSE)
+ {
+ if (n->MessageData != NULL && n->MessageData->Size == sizeof(UINT))
+ {
+ UINT seq_no = READ_UINT(n->MessageData->Buf);
+
+ if (n->Spi->Size == (sizeof(UINT64) * 2))
+ {
+ UINT64 init_cookie = READ_UINT64(((UCHAR *)n->Spi->Buf));
+ UINT64 resp_cookie = READ_UINT64(((UCHAR *)n->Spi->Buf) + sizeof(UINT64));
+
+ if (init_cookie != 0 && resp_cookie != 0)
+ {
+ IKE_SA *found_ike_sa = SearchIkeSaByCookie(ike, init_cookie, resp_cookie);
+
+ if (found_ike_sa != NULL && found_ike_sa->IkeClient == c)
+ {
+ if (n->MessageType == IKE_NOTICE_DPD_REQUEST)
+ {
+ // Return the DPD Response (ACK) for the DPD Request
+ SendInformationalExchangePacket(ike, c,
+ IkeNewNoticeDpdPayload(true, init_cookie, resp_cookie,
+ seq_no));
+ }
+
+ // Update the status of the IKE SA
+ found_ike_sa->LastCommTick = ike->Now;
+ ike_sa->LastCommTick = ike->Now;
+ found_ike_sa->IkeClient->LastCommTick = ike->Now;
+ ike_sa->IkeClient->LastCommTick = ike->Now;
+ ike_sa->IkeClient->CurrentIkeSa = ike_sa;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ FreeBuf(hash1_buf);
+ }
+ }
+
+ IkeFree(pr);
+ }
+ }
+}
+
+// Create a new message ID
+UINT GenerateNewMessageId(IKE_SERVER *ike)
+{
+ UINT ret;
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return 0;
+ }
+
+ while (true)
+ {
+ ret = Rand32();
+
+ if (ret != 0 && ret != 0xffffffff)
+ {
+ UINT i;
+ bool ok = true;
+
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+
+ if (sa->MessageId == ret)
+ {
+ ok = false;
+ break;
+ }
+ }
+
+ if (ok)
+ {
+ return ret;
+ }
+ }
+ }
+}
+
+// Start the quick mode
+void StartQuickMode(IKE_SERVER *ike, IKE_CLIENT *c)
+{
+ IPSEC_SA_TRANSFORM_SETTING setting;
+ IKE_SA *ike_sa;
+ UINT message_id;
+ UCHAR iv[IKE_MAX_BLOCK_SIZE];
+ // Validate arguments
+ if (ike == NULL || c == NULL)
+ {
+ return;
+ }
+
+ if (IsZero(&c->CachedTransformSetting, sizeof(IPSEC_SA_TRANSFORM_SETTING)))
+ {
+ // Cached transform setting does not exist
+ Debug("Error: c->CachedTransformSetting is not existing.\n");
+ return;
+ }
+
+ ike_sa = c->CurrentIkeSa;
+ if (ike_sa == NULL)
+ {
+ return;
+ }
+
+ IPsecLog(ike, NULL, ike_sa, NULL, "LI_START_QM_FROM_SERVER");
+
+ Copy(&setting, &c->CachedTransformSetting, sizeof(IPSEC_SA_TRANSFORM_SETTING));
+
+ message_id = GenerateNewMessageId(ike);
+
+ IkeCalcPhase2InitialIv(iv, ike_sa, message_id);
+
+#ifdef FORCE_LIFETIME_QM
+ setting.LifeSeconds = FORCE_LIFETIME_QM;
+#endif // FORCE_LIFETIME_QM
+
+ if (true)
+ {
+ IKE_PACKET *ps;
+ LIST *payload_list;
+ IKE_PACKET_PAYLOAD *send_hash_payload;
+ IKE_PACKET_PAYLOAD *send_sa_payload;
+ IKE_PACKET_PAYLOAD *send_proposal_payload;
+ IKE_PACKET_PAYLOAD *send_transform_payload;
+ IKE_PACKET_PAYLOAD *send_rand_payload;
+ IKE_PACKET_PAYLOAD *send_key_payload = NULL;
+ IKE_PACKET_PAYLOAD *send_id_1 = NULL, *send_id_2 = NULL;
+ UINT shared_key_size = 0;
+ UCHAR *shared_key = NULL;
+ BUF *initiator_rand;
+ IPSECSA *ipsec_sa_s_c, *ipsec_sa_c_s;
+ BUF *ps_buf;
+ UINT after_hash_offset, after_hash_size;
+ BUF *ps_buf_after_hash;
+ BUF *tmp_buf;
+ UINT spi;
+ UINT spi_be;
+ UCHAR hash1[IKE_MAX_HASH_SIZE];
+ UCHAR zero = 0;
+ DH_CTX *dh = NULL;
+ UCHAR dummy_hash_data[IKE_MAX_HASH_SIZE];
+
+ initiator_rand = RandBuf(IKE_SA_RAND_SIZE);
+
+ if (setting.Dh != NULL)
+ {
+ // Generate DH
+ dh = IkeDhNewCtx(setting.Dh);
+
+ if (dh != NULL)
+ {
+ send_key_payload = IkeNewDataPayload(IKE_PAYLOAD_KEY_EXCHANGE,
+ dh->MyPublicKey->Buf, dh->MyPublicKey->Size);
+ }
+ }
+
+ Zero(dummy_hash_data, sizeof(dummy_hash_data));
+
+ // Dummy hash value
+ payload_list = NewListFast(NULL);
+ send_hash_payload = IkeNewDataPayload(IKE_PAYLOAD_HASH, dummy_hash_data, ike_sa->HashSize);
+ Add(payload_list, send_hash_payload);
+
+ // Determine the SPI
+ spi = GenerateNewIPsecSaSpi(ike, 0);
+ spi_be = Endian32(spi);
+
+ // SA
+ send_transform_payload = TransformSettingToTransformPayloadForIPsec(ike, &setting);
+ send_proposal_payload = IkeNewProposalPayload(1, IKE_PROTOCOL_ID_IPSEC_ESP, &spi_be, sizeof(spi_be),
+ NewListSingle(send_transform_payload));
+ send_sa_payload = IkeNewSaPayload(NewListSingle(send_proposal_payload));
+ Add(payload_list, send_sa_payload);
+
+ // Random number
+ send_rand_payload = IkeNewDataPayload(IKE_PAYLOAD_RAND, initiator_rand->Buf, initiator_rand->Size);
+ Add(payload_list, send_rand_payload);
+
+ // Key exchange
+ if (send_key_payload != NULL)
+ {
+ Add(payload_list, send_key_payload);
+ }
+
+ if (c->SendID1andID2)
+ {
+ // Add the ID payload
+ if (setting.CapsuleMode == IKE_P2_CAPSULE_NAT_TUNNEL_1 || setting.CapsuleMode == IKE_P2_CAPSULE_NAT_TUNNEL_2)
+ {
+ UCHAR zero[32];
+
+ Zero(zero, sizeof(zero));
+
+ // Tunnel Mode
+ send_id_1 = IkeNewIdPayload((IsIP4(&c->ServerIP) ? IKE_ID_IPV4_ADDR_SUBNET : IKE_ID_IPV6_ADDR_SUBNET),
+ 0, 0,
+ zero, (IsIP4(&c->ServerIP) ? 8 : 32));
+
+ send_id_2 = IkeNewIdPayload(c->SendID1_Type,
+ c->SendID1_Protocol, c->SendID1_Port,
+ c->SendID1_Buf->Buf, c->SendID1_Buf->Size);
+ }
+ else
+ {
+ // Transport mode
+ // Specify in the reverse order in which the client has been specified
+ send_id_2 = IkeNewIdPayload(c->SendID1_Type,
+ c->SendID1_Protocol, c->SendID1_Port,
+ c->SendID1_Buf->Buf, c->SendID1_Buf->Size);
+
+ send_id_1 = IkeNewIdPayload(c->SendID2_Type,
+ c->SendID2_Protocol, c->SendID2_Port,
+ c->SendID2_Buf->Buf, c->SendID2_Buf->Size);
+ }
+
+ Add(payload_list, send_id_1);
+ Add(payload_list, send_id_2);
+ }
+
+ if (true)
+ {
+ // NAT-OA payload
+ if (c->SendNatOaDraft1)
+ {
+ Add(payload_list, IkeNewNatOaPayload(IKE_PAYLOAD_NAT_OA_DRAFT, &c->ServerIP));
+ }
+
+ if (c->SendNatOaDraft2)
+ {
+ Add(payload_list, IkeNewNatOaPayload(IKE_PAYLOAD_NAT_OA_DRAFT_2, &c->ServerIP));
+ }
+
+ if (c->SendNatOaRfc)
+ {
+ Add(payload_list, IkeNewNatOaPayload(IKE_PAYLOAD_NAT_OA, &c->ClientIP));
+ Add(payload_list, IkeNewNatOaPayload(IKE_PAYLOAD_NAT_OA, &c->ServerIP));
+ }
+ }
+
+ // Build a packet
+ ps = IkeNew(ike_sa->InitiatorCookie, ike_sa->ResponderCookie, IKE_EXCHANGE_TYPE_QUICK,
+ false, false, false, message_id, payload_list);
+
+ // Build a temporary packet
+ ps_buf = IkeBuild(ps, NULL);
+
+ // Get the payload after the hash part
+ after_hash_offset = sizeof(IKE_HEADER) + send_hash_payload->BitArray->Size + sizeof(IKE_COMMON_HEADER);
+ after_hash_size = ((ps_buf->Size > after_hash_offset) ? (ps_buf->Size - after_hash_offset) : 0);
+
+ ps_buf_after_hash = MemToBuf(((UCHAR *)ps_buf->Buf) + after_hash_offset, after_hash_size);
+ FreeBuf(ps_buf);
+
+ // Calculate the hash #1
+ tmp_buf = NewBuf();
+ WriteBufInt(tmp_buf, message_id);
+ WriteBufBuf(tmp_buf, ps_buf_after_hash);
+ IkeHMac(ike_sa->TransformSetting.Hash, hash1, ike_sa->SKEYID_a, ike_sa->HashSize, tmp_buf->Buf, tmp_buf->Size);
+ FreeBuf(tmp_buf);
+
+ // Overwrite hash #1
+ Copy(send_hash_payload->Payload.Hash.Data->Buf, hash1, ike_sa->HashSize);
+
+ // Create an IPsec SA
+ ipsec_sa_c_s = NewIPsecSa(ike, c, ike_sa, true, message_id, false, iv, spi,
+ initiator_rand->Buf, initiator_rand->Size, NULL, 0,
+ &setting, shared_key, shared_key_size);
+
+ ipsec_sa_s_c = NewIPsecSa(ike, c, ike_sa, true, message_id, true, iv, 0,
+ initiator_rand->Buf, initiator_rand->Size, NULL, 0,
+ &setting, shared_key, shared_key_size);
+
+ ipsec_sa_c_s->PairIPsecSa = ipsec_sa_s_c;
+ ipsec_sa_s_c->PairIPsecSa = ipsec_sa_c_s;
+
+ ipsec_sa_s_c->Dh = dh;
+
+ Insert(ike->IPsecSaList, ipsec_sa_c_s);
+ Insert(ike->IPsecSaList, ipsec_sa_s_c);
+
+ // Packet transmission
+ ps->FlagEncrypted = true;
+ IPsecSaSendPacket(ike, ipsec_sa_s_c, ps);
+ ipsec_sa_s_c->NumResends = 3;
+#ifdef RAW_DEBUG
+ IkeDebugUdpSendRawPacket(ps);
+#endif // RAW_DEBUG
+
+ IkeFree(ps);
+ Free(shared_key);
+ FreeBuf(ps_buf_after_hash);
+ FreeBuf(initiator_rand);
+ }
+}
+
+// Process the quick mode received packet
+void ProcIkeQuickModePacketRecv(IKE_SERVER *ike, UDPPACKET *p, IKE_PACKET *header)
+{
+ IKE_CLIENT *c;
+ IKE_SA *ike_sa;
+ // Validate arguments
+ if (ike == NULL || p == NULL || header == NULL || header->InitiatorCookie == 0 || header->ResponderCookie == 0
+ || header->MessageId == 0 || header->FlagEncrypted == false)
+ {
+ return;
+ }
+
+ c = SearchOrCreateNewIkeClientForIkePacket(ike, &p->SrcIP, p->SrcPort, &p->DstIP, p->DestPort, header);
+
+ if (c == NULL)
+ {
+ return;
+ }
+
+ ike_sa = FindIkeSaByResponderCookieAndClient(ike, header->ResponderCookie, c);
+
+ if (ike_sa == NULL)
+ {
+ // IKE SA does not exist
+ SendInformationalExchangePacketEx(ike, c, IkeNewNoticeErrorInvalidCookiePayload(header->InitiatorCookie,
+ header->ResponderCookie), true, header->InitiatorCookie, header->ResponderCookie);
+ }
+
+ if (ike_sa != NULL && ike_sa->Established)
+ {
+ // Update the status of the IKE SA
+ ike_sa->LastCommTick = ike->Now;
+ ike_sa->IkeClient->LastCommTick = ike->Now;
+ ike_sa->IkeClient->CurrentIkeSa = ike_sa;
+
+ // Search whether the Message ID is already in the database
+ if (SearchIPsecSaByMessageId(ike, c, header->MessageId) == NULL)
+ {
+ IKE_PACKET *pr;
+ IKE_CRYPTO_PARAM cp;
+
+ // Message ID does not exist. Start a new Quick Mode session
+ Zero(&cp, sizeof(cp));
+ cp.Key = ike_sa->CryptoKey;
+ IkeCalcPhase2InitialIv(cp.Iv, ike_sa, header->MessageId);
+
+ pr = IkeParse(p->Data, p->Size, &cp);
+#ifdef RAW_DEBUG
+ IkeDebugUdpSendRawPacket(pr);
+#endif // RAW_DEBUG
+ if (pr != NULL)
+ {
+ // Get the hash payload
+ IKE_PACKET_PAYLOAD *hash_payload;
+
+ hash_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_HASH, 0);
+ if (hash_payload != NULL)
+ {
+ // Get the payload after the hash
+ UINT header_and_hash_size = sizeof(IKE_COMMON_HEADER) + hash_payload->BitArray->Size;
+ void *after_hash_data = ((UCHAR *)pr->DecryptedPayload->Buf) + header_and_hash_size;
+ if (pr->DecryptedPayload->Size > header_and_hash_size)
+ {
+ UINT after_hash_size = pr->DecryptedPayload->Size - header_and_hash_size;
+ UCHAR hash1[IKE_MAX_HASH_SIZE];
+ BUF *hash1_buf;
+
+ hash1_buf = NewBuf();
+ WriteBufInt(hash1_buf, header->MessageId);
+ WriteBuf(hash1_buf, after_hash_data, after_hash_size);
+
+ IkeHMac(ike_sa->TransformSetting.Hash, hash1, ike_sa->SKEYID_a, ike_sa->HashSize,
+ hash1_buf->Buf, hash1_buf->Size);
+
+ // Compare the hash value
+ if (IkeCompareHash(hash_payload, hash1, ike_sa->HashSize))
+ {
+ IKE_PACKET_PAYLOAD *sa_payload, *rand_payload, *key_payload, *id_payload_1, *id_payload_2;
+
+ // Get the payload of other
+ sa_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_SA, 0);
+ rand_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_RAND, 0);
+ key_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_KEY_EXCHANGE, 0);
+ id_payload_1 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_ID, 0);
+ id_payload_2 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_ID, 1);
+
+ if (sa_payload != NULL && rand_payload != NULL)
+ {
+ IPSEC_SA_TRANSFORM_SETTING setting;
+
+ Zero(&setting, sizeof(setting));
+
+ // Interpret the SA payload
+ if (GetBestTransformSettingForIPsecSa(ike, pr, &setting, &p->DstIP) && (GetNumberOfIPsecSaOfIkeClient(ike, c) <= IKE_QUOTA_MAX_SA_PER_CLIENT))
+ {
+ // Appropriate transform setting is selected
+ Debug("P2 Transform: %s %s %s(%u) %u %u\n",
+ (setting.Dh == NULL ? NULL : setting.Dh->Name), setting.Hash->Name, setting.Crypto->Name, setting.CryptoKeySize,
+ setting.LifeKilobytes, setting.LifeSeconds);
+
+#ifdef FORCE_LIFETIME_QM
+ setting.LifeSeconds = FORCE_LIFETIME_QM;
+#endif // FORCE_LIFETIME_QM
+
+ // Cache the transform attribute value
+ Copy(&c->CachedTransformSetting, &setting, sizeof(IPSEC_SA_TRANSFORM_SETTING));
+
+ // Check the key exchange payload if the PFS is specified
+ if (setting.Dh == NULL || (setting.Dh != NULL && key_payload != NULL &&
+ key_payload->Payload.KeyExchange.Data->Size <= setting.Dh->KeySize))
+ {
+ // Create a payload for response
+ IKE_PACKET *ps;
+ LIST *payload_list;
+ IKE_PACKET_PAYLOAD *send_hash_payload;
+ IKE_PACKET_PAYLOAD *send_sa_payload;
+ IKE_PACKET_PAYLOAD *send_proposal_payload;
+ IKE_PACKET_PAYLOAD *send_transform_payload;
+ IKE_PACKET_PAYLOAD *send_rand_payload;
+ IKE_PACKET_PAYLOAD *send_key_payload = NULL;
+ IKE_PACKET_PAYLOAD *send_id_1 = NULL, *send_id_2 = NULL;
+ UCHAR dummy_hash_data[IKE_MAX_HASH_SIZE];
+ DH_CTX *dh = NULL;
+ UINT shared_key_size = 0;
+ UCHAR *shared_key = NULL;
+ BUF *initiator_rand, *responder_rand;
+ IPSECSA *ipsec_sa_s_c, *ipsec_sa_c_s;
+ BUF *ps_buf;
+ UINT after_hash_offset, after_hash_size;
+ BUF *ps_buf_after_hash;
+ BUF *tmp_buf;
+ UINT spi;
+ UINT spi_be;
+ UCHAR hash2[IKE_MAX_HASH_SIZE];
+ UCHAR hash3[IKE_MAX_HASH_SIZE];
+ UCHAR zero = 0;
+
+ IPsecLog(ike, NULL, ike_sa, NULL, "LI_START_QM_FROM_CLIENT");
+
+ initiator_rand = CloneBuf(rand_payload->Payload.Rand.Data);
+ responder_rand = RandBuf(IKE_SA_RAND_SIZE);
+
+ if (setting.Dh != NULL)
+ {
+ // Calculate DH
+ dh = IkeDhNewCtx(setting.Dh);
+ shared_key_size = (dh == NULL ? 0 : dh->Size);
+ shared_key = ZeroMalloc(shared_key_size);
+
+ if (DhCompute(dh, shared_key, key_payload->Payload.KeyExchange.Data->Buf, key_payload->Payload.KeyExchange.Data->Size))
+ {
+ // DH calculation success
+ Debug("P2 DH Ok.\n");
+
+ send_key_payload = IkeNewDataPayload(IKE_PAYLOAD_KEY_EXCHANGE,
+ dh->MyPublicKey->Buf, dh->MyPublicKey->Size);
+
+ IkeDhFreeCtx(dh);
+ }
+ else
+ {
+ // DH calculation failure
+ Debug("P2 DhCompute failed.\n");
+
+ shared_key = NULL;
+ Free(shared_key);
+ shared_key_size = 0;
+
+ IPsecLog(ike, NULL, ike_sa, NULL, "LI_QM_DH_ERROR");
+ }
+ }
+
+ Zero(dummy_hash_data, sizeof(dummy_hash_data));
+
+ // Dummy hash value
+ payload_list = NewListFast(NULL);
+ send_hash_payload = IkeNewDataPayload(IKE_PAYLOAD_HASH, dummy_hash_data, ike_sa->HashSize);
+ Add(payload_list, send_hash_payload);
+
+ // Determine the SPI
+ spi = GenerateNewIPsecSaSpi(ike, setting.SpiServerToClient);
+ spi_be = Endian32(spi);
+
+ // SA
+ send_transform_payload = TransformSettingToTransformPayloadForIPsec(ike, &setting);
+ send_proposal_payload = IkeNewProposalPayload(1, IKE_PROTOCOL_ID_IPSEC_ESP, &spi_be, sizeof(spi_be),
+ NewListSingle(send_transform_payload));
+ send_sa_payload = IkeNewSaPayload(NewListSingle(send_proposal_payload));
+ Add(payload_list, send_sa_payload);
+
+ // Random number
+ send_rand_payload = IkeNewDataPayload(IKE_PAYLOAD_RAND, responder_rand->Buf, responder_rand->Size);
+ Add(payload_list, send_rand_payload);
+
+ // Key exchange
+ if (send_key_payload != NULL)
+ {
+ Add(payload_list, send_key_payload);
+ }
+
+ // ID
+ if (id_payload_1 != NULL && id_payload_2 != NULL)
+ {
+ send_id_1 = IkeNewIdPayload(id_payload_1->Payload.Id.Type,
+ id_payload_1->Payload.Id.ProtocolId, id_payload_1->Payload.Id.Port,
+ id_payload_1->Payload.Id.IdData->Buf, id_payload_1->Payload.Id.IdData->Size);
+
+ send_id_2 = IkeNewIdPayload(id_payload_2->Payload.Id.Type,
+ id_payload_2->Payload.Id.ProtocolId, id_payload_2->Payload.Id.Port,
+ id_payload_2->Payload.Id.IdData->Buf, id_payload_2->Payload.Id.IdData->Size);
+
+ Add(payload_list, send_id_1);
+ Add(payload_list, send_id_2);
+
+ if (c->SendID1_Buf != NULL)
+ {
+ FreeBuf(c->SendID1_Buf);
+ }
+
+ if (c->SendID2_Buf != NULL)
+ {
+ FreeBuf(c->SendID2_Buf);
+ }
+
+ c->SendID1_Type = id_payload_1->Payload.Id.Type;
+ c->SendID1_Protocol = id_payload_1->Payload.Id.ProtocolId;
+ c->SendID1_Port = id_payload_1->Payload.Id.Port;
+ c->SendID1_Buf = CloneBuf(id_payload_1->Payload.Id.IdData);
+
+ c->SendID2_Type = id_payload_2->Payload.Id.Type;
+ c->SendID2_Protocol = id_payload_2->Payload.Id.ProtocolId;
+ c->SendID2_Port = id_payload_2->Payload.Id.Port;
+ c->SendID2_Buf = CloneBuf(id_payload_2->Payload.Id.IdData);
+
+ c->SendID1andID2 = true;
+ }
+ else
+ {
+ c->SendID1andID2 = false;
+ }
+
+ if (true)
+ {
+ // Reply if NAT-OA payload is presented by the client
+ IKE_PACKET_PAYLOAD *nat_oa_draft1 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_OA_DRAFT, 0);
+ IKE_PACKET_PAYLOAD *nat_oa_draft2 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_OA_DRAFT_2, 0);
+ IKE_PACKET_PAYLOAD *nat_oa_rfc_0 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_OA, 0);
+ IKE_PACKET_PAYLOAD *nat_oa_rfc_1 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_OA, 1);
+
+ c->SendNatOaDraft1 = c->SendNatOaDraft2 = c->SendNatOaRfc = false;
+
+ c->ShouldCalcChecksumForUDP = false;
+
+ if (nat_oa_draft1 != NULL)
+ {
+ Add(payload_list, IkeNewNatOaPayload(IKE_PAYLOAD_NAT_OA_DRAFT, &c->ServerIP));
+ c->SendNatOaDraft1 = true;
+
+ if (IsIP4(&nat_oa_draft1->Payload.NatOa.IpAddress) == IsIP4(&c->ServerIP))
+ {
+ Copy(&c->TransportModeClientIP, &nat_oa_draft1->Payload.NatOa.IpAddress, sizeof(IP));
+ Copy(&c->TransportModeServerIP, &c->ServerIP, sizeof(IP));
+
+ c->ShouldCalcChecksumForUDP = true;
+ }
+ }
+
+ if (nat_oa_draft2 != NULL)
+ {
+ Add(payload_list, IkeNewNatOaPayload(IKE_PAYLOAD_NAT_OA_DRAFT_2, &c->ServerIP));
+ c->SendNatOaDraft2 = true;
+
+ if (IsIP4(&nat_oa_draft2->Payload.NatOa.IpAddress) == IsIP4(&c->ServerIP))
+ {
+ Copy(&c->TransportModeClientIP, &nat_oa_draft2->Payload.NatOa.IpAddress, sizeof(IP));
+ Copy(&c->TransportModeServerIP, &c->ServerIP, sizeof(IP));
+
+ c->ShouldCalcChecksumForUDP = true;
+ }
+ }
+
+ if (nat_oa_rfc_0 != NULL && nat_oa_rfc_1 != NULL)
+ {
+ Add(payload_list, IkeNewNatOaPayload(IKE_PAYLOAD_NAT_OA, &c->ClientIP));
+ Add(payload_list, IkeNewNatOaPayload(IKE_PAYLOAD_NAT_OA, &c->ServerIP));
+ c->SendNatOaRfc = true;
+
+ if (IsIP4(&nat_oa_rfc_0->Payload.NatOa.IpAddress) == IsIP4(&c->ServerIP))
+ {
+ Copy(&c->TransportModeClientIP, &nat_oa_rfc_0->Payload.NatOa.IpAddress, sizeof(IP));
+ Copy(&c->TransportModeServerIP, &c->ServerIP, sizeof(IP));
+
+ c->ShouldCalcChecksumForUDP = true;
+ }
+ }
+ }
+
+ // Build a packet
+ ps = IkeNew(ike_sa->InitiatorCookie, ike_sa->ResponderCookie, IKE_EXCHANGE_TYPE_QUICK,
+ false, false, false, header->MessageId, payload_list);
+
+ // Build a temporary packet
+ ps_buf = IkeBuild(ps, NULL);
+
+ // Get the payload after the hash part
+ after_hash_offset = sizeof(IKE_HEADER) + send_hash_payload->BitArray->Size + sizeof(IKE_COMMON_HEADER);
+ after_hash_size = ((ps_buf->Size > after_hash_offset) ? (ps_buf->Size - after_hash_offset) : 0);
+
+ ps_buf_after_hash = MemToBuf(((UCHAR *)ps_buf->Buf) + after_hash_offset, after_hash_size);
+ FreeBuf(ps_buf);
+
+ // Calculate the hash #2
+ tmp_buf = NewBuf();
+ WriteBufInt(tmp_buf, header->MessageId);
+ WriteBufBuf(tmp_buf, initiator_rand);
+ WriteBufBuf(tmp_buf, ps_buf_after_hash);
+ IkeHMac(ike_sa->TransformSetting.Hash, hash2, ike_sa->SKEYID_a, ike_sa->HashSize, tmp_buf->Buf, tmp_buf->Size);
+ FreeBuf(tmp_buf);
+
+ // Calculate the hash #3
+ tmp_buf = NewBuf();
+ WriteBuf(tmp_buf, &zero, 1);
+ WriteBufInt(tmp_buf, header->MessageId);
+ WriteBufBuf(tmp_buf, initiator_rand);
+ WriteBufBuf(tmp_buf, responder_rand);
+ IkeHMac(ike_sa->TransformSetting.Hash, hash3, ike_sa->SKEYID_a, ike_sa->HashSize, tmp_buf->Buf, tmp_buf->Size);
+ FreeBuf(tmp_buf);
+
+ // Create an IPsec SA
+ ipsec_sa_c_s = NewIPsecSa(ike, c, ike_sa, false, header->MessageId, false, cp.NextIv, spi,
+ initiator_rand->Buf, initiator_rand->Size, responder_rand->Buf, responder_rand->Size,
+ &setting, shared_key, shared_key_size);
+ ipsec_sa_s_c = NewIPsecSa(ike, c, ike_sa, false, header->MessageId, true, cp.NextIv, setting.SpiServerToClient,
+ initiator_rand->Buf, initiator_rand->Size, responder_rand->Buf, responder_rand->Size,
+ &setting, shared_key, shared_key_size);
+
+ ipsec_sa_c_s->PairIPsecSa = ipsec_sa_s_c;
+ ipsec_sa_s_c->PairIPsecSa = ipsec_sa_c_s;
+
+ Insert(ike->IPsecSaList, ipsec_sa_c_s);
+ Insert(ike->IPsecSaList, ipsec_sa_s_c);
+
+ Copy(ipsec_sa_c_s->Hash3, hash3, ike_sa->HashSize);
+
+ // Overwrite hash #2
+ Copy(send_hash_payload->Payload.Hash.Data->Buf, hash2, ike_sa->HashSize);
+
+ // Packet reply
+ ps->FlagEncrypted = true;
+ IPsecSaSendPacket(ike, ipsec_sa_s_c, ps);
+ IkeSaSendPacket(ike, ike_sa, NULL);
+
+#ifdef RAW_DEBUG
+ IkeDebugUdpSendRawPacket(ps);
+#endif // RAW_DEBUG
+
+ IkeFree(ps);
+ Free(shared_key);
+ FreeBuf(ps_buf_after_hash);
+ FreeBuf(initiator_rand);
+ FreeBuf(responder_rand);
+ }
+ }
+ else
+ {
+ // No appropriate transform setting
+ Debug("No Appropriate Transform was Found.\n");
+
+ IPsecLog(ike, NULL, ike_sa, NULL, "LI_IPSEC_NO_TRANSFORM");
+
+ SendInformationalExchangePacket(ike, c, IkeNewNoticeErrorNoProposalChosenPayload(true, header->InitiatorCookie, header->ResponderCookie));
+ }
+ }
+ }
+ else
+ {
+ Debug("QM-1: Hash 1 is invalid.\n");
+ }
+
+ FreeBuf(hash1_buf);
+ }
+ }
+
+ IkeFree(pr);
+ }
+ }
+ else
+ {
+ // Get the IPsec SA
+ IPSECSA *ipsec_sa_cs = SearchIPsecSaByMessageId(ike, c, header->MessageId);
+ if (ipsec_sa_cs != NULL)
+ {
+ IPSECSA *ipsec_sa_sc = ipsec_sa_cs->PairIPsecSa;
+ if (ipsec_sa_sc != NULL)
+ {
+ if (ipsec_sa_sc->Established == false && ipsec_sa_cs->Established == false)
+ {
+ IKE_PACKET *pr = IPsecSaRecvPacket(ike, ipsec_sa_cs, p->Data, p->Size);
+
+#ifdef RAW_DEBUG
+ IkeDebugUdpSendRawPacket(pr);
+#endif // RAW_DEBUG
+
+ if (pr != NULL)
+ {
+ if (ipsec_sa_cs->Initiated == false)
+ {
+ // Initiator is client-side
+ // Check hash3 payload
+ IKE_PACKET_PAYLOAD *hash_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_HASH, 0);
+
+ if (hash_payload != NULL)
+ {
+ BUF *hash_buf = hash_payload->Payload.Hash.Data;
+ if (hash_buf != NULL)
+ {
+ if (hash_buf->Size == ipsec_sa_cs->IkeSa->HashSize)
+ {
+ if (Cmp(hash_buf->Buf, ipsec_sa_cs->Hash3, hash_buf->Size) == 0)
+ {
+ ipsec_sa_cs->Established = ipsec_sa_sc->Established = true;
+ ipsec_sa_cs->EstablishedTick = ipsec_sa_sc->EstablishedTick = ike->Now;
+ ipsec_sa_cs->LastCommTick = ipsec_sa_sc->LastCommTick = ike->Now;
+
+ c->CurrentIpSecSaRecv = ipsec_sa_cs;
+ c->CurrentIpSecSaSend = ipsec_sa_sc;
+
+ Debug("IPsec SA 0x%X & 0x%X Established.\n",
+ ipsec_sa_cs->Spi,
+ ipsec_sa_sc->Spi);
+
+ IPsecLog(ike, NULL, NULL, ipsec_sa_sc, "LI_IPSEC_SA_ESTABLISHED");
+
+ IPsecSaSendPacket(ike, ipsec_sa_sc, NULL);
+ }
+ else
+ {
+ Debug("QM-3: Hash 3 is invalid.\n");
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Initiator is server-side
+ // Get hash payload
+ IKE_PACKET_PAYLOAD *hash_payload;
+
+ hash_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_HASH, 0);
+ if (hash_payload != NULL && ipsec_sa_sc->InitiatorRand != NULL)
+ {
+ // Get the payload after the hash
+ UINT header_and_hash_size = sizeof(IKE_COMMON_HEADER) + hash_payload->BitArray->Size;
+ void *after_hash_data = ((UCHAR *)pr->DecryptedPayload->Buf) + header_and_hash_size;
+ if (pr->DecryptedPayload->Size > header_and_hash_size)
+ {
+ UINT after_hash_size = pr->DecryptedPayload->Size - header_and_hash_size;
+ UCHAR hash2[IKE_MAX_HASH_SIZE];
+ BUF *hash2_buf;
+
+ hash2_buf = NewBuf();
+ WriteBufInt(hash2_buf, header->MessageId);
+ WriteBufBuf(hash2_buf, ipsec_sa_sc->InitiatorRand);
+ WriteBuf(hash2_buf, after_hash_data, after_hash_size);
+
+ IkeHMac(ipsec_sa_sc->SKEYID_Hash, hash2, ipsec_sa_sc->SKEYID_a, ipsec_sa_sc->SKEYID_Hash->HashSize,
+ hash2_buf->Buf, hash2_buf->Size);
+
+ FreeBuf(hash2_buf);
+
+ // Compare the hash value
+ if (IkeCompareHash(hash_payload, hash2, ike_sa->HashSize))
+ {
+ IKE_PACKET_PAYLOAD *sa_payload, *rand_payload, *key_payload, *id_payload_1, *id_payload_2;
+
+ // Get the payload of other
+ sa_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_SA, 0);
+ rand_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_RAND, 0);
+ key_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_KEY_EXCHANGE, 0);
+ id_payload_1 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_ID, 0);
+ id_payload_2 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_ID, 1);
+
+ if (sa_payload != NULL && rand_payload != NULL)
+ {
+ IPSEC_SA_TRANSFORM_SETTING setting;
+
+ // Interpret the SA payload
+ if (GetBestTransformSettingForIPsecSa(ike, pr, &setting, &p->DstIP))
+ {
+ // Appropriate transform setting is selected
+ Debug("P2 Transform: %s %s %s(%u) %u %u\n",
+ (setting.Dh == NULL ? NULL : setting.Dh->Name), setting.Hash->Name, setting.Crypto->Name, setting.CryptoKeySize,
+ setting.LifeKilobytes, setting.LifeSeconds);
+
+#ifdef FORCE_LIFETIME_QM
+ setting.LifeSeconds = FORCE_LIFETIME_QM;
+#endif // FORCE_LIFETIME_QM
+
+ // Check the key exchange payload if the PFS is specified
+ if (setting.Dh == NULL || (setting.Dh != NULL && key_payload != NULL && ipsec_sa_sc->Dh != NULL &&
+ key_payload->Payload.KeyExchange.Data->Size <= setting.Dh->KeySize))
+ {
+ IKE_PACKET *ps;
+ LIST *payload_list;
+ IKE_PACKET_PAYLOAD *send_hash_payload;
+ IKE_PACKET_PAYLOAD *send_key_payload = NULL;
+ IKE_PACKET_PAYLOAD *send_id_1 = NULL, *send_id_2 = NULL;
+ DH_CTX *dh = NULL;
+ UINT shared_key_size = 0;
+ UCHAR *shared_key = NULL;
+ BUF *initiator_rand, *responder_rand;
+ BUF *tmp_buf;
+ UCHAR hash3[IKE_MAX_HASH_SIZE];
+ char tmp[MAX_SIZE];
+ UCHAR zero = 0;
+
+ initiator_rand = ipsec_sa_sc->InitiatorRand;
+ responder_rand = CloneBuf(rand_payload->Payload.Rand.Data);
+
+ if (setting.Dh != NULL)
+ {
+ // Calculate DH
+ DH_CTX *dh = ipsec_sa_sc->Dh;
+
+ shared_key_size = (dh == NULL ? 0 : dh->Size);
+ shared_key = ZeroMalloc(shared_key_size);
+
+ if (DhCompute(dh, shared_key, key_payload->Payload.KeyExchange.Data->Buf, key_payload->Payload.KeyExchange.Data->Size))
+ {
+ // DH calculation success
+ Debug("P2 DH Ok.\n");
+ }
+ else
+ {
+ // DH calculation failure
+ Debug("P2 DhCompute failed.\n");
+
+ shared_key = NULL;
+ Free(shared_key);
+ shared_key_size = 0;
+
+ IPsecLog(ike, NULL, ike_sa, NULL, "LI_QM_DH_ERROR");
+ }
+ }
+
+ // Update the information of IPsec SA
+ if (shared_key != NULL)
+ {
+ ipsec_sa_sc->SharedKey = NewBuf(shared_key, shared_key_size);
+ ipsec_sa_cs->SharedKey = NewBuf(shared_key, shared_key_size);
+ }
+
+ ipsec_sa_sc->Spi = setting.SpiServerToClient;
+ IPsecLog(ike, NULL, NULL, ipsec_sa_sc, "LI_IPSEC_SA_SPI_SET", ipsec_sa_sc->Spi);
+ ike->IPsecSaList->sorted = false;
+
+ ipsec_sa_sc->ResponderRand = CloneBuf(responder_rand);
+ ipsec_sa_cs->ResponderRand = CloneBuf(responder_rand);
+
+ Copy(&ipsec_sa_sc->TransformSetting, &setting, sizeof(IPSEC_SA_TRANSFORM_SETTING));
+ Copy(&ipsec_sa_cs->TransformSetting, &setting, sizeof(IPSEC_SA_TRANSFORM_SETTING));
+
+ ipsec_sa_sc->Established = true;
+ ipsec_sa_cs->Established = true;
+
+ IPsecLog(ike, NULL, NULL, ipsec_sa_sc, "LI_IPSEC_SA_ESTABLISHED");
+
+ ipsec_sa_sc->LastCommTick = ike->Now;
+ ipsec_sa_cs->LastCommTick = ike->Now;
+
+ c->CurrentIpSecSaRecv = ipsec_sa_cs;
+ c->CurrentIpSecSaSend = ipsec_sa_sc;
+
+ // Calculate the KEYMAT
+ IPsecCalcKeymat(ike, ipsec_sa_sc->SKEYID_Hash, ipsec_sa_sc->KeyMat, sizeof(ipsec_sa_sc->KeyMat),
+ ipsec_sa_sc->SKEYID_d, ipsec_sa_sc->SKEYID_Hash->HashSize, IKE_PROTOCOL_ID_IPSEC_ESP,
+ ipsec_sa_sc->Spi, initiator_rand->Buf, initiator_rand->Size,
+ responder_rand->Buf, responder_rand->Size,
+ shared_key, shared_key_size);
+
+ IPsecCalcKeymat(ike, ipsec_sa_cs->SKEYID_Hash, ipsec_sa_cs->KeyMat, sizeof(ipsec_sa_cs->KeyMat),
+ ipsec_sa_cs->SKEYID_d, ipsec_sa_cs->SKEYID_Hash->HashSize, IKE_PROTOCOL_ID_IPSEC_ESP,
+ ipsec_sa_cs->Spi, initiator_rand->Buf, initiator_rand->Size,
+ responder_rand->Buf, responder_rand->Size,
+ shared_key, shared_key_size);
+
+ IkeFreeKey(ipsec_sa_sc->CryptoKey);
+ IkeFreeKey(ipsec_sa_cs->CryptoKey);
+
+ ipsec_sa_sc->CryptoKey = IkeNewKey(setting.Crypto, ipsec_sa_sc->KeyMat, setting.CryptoKeySize);
+ ipsec_sa_cs->CryptoKey = IkeNewKey(setting.Crypto, ipsec_sa_cs->KeyMat, setting.CryptoKeySize);
+
+ Copy(ipsec_sa_sc->HashKey, ipsec_sa_sc->KeyMat + setting.CryptoKeySize, setting.Hash->HashSize);
+ Copy(ipsec_sa_cs->HashKey, ipsec_sa_cs->KeyMat + setting.CryptoKeySize, setting.Hash->HashSize);
+
+ BinToStrEx(tmp, sizeof(tmp), ipsec_sa_sc->KeyMat, ipsec_sa_sc->TransformSetting.CryptoKeySize);
+ Debug(" KEYMAT (SC): %s\n", tmp);
+
+ BinToStrEx(tmp, sizeof(tmp), ipsec_sa_cs->KeyMat, ipsec_sa_cs->TransformSetting.CryptoKeySize);
+ Debug(" KEYMAT (CS): %s\n", tmp);
+
+ Debug("IPsec SA 0x%X & 0x%X Established (Server is Initiator).\n",
+ ipsec_sa_cs->Spi,
+ ipsec_sa_sc->Spi);
+
+ // Calculate the hash #3
+ tmp_buf = NewBuf();
+ WriteBuf(tmp_buf, &zero, 1);
+ WriteBufInt(tmp_buf, header->MessageId);
+ WriteBufBuf(tmp_buf, initiator_rand);
+ WriteBufBuf(tmp_buf, responder_rand);
+ IkeHMac(ipsec_sa_cs->SKEYID_Hash, hash3, ipsec_sa_cs->SKEYID_a, ipsec_sa_cs->SKEYID_Hash->HashSize, tmp_buf->Buf, tmp_buf->Size);
+ FreeBuf(tmp_buf);
+
+ // Return the hash #3
+ send_hash_payload = IkeNewDataPayload(IKE_PAYLOAD_HASH, hash3, ipsec_sa_cs->SKEYID_Hash->HashSize);
+
+ payload_list = NewListSingle(send_hash_payload);
+ ps = IkeNew(ike_sa->InitiatorCookie, ike_sa->ResponderCookie,
+ IKE_EXCHANGE_TYPE_QUICK, true, false, false, header->MessageId, payload_list);
+
+ IPsecSaSendPacket(ike, ipsec_sa_sc, ps);
+#ifdef RAW_DEBUG
+ IkeDebugUdpSendRawPacket(ps);
+#endif // RAW_DEBUG
+ ipsec_sa_sc->NumResends = 3;
+
+ if (false)
+ {
+ UINT i;
+
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+
+ if (sa != ipsec_sa_sc && sa != ipsec_sa_cs)
+ {
+ MarkIPsecSaAsDeleted(ike, sa);
+ }
+ }
+ }
+
+ IkeFree(ps);
+
+ // Release the memory
+ FreeBuf(responder_rand);
+ }
+ }
+ else
+ {
+ // No appropriate transform setting
+ Debug("No Appropriate Transform was Found.\n");
+
+ IPsecLog(ike, NULL, ike_sa, NULL, "LI_IPSEC_NO_TRANSFORM");
+
+ SendInformationalExchangePacket(ike, c, IkeNewNoticeErrorNoProposalChosenPayload(true, header->InitiatorCookie, header->ResponderCookie));
+ }
+ }
+ }
+ }
+ }
+ }
+ IkeFree(pr);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// Calculate the KEYMAT
+void IPsecCalcKeymat(IKE_SERVER *ike, IKE_HASH *h, void *dst, UINT dst_size, void *skeyid_d_data, UINT skeyid_d_size, UCHAR protocol, UINT spi, void *rand_init_data, UINT rand_init_size,
+ void *rand_resp_data, UINT rand_resp_size, void *df_key_data, UINT df_key_size)
+{
+ BUF *k;
+ BUF *ret;
+ // Validate arguments
+ if (ike == NULL || dst == NULL || h == NULL || rand_init_data == NULL || rand_resp_data == NULL||
+ (df_key_size != 0 && df_key_data == NULL))
+ {
+ return;
+ }
+
+ ret = NewBuf();
+
+ k = NULL;
+
+ while (true)
+ {
+ BUF *tmp = NewBuf();
+ UCHAR hash[IKE_MAX_HASH_SIZE];
+
+ if (k != NULL)
+ {
+ WriteBufBuf(tmp, k);
+ }
+
+ if (df_key_data != NULL)
+ {
+ WriteBuf(tmp, df_key_data, df_key_size);
+ }
+
+ WriteBuf(tmp, &protocol, 1);
+
+ WriteBufInt(tmp, spi);
+
+ WriteBuf(tmp, rand_init_data, rand_init_size);
+ WriteBuf(tmp, rand_resp_data, rand_resp_size);
+
+ if (k != NULL)
+ {
+ FreeBuf(k);
+ }
+
+ IkeHMac(h, hash, skeyid_d_data, skeyid_d_size, tmp->Buf, tmp->Size);
+
+ FreeBuf(tmp);
+
+ k = MemToBuf(hash, h->HashSize);
+
+ WriteBufBuf(ret, k);
+
+ if (ret->Size >= dst_size)
+ {
+ break;
+ }
+ }
+
+ Copy(dst, ret->Buf, dst_size);
+
+ FreeBuf(ret);
+ FreeBuf(k);
+}
+
+// Search for IPsec SA from Message ID
+IPSECSA *SearchIPsecSaByMessageId(IKE_SERVER *ike, IKE_CLIENT *c, UINT message_id)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL || c == NULL || message_id == 0)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+
+ if (sa->IkeClient == c)
+ {
+ if (sa->MessageId == message_id)
+ {
+ if (sa->ServerToClient == false)
+ {
+ if (sa->Established == false)
+ {
+ return sa;
+ }
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+// Search for IPsec SA from SPI value
+IPSECSA *SearchClientToServerIPsecSaBySpi(IKE_SERVER *ike, UINT spi)
+{
+ IPSECSA t;
+ // Validate arguments
+ if (ike == NULL || spi == 0)
+ {
+ return NULL;
+ }
+
+ t.ServerToClient = false;
+ t.Spi = spi;
+
+ return Search(ike->IPsecSaList, &t);
+}
+IPSECSA *SearchIPsecSaBySpi(IKE_SERVER *ike, IKE_CLIENT *c, UINT spi)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL || c == NULL || spi == 0)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+
+ if (sa->Spi == spi)
+ {
+ if (sa->IkeClient == c)
+ {
+ return sa;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+// Search an IKE SA from the value of the Cookie
+IKE_SA *SearchIkeSaByCookie(IKE_SERVER *ike, UINT64 init_cookie, UINT64 resp_cookie)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+
+ if (sa->InitiatorCookie == init_cookie && sa->ResponderCookie == resp_cookie)
+ {
+ return sa;
+ }
+ }
+
+ return NULL;
+}
+
+// Generate the SPI value of new IPsec SA
+UINT GenerateNewIPsecSaSpi(IKE_SERVER *ike, UINT counterpart_spi)
+{
+ UINT ret;
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return 0;
+ }
+
+ while (true)
+ {
+ ret = Rand32();
+
+ if (ret != counterpart_spi)
+ {
+ if (ret >= 4096 && ret != INFINITE)
+ {
+ if (SearchClientToServerIPsecSaBySpi(ike, ret) == NULL)
+ {
+ return ret;
+ }
+ }
+ }
+ }
+}
+
+// Calculate the initial IV for Phase 2
+void IkeCalcPhase2InitialIv(void *iv, IKE_SA *sa, UINT message_id)
+{
+ BUF *b;
+ UCHAR hash[IKE_MAX_HASH_SIZE];
+ // Validate arguments
+ if (iv == NULL || sa == NULL)
+ {
+ return;
+ }
+
+ message_id = Endian32(message_id);
+
+ b = NewBuf();
+ WriteBuf(b, sa->Iv, sa->BlockSize);
+ WriteBuf(b, &message_id, sizeof(UINT));
+
+ IkeHash(sa->TransformSetting.Hash, hash, b->Buf, b->Size);
+
+ Copy(iv, hash, sa->TransformSetting.Crypto->BlockSize);
+
+ FreeBuf(b);
+}
+
+// Create a new IPsec SA
+IPSECSA *NewIPsecSa(IKE_SERVER *ike, IKE_CLIENT *c, IKE_SA *ike_sa, bool initiate, UINT message_id, bool server_to_client, void *iv, UINT spi, void *init_rand_data, UINT init_rand_size, void *res_rand_data, UINT res_rand_size, IPSEC_SA_TRANSFORM_SETTING *setting, void *shared_key_data, UINT shared_key_size)
+{
+ IPSECSA *sa;
+ char tmp[MAX_SIZE];
+ UINT total_key_size;
+ // Validate arguments
+ if (ike == NULL || c == NULL || ike_sa == NULL || message_id == 0 || iv == NULL || setting == NULL ||
+ (shared_key_data == NULL && shared_key_size != 0))
+ {
+ return NULL;
+ }
+
+ sa = ZeroMalloc(sizeof(IPSECSA));
+
+ if (server_to_client == false)
+ {
+ ike->CurrentIPsecSaId++;
+ }
+ sa->Id = ike->CurrentIPsecSaId;
+
+ sa->IkeClient = c;
+ sa->IkeSa = ike_sa;
+
+ sa->MessageId = message_id;
+ sa->FirstCommTick = ike->Now;
+ sa->LastCommTick = ike->Now;
+ sa->Initiated = initiate;
+
+ sa->ServerToClient = server_to_client;
+
+ sa->Spi = spi;
+
+ sa->SKEYID_Hash = ike_sa->TransformSetting.Hash;
+ Copy(sa->SKEYID_a, ike_sa->SKEYID_a, sa->SKEYID_Hash->HashSize);
+ Copy(sa->SKEYID_d, ike_sa->SKEYID_d, sa->SKEYID_Hash->HashSize);
+
+ sa->InitiatorRand = MemToBuf(init_rand_data, init_rand_size);
+
+ if (initiate == false)
+ {
+ sa->ResponderRand = MemToBuf(res_rand_data, res_rand_size);
+ }
+
+ Copy(sa->Iv, iv, ike_sa->BlockSize);
+
+ Copy(&sa->TransformSetting, setting, sizeof(IPSEC_SA_TRANSFORM_SETTING));
+
+ if (shared_key_data != NULL)
+ {
+ sa->SharedKey = MemToBuf(shared_key_data, shared_key_size);
+ }
+
+ total_key_size = sa->TransformSetting.CryptoKeySize + sa->TransformSetting.Hash->HashSize;
+
+ if (initiate == false)
+ {
+ IPsecCalcKeymat(ike, ike_sa->TransformSetting.Hash, sa->KeyMat, total_key_size,
+ ike_sa->SKEYID_d, ike_sa->HashSize, IKE_PROTOCOL_ID_IPSEC_ESP, spi, sa->InitiatorRand->Buf,
+ sa->InitiatorRand->Size, sa->ResponderRand->Buf, sa->ResponderRand->Size,
+ shared_key_data, shared_key_size);
+
+ sa->CryptoKey = IkeNewKey(sa->TransformSetting.Crypto, sa->KeyMat, sa->TransformSetting.CryptoKeySize);
+
+ Copy(sa->HashKey, sa->KeyMat + sa->TransformSetting.CryptoKeySize, sa->TransformSetting.Hash->HashSize);
+ }
+
+ Debug("New IPsec SA (StoC = %u): 0x%X 0x%X (%s %s %s(%u) %u %u)\n",
+ sa->ServerToClient,
+ sa->MessageId,
+ sa->Spi,
+ (setting->Dh == NULL ? NULL : setting->Dh->Name), setting->Hash->Name, setting->Crypto->Name, setting->CryptoKeySize,
+ setting->LifeKilobytes, setting->LifeSeconds);
+
+ IPsecLog(ike, c, NULL, sa, "LI_NEW_IPSEC_SA",
+ (sa->ServerToClient ? _UU("LI_TAG_SERVER_TO_CLIENT") : _UU("LI_TAG_CLIENT_TO_SERVER")),
+ sa->Spi,
+ (setting->Dh == NULL ? NULL : setting->Dh->Name), setting->Hash->Name, setting->Crypto->Name, setting->CryptoKeySize * 8,
+ setting->LifeKilobytes, setting->LifeSeconds);
+
+ Rand(sa->EspIv, sizeof(sa->EspIv));
+
+ if (initiate == false)
+ {
+ BinToStrEx(tmp, sizeof(tmp), sa->KeyMat, sa->TransformSetting.CryptoKeySize);
+ Debug(" KEYMAT: %s\n", tmp);
+ }
+
+ // Set the expiration time
+ if (setting->LifeSeconds != 0)
+ {
+ UINT64 span = (UINT64)(setting->LifeSeconds * 1000) + (UINT64)IKE_SOFT_EXPIRES_MARGIN;
+ sa->ExpiresHardTick = ike->Now + span;
+ sa->ExpiresSoftTick = ike->Now + span;
+ //sa->ExpiresSoftTick = ike->Now + (UINT64)5000;
+
+ AddInterrupt(ike->Interrupts, sa->ExpiresSoftTick);
+ }
+
+ return sa;
+}
+
+// Treat aggressive mode packet reception
+void ProcIkeAggressiveModePacketRecv(IKE_SERVER *ike, UDPPACKET *p, IKE_PACKET *header)
+{
+ IKE_CLIENT *c;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (ike == NULL || p == NULL || header == NULL || header->InitiatorCookie == 0)
+ {
+ return;
+ }
+
+ c = SearchOrCreateNewIkeClientForIkePacket(ike, &p->SrcIP, p->SrcPort, &p->DstIP, p->DestPort, header);
+
+ if (c == NULL)
+ {
+ return;
+ }
+
+ if (header->ResponderCookie == 0)
+ {
+ // Start process of the state 1
+ IKE_CAPS caps;
+ IKE_SA *sa;
+ IKE_PACKET *pr = IkeParse(p->Data, p->Size, NULL);
+
+ if (pr != NULL)
+ {
+ // Determine the CAPS
+ IkeCheckCaps(&caps, pr);
+ if (caps.MS_L2TPIPSecVPNClient || caps.MS_NT5_ISAKMP_OAKLEY || caps.MS_Vid_InitialContact)
+ {
+ c->IsMicrosoft = true;
+ }
+
+ if ((caps.NatTraversalDraftIetf || caps.NatTraversalRfc3947) || (IsUdpPortOpened(ike->IPsec->UdpListener, &p->DstIP, IPSEC_PORT_IPSEC_ESP_RAW)))
+ {
+ sa = FindIkeSaByEndPointAndInitiatorCookie(ike, &p->DstIP, p->DestPort, &p->SrcIP, p->SrcPort, header->InitiatorCookie, IKE_SA_AGRESSIVE_MODE);
+
+ if (sa == NULL)
+ {
+ // Check whether there is acceptable SA parameters by analyzing proposed parameters
+ IKE_SA_TRANSFORM_SETTING setting;
+
+ if (GetBestTransformSettingForIkeSa(ike, pr, &setting) && (GetNumberOfIkeSaOfIkeClient(ike, c) <= IKE_QUOTA_MAX_SA_PER_CLIENT))
+ {
+ IKE_PACKET_PAYLOAD *tp;
+ IKE_PACKET_PAYLOAD *pp;
+ IKE_PACKET_PAYLOAD *sap;
+ IKE_PACKET_PAYLOAD *client_sa_payload;
+ IKE_PACKET_PAYLOAD *your_key_payload;
+ IKE_PACKET_PAYLOAD *your_rand_payload;
+ IKE_PACKET_PAYLOAD *your_id_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_ID, 0);
+
+ // Appropriate transform setting is selected
+ Debug("P1 Transform: %s %s %s(%u) %u %u\n",
+ setting.Dh->Name, setting.Hash->Name, setting.Crypto->Name, setting.CryptoKeySize,
+ setting.LifeKilobytes, setting.LifeSeconds);
+
+ // Receive a key exchange packet
+ your_key_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_KEY_EXCHANGE, 0);
+ your_rand_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_RAND, 0);
+ if (your_key_payload != NULL && your_rand_payload != NULL && your_id_payload != NULL)
+ {
+ // Check the key payload
+ BUF *your_key_buf = your_key_payload->Payload.KeyExchange.Data;
+ BUF *your_rand_buf = your_rand_payload->Payload.Rand.Data;
+
+ // DH generation
+ DH_CTX *dh = IkeDhNewCtx(setting.Dh);
+ UINT shared_key_size = (dh == NULL ? 0 : dh->Size);
+ UCHAR *shared_key = ZeroMalloc(shared_key_size);
+
+ // DH calculation
+ if (DhCompute(dh, shared_key, your_key_buf->Buf, your_key_buf->Size))
+ {
+ IKE_PACKET *ps;
+ LIST *payload_list;
+ IKE_PACKET_PAYLOAD *my_key_payload;
+ IKE_PACKET_PAYLOAD *my_rand_payload;
+ BUF *nat_buf1, *nat_buf2;
+ BUF *iv_buf;
+ UCHAR iv_hashed_data[IKE_MAX_HASH_SIZE];
+ UCHAR initiator_hash[IKE_MAX_HASH_SIZE];
+ BUF *b;
+ IKE_PACKET_PAYLOAD *my_id_payload, *my_hash_payload;
+ UCHAR responder_hash[IKE_MAX_HASH_SIZE];
+ BUF *idir_b;
+ IKE_PACKET_PAYLOAD *your_nat_d_1 = NULL;
+ IKE_PACKET_PAYLOAD *your_nat_d_2 = NULL;
+
+ // Create an IKE SA
+ sa = NewIkeSa(ike, c, header->InitiatorCookie, IKE_SA_AGRESSIVE_MODE, &setting);
+ Copy(&sa->Caps, &caps, sizeof(IKE_CAPS));
+ sa->State= IKE_SA_AM_STATE_1_SA;
+ Insert(ike->IkeSaList, sa);
+
+ sa->HashSize = sa->TransformSetting.Hash->HashSize;
+ sa->KeySize = sa->TransformSetting.CryptoKeySize;
+ sa->BlockSize = sa->TransformSetting.Crypto->BlockSize;
+
+ // Get the Caps additionally
+ if (sa->Caps.NatTraversalRfc3947)
+ {
+ sa->Caps.UsingNatTraversalRfc3947 = true;
+
+ your_nat_d_1 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_D, 0);
+ your_nat_d_2 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_D, 1);
+ }
+ else if (sa->Caps.NatTraversalDraftIetf)
+ {
+ sa->Caps.UsingNatTraversalDraftIetf = true;
+
+ your_nat_d_1 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_D_DRAFT, 0);
+ your_nat_d_2 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_D_DRAFT, 1);
+ }
+
+ // Calculation success
+ sa->DhSharedKey = MemToBuf(shared_key, shared_key_size);
+ sa->InitiatorRand = RandBuf(IKE_SA_RAND_SIZE);
+ sa->ResponderRand = CloneBuf(your_rand_buf);
+
+ // Save a bit array of SA payload presented by the client
+ client_sa_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_SA, 0);
+ sa->SAi_b = CloneBuf(client_sa_payload->BitArray);
+
+ // Save the ID payload presented by the client
+ sa->YourIDPayloadForAM = CloneBuf(your_id_payload->BitArray);
+
+ //// Assemble the SA payload
+ // Construct transform payload
+ tp = TransformSettingToTransformPayloadForIke(ike, &setting);
+
+ // Build a proposal payload
+ pp = IkeNewProposalPayload(1, IKE_PROTOCOL_ID_IKE, NULL, 0, NewListSingle(tp));
+
+ // Build the SA payload
+ sap = IkeNewSaPayload(NewListSingle(pp));
+
+ payload_list = NewListSingle(sap);
+
+ // Send a key exchange packet
+ my_key_payload = IkeNewDataPayload(IKE_PAYLOAD_KEY_EXCHANGE, dh->MyPublicKey->Buf, dh->MyPublicKey->Size);
+ my_rand_payload = IkeNewDataPayload(IKE_PAYLOAD_RAND, sa->InitiatorRand->Buf, sa->InitiatorRand->Size);
+
+ Add(payload_list, my_key_payload);
+ Add(payload_list, my_rand_payload);
+
+ // NAT-D Packet
+ // Address of the opponent. Randomize in order to be forced to use NAT
+ nat_buf1 = IkeCalcNatDetectHash(ike, sa->TransformSetting.Hash, Rand64(), Rand64(), &c->ClientIP, Rand16());
+
+ // My address
+ if (c->IsMicrosoft == false || (your_nat_d_1 == NULL || your_nat_d_2 == NULL || your_nat_d_1->BitArray == NULL))
+ {
+ // Calculate exactly
+ nat_buf2 = IkeCalcNatDetectHash(ike, sa->TransformSetting.Hash,
+ sa->InitiatorCookie, sa->ResponderCookie, &c->ServerIP, c->ServerPort);
+ }
+ else
+ {
+ // Parrot the NAT_D payload indicating myself I got from
+ // the other if it has connected from a Microsoft VPN Client
+ nat_buf2 = CloneBuf(your_nat_d_1->BitArray);
+ }
+
+ // Save DH information
+ sa->GXi = CloneBuf(your_key_buf);
+ sa->GXr = CloneBuf(dh->MyPublicKey);
+
+ // Calculate the key set
+ IkeCalcSaKeySet(ike, sa, NULL);
+
+ // Calculate the initiator side hash value
+ b = NewBuf();
+ WriteBufBuf(b, sa->GXi);
+ WriteBufBuf(b, sa->GXr);
+ WriteBufInt64(b, sa->InitiatorCookie);
+ WriteBufInt64(b, sa->ResponderCookie);
+ WriteBufBuf(b, sa->SAi_b);
+ WriteBufBuf(b, sa->YourIDPayloadForAM);
+
+ IkeHMac(sa->TransformSetting.Hash, initiator_hash, sa->SKEYID, sa->HashSize,
+ b->Buf, b->Size);
+
+ FreeBuf(b);
+
+ Copy(sa->InitiatorHashForAM, initiator_hash, sa->HashSize);
+
+ // Prepare the response ID payload
+ // Generate the ID payload
+ if (IsIP6(&sa->IkeClient->ServerIP))
+ {
+ // IPv6 address
+ my_id_payload = IkeNewIdPayload(IKE_ID_IPV6_ADDR, 0, 0, sa->IkeClient->ServerIP.ipv6_addr, 16);
+ }
+ else
+ {
+ // IPv4 address
+ my_id_payload = IkeNewIdPayload(IKE_ID_IPV4_ADDR, 0, 0, sa->IkeClient->ServerIP.addr, 4);
+ }
+
+ // Build the ID payload tentatively
+ idir_b = IkeBuildIdPayload(&my_id_payload->Payload.Id);
+
+ b = NewBuf();
+ WriteBufBuf(b, sa->GXr);
+ WriteBufBuf(b, sa->GXi);
+ WriteBufInt64(b, sa->ResponderCookie);
+ WriteBufInt64(b, sa->InitiatorCookie);
+ WriteBufBuf(b, sa->SAi_b);
+ WriteBufBuf(b, idir_b);
+
+ IkeHMac(sa->TransformSetting.Hash, responder_hash, sa->SKEYID, sa->HashSize,
+ b->Buf, b->Size);
+
+ FreeBuf(b);
+ FreeBuf(idir_b);
+
+ my_hash_payload = IkeNewDataPayload(IKE_PAYLOAD_HASH, responder_hash, sa->HashSize);
+
+ Add(payload_list, my_id_payload);
+ Add(payload_list, my_hash_payload);
+
+ ps = IkeNew(sa->InitiatorCookie, sa->ResponderCookie, IKE_EXCHANGE_TYPE_AGGRESSIVE,
+ false, false, false, 0, payload_list);
+
+ // Add the vendor ID
+ IkeAddVendorIdPayloads(ps);
+
+ // NAT-D related
+ if (sa->Caps.UsingNatTraversalRfc3947)
+ {
+ // RFC-compliant
+ Add(payload_list, IkeNewDataPayload(IKE_PAYLOAD_NAT_D, nat_buf1->Buf, nat_buf1->Size));
+ Add(payload_list, IkeNewDataPayload(IKE_PAYLOAD_NAT_D, nat_buf2->Buf, nat_buf2->Size));
+ }
+
+ if (sa->Caps.UsingNatTraversalDraftIetf)
+ {
+ // Draft compliant
+ Add(payload_list, IkeNewDataPayload(IKE_PAYLOAD_NAT_D_DRAFT, nat_buf1->Buf, nat_buf1->Size));
+ Add(payload_list, IkeNewDataPayload(IKE_PAYLOAD_NAT_D_DRAFT, nat_buf2->Buf, nat_buf2->Size));
+ }
+
+ FreeBuf(nat_buf1);
+ FreeBuf(nat_buf2);
+
+ StrCpy(c->ClientId, sizeof(c->ClientId), your_id_payload->Payload.Id.StrData);
+ Debug("Client ID = %s\n", c->ClientId);
+
+ IPsecLog(ike, c, NULL, NULL, NULL, "LI_SET_CLIENT_ID", c->ClientId);
+
+ // Initial IV setting
+ iv_buf = NewBuf();
+ WriteBuf(iv_buf, your_key_buf->Buf, your_key_buf->Size);
+ WriteBuf(iv_buf, dh->MyPublicKey->Buf, dh->MyPublicKey->Size);
+ IkeHash(sa->TransformSetting.Hash, iv_hashed_data, iv_buf->Buf, iv_buf->Size);
+
+ BinToStrEx(tmp, sizeof(tmp), iv_hashed_data, sa->BlockSize);
+ Debug("Initial IV: %s\n", tmp);
+
+ IkeSaUpdateIv(sa, iv_hashed_data, sa->HashSize);
+
+ FreeBuf(iv_buf);
+
+ // Transmission
+ IkeSaSendPacket(ike, sa, ps);
+
+ IkeFree(ps);
+ }
+ else
+ {
+ // DH calculation failure
+ Debug("DhCompute failed.\n");
+ }
+
+ Free(shared_key);
+ DhFree(dh);
+ }
+ }
+ else
+ {
+ // No appropriate transform setting
+ Debug("No Appropriate Transform was Found.\n");
+
+ IPsecLog(ike, c, NULL, NULL, "LI_IKE_NO_TRANSFORM");
+
+ SendInformationalExchangePacket(ike, c, IkeNewNoticeErrorNoProposalChosenPayload(false, header->InitiatorCookie, header->ResponderCookie));
+ }
+ }
+ }
+ else
+ {
+ // Client does not support NAT Traversal
+ Debug("Client doesn't support NAT-T.\n");
+
+ IPsecLog(ike, c, NULL, NULL, "LI_IKE_NO_NAT_T");
+ }
+
+ IkeFree(pr);
+ }
+ }
+ else
+ {
+ // Process of state 2
+ IKE_SA *sa;
+
+ sa = FindIkeSaByResponderCookieAndClient(ike, header->ResponderCookie, c);
+
+ if (sa == NULL)
+ {
+ SendInformationalExchangePacketEx(ike, c, IkeNewNoticeErrorInvalidCookiePayload(header->InitiatorCookie,
+ header->ResponderCookie), true, header->InitiatorCookie, header->ResponderCookie);
+ }
+
+ if (sa != NULL && sa->Mode == IKE_SA_AGRESSIVE_MODE)
+ {
+ IKE_PACKET *pr = NULL;
+
+ sa->LastCommTick = ike->Now;
+
+ switch (sa->State)
+ {
+ case IKE_SA_AM_STATE_1_SA:
+ pr = IkeSaRecvPacket(ike, sa, p->Data, p->Size);
+ if (pr != NULL)
+ {
+ IKE_PACKET_PAYLOAD *your_hash_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_HASH, 0);
+
+ if (your_hash_payload != NULL)
+ {
+ // Compare the hash
+ if (IkeCompareHash(your_hash_payload, sa->InitiatorHashForAM, sa->HashSize))
+ {
+ // Transit to the established state
+ Debug("IKE SA 0x%X Established.\n", sa);
+ sa->State = IKE_SA_AM_STATE_2_ESTABLISHED;
+ sa->EstablishedTick = ike->Now;
+ sa->Established = true;
+ c->CurrentIkeSa = sa;
+ c->NextDpdSendTick = ike->Now + (UINT64)IKE_INTERVAL_DPD_KEEPALIVE;
+ StrCpy(c->Secret, sizeof(c->Secret), sa->Secret);
+
+ IPsecLog(ike, NULL, sa, NULL, "LI_IKE_SA_ESTABLISHED");
+
+ IkeSaSendPacket(ike, sa, NULL);
+ }
+ else
+ {
+ Debug("IKE SA 0x%X Invalid Hash.\n", sa);
+ }
+ }
+ }
+ break;
+ }
+
+ if (pr != NULL)
+ {
+ IkeFree(pr);
+ }
+ }
+ }
+}
+
+// Process of the main mode packet reception
+void ProcIkeMainModePacketRecv(IKE_SERVER *ike, UDPPACKET *p, IKE_PACKET *header)
+{
+ IKE_CLIENT *c;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (ike == NULL || p == NULL || header == NULL || header->InitiatorCookie == 0)
+ {
+ return;
+ }
+
+ c = SearchOrCreateNewIkeClientForIkePacket(ike, &p->SrcIP, p->SrcPort, &p->DstIP, p->DestPort, header);
+
+ if (c == NULL)
+ {
+ return;
+ }
+
+ if (header->ResponderCookie == 0)
+ {
+ // Start process of the state 1
+ IKE_CAPS caps;
+ IKE_SA *sa;
+ IKE_PACKET *pr = IkeParse(p->Data, p->Size, NULL);
+
+ if (pr != NULL)
+ {
+ // Determine the CAPS
+ IkeCheckCaps(&caps, pr);
+ if (caps.MS_L2TPIPSecVPNClient || caps.MS_NT5_ISAKMP_OAKLEY || caps.MS_Vid_InitialContact)
+ {
+ c->IsMicrosoft = true;
+ }
+
+ if ((caps.NatTraversalDraftIetf || caps.NatTraversalRfc3947) || (IsUdpPortOpened(ike->IPsec->UdpListener, &p->DstIP, IPSEC_PORT_IPSEC_ESP_RAW)))
+ {
+ sa = FindIkeSaByEndPointAndInitiatorCookie(ike, &p->DstIP, p->DestPort, &p->SrcIP, p->SrcPort, header->InitiatorCookie, IKE_SA_MAIN_MODE);
+
+ if (sa == NULL)
+ {
+ // Check whether there is acceptable SA parameters by analyzing proposed parameters
+ IKE_SA_TRANSFORM_SETTING setting;
+
+ if (GetBestTransformSettingForIkeSa(ike, pr, &setting) && (GetNumberOfIkeSaOfIkeClient(ike, c) <= IKE_QUOTA_MAX_SA_PER_CLIENT))
+ {
+ IKE_PACKET *ps;
+ IKE_PACKET_PAYLOAD *tp;
+ IKE_PACKET_PAYLOAD *pp;
+ IKE_PACKET_PAYLOAD *sap;
+ LIST *payload_list;
+ IKE_PACKET_PAYLOAD *client_sa_payload;
+
+ // Appropriate transform setting is selected
+ Debug("P1 Transform: %s %s %s(%u) %u %u\n",
+ setting.Dh->Name, setting.Hash->Name, setting.Crypto->Name, setting.CryptoKeySize,
+ setting.LifeKilobytes, setting.LifeSeconds);
+
+#ifdef FORCE_LIFETIME_MM
+ setting.LifeSeconds = FORCE_LIFETIME_MM;
+#endif // FORCE_LIFETIME_MM
+
+ // Create an IKE SA
+ sa = NewIkeSa(ike, c, header->InitiatorCookie, IKE_SA_MAIN_MODE, &setting);
+
+ Copy(&sa->Caps, &caps, sizeof(IKE_CAPS));
+
+ Insert(ike->IkeSaList, sa);
+
+ // Answer the SA parameter selection results
+ sa->State = IKE_SA_MM_STATE_1_SA;
+
+ // Save a bit array of SA payload presented by the client
+ client_sa_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_SA, 0);
+ sa->SAi_b = CloneBuf(client_sa_payload->BitArray);
+
+ //// Assemble the SA payload
+ // Construct a transform payload
+ tp = TransformSettingToTransformPayloadForIke(ike, &setting);
+
+ // Build a proposal payload
+ pp = IkeNewProposalPayload(1, IKE_PROTOCOL_ID_IKE, NULL, 0, NewListSingle(tp));
+
+ // Build a SA payload
+ sap = IkeNewSaPayload(NewListSingle(pp));
+
+ payload_list = NewListSingle(sap);
+
+ ps = IkeNew(sa->InitiatorCookie, sa->ResponderCookie, IKE_EXCHANGE_TYPE_MAIN,
+ false, false, false, 0, payload_list);
+
+ // Add the vendor ID payload
+ IkeAddVendorIdPayloads(ps);
+
+ IkeSaSendPacket(ike, sa, ps);
+
+ sa->HashSize = sa->TransformSetting.Hash->HashSize;
+ sa->KeySize = sa->TransformSetting.CryptoKeySize;
+ sa->BlockSize = sa->TransformSetting.Crypto->BlockSize;
+
+ IkeFree(ps);
+ }
+ else
+ {
+ // No appropriate transform setting
+ Debug("No Appropriate Transform was Found.\n");
+
+ IPsecLog(ike, c, NULL, NULL, "LI_IKE_NO_TRANSFORM");
+
+ SendInformationalExchangePacket(ike, c, IkeNewNoticeErrorNoProposalChosenPayload(false, header->InitiatorCookie, header->ResponderCookie));
+ }
+ }
+ else
+ {
+ // Ignore for IKE SA which already exists (Because it's likely to be a re-transmission)
+ }
+ }
+ else
+ {
+ // It does not support NAT Traversal
+ Debug("Client doesn't support NAT-T.\n");
+
+ IPsecLog(ike, c, NULL, NULL, "LI_IKE_NO_NAT_T");
+ }
+ IkeFree(pr);
+ }
+ }
+ else
+ {
+ // Process of state 2 or later
+ IKE_SA *sa;
+
+ sa = FindIkeSaByResponderCookieAndClient(ike, header->ResponderCookie, c);
+
+ if (sa == NULL)
+ {
+ SendInformationalExchangePacketEx(ike, c, IkeNewNoticeErrorInvalidCookiePayload(header->InitiatorCookie,
+ header->ResponderCookie), true, header->InitiatorCookie, header->ResponderCookie);
+ }
+
+ if (sa != NULL && sa->Mode == IKE_SA_MAIN_MODE)
+ {
+ IKE_PACKET *pr = NULL;
+
+ sa->LastCommTick = ike->Now;
+
+ switch (sa->State)
+ {
+ case IKE_SA_MM_STATE_1_SA:
+ pr = IkeSaRecvPacket(ike, sa, p->Data, p->Size);
+ if (pr != NULL)
+ {
+ // Receive a key exchange packet
+ IKE_PACKET_PAYLOAD *your_key_payload;
+ IKE_PACKET_PAYLOAD *your_rand_payload;
+ IKE_PACKET_PAYLOAD *your_nat_d_1 = NULL;
+ IKE_PACKET_PAYLOAD *your_nat_d_2 = NULL;
+
+ your_key_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_KEY_EXCHANGE, 0);
+ your_rand_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_RAND, 0);
+
+ if (IkeGetPayloadNum(pr->PayloadList, IKE_PAYLOAD_NAT_D) != 0)
+ {
+ sa->Caps.UsingNatTraversalRfc3947 = true;
+
+ your_nat_d_1 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_D, 0);
+ your_nat_d_2 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_D, 1);
+ }
+
+ if (IkeGetPayloadNum(pr->PayloadList, IKE_PAYLOAD_NAT_D_DRAFT) != 0)
+ {
+ sa->Caps.UsingNatTraversalDraftIetf = true;
+
+ your_nat_d_1 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_D_DRAFT, 0);
+ your_nat_d_2 = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_NAT_D_DRAFT, 1);
+ }
+
+ if (your_key_payload != NULL && your_rand_payload != NULL)
+ {
+ // Check the key payload
+ BUF *your_key_buf = your_key_payload->Payload.KeyExchange.Data;
+ BUF *your_rand_buf = your_rand_payload->Payload.Rand.Data;
+
+ // DH generation
+ DH_CTX *dh = IkeDhNewCtx(sa->TransformSetting.Dh);
+ UINT shared_key_size = (dh == NULL ? 0 : dh->Size);
+ UCHAR *shared_key = ZeroMalloc(shared_key_size);
+
+ // DH calculation
+ if (DhCompute(dh, shared_key, your_key_buf->Buf, your_key_buf->Size))
+ {
+ IKE_PACKET *ps;
+ LIST *payload_list;
+ IKE_PACKET_PAYLOAD *my_key_payload;
+ IKE_PACKET_PAYLOAD *my_rand_payload;
+ BUF *nat_buf1, *nat_buf2;
+ BUF *iv_buf;
+ UCHAR iv_hashed_data[IKE_MAX_HASH_SIZE];
+
+ // Calculation success
+ sa->DhSharedKey = MemToBuf(shared_key, shared_key_size);
+ sa->InitiatorRand = RandBuf(IKE_SA_RAND_SIZE);
+ sa->ResponderRand = CloneBuf(your_rand_buf);
+
+ // Send a key exchange packet
+ my_key_payload = IkeNewDataPayload(IKE_PAYLOAD_KEY_EXCHANGE, dh->MyPublicKey->Buf, dh->MyPublicKey->Size);
+ my_rand_payload = IkeNewDataPayload(IKE_PAYLOAD_RAND, sa->InitiatorRand->Buf, sa->InitiatorRand->Size);
+
+ payload_list = NewListSingle(my_key_payload);
+ Add(payload_list, my_rand_payload);
+
+ // NAT-D packet
+ // Address of the opponent. Randomize in order to be forced to use NAT
+ nat_buf1 = IkeCalcNatDetectHash(ike, sa->TransformSetting.Hash, Rand64(), Rand64(), &c->ClientIP, Rand16());
+ //nat_buf1 = IkeCalcNatDetectHash(ike, sa->TransformSetting.Hash, sa->InitiatorCookie, sa->ResponderCookie, &c->ClientIP, c->ClientPort);
+ // My address
+
+ if (c->IsMicrosoft == false || (your_nat_d_1 == NULL || your_nat_d_2 == NULL || your_nat_d_1->BitArray == NULL))
+ {
+ // Calculate exactly
+ nat_buf2 = IkeCalcNatDetectHash(ike, sa->TransformSetting.Hash,
+ sa->InitiatorCookie, sa->ResponderCookie, &c->ServerIP, c->ServerPort);
+ }
+ else
+ {
+ // Parrot the NAT_D payload indicating myself I got from
+ // the other if it has connected from a Microsoft VPN Client
+ nat_buf2 = CloneBuf(your_nat_d_1->BitArray);
+ }
+
+ if (sa->Caps.UsingNatTraversalRfc3947)
+ {
+ // RFC-compliant
+ Add(payload_list, IkeNewDataPayload(IKE_PAYLOAD_NAT_D, nat_buf1->Buf, nat_buf1->Size));
+ Add(payload_list, IkeNewDataPayload(IKE_PAYLOAD_NAT_D, nat_buf2->Buf, nat_buf2->Size));
+ }
+
+ if (sa->Caps.UsingNatTraversalDraftIetf)
+ {
+ // Draft compliant
+ Add(payload_list, IkeNewDataPayload(IKE_PAYLOAD_NAT_D_DRAFT, nat_buf1->Buf, nat_buf1->Size));
+ Add(payload_list, IkeNewDataPayload(IKE_PAYLOAD_NAT_D_DRAFT, nat_buf2->Buf, nat_buf2->Size));
+ }
+
+ FreeBuf(nat_buf1);
+ FreeBuf(nat_buf2);
+
+ ps = IkeNew(sa->InitiatorCookie, sa->ResponderCookie, IKE_EXCHANGE_TYPE_MAIN,
+ false, false, false, 0, payload_list);
+
+ // Initial IV setting
+ iv_buf = NewBuf();
+ WriteBuf(iv_buf, your_key_buf->Buf, your_key_buf->Size);
+ WriteBuf(iv_buf, dh->MyPublicKey->Buf, dh->MyPublicKey->Size);
+ IkeHash(sa->TransformSetting.Hash, iv_hashed_data, iv_buf->Buf, iv_buf->Size);
+
+ BinToStrEx(tmp, sizeof(tmp), iv_hashed_data, sa->BlockSize);
+ Debug("Initial IV: %s\n", tmp);
+
+ IkeSaUpdateIv(sa, iv_hashed_data, sa->HashSize);
+
+ FreeBuf(iv_buf);
+
+ // Save the DH information
+ sa->GXi = CloneBuf(your_key_buf);
+ sa->GXr = CloneBuf(dh->MyPublicKey);
+
+ // Transmission
+ IkeSaSendPacket(ike, sa, ps);
+
+ IkeFree(ps);
+
+ // Calculate the key set
+ IkeCalcSaKeySet(ike, sa, NULL);
+
+ sa->State = IKE_SA_MM_STATE_2_KEY;
+ }
+ else
+ {
+ // DH calculation failure
+ Debug("DhCompute failed.\n");
+ }
+
+ Free(shared_key);
+ DhFree(dh);
+ }
+ }
+ break;
+
+ case IKE_SA_MM_STATE_2_KEY:
+ pr = IkeSaRecvPacket(ike, sa, p->Data, p->Size);
+ if (pr != NULL && pr->FlagEncrypted)
+ {
+ // Receive an ID exchange packet
+ IKE_PACKET_PAYLOAD *your_id_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_ID, 0);
+ IKE_PACKET_PAYLOAD *your_hash_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_HASH, 0);
+
+ if (your_id_payload && your_hash_payload)
+ {
+ UCHAR initiator_hash[IKE_MAX_HASH_SIZE];
+ BUF *b;
+
+ // Calculate the initiator side hash value
+ b = NewBuf();
+ WriteBufBuf(b, sa->GXi);
+ WriteBufBuf(b, sa->GXr);
+ WriteBufInt64(b, sa->InitiatorCookie);
+ WriteBufInt64(b, sa->ResponderCookie);
+ WriteBufBuf(b, sa->SAi_b);
+ WriteBufBuf(b, your_id_payload->BitArray);
+
+ StrCpy(c->ClientId, sizeof(c->ClientId), your_id_payload->Payload.Id.StrData);
+ Debug("Client ID = %s\n", c->ClientId);
+ IPsecLog(ike, c, NULL, NULL, NULL, "LI_SET_CLIENT_ID", c->ClientId);
+
+ IkeHMac(sa->TransformSetting.Hash, initiator_hash, sa->SKEYID, sa->HashSize,
+ b->Buf, b->Size);
+
+ FreeBuf(b);
+
+ // Hash comparison
+ if (IkeCompareHash(your_hash_payload, initiator_hash, sa->HashSize))
+ {
+ // Generate a response packet
+ IKE_PACKET *ps;
+ LIST *payload_list = NewListFast(NULL);
+ IKE_PACKET_PAYLOAD *my_id_payload, *my_hash_payload;
+ UCHAR responder_hash[IKE_MAX_HASH_SIZE];
+ BUF *idir_b;
+
+ // Generate an ID payload
+ if (IsIP6(&sa->IkeClient->ServerIP))
+ {
+ // IPv6 address
+ my_id_payload = IkeNewIdPayload(IKE_ID_IPV6_ADDR, 0, 0, sa->IkeClient->ServerIP.ipv6_addr, 16);
+ }
+ else
+ {
+ // IPv4 address
+ my_id_payload = IkeNewIdPayload(IKE_ID_IPV4_ADDR, 0, 0, sa->IkeClient->ServerIP.addr, 4);
+ }
+
+ // Build the ID payload tentatively
+ idir_b = IkeBuildIdPayload(&my_id_payload->Payload.Id);
+
+ // Generate the hash payload
+ b = NewBuf();
+ WriteBufBuf(b, sa->GXr);
+ WriteBufBuf(b, sa->GXi);
+ WriteBufInt64(b, sa->ResponderCookie);
+ WriteBufInt64(b, sa->InitiatorCookie);
+ WriteBufBuf(b, sa->SAi_b);
+ WriteBufBuf(b, idir_b);
+
+ IkeHMac(sa->TransformSetting.Hash, responder_hash, sa->SKEYID, sa->HashSize,
+ b->Buf, b->Size);
+
+ FreeBuf(b);
+ FreeBuf(idir_b);
+
+ my_hash_payload = IkeNewDataPayload(IKE_PAYLOAD_HASH, responder_hash, sa->HashSize);
+
+ Add(payload_list, my_id_payload);
+ Add(payload_list, my_hash_payload);
+
+ ps = IkeNew(sa->InitiatorCookie, sa->ResponderCookie, IKE_EXCHANGE_TYPE_MAIN, true, false,
+ false, 0, payload_list);
+
+ // Transmission
+ IkeSaSendPacket(ike, sa, ps);
+ sa->NumResends = 3;
+
+ IkeFree(ps);
+
+ StrCpy(c->ClientId, sizeof(c->ClientId), your_id_payload->Payload.Id.StrData);
+
+ // Transit to the established state
+ Debug("IKE SA 0x%X Established. Client ID=%s\n", sa, c->ClientId);
+ sa->State = IKE_SA_MM_STATE_3_ESTABLISHED;
+ sa->EstablishedTick = ike->Now;
+ c->CurrentIkeSa = sa;
+ c->NextDpdSendTick = ike->Now + (UINT64)IKE_INTERVAL_DPD_KEEPALIVE;
+ StrCpy(c->Secret, sizeof(c->Secret), sa->Secret);
+ sa->Established = true;
+
+ IPsecLog(ike, NULL, sa, NULL, "LI_IKE_SA_ESTABLISHED");
+ }
+ else
+ {
+ Debug("IKE SA 0x%X Invalid Hash.\n", sa);
+ }
+ }
+ }
+ break;
+ }
+
+ if (pr != NULL)
+ {
+ IkeFree(pr);
+ }
+ }
+ }
+}
+
+// Update the IV of IPsec SA
+void IPsecSaUpdateIv(IPSECSA *sa, void *iv, UINT iv_size)
+{
+ // Validate arguments
+ if (sa == NULL || iv == NULL)
+ {
+ return;
+ }
+
+ Copy(sa->Iv, iv, MIN(sa->IkeSa->BlockSize, iv_size));
+
+ if (iv_size < sa->IkeSa->BlockSize)
+ {
+ Zero(sa->Iv + sa->IkeSa->BlockSize, sa->IkeSa->BlockSize - iv_size);
+ }
+
+ sa->IsIvExisting = true;
+}
+
+// Update the IV of the IKE SA
+void IkeSaUpdateIv(IKE_SA *sa, void *iv, UINT iv_size)
+{
+ // Validate arguments
+ if (sa == NULL || iv == NULL)
+ {
+ return;
+ }
+
+ Copy(sa->Iv, iv, MIN(sa->BlockSize, iv_size));
+
+ if (iv_size < sa->BlockSize)
+ {
+ Zero(sa->Iv + sa->BlockSize, sa->BlockSize - iv_size);
+ }
+
+ sa->IsIvExisting = true;
+}
+
+// Calculate the key set of the IKE SA
+void IkeCalcSaKeySet(IKE_SERVER *ike, IKE_SA *sa, char *secret)
+{
+ BUF *secret_buf;
+ BUF *rand_buf;
+ BUF *d_buf, *a_buf, *e_buf;
+ UCHAR u;
+ IKE_HASH *h;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (ike == NULL || sa == NULL)
+ {
+ return;
+ }
+
+ h = sa->TransformSetting.Hash;
+
+ // Calculation of SKEYID
+ StrCpy(sa->Secret, sizeof(sa->Secret), secret == NULL ? ike->Secret : secret);
+ secret_buf = IkeStrToPassword(sa->Secret);
+ rand_buf = CloneBuf(sa->ResponderRand);
+ SeekBufToEnd(rand_buf);
+ BinToStrEx(tmp, sizeof(tmp), rand_buf->Buf, rand_buf->Size);
+ Debug("ResponderRand: %s\n", tmp);
+ BinToStrEx(tmp, sizeof(tmp), sa->InitiatorRand->Buf, sa->InitiatorRand->Size);
+ Debug("InitiatorRand: %s\n", tmp);
+
+ WriteBufBuf(rand_buf, sa->InitiatorRand);
+
+ IkeHMacBuf(h, sa->SKEYID, secret_buf, rand_buf);
+
+ BinToStrEx(tmp, sizeof(tmp), sa->SKEYID, sa->HashSize);
+ Debug("SKEYID: %s\n", tmp);
+
+ // SKEYID_d
+ d_buf = CloneBuf(sa->DhSharedKey);
+ SeekBufToEnd(d_buf);
+ WriteBufInt64(d_buf, sa->InitiatorCookie);
+ WriteBufInt64(d_buf, sa->ResponderCookie);
+ u = 0;
+ WriteBuf(d_buf, &u, 1);
+ IkeHMac(h, sa->SKEYID_d, sa->SKEYID, sa->HashSize, d_buf->Buf, d_buf->Size);
+
+ BinToStrEx(tmp, sizeof(tmp), sa->SKEYID_d, sa->HashSize);
+ Debug("SKEYID_d: %s\n", tmp);
+
+ // SKEYID_a
+ a_buf = MemToBuf(sa->SKEYID_d, sa->HashSize);
+ SeekBufToEnd(a_buf);
+ WriteBufBuf(a_buf, sa->DhSharedKey);
+ WriteBufInt64(a_buf, sa->InitiatorCookie);
+ WriteBufInt64(a_buf, sa->ResponderCookie);
+ u = 1;
+ WriteBuf(a_buf, &u, 1);
+ IkeHMac(h, sa->SKEYID_a, sa->SKEYID, sa->HashSize, a_buf->Buf, a_buf->Size);
+
+ BinToStrEx(tmp, sizeof(tmp), sa->SKEYID_a, sa->HashSize);
+ Debug("SKEYID_a: %s\n", tmp);
+
+ // SKEYID_e
+ e_buf = MemToBuf(sa->SKEYID_a, sa->HashSize);
+ SeekBufToEnd(e_buf);
+ WriteBufBuf(e_buf, sa->DhSharedKey);
+ WriteBufInt64(e_buf, sa->InitiatorCookie);
+ WriteBufInt64(e_buf, sa->ResponderCookie);
+ u = 2;
+ WriteBuf(e_buf, &u, 1);
+ IkeHMac(h, sa->SKEYID_e, sa->SKEYID, sa->HashSize, e_buf->Buf, e_buf->Size);
+
+ BinToStrEx(tmp, sizeof(tmp), sa->SKEYID_e, sa->HashSize);
+ Debug("SKEYID_e: %s\n", tmp);
+
+ if (sa->CryptoKey != NULL)
+ {
+ IkeFreeKey(sa->CryptoKey);
+ }
+
+ sa->CryptoKey = IkeNewCryptoKeyFromK(ike, sa->SKEYID_e, sa->HashSize, sa->TransformSetting.Hash,
+ sa->TransformSetting.Crypto, sa->TransformSetting.CryptoKeySize);
+
+ // Release the memory
+ FreeBuf(secret_buf);
+ FreeBuf(rand_buf);
+ FreeBuf(d_buf);
+ FreeBuf(a_buf);
+ FreeBuf(e_buf);
+}
+
+// Extend the key size
+BUF *IkeExpandKeySize(IKE_HASH *h, void *k, UINT k_size, UINT target_size)
+{
+ BUF *b1, *b2;
+ UCHAR tmp[IKE_MAX_HASH_SIZE];
+ UINT tmp_size;
+ // Validate arguments
+ if (h == NULL || k == NULL || k_size == 0)
+ {
+ return NULL;
+ }
+
+ if (k_size >= target_size)
+ {
+ return MemToBuf(k, target_size);
+ }
+
+ tmp[0] = 0;
+ tmp_size = 1;
+ b1 = NewBuf();
+
+ do
+ {
+ IkeHMac(h, tmp, k, k_size, tmp, tmp_size);
+ WriteBuf(b1, tmp, h->HashSize);
+
+ tmp_size = h->HashSize;
+ }
+ while (b1->Size < target_size);
+
+ b2 = MemToBuf(b1->Buf, target_size);
+
+ FreeBuf(b1);
+
+ return b2;
+}
+
+// Generate a key from K
+IKE_CRYPTO_KEY *IkeNewCryptoKeyFromK(IKE_SERVER *ike, void *k, UINT k_size, IKE_HASH *h, IKE_CRYPTO *c, UINT crypto_key_size)
+{
+ BUF *key_buf;
+ IKE_CRYPTO_KEY *ret;
+ // Validate arguments
+ if (ike == NULL || k == NULL || k_size == 0 || h == NULL || c == NULL || crypto_key_size == 0)
+ {
+ return NULL;
+ }
+
+ key_buf = IkeExpandKeySize(h, k, k_size, crypto_key_size);
+ if (key_buf == NULL)
+ {
+ return NULL;
+ }
+
+ ret = IkeNewKey(c, key_buf->Buf, key_buf->Size);
+
+ FreeBuf(key_buf);
+
+ return ret;
+}
+
+// Generate a hash for NAT detection
+BUF *IkeCalcNatDetectHash(IKE_SERVER *ike, IKE_HASH *hash, UINT64 initiator_cookie, UINT64 responder_cookie, IP *ip, UINT port)
+{
+ BUF *b;
+ USHORT us;
+ USHORT hash_data[IKE_MAX_HASH_SIZE];
+ // Validate arguments
+ if (ike == NULL || ip == NULL || hash == NULL)
+ {
+ return NewBuf();
+ }
+
+ b = NewBuf();
+
+ WriteBufInt64(b, initiator_cookie);
+ WriteBufInt64(b, responder_cookie);
+
+ if (IsIP6(ip))
+ {
+ WriteBuf(b, ip->ipv6_addr, sizeof(ip->ipv6_addr));
+ }
+ else
+ {
+ WriteBuf(b, ip->addr, sizeof(ip->addr));
+ }
+
+ us = Endian16((USHORT)port);
+
+ WriteBuf(b, &us, sizeof(USHORT));
+
+ IkeHash(hash, hash_data, b->Buf, b->Size);
+
+ FreeBuf(b);
+
+ return MemToBuf(hash_data, hash->HashSize);
+}
+
+// Check the capacity of the opposite IPsec client
+void IkeCheckCaps(IKE_CAPS *caps, IKE_PACKET *p)
+{
+ // Validate arguments
+ if (caps == NULL || p == NULL)
+ {
+ Zero(caps, sizeof(IKE_CAPS));
+ return;
+ }
+
+ Zero(caps, sizeof(IKE_CAPS));
+
+ caps->NatTraversalRfc3947 = IkeIsVendorIdExists(p, IKE_VENDOR_ID_RFC3947_NAT_T);
+
+ caps->NatTraversalDraftIetf = IkeIsVendorIdExists(p, IKE_VENDOR_ID_IPSEC_NAT_T_IKE_03) ||
+ IkeIsVendorIdExists(p, IKE_VENDOR_ID_IPSEC_NAT_T_IKE_02) ||
+ IkeIsVendorIdExists(p, IKE_VENDOR_ID_IPSEC_NAT_T_IKE_02_2) ||
+ IkeIsVendorIdExists(p, IKE_VENDOR_ID_IPSEC_NAT_T_IKE_00);
+
+ caps->DpdRfc3706 = IkeIsVendorIdExists(p, IKE_VENDOR_ID_RFC3706_DPD);
+
+ caps->MS_L2TPIPSecVPNClient = IkeIsVendorIdExists(p, IKE_VENDOR_ID_MICROSOFT_L2TP);
+ caps->MS_NT5_ISAKMP_OAKLEY = IkeIsVendorIdExists(p, IKE_VENDOR_ID_MS_NT5_ISAKMPOAKLEY);
+ caps->MS_Vid_InitialContact = IkeIsVendorIdExists(p, IKE_VENDOR_ID_MS_VID_INITIALCONTACT);
+}
+
+// Check whether the specified vendor ID is contained in the packet
+bool IkeIsVendorIdExists(IKE_PACKET *p, char *str)
+{
+ BUF *buf;
+ UINT i, num;
+ bool ok = false;
+ // Validate arguments
+ if (p == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ buf = IkeStrToVendorId(str);
+ if (buf == NULL)
+ {
+ return false;
+ }
+
+ num = IkeGetPayloadNum(p->PayloadList, IKE_PAYLOAD_VENDOR_ID);
+ for (i = 0;i < num;i++)
+ {
+ IKE_PACKET_PAYLOAD *payload = IkeGetPayload(p->PayloadList, IKE_PAYLOAD_VENDOR_ID, i);
+
+ if (CompareBuf(payload->Payload.VendorId.Data, buf))
+ {
+ ok = true;
+ }
+ else
+ {
+ if (payload->Payload.VendorId.Data != NULL)
+ {
+ if (payload->Payload.VendorId.Data->Size >= buf->Size)
+ {
+ if (Cmp(payload->Payload.VendorId.Data->Buf, buf->Buf, buf->Size) == 0)
+ {
+ ok = true;
+ }
+ }
+ }
+ }
+ }
+
+ FreeBuf(buf);
+
+ return ok;
+}
+
+// Add the vendor ID payload list
+void IkeAddVendorIdPayloads(IKE_PACKET *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ IkeAddVendorId(p, IKE_VENDOR_ID_RFC3947_NAT_T);
+ IkeAddVendorId(p, IKE_VENDOR_ID_IPSEC_NAT_T_IKE_03);
+ IkeAddVendorId(p, IKE_VENDOR_ID_IPSEC_NAT_T_IKE_02);
+ IkeAddVendorId(p, IKE_VENDOR_ID_IPSEC_NAT_T_IKE_02_2);
+ IkeAddVendorId(p, IKE_VENDOR_ID_IPSEC_NAT_T_IKE_00);
+ IkeAddVendorId(p, IKE_VENDOR_ID_RFC3706_DPD);
+}
+
+// Add the vendor ID payload
+void IkeAddVendorId(IKE_PACKET *p, char *str)
+{
+ BUF *buf;
+ IKE_PACKET_PAYLOAD *payload;
+ // Validate arguments
+ if (p == NULL || str == NULL)
+ {
+ return;
+ }
+
+ buf = IkeStrToVendorId(str);
+ if (buf == NULL)
+ {
+ return;
+ }
+
+ payload = IkeNewDataPayload(IKE_PAYLOAD_VENDOR_ID, buf->Buf, buf->Size);
+
+ Add(p->PayloadList, payload);
+
+ FreeBuf(buf);
+}
+
+// Convert string to the vendor ID
+BUF *IkeStrToVendorId(char *str)
+{
+ // Validate arguments
+ if (IsEmptyStr(str))
+ {
+ return NULL;
+ }
+
+ if (StartWith(str, "0x"))
+ {
+ BUF *buf = StrToBin(str + 2);
+
+ if (buf == NULL || buf->Size == 0)
+ {
+ FreeBuf(buf);
+ return NULL;
+ }
+
+ return buf;
+ }
+ else
+ {
+ BUF *buf;
+ UCHAR hash[MD5_SIZE];
+
+ Hash(hash, str, StrLen(str), false);
+
+ buf = MemToBuf(hash, sizeof(hash));
+
+ return buf;
+ }
+}
+
+// Receive a packet using the IKE SA
+IKE_PACKET *IkeSaRecvPacket(IKE_SERVER *ike, IKE_SA *sa, void *data, UINT size)
+{
+ IKE_PACKET *ret;
+ // Validate arguments
+ if (ike == NULL || sa == NULL || (size != 0 && data == NULL))
+ {
+ return NULL;
+ }
+
+ if (sa->IsIvExisting == false || sa->CryptoKey == NULL)
+ {
+ ret = IkeParse(data, size, NULL);
+ }
+ else
+ {
+ IKE_CRYPTO_PARAM cp;
+
+ Copy(&cp.Iv, sa->Iv, sa->BlockSize);
+ cp.Key = sa->CryptoKey;
+
+ ret = IkeParse(data, size, &cp);
+
+ if (ret->FlagEncrypted)
+ {
+ IkeSaUpdateIv(sa, cp.NextIv, sa->BlockSize);
+ }
+ }
+
+ return ret;
+}
+
+// Receive a packet using IPsec SA (Quick Mode received)
+IKE_PACKET *IPsecSaRecvPacket(IKE_SERVER *ike, IPSECSA *sa, void *data, UINT size)
+{
+ IKE_PACKET *ret;
+ // Validate arguments
+ if (ike == NULL || sa == NULL || (size != 0 && data == NULL))
+ {
+ return NULL;
+ }
+
+ if (sa->IsIvExisting == false || sa->IkeSa->CryptoKey == NULL)
+ {
+ ret = IkeParse(data, size, NULL);
+ }
+ else
+ {
+ IKE_CRYPTO_PARAM cp;
+
+ Copy(&cp.Iv, sa->Iv, sa->IkeSa->BlockSize);
+ cp.Key = sa->IkeSa->CryptoKey;
+
+ ret = IkeParse(data, size, &cp);
+
+ if (ret->FlagEncrypted)
+ {
+ IPsecSaUpdateIv(sa, cp.NextIv, sa->IkeSa->BlockSize);
+ IPsecSaUpdateIv(sa->PairIPsecSa, cp.NextIv, sa->IkeSa->BlockSize);
+ }
+ }
+
+ return ret;
+}
+
+// Send a packet using IPsec SA (Quick Mode transmission)
+void IPsecSaSendPacket(IKE_SERVER *ike, IPSECSA *sa, IKE_PACKET *p)
+{
+ BUF *buf;
+ // Validate arguments
+ if (ike == NULL || sa == NULL)
+ {
+ return;
+ }
+
+ if (p == NULL)
+ {
+ FreeBuf(sa->SendBuffer);
+ sa->SendBuffer = NULL;
+ sa->NextSendTick = 0;
+ return;
+ }
+
+ // Build a packet
+ if (p->FlagEncrypted == false)
+ {
+ buf = IkeBuild(p, NULL);
+ }
+ else
+ {
+ IKE_CRYPTO_PARAM cp;
+
+ Copy(cp.Iv, sa->Iv, sa->IkeSa->BlockSize);
+ cp.Key = sa->IkeSa->CryptoKey;
+
+ buf = IkeBuild(p, &cp);
+
+ IPsecSaUpdateIv(sa, cp.NextIv, sa->IkeSa->BlockSize);
+ IPsecSaUpdateIv(sa->PairIPsecSa, cp.NextIv, sa->IkeSa->BlockSize);
+ }
+
+ if (buf == NULL)
+ {
+ return;
+ }
+
+ // Register the last packet to re-transmit
+ if (sa->SendBuffer != NULL)
+ {
+ FreeBuf(sa->SendBuffer);
+ }
+
+ sa->SendBuffer = CloneBuf(buf);
+ sa->NextSendTick = ike->Now + (UINT64)(IKE_SA_RESEND_INTERVAL);
+ AddInterrupt(ike->Interrupts, sa->NextSendTick);
+
+ IkeSendUdpPacket(ike, IKE_UDP_TYPE_ISAKMP, &sa->IkeClient->ServerIP, sa->IkeClient->ServerPort,
+ &sa->IkeClient->ClientIP, sa->IkeClient->ClientPort,
+ buf->Buf, buf->Size);
+
+ Free(buf);
+}
+
+// Send a packet using the IKE SA
+void IkeSaSendPacket(IKE_SERVER *ike, IKE_SA *sa, IKE_PACKET *p)
+{
+ BUF *buf;
+ // Validate arguments
+ if (ike == NULL || sa == NULL)
+ {
+ return;
+ }
+
+ if (p == NULL)
+ {
+ FreeBuf(sa->SendBuffer);
+ sa->SendBuffer = NULL;
+ sa->NextSendTick = 0;
+ return;
+ }
+
+ // Build a packet
+ if (p->FlagEncrypted == false)
+ {
+ buf = IkeBuild(p, NULL);
+ }
+ else
+ {
+ IKE_CRYPTO_PARAM cp;
+
+ Copy(cp.Iv, sa->Iv, sa->BlockSize);
+ cp.Key = sa->CryptoKey;
+
+ buf = IkeBuild(p, &cp);
+
+ IkeSaUpdateIv(sa, cp.NextIv, sa->BlockSize);
+ }
+
+ if (buf == NULL)
+ {
+ return;
+ }
+
+ if (p->ExchangeType != IKE_EXCHANGE_TYPE_INFORMATION)
+ {
+ // Register the last packet to re-transmit
+ if (sa->SendBuffer != NULL)
+ {
+ FreeBuf(sa->SendBuffer);
+ }
+
+ sa->SendBuffer = CloneBuf(buf);
+ sa->NextSendTick = ike->Now + (UINT64)(IKE_SA_RESEND_INTERVAL);
+ AddInterrupt(ike->Interrupts, sa->NextSendTick);
+ }
+
+ IkeSendUdpPacket(ike, IKE_UDP_TYPE_ISAKMP, &sa->IkeClient->ServerIP, sa->IkeClient->ServerPort,
+ &sa->IkeClient->ClientIP, sa->IkeClient->ClientPort,
+ buf->Buf, buf->Size);
+
+ Free(buf);
+}
+
+// Send an UDP packet
+void IkeSendUdpPacket(IKE_SERVER *ike, UINT type, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, void *data, UINT size)
+{
+ UDPPACKET *p;
+ // Validate arguments
+ if (ike == NULL || server_ip == NULL || client_ip == NULL || server_port == 0 || client_port == 0 || data == NULL || size == 0)
+ {
+ return;
+ }
+
+ p = NewUdpPacket(server_ip, server_port, client_ip, client_port, data, size);
+
+ p->Type = type;
+
+ Add(ike->SendPacketList, p);
+}
+
+// Create an IKE SA
+IKE_SA *NewIkeSa(IKE_SERVER *ike, IKE_CLIENT *c, UINT64 init_cookie, UINT mode, IKE_SA_TRANSFORM_SETTING *setting)
+{
+ IKE_SA *sa;
+ // Validate arguments
+ if (ike == NULL || c == NULL || init_cookie == 0 || setting == NULL)
+ {
+ return NULL;
+ }
+
+ sa = ZeroMalloc(sizeof(IKE_SA));
+
+ sa->Id = ++ike->CurrentIkeSaId;
+
+ sa->IkeClient = c;
+ sa->InitiatorCookie = init_cookie;
+ sa->ResponderCookie = GenerateNewResponserCookie(ike);
+ sa->Mode = mode;
+ sa->FirstCommTick = sa->LastCommTick = ike->Now;
+ Copy(&sa->TransformSetting, setting, sizeof(IKE_SA_TRANSFORM_SETTING));
+
+ Debug("New IKE SA (Mode = %u): %I64u <--> %I64u (%s %s %s(%u) %u %u)\n",
+ mode,
+ sa->InitiatorCookie,
+ sa->ResponderCookie,
+ setting->Dh->Name, setting->Hash->Name, setting->Crypto->Name, setting->CryptoKeySize,
+ setting->LifeKilobytes, setting->LifeSeconds);
+
+ IPsecLog(ike, NULL, sa, NULL, "LI_NEW_IKE_SA",
+ (mode == IKE_SA_MAIN_MODE ? _UU("LI_TAG_MAINMODE") : _UU("LI_TAG_AGGRESSIVE")),
+ sa->InitiatorCookie, sa->ResponderCookie,
+ setting->Dh->Name, setting->Hash->Name, setting->Crypto->Name, setting->CryptoKeySize * 8,
+ setting->LifeKilobytes, setting->LifeSeconds);
+
+ return sa;
+}
+
+// Search an IKE SA from the Responder Cookie
+IKE_SA *FindIkeSaByResponderCookie(IKE_SERVER *ike, UINT64 responder_cookie)
+{
+ IKE_SA t;
+ // Validate arguments
+ if (ike == NULL || responder_cookie == 0)
+ {
+ return NULL;
+ }
+
+ t.ResponderCookie = responder_cookie;
+
+ return Search(ike->IkeSaList, &t);
+}
+
+// Search an IKE SA from the Responder Cookie and the IKE_CLIENT
+IKE_SA *FindIkeSaByResponderCookieAndClient(IKE_SERVER *ike, UINT64 responder_cookie, IKE_CLIENT *c)
+{
+ IKE_SA *sa;
+ // Validate arguments
+ if (ike == NULL || responder_cookie == 0 || c == NULL)
+ {
+ return NULL;
+ }
+
+ sa = FindIkeSaByResponderCookie(ike, responder_cookie);
+ if (sa == NULL)
+ {
+ return NULL;
+ }
+
+ if (sa->IkeClient != c)
+ {
+ return NULL;
+ }
+
+ return sa;
+}
+
+// Search an IKE SA from the endpoint and the Initiator Cookie
+IKE_SA *FindIkeSaByEndPointAndInitiatorCookie(IKE_SERVER *ike, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, UINT64 init_cookie, UINT mode)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL || client_ip == NULL || server_ip == NULL || client_port == 0 || server_port == 0 || init_cookie == 0)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+ IKE_CLIENT *c;
+
+ c = sa->IkeClient;
+
+ if (CmpIpAddr(&c->ClientIP, client_ip) == 0 &&
+ CmpIpAddr(&c->ServerIP, server_ip) == 0 &&
+ c->ClientPort == client_port &&
+ c->ServerPort == server_port &&
+ sa->InitiatorCookie == init_cookie &&
+ sa->Mode == mode)
+ {
+ return sa;
+ }
+ }
+
+ return NULL;
+}
+
+// Get the number of IPsec SA that is associated with the IKE_CLIENT
+UINT GetNumberOfIPsecSaOfIkeClient(IKE_SERVER *ike, IKE_CLIENT *c)
+{
+ UINT num = 0, i;
+ // Validate arguments
+ if (ike == NULL || c == NULL)
+ {
+ return 0;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+
+ if (sa->IkeClient == c)
+ {
+ num++;
+ }
+ }
+
+ return num;
+}
+
+// Get the number of IKE SA that is associated with the IKE_CLIENT
+UINT GetNumberOfIkeSaOfIkeClient(IKE_SERVER *ike, IKE_CLIENT *c)
+{
+ UINT num = 0, i;
+ // Validate arguments
+ if (ike == NULL || c == NULL)
+ {
+ return 0;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+
+ if (sa->IkeClient == c)
+ {
+ num++;
+ }
+ }
+
+ return num;
+}
+
+// Get the number of clients that are connected from the specified IP address
+UINT GetNumberOfIkeClientsFromIP(IKE_SERVER *ike, IP *client_ip)
+{
+ UINT i, num;
+ // Validate arguments
+ if (ike == NULL || client_ip == NULL)
+ {
+ return 0;
+ }
+
+ num = 0;
+
+ for (i = 0;i < LIST_NUM(ike->ClientList);i++)
+ {
+ IKE_CLIENT *c = LIST_DATA(ike->ClientList, i);
+
+ if (CmpIpAddr(&c->ClientIP, client_ip) == 0)
+ {
+ num++;
+ }
+ }
+
+ return num;
+}
+
+// Find the appropriate IKE client. Create if it is absent
+IKE_CLIENT *SearchOrCreateNewIkeClientForIkePacket(IKE_SERVER *ike, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, IKE_PACKET *pr)
+{
+ IKE_CLIENT *c;
+ // Validate arguments
+ if (ike == NULL || pr == NULL || client_ip == NULL || server_ip == NULL || client_port == 0 || server_port == 0 || pr == NULL)
+ {
+ return NULL;
+ }
+
+ c = SearchIkeClientForIkePacket(ike, client_ip, client_port, server_ip, server_port, pr);
+ if (c == NULL)
+ {
+ if (GetNumberOfIkeClientsFromIP(ike, client_ip) > IKE_QUOTA_MAX_NUM_CLIENTS_PER_IP ||
+ LIST_NUM(ike->ClientList) > IKE_QUOTA_MAX_NUM_CLIENTS)
+ {
+ return NULL;
+ }
+
+
+ c = NewIkeClient(ike, client_ip, client_port, server_ip, server_port);
+
+ Insert(ike->ClientList, c);
+ }
+
+ return SetIkeClientEndpoint(ike, c, client_ip, client_port, server_ip, server_port);
+}
+
+// Create an IKE client
+IKE_CLIENT *NewIkeClient(IKE_SERVER *ike, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port)
+{
+ IKE_CLIENT *c;
+ char client_ip_str[MAX_SIZE];
+ char server_ip_str[MAX_SIZE];
+ // Validate arguments
+ if (ike == NULL || client_ip == NULL || server_ip == NULL || client_port == 0 || server_port == 0)
+ {
+ return NULL;
+ }
+
+ c = ZeroMalloc(sizeof(IKE_CLIENT));
+
+ c->Id = ++ike->CurrentIkeClientId;
+
+ Copy(&c->ClientIP, client_ip, sizeof(IP));
+ c->ClientPort = client_port;
+
+ Copy(&c->ServerIP, server_ip, sizeof(IP));
+ Copy(&c->TransportModeServerIP, server_ip, sizeof(IP));
+ Copy(&c->TransportModeClientIP, client_ip, sizeof(IP));
+ c->ServerPort = server_port;
+
+ c->LastCommTick = ike->Now;
+ c->FirstCommTick = ike->Now;
+
+ IPToStr(client_ip_str, sizeof(client_ip_str), client_ip);
+ IPToStr(server_ip_str, sizeof(server_ip_str), server_ip);
+
+ Debug("New IKE_CLIENT: %p: %s:%u -> %s:%u\n", c, client_ip_str, client_port, server_ip_str, server_port);
+
+ IPsecLog(ike, c, NULL, NULL, "LI_NEW_IKE_CLIENT");
+
+ return c;
+}
+
+// Search for the best associated IKE client when an IKE packet has been received
+IKE_CLIENT *SearchIkeClientForIkePacket(IKE_SERVER *ike, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, IKE_PACKET *pr)
+{
+ IKE_CLIENT t;
+ IKE_CLIENT *c = NULL;
+ // Validate arguments
+ if (ike == NULL || pr == NULL || client_ip == NULL || server_ip == NULL || client_port == 0 || server_port == 0)
+ {
+ return NULL;
+ }
+
+ if (true)
+ {
+ UINT i;
+
+ if (pr->InitiatorCookie != 0 && pr->ResponderCookie != 0)
+ {
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+
+ // Extract what Cookie matches exactly
+ if (sa->InitiatorCookie == pr->InitiatorCookie && sa->ResponderCookie == pr->ResponderCookie)
+ {
+ IKE_CLIENT *cc = sa->IkeClient;
+
+ if (CmpIpAddr(&cc->ServerIP, server_ip) == 0 &&
+ CmpIpAddr(&cc->ClientIP, client_ip) == 0)
+ {
+ c = cc;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (c == NULL)
+ {
+ // Search by a pair of IP address and port number
+ Copy(&t.ClientIP, client_ip, sizeof(IP));
+ t.ClientPort = client_port;
+ Copy(&t.ServerIP, server_ip, sizeof(IP));
+ t.ServerPort = server_port;
+
+ c = Search(ike->ClientList, &t);
+
+ if (c != NULL)// && server_port == IPSEC_PORT_IPSEC_ISAKMP)
+ {
+ // Search that the IKE_SA that points to this IKE_CLIENT exists and match the Cookie
+ bool ok = false;
+ UINT i;
+
+ if (server_port == IPSEC_PORT_IPSEC_ESP_UDP)
+ {
+ // Regard as OK if the port number exactly match in the case of connecting to a server-side 4500
+ ok = true;
+ }
+ else
+ {
+ if (c->CurrentIkeSa != NULL &&
+ c->CurrentIkeSa->InitiatorCookie == pr->InitiatorCookie &&
+ c->CurrentIkeSa->ResponderCookie == pr->ResponderCookie)
+ {
+ ok = true;
+ }
+ else
+ {
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+
+ if (sa->IkeClient == c)
+ {
+ if (sa->InitiatorCookie == pr->InitiatorCookie &&
+ sa->ResponderCookie == pr->ResponderCookie)
+ {
+ ok = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (ok == false)
+ {
+ // Not found
+ c = NULL;
+ }
+ }
+ }
+
+ return c;
+}
+
+// Comparison of IPsec SA
+int CmpIPsecSa(void *p1, void *p2)
+{
+ IPSECSA *sa1, *sa2;
+ int r;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ sa1 = *(IPSECSA **)p1;
+ sa2 = *(IPSECSA **)p2;
+ if (sa1 == NULL || sa2 == NULL)
+ {
+ return 0;
+ }
+
+ r = COMPARE_RET(sa1->ServerToClient, sa2->ServerToClient);
+ if (r != 0)
+ {
+ return r;
+ }
+
+ r = COMPARE_RET(sa1->Spi, sa2->Spi);
+
+ return r;
+}
+
+// Comparison of IKE_SA
+int CmpIkeSa(void *p1, void *p2)
+{
+ IKE_SA *sa1, *sa2;
+ int r;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ sa1 = *(IKE_SA **)p1;
+ sa2 = *(IKE_SA **)p2;
+ if (sa1 == NULL || sa2 == NULL)
+ {
+ return 0;
+ }
+
+ r = COMPARE_RET(sa1->ResponderCookie, sa2->ResponderCookie);
+
+ return r;
+}
+
+// Comparison of IKE_CLIENT
+int CmpIkeClient(void *p1, void *p2)
+{
+ IKE_CLIENT *c1, *c2;
+ int r;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ c1 = *(IKE_CLIENT **)p1;
+ c2 = *(IKE_CLIENT **)p2;
+ if (c1 == NULL || c2 == NULL)
+ {
+ return 0;
+ }
+
+ r = CmpIpAddr(&c1->ClientIP, &c2->ClientIP);
+ if (r != 0)
+ {
+ return r;
+ }
+
+ r = CmpIpAddr(&c1->ServerIP, &c2->ServerIP);
+ if (r != 0)
+ {
+ return r;
+ }
+
+ r = COMPARE_RET(c1->ClientPort, c2->ClientPort);
+ if (r != 0)
+ {
+ return r;
+ }
+
+ r = COMPARE_RET(c1->ServerPort, c2->ServerPort);
+ if (r != 0)
+ {
+ return r;
+ }
+
+ return 0;
+}
+
+// Update the endpoint information of IKE_CLIENT
+IKE_CLIENT *SetIkeClientEndpoint(IKE_SERVER *ike, IKE_CLIENT *c, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port)
+{
+ char client_ip_str[MAX_SIZE];
+ char server_ip_str[MAX_SIZE];
+ IKE_CLIENT *ret = c;
+ IKE_CLIENT *cc;
+ IKE_CLIENT t;
+ // Validate arguments
+ if (ike == NULL || c == NULL || client_ip == NULL || client_port == 0 || server_ip == NULL || server_port == 0)
+ {
+ return NULL;
+ }
+
+ if (CmpIpAddr(&c->ClientIP, client_ip) == 0 &&
+ CmpIpAddr(&c->ServerIP, server_ip) == 0 &&
+ c->ClientPort == client_port &&
+ c->ServerPort == server_port)
+ {
+ // No change
+ return ret;
+ }
+
+ if (IS_SPECIAL_PORT(client_port) || IS_SPECIAL_PORT(server_port))
+ {
+ // Don't change in the case of Raw socket
+ return ret;
+ }
+
+ // Search for an existing IKE_CLIENT which exactly matches to combination of the new IP address and the port number
+ Copy(&t.ClientIP, client_ip, sizeof(IP));
+ t.ClientPort = client_port;
+ Copy(&t.ServerIP, server_ip, sizeof(IP));
+ t.ServerPort = server_port;
+
+ cc = Search(ike->ClientList, &t);
+ if (cc != NULL && c != cc && cc->Deleting == false && c->L2TP == NULL)
+ {
+ UINT i;
+ // Merge into this existing IKE_CLIENT since it found
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+
+ if (sa->IkeClient == c)
+ {
+ sa->IkeClient = cc;
+ }
+ }
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+
+ if (sa->IkeClient == c)
+ {
+ sa->IkeClient = cc;
+ }
+ }
+
+ if (cc->LastCommTick < c->LastCommTick)
+ {
+ StrCpy(cc->ClientId, sizeof(cc->ClientId), c->ClientId);
+ }
+
+ cc->FirstCommTick = MIN(cc->FirstCommTick, c->FirstCommTick);
+ cc->LastCommTick = MAX(cc->LastCommTick, c->LastCommTick);
+
+ ret = cc;
+
+ IPToStr(client_ip_str, sizeof(client_ip_str), client_ip);
+ IPToStr(server_ip_str, sizeof(server_ip_str), server_ip);
+
+ Debug("Merge IKE_CLIENT: %p->%p: %s:%u -> %s:%u\n", c, cc, client_ip_str, client_port, server_ip_str, server_port);
+
+ IPsecLog(ike, c, NULL, NULL, "LI_CLIENT_MERGE", c->Id, cc->Id, cc->Id);
+
+ // Remove old IKE_CLIENT from the list and free
+ Delete(ike->ClientList, c);
+ FreeIkeClient(ike, c);
+ }
+ else
+ {
+ // Rewrite the end point information of this IKE_CLIENT because not found
+ Copy(&c->ClientIP, client_ip, sizeof(IP));
+ Copy(&c->ServerIP, server_ip, sizeof(IP));
+ c->ClientPort = client_port;
+ c->ServerPort = server_port;
+
+ IPToStr(client_ip_str, sizeof(client_ip_str), client_ip);
+ IPToStr(server_ip_str, sizeof(server_ip_str), server_ip);
+
+ Debug("Update IKE_CLIENT: %p: %s:%u -> %s:%u\n", c, client_ip_str, client_port, server_ip_str, server_port);
+
+ IPsecLog(ike, c, NULL, NULL, "LI_CLIENT_UPDATE");
+
+ ike->ClientList->sorted = false;
+ }
+
+ return ret;
+}
+
+// Select the optimal transform setting for IPsec SA
+bool GetBestTransformSettingForIPsecSa(IKE_SERVER *ike, IKE_PACKET *pr, IPSEC_SA_TRANSFORM_SETTING *setting, IP *server_ip)
+{
+ IKE_PACKET_PAYLOAD *sa_payload;
+ IKE_PACKET_SA_PAYLOAD *sa;
+ UINT i, num;
+ bool ocmii_flag = false;
+ // Validate arguments
+ if (ike == NULL || pr == NULL || setting == NULL || server_ip == NULL)
+ {
+ return false;
+ }
+
+ Zero(setting, sizeof(IPSEC_SA_TRANSFORM_SETTING));
+
+ // Get the SA payload
+ sa_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_SA, 0);
+ if (sa_payload == NULL)
+ {
+ return false;
+ }
+
+ sa = &sa_payload->Payload.Sa;
+
+ // Scan all proposal payloads
+ num = IkeGetPayloadNum(sa->PayloadList, IKE_PAYLOAD_PROPOSAL);
+ for (i = 0;i < num;i++)
+ {
+ IKE_PACKET_PAYLOAD *proposal_payload = IkeGetPayload(sa->PayloadList, IKE_PAYLOAD_PROPOSAL, i);
+
+ if (proposal_payload != NULL)
+ {
+ IKE_PACKET_PROPOSAL_PAYLOAD *proposal = &proposal_payload->Payload.Proposal;
+
+ // Examine the contents of the proposal payload
+ if (proposal->ProtocolId == IKE_PROTOCOL_ID_IPSEC_ESP && proposal->Spi->Size == 4)
+ {
+ // Scan all transform payloads
+ UINT j, num2;
+
+ num2 = IkeGetPayloadNum(proposal->PayloadList, IKE_PAYLOAD_TRANSFORM);
+ for (j = 0;j < num2;j++)
+ {
+ IKE_PACKET_PAYLOAD *transform_payload = IkeGetPayload(proposal->PayloadList, IKE_PAYLOAD_TRANSFORM, j);
+ if (transform_payload != NULL)
+ {
+ IKE_PACKET_TRANSFORM_PAYLOAD *transform = &transform_payload->Payload.Transform;
+ IPSEC_SA_TRANSFORM_SETTING set;
+
+ if (TransformPayloadToTransformSettingForIPsecSa(ike, transform, &set, server_ip))
+ {
+ Copy(setting, &set, sizeof(IPSEC_SA_TRANSFORM_SETTING));
+
+ setting->SpiServerToClient = READ_UINT(proposal->Spi->Buf);
+
+ return true;
+ }
+ else
+ {
+ if (set.OnlyCapsuleModeIsInvalid)
+ {
+ if (ocmii_flag == false)
+ {
+ Copy(setting, &set, sizeof(IPSEC_SA_TRANSFORM_SETTING));
+ ocmii_flag = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+// Select the optimal transform settings for the IKE SA
+bool GetBestTransformSettingForIkeSa(IKE_SERVER *ike, IKE_PACKET *pr, IKE_SA_TRANSFORM_SETTING *setting)
+{
+ IKE_PACKET_PAYLOAD *sa_payload;
+ IKE_PACKET_SA_PAYLOAD *sa;
+ UINT i, num;
+ // Validate arguments
+ if (ike == NULL || pr == NULL || setting == NULL)
+ {
+ return false;
+ }
+
+ // Get the SA payload
+ sa_payload = IkeGetPayload(pr->PayloadList, IKE_PAYLOAD_SA, 0);
+ if (sa_payload == NULL)
+ {
+ return false;
+ }
+
+ sa = &sa_payload->Payload.Sa;
+
+ // Scan all proposal payloads
+ num = IkeGetPayloadNum(sa->PayloadList, IKE_PAYLOAD_PROPOSAL);
+ for (i = 0;i < num;i++)
+ {
+ IKE_PACKET_PAYLOAD *proposal_payload = IkeGetPayload(sa->PayloadList, IKE_PAYLOAD_PROPOSAL, i);
+
+ if (proposal_payload != NULL)
+ {
+ IKE_PACKET_PROPOSAL_PAYLOAD *proposal = &proposal_payload->Payload.Proposal;
+
+ // Examine the contents of the proposal payload
+ if (proposal->ProtocolId == IKE_PROTOCOL_ID_IKE)
+ {
+ // Scan all transform payloads
+ UINT j, num2;
+
+ num2 = IkeGetPayloadNum(proposal->PayloadList, IKE_PAYLOAD_TRANSFORM);
+ for (j = 0;j < num2;j++)
+ {
+ IKE_PACKET_PAYLOAD *transform_payload = IkeGetPayload(proposal->PayloadList, IKE_PAYLOAD_TRANSFORM, j);
+ if (transform_payload != NULL)
+ {
+ IKE_PACKET_TRANSFORM_PAYLOAD *transform = &transform_payload->Payload.Transform;
+
+ if (transform->TransformId == IKE_TRANSFORM_ID_P1_KEY_IKE)
+ {
+ IKE_SA_TRANSFORM_SETTING set;
+
+ if (TransformPayloadToTransformSettingForIkeSa(ike, transform, &set))
+ {
+ Copy(setting, &set, sizeof(IKE_SA_TRANSFORM_SETTING));
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+// Convert a structure to the transform payload (for IPsec SA)
+IKE_PACKET_PAYLOAD *TransformSettingToTransformPayloadForIPsec(IKE_SERVER *ike, IPSEC_SA_TRANSFORM_SETTING *setting)
+{
+ LIST *value_list;
+ // Validate arguments
+ if (ike == NULL || setting == NULL)
+ {
+ return NULL;
+ }
+
+ value_list = NewListFast(NULL);
+
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P2_HMAC, setting->HashId));
+
+ if (setting->Dh != NULL)
+ {
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P2_DH_GROUP, setting->DhId));
+ }
+
+ if (setting->LifeSeconds != INFINITE)
+ {
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P2_LIFE_TYPE, IKE_P2_LIFE_TYPE_SECONDS));
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P2_LIFE_VALUE, setting->LifeSeconds));
+ }
+
+ if (setting->LifeKilobytes != INFINITE)
+ {
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P2_LIFE_TYPE, IKE_P2_LIFE_TYPE_KILOBYTES));
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P2_LIFE_VALUE, setting->LifeKilobytes));
+ }
+
+ if (setting->Crypto->VariableKeySize)
+ {
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P2_KEY_SIZE, setting->CryptoKeySize * 8));
+ }
+
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P2_CAPSULE, setting->CapsuleMode));
+
+ return IkeNewTransformPayload(1, setting->CryptoId, value_list);
+}
+
+// Convert a structure to the transform payload (for IKE SA)
+IKE_PACKET_PAYLOAD *TransformSettingToTransformPayloadForIke(IKE_SERVER *ike, IKE_SA_TRANSFORM_SETTING *setting)
+{
+ LIST *value_list;
+ // Validate arguments
+ if (ike == NULL || setting == NULL)
+ {
+ return NULL;
+ }
+
+ value_list = NewListFast(NULL);
+
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P1_CRYPTO, setting->CryptoId));
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P1_HASH, setting->HashId));
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P1_AUTH_METHOD, IKE_P1_AUTH_METHOD_PRESHAREDKEY));
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P1_DH_GROUP, setting->DhId));
+
+ if (setting->LifeSeconds != INFINITE)
+ {
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P1_LIFE_TYPE, IKE_P1_LIFE_TYPE_SECONDS));
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P1_LIFE_VALUE, setting->LifeSeconds));
+ }
+
+ if (setting->LifeKilobytes != INFINITE)
+ {
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P1_LIFE_TYPE, IKE_P1_LIFE_TYPE_KILOBYTES));
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P1_LIFE_VALUE, setting->LifeKilobytes));
+ }
+
+ if (setting->Crypto->VariableKeySize)
+ {
+ Add(value_list, IkeNewTransformValue(IKE_TRANSFORM_VALUE_P1_KET_SIZE, setting->CryptoKeySize * 8));
+ }
+
+ return IkeNewTransformPayload(1, IKE_TRANSFORM_ID_P1_KEY_IKE, value_list);
+}
+
+// Convert a transform payload to a structure (for IPsec SA)
+bool TransformPayloadToTransformSettingForIPsecSa(IKE_SERVER *ike, IKE_PACKET_TRANSFORM_PAYLOAD *transform, IPSEC_SA_TRANSFORM_SETTING *setting, IP *server_ip)
+{
+ UINT i;
+ UINT capsule_mode;
+ bool is_esp_supported;
+ // Validate arguments
+ if (ike == NULL || transform == NULL || setting == NULL || server_ip == NULL)
+ {
+ return false;
+ }
+
+ is_esp_supported = IsUdpPortOpened(ike->IPsec->UdpListener, server_ip, IPSEC_PORT_IPSEC_ESP_RAW);
+
+ Zero(setting, sizeof(IPSEC_SA_TRANSFORM_SETTING));
+
+ setting->CryptoId = transform->TransformId;
+ setting->HashId = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P2_HMAC, 0);
+
+ setting->DhId = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P2_DH_GROUP, 0);
+
+ setting->LifeKilobytes = INFINITE;
+ setting->LifeSeconds = INFINITE;
+
+ for (i = 0;i < IkeGetTransformValueNum(transform, IKE_TRANSFORM_VALUE_P2_LIFE_TYPE);i++)
+ {
+ UINT life_type = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P2_LIFE_TYPE, i);
+
+ switch (life_type)
+ {
+ case IKE_P2_LIFE_TYPE_SECONDS: // Number of seconds
+ setting->LifeSeconds = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P2_LIFE_VALUE, i);
+ break;
+
+ case IKE_P2_LIFE_TYPE_KILOBYTES: // Kilobytes
+ setting->LifeKilobytes = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P2_LIFE_VALUE, i);
+ break;
+
+ default:
+ // Unsupported expiration type
+ return false;
+ }
+ }
+
+ setting->Crypto = GetIkeCrypto(ike->Engine, true, setting->CryptoId);
+ setting->Hash = GetIkeHash(ike->Engine, true, setting->HashId);
+ setting->Dh = GetIkeDh(ike->Engine, true, setting->DhId);
+
+ if (setting->Crypto == NULL || setting->Hash == NULL)
+ {
+ // Unsupported algorithm
+ return false;
+ }
+
+ if (setting->Crypto->VariableKeySize)
+ {
+ // Get the actual key size in the case of variable key size
+ setting->CryptoKeySize = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P2_KEY_SIZE, 0);
+
+ // bits -> bytes
+ setting->CryptoKeySize = setting->CryptoKeySize / 8;
+
+ if (setting->CryptoKeySize == 0 || IkeCheckKeySize(setting->Crypto, setting->CryptoKeySize) == false)
+ {
+ // The key size is not specified or inappropriate
+ return false;
+ }
+ }
+ else
+ {
+ // Get a fixed key length for fixed key size
+ setting->CryptoKeySize = setting->Crypto->KeySizes[0];
+ }
+
+ capsule_mode = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P2_CAPSULE, 0);
+ if (capsule_mode != IKE_P2_CAPSULE_NAT_TUNNEL_1 && capsule_mode != IKE_P2_CAPSULE_NAT_TUNNEL_2 &&
+ capsule_mode != IKE_P2_CAPSULE_NAT_TRANSPORT_1 && capsule_mode != IKE_P2_CAPSULE_NAT_TRANSPORT_2)
+ {
+ // No support for UDP encapsulation mode except for the NAT-Traversal
+ if (capsule_mode == IKE_P2_CAPSULE_TRANSPORT || capsule_mode == IKE_P2_CAPSULE_TUNNEL)
+ {
+ if (is_esp_supported == false)
+ {
+ setting->OnlyCapsuleModeIsInvalid = true;
+ return false;
+ }
+ else
+ {
+ // It is an environment that can send and receive ESP packets
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ setting->CapsuleMode = capsule_mode;
+
+ return true;
+}
+
+// Convert a transform payload to a structure (for IKE SA)
+bool TransformPayloadToTransformSettingForIkeSa(IKE_SERVER *ike, IKE_PACKET_TRANSFORM_PAYLOAD *transform, IKE_SA_TRANSFORM_SETTING *setting)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL || transform == NULL || setting == NULL)
+ {
+ return false;
+ }
+
+ Zero(setting, sizeof(IKE_SA_TRANSFORM_SETTING));
+
+ setting->CryptoId = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P1_CRYPTO, 0);
+ setting->HashId = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P1_HASH, 0);
+
+ if (IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P1_AUTH_METHOD, 0) != IKE_P1_AUTH_METHOD_PRESHAREDKEY)
+ {
+ // Only PSK authentication method is supported
+ return false;
+ }
+
+ setting->DhId = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P1_DH_GROUP, 0);
+
+ setting->LifeKilobytes = INFINITE;
+ setting->LifeSeconds = INFINITE;
+
+ for (i = 0;i < IkeGetTransformValueNum(transform, IKE_TRANSFORM_VALUE_P1_LIFE_TYPE);i++)
+ {
+ UINT life_type = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P1_LIFE_TYPE, i);
+
+ switch (life_type)
+ {
+ case IKE_P1_LIFE_TYPE_SECONDS: // Number of seconds
+ setting->LifeSeconds = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P1_LIFE_VALUE, i);
+ break;
+
+ case IKE_P1_LIFE_TYPE_KILOBYTES: // Kilobytes
+ setting->LifeKilobytes = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P1_LIFE_VALUE, i);
+ break;
+
+ default:
+ // Unsupported expiration type
+ return false;
+ }
+ }
+
+ setting->Crypto = GetIkeCrypto(ike->Engine, false, setting->CryptoId);
+ setting->Hash = GetIkeHash(ike->Engine, false, setting->HashId);
+ setting->Dh = GetIkeDh(ike->Engine, false, setting->DhId);
+
+ if (setting->Crypto == NULL || setting->Hash == NULL || setting->Dh == NULL)
+ {
+ // Unsupported algorithm
+ return false;
+ }
+
+ if (setting->Crypto->VariableKeySize)
+ {
+ // Get the actual key size in the case of variable key size
+ setting->CryptoKeySize = IkeGetTransformValue(transform, IKE_TRANSFORM_VALUE_P1_KET_SIZE, 0);
+
+ // bits -> bytes
+ setting->CryptoKeySize = setting->CryptoKeySize / 8;
+
+ if (setting->CryptoKeySize == 0 || IkeCheckKeySize(setting->Crypto, setting->CryptoKeySize) == false)
+ {
+ // The key size is not specified or inappropriate
+ return false;
+ }
+ }
+ else
+ {
+ // Get a fixed key length for fixed key size
+ setting->CryptoKeySize = setting->Crypto->KeySizes[0];
+ }
+
+ return true;
+}
+
+// Creating a new Responder Cookie
+UINT64 GenerateNewResponserCookie(IKE_SERVER *ike)
+{
+ UINT64 c;
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return 0;
+ }
+
+ while (true)
+ {
+ bool b = false;
+ UINT i;
+
+ c = Rand64();
+
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+
+ if (sa->ResponderCookie == c)
+ {
+ b = true;
+ break;
+ }
+ }
+
+ if (b == false)
+ {
+ return c;
+ }
+ }
+}
+
+// Parse the IKE packet header
+IKE_PACKET *ParseIKEPacketHeader(UDPPACKET *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ return IkeParseHeader(p->Data, p->Size, NULL);
+}
+
+// Search for another IPsec SA belonging to the IKE_CLIENT which have same conditions to the specified IPsec SA
+IPSECSA *GetOtherLatestIPsecSa(IKE_SERVER *ike, IPSECSA *sa)
+{
+ UINT i;
+ UINT64 min_value = 0;
+ IPSECSA *max_sa = NULL;
+ // Validate arguments
+ if (ike == NULL || sa == NULL)
+ {
+ return NULL;
+ }
+
+ if (sa->IkeClient == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa2 = LIST_DATA(ike->IPsecSaList, i);
+
+ if (sa2 != sa)
+ {
+ if (sa2->IkeClient == sa->IkeClient)
+ {
+ if (sa2->ServerToClient == sa->ServerToClient)
+ {
+ if (sa2->Deleting == false)
+ {
+ if (sa2->Established)
+ {
+ UINT64 last_comm_tick = sa2->LastCommTick;
+
+ if (sa2->ServerToClient)
+ {
+ if (sa2->PairIPsecSa != NULL)
+ {
+ last_comm_tick = sa2->PairIPsecSa->LastCommTick;
+ }
+ }
+
+ if (min_value < last_comm_tick)
+ {
+ min_value = last_comm_tick;
+
+ max_sa = sa2;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return max_sa;
+}
+
+// Search for another IKE_SA belonging to the IKE_CLIENT which have same conditions to the specified IKE_SA
+IKE_SA *GetOtherLatestIkeSa(IKE_SERVER *ike, IKE_SA *sa)
+{
+ UINT i;
+ UINT64 min_value = 0;
+ IKE_SA *max_sa = NULL;
+ // Validate arguments
+ if (ike == NULL || sa == NULL)
+ {
+ return NULL;
+ }
+
+ if (sa->IkeClient == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa2 = LIST_DATA(ike->IkeSaList, i);
+
+ if (sa2 != sa)
+ {
+ if (sa2->IkeClient == sa->IkeClient)
+ {
+ if (sa2->Deleting == false)
+ {
+ if (sa2->Established)
+ {
+ if (min_value < sa2->LastCommTick)
+ {
+ min_value = sa2->LastCommTick;
+
+ max_sa = sa2;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return max_sa;
+}
+
+// Purge the IPsec SA
+void PurgeIPsecSa(IKE_SERVER *ike, IPSECSA *sa)
+{
+ UINT i;
+ IPSECSA *other_sa;
+ // Validate arguments
+ if (ike == NULL || sa == NULL)
+ {
+ return;
+ }
+
+ other_sa = GetOtherLatestIPsecSa(ike, sa);
+
+ // Rewrite the pairing partner by looking for IPsec SA that are paired
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa2 = LIST_DATA(ike->IPsecSaList, i);
+
+ if (sa2->PairIPsecSa == sa)
+ {
+ sa2->PairIPsecSa = other_sa;
+ }
+ }
+
+ // Rewrite the IKE_CLIENT using this IPsec SA to use alternate
+ for (i = 0;i < LIST_NUM(ike->ClientList);i++)
+ {
+ IKE_CLIENT *c = LIST_DATA(ike->ClientList, i);
+
+ if (c->CurrentIpSecSaRecv == sa)
+ {
+ c->CurrentIpSecSaRecv = other_sa;
+ }
+
+ if (c->CurrentIpSecSaSend == sa)
+ {
+ c->CurrentIpSecSaSend = other_sa;
+ }
+ }
+
+ Delete(ike->IPsecSaList, sa);
+ FreeIPsecSa(sa);
+}
+
+// Remove the IKE SA
+void PurgeIkeSa(IKE_SERVER *ike, IKE_SA *sa)
+{
+ IKE_SA *other_sa;
+ UINT i;
+ // Validate arguments
+ if (ike == NULL || sa == NULL)
+ {
+ return;
+ }
+
+ Debug("Purging IKE SA %I64u-%I64u\n", sa->InitiatorCookie, sa->ResponderCookie);
+
+ // Rewrite to alternative IKE_SA of all IPsec SA that are using this IKE_SA
+ other_sa = GetOtherLatestIkeSa(ike, sa);
+
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *ipsec_sa = LIST_DATA(ike->IPsecSaList, i);
+
+ if (ipsec_sa->IkeSa == sa)
+ {
+ if (other_sa == NULL)
+ {
+ // Remove this IPsec SA because there is no alternative IKE_SA
+ Debug(" Deleting IPsec SA 0x%X of this IKE SA (no alternatives)\n", ipsec_sa->Spi);
+ MarkIPsecSaAsDeleted(ike, ipsec_sa);
+ ipsec_sa->IkeSa = NULL;
+ }
+ else
+ {
+ // Replace to the alternative IKE_SA
+ Debug(" Replacing IKE SA of IPsec SA 0x%X from %I64u-%I64u to %I64u-%I64u\n", ipsec_sa->Spi,
+ sa->InitiatorCookie, sa->ResponderCookie,
+ other_sa->InitiatorCookie, other_sa->ResponderCookie);
+ ipsec_sa->IkeSa = other_sa;
+ }
+ }
+ }
+
+ // Substitute the IKE_SA of all IKE_CLIENT that are using this IKE_SA with alternative
+ for (i = 0;i < LIST_NUM(ike->ClientList);i++)
+ {
+ IKE_CLIENT *c = LIST_DATA(ike->ClientList, i);
+
+ if (c->CurrentIkeSa == sa)
+ {
+ c->CurrentIkeSa = other_sa;
+ }
+ }
+
+ Delete(ike->IkeSaList, sa);
+ FreeIkeSa(sa);
+}
+
+// Purge the IKE_CLIENT
+void PurgeIkeClient(IKE_SERVER *ike, IKE_CLIENT *c)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL || c == NULL)
+ {
+ return;
+ }
+
+ // Delete all of IPsec SA and IKE SA that belong to this IKE Client
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+
+ if (sa->IkeClient == c)
+ {
+ MarkIkeSaAsDeleted(ike, sa);
+ }
+ }
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+
+ if (sa->IkeClient == c)
+ {
+ MarkIPsecSaAsDeleted(ike, sa);
+ }
+ }
+
+ Delete(ike->ClientList, c);
+ FreeIkeClient(ike, c);
+}
+
+// Remove the SA that has been marked to delete
+void PurgeDeletingSAsAndClients(IKE_SERVER *ike)
+{
+ UINT i;
+ LIST *o = NULL;
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+ if (sa->Deleting)
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Add(o, sa);
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IKE_SA *sa = LIST_DATA(o, i);
+
+ PurgeIkeSa(ike, sa);
+ }
+
+ ReleaseList(o);
+
+ o = NULL;
+
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+ if (sa->Deleting)
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Add(o, sa);
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IPSECSA *sa = LIST_DATA(o, i);
+
+ PurgeIPsecSa(ike, sa);
+ }
+
+ ReleaseList(o);
+
+ o = NULL;
+
+ for (i = 0;i < LIST_NUM(ike->ClientList);i++)
+ {
+ IKE_CLIENT *c = LIST_DATA(ike->ClientList, i);
+ if (c->Deleting)
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Add(o, c);
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IKE_CLIENT *c = LIST_DATA(o, i);
+
+ PurgeIkeClient(ike, c);
+ }
+
+ ReleaseList(o);
+}
+
+// IKE interrupt process
+void ProcessIKEInterrupts(IKE_SERVER *ike)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(ike->ClientList);i++)
+ {
+ IKE_CLIENT *c = LIST_DATA(ike->ClientList, i);
+
+ c->CurrentExpiresSoftTick_CtoS = 0;
+ c->CurrentExpiresSoftTick_StoC = 0;
+ c->CurrentNumEstablishedIPsecSA_CtoS = 0;
+ c->CurrentNumEstablishedIPsecSA_StoC = 0;
+ c->CurrentNumHealtyIPsecSA_CtoS = 0;
+ c->CurrentNumHealtyIPsecSA_StoC = 0;
+ }
+
+ // Packet retransmission by scanning all IKE SA
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+
+ if (sa->SendBuffer != NULL)
+ {
+ if (ike->Now >= sa->NextSendTick)
+ {
+ IKE_CLIENT *c = sa->IkeClient;
+
+ IkeSendUdpPacket(ike, IKE_UDP_TYPE_ISAKMP, &c->ServerIP, c->ServerPort, &c->ClientIP, c->ClientPort,
+ Clone(sa->SendBuffer->Buf, sa->SendBuffer->Size), sa->SendBuffer->Size);
+
+ sa->NextSendTick += (UINT64)(IKE_SA_RESEND_INTERVAL);
+
+ AddInterrupt(ike->Interrupts, sa->NextSendTick);
+
+ if (sa->NumResends != 0)
+ {
+ sa->NumResends--;
+ if (sa->NumResends == 0)
+ {
+ sa->NextSendTick = 0;
+ FreeBuf(sa->SendBuffer);
+ sa->SendBuffer = NULL;
+ }
+ }
+ }
+ }
+
+ // Remove those of non-communication
+ if (sa->IkeClient == NULL || (sa->IkeClient->CurrentIkeSa != sa))
+ {
+ // When the IKE_CLIENT don't point this
+ if (sa->Established == false)
+ {
+ // Make time-out in a short time when it is not established
+ if ((sa->LastCommTick + (UINT64)IKE_TIMEOUT_FOR_IKE_CLIENT_FOR_NOT_ESTABLISHED) <= ike->Now)
+ {
+ WHERE;
+ MarkIkeSaAsDeleted(ike, sa);
+ }
+ }
+ else
+ {
+ // Timeout in a long time in the case of established
+ if ((sa->LastCommTick + (UINT64)IKE_TIMEOUT_FOR_IKE_CLIENT) <= ike->Now)
+ {
+ WHERE;
+ MarkIkeSaAsDeleted(ike, sa);
+ }
+ }
+ }
+ }
+
+ // Packet retransmission by scanning all IPsec SA
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+ IKE_CLIENT *c = sa->IkeClient;
+
+ if (sa->SendBuffer != NULL)
+ {
+ if (ike->Now >= sa->NextSendTick)
+ {
+ IKE_CLIENT *c = sa->IkeClient;
+
+ IkeSendUdpPacket(ike, IKE_UDP_TYPE_ISAKMP, &c->ServerIP, c->ServerPort, &c->ClientIP, c->ClientPort,
+ Clone(sa->SendBuffer->Buf, sa->SendBuffer->Size), sa->SendBuffer->Size);
+
+ sa->NextSendTick += (UINT64)(IKE_SA_RESEND_INTERVAL);
+
+ AddInterrupt(ike->Interrupts, sa->NextSendTick);
+
+ if (sa->NumResends != 0)
+ {
+ sa->NumResends--;
+
+ if (sa->NumResends == 0)
+ {
+ sa->NextSendTick = 0;
+ FreeBuf(sa->SendBuffer);
+ sa->SendBuffer = NULL;
+ }
+ }
+ }
+ }
+
+ if (sa->Established && sa->Deleting == false && c != NULL)
+ {
+ // Get the flexible expiration date of SA for each IKE_CLIENT
+ if (sa->ServerToClient)
+ {
+ c->CurrentExpiresSoftTick_StoC = MAX(c->CurrentExpiresSoftTick_StoC, sa->ExpiresSoftTick);
+ c->CurrentNumEstablishedIPsecSA_StoC++;
+
+ if (sa->ExpiresSoftTick == 0 || sa->ExpiresSoftTick > ike->Now)
+ {
+ c->CurrentNumHealtyIPsecSA_StoC++;
+ }
+ }
+ else
+ {
+ c->CurrentExpiresSoftTick_CtoS = MAX(c->CurrentExpiresSoftTick_CtoS, sa->ExpiresSoftTick);
+ c->CurrentNumEstablishedIPsecSA_CtoS++;
+
+ if (sa->ExpiresSoftTick == 0 || sa->ExpiresSoftTick > ike->Now)
+ {
+ c->CurrentNumHealtyIPsecSA_CtoS++;
+ }
+ }
+ }
+
+ // Remove those of non-communication
+ if (sa->IkeClient == NULL || (sa->IkeClient->CurrentIpSecSaRecv != sa && sa->IkeClient->CurrentIpSecSaSend != sa))
+ {
+ // When the IKE_CLIENT don't point this
+ UINT64 last_comm_tick = sa->LastCommTick;
+
+ if (sa->ServerToClient && sa->PairIPsecSa != NULL)
+ {
+ last_comm_tick = sa->PairIPsecSa->LastCommTick;
+ }
+
+ if (sa->Established == false)
+ {
+ // Make time-out in a short time when it is not established
+ if ((last_comm_tick + (UINT64)IKE_TIMEOUT_FOR_IKE_CLIENT_FOR_NOT_ESTABLISHED) <= ike->Now)
+ {
+ WHERE;
+ MarkIPsecSaAsDeleted(ike, sa);
+ }
+ }
+ else
+ {
+ // Timeout in a long time in the case of established
+ if ((last_comm_tick + (UINT64)IKE_TIMEOUT_FOR_IKE_CLIENT) <= ike->Now)
+ {
+ WHERE;
+ MarkIPsecSaAsDeleted(ike, sa);
+ }
+ }
+ }
+ }
+
+ // IKE_CLIENT scanning process
+ for (i = 0;i < LIST_NUM(ike->ClientList);i++)
+ {
+ IKE_CLIENT *c = LIST_DATA(ike->ClientList, i);
+ UINT64 tick;
+ UCHAR data[1];
+ bool need_qm = false;
+ bool need_qm_hard = false;
+ UINT64 qm_soft_tick = 0;
+
+ // Determine whether it is necessary to start a new Quick Mode
+ if (c->CurrentExpiresSoftTick_StoC != 0 && ike->Now >= c->CurrentExpiresSoftTick_StoC)
+ {
+ need_qm = true;
+ qm_soft_tick = MAX(qm_soft_tick, c->CurrentExpiresSoftTick_StoC);
+ }
+
+ if (c->CurrentExpiresSoftTick_CtoS != 0 && ike->Now >= c->CurrentExpiresSoftTick_CtoS)
+ {
+ need_qm = true;
+ qm_soft_tick = MAX(qm_soft_tick, c->CurrentExpiresSoftTick_StoC);
+ }
+
+ if (c->CurrentNumHealtyIPsecSA_CtoS == 0 || c->CurrentNumHealtyIPsecSA_StoC == 0)
+ {
+ need_qm = true;
+ need_qm_hard = true;
+ }
+
+ if (c->StartQuickModeAsSoon)
+ {
+ need_qm = true;
+ need_qm_hard = true;
+ }
+
+ if (c->Deleting || c->CurrentIkeSa == NULL || c->CurrentIkeSa->Deleting)
+ {
+ need_qm = false;
+ need_qm_hard = true;
+ }
+
+ if (need_qm)
+ {
+ if (c->StartQuickModeAsSoon || ((c->LastQuickModeStartTick + (UINT64)IKE_QUICKMODE_START_INTERVAL) <= ike->Now))
+ {
+ // Start the Quick Mode
+ Debug("IKE_CLIENT 0x%X: Begin QuickMode\n", c);
+ c->StartQuickModeAsSoon = false;
+ c->LastQuickModeStartTick = ike->Now;
+
+ AddInterrupt(ike->Interrupts, c->LastQuickModeStartTick + (UINT64)IKE_QUICKMODE_START_INTERVAL);
+
+ StartQuickMode(ike, c);
+ }
+ }
+
+ if (need_qm_hard)
+ {
+ if (c->NeedQmBeginTick == 0)
+ {
+ c->NeedQmBeginTick = ike->Now;
+ }
+ }
+ else
+ {
+ c->NeedQmBeginTick = 0;
+ }
+
+ if (((c->LastCommTick + (UINT64)IKE_TIMEOUT_FOR_IKE_CLIENT) <= ike->Now) ||
+ ((c->CurrentIkeSa == NULL && c->CurrentIpSecSaRecv == NULL && c->CurrentIpSecSaSend == NULL) && (c->LastCommTick + (UINT64)IKE_TIMEOUT_FOR_IKE_CLIENT_FOR_NOT_ESTABLISHED) <= ike->Now) ||
+ (c->NeedQmBeginTick != 0 && ((c->NeedQmBeginTick + (UINT64)IKE_QUICKMODE_FAILED_TIMEOUT) <= ike->Now)))
+ {
+ // Remove IKE_CLIENT not communicating for a certain period of time
+ WHERE;
+ MarkIkeClientAsDeleted(ike, c);
+ }
+
+ // L2TP processing
+ if (c->L2TP != NULL)
+ {
+ IPsecIkeClientManageL2TPServer(ike, c);
+
+ // Interrupt processing occurs
+ L2TPProcessInterrupts(c->L2TP);
+
+ // Packet transmission
+ IPsecIkeClientSendL2TPPackets(ike, c, c->L2TP);
+ }
+
+ // EtherIP processing
+ if (c->EtherIP != NULL)
+ {
+ IPsecIkeClientManageEtherIPServer(ike, c);
+
+ // Interrupt processing occurs
+ EtherIPProcInterrupts(c->EtherIP);
+
+ // Packet transmission
+ IPsecIkeClientSendEtherIPPackets(ike, c, c->EtherIP);
+ }
+
+ // KeepAlive transmission
+ tick = MAX(c->LastCommTick + (UINT64)IKE_INTERVAL_UDP_KEEPALIVE, c->NextKeepAliveSendTick);
+
+ if (tick <= ike->Now && c->ServerPort == IPSEC_PORT_IPSEC_ESP_UDP)
+ {
+ c->NextKeepAliveSendTick = ike->Now + (UINT64)IKE_INTERVAL_UDP_KEEPALIVE;
+
+ AddInterrupt(ike->Interrupts, c->NextKeepAliveSendTick);
+
+ Zero(data, sizeof(data));
+ data[0] = 0xff;
+
+ IkeSendUdpPacket(ike, IKE_UDP_KEEPALIVE, &c->ServerIP, c->ServerPort, &c->ClientIP, c->ClientPort, Clone(data, sizeof(data)), sizeof(data));
+ }
+
+ // DPD transmission
+ if (c->NextDpdSendTick == 0 || c->NextDpdSendTick <= ike->Now)
+ {
+ if (c->CurrentIkeSa != NULL && c->CurrentIkeSa->Established)
+ {
+ if (c->CurrentIkeSa->Caps.DpdRfc3706)
+ {
+ c->NextDpdSendTick = ike->Now + (UINT64)IKE_INTERVAL_DPD_KEEPALIVE;
+
+ AddInterrupt(ike->Interrupts, c->NextDpdSendTick);
+
+ SendInformationalExchangePacket(ike, c,
+ IkeNewNoticeDpdPayload(false, c->CurrentIkeSa->InitiatorCookie, c->CurrentIkeSa->ResponderCookie,
+ c->DpdSeqNo++));
+ }
+ }
+ }
+ }
+
+ do
+ {
+ ike->StateHasChanged = false;
+
+ // Deletion process
+ PurgeDeletingSAsAndClients(ike);
+ }
+ while (ike->StateHasChanged);
+
+ // Maintenance of the thread list
+ MainteThreadList(ike->ThreadList);
+ /*Debug("ike->ThreadList: %u\n", LIST_NUM(ike->ThreadList));
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(ike->ThreadList);i++)
+ {
+ THREAD *t = LIST_DATA(ike->ThreadList, i);
+
+ Debug(" Thread %u: 0x%p ID: %u Stop: %u Ref: %u\n", i, t, t->ThreadId, t->Stopped, t->ref->c->c);
+ }
+ }*/
+}
+
+// Stop the IKE server
+void StopIKEServer(IKE_SERVER *ike)
+{
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return;
+ }
+}
+
+// Set the socket events in IKE server
+void SetIKEServerSockEvent(IKE_SERVER *ike, SOCK_EVENT *e)
+{
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return;
+ }
+
+ if (e != NULL)
+ {
+ AddRef(e->ref);
+ }
+
+ if (ike->SockEvent != NULL)
+ {
+ ReleaseSockEvent(ike->SockEvent);
+ }
+
+ ike->SockEvent = e;
+}
+
+// Release the IKE client
+void FreeIkeClient(IKE_SERVER *ike, IKE_CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL || ike == NULL)
+ {
+ return;
+ }
+
+ if (c->L2TP != NULL)
+ {
+ StopL2TPServer(c->L2TP, true);
+ FreeL2TPServer(c->L2TP);
+ }
+
+ if (c->EtherIP != NULL)
+ {
+ ReleaseEtherIPServer(c->EtherIP);
+ }
+
+ FreeBuf(c->SendID1_Buf);
+ FreeBuf(c->SendID2_Buf);
+
+ Free(c);
+}
+
+// Release the IPsec SA
+void FreeIPsecSa(IPSECSA *sa)
+{
+ // Validate arguments
+ if (sa == NULL)
+ {
+ return;
+ }
+
+ IkeFreeKey(sa->CryptoKey);
+
+ FreeBuf(sa->SendBuffer);
+
+ FreeBuf(sa->InitiatorRand);
+ FreeBuf(sa->ResponderRand);
+
+ FreeBuf(sa->SharedKey);
+
+ IkeDhFreeCtx(sa->Dh);
+
+ Free(sa);
+}
+
+// Release the IKE SA
+void FreeIkeSa(IKE_SA *sa)
+{
+ // Validate arguments
+ if (sa == NULL)
+ {
+ return;
+ }
+
+ FreeBuf(sa->SendBuffer);
+
+ FreeBuf(sa->InitiatorRand);
+ FreeBuf(sa->ResponderRand);
+ FreeBuf(sa->DhSharedKey);
+ FreeBuf(sa->YourIDPayloadForAM);
+
+ FreeBuf(sa->GXi);
+ FreeBuf(sa->GXr);
+
+ FreeBuf(sa->SAi_b);
+
+ IkeFreeKey(sa->CryptoKey);
+
+ Free(sa);
+}
+
+// Release the IKE server
+void FreeIKEServer(IKE_SERVER *ike)
+{
+ UINT i;
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return;
+ }
+
+ IPsecLog(ike, NULL, NULL, NULL, "LI_STOPPING");
+
+ for (i = 0;i < LIST_NUM(ike->SendPacketList);i++)
+ {
+ UDPPACKET *udp = LIST_DATA(ike->SendPacketList, i);
+
+ FreeUdpPacket(udp);
+ }
+
+ ReleaseList(ike->SendPacketList);
+
+ Debug("Num of IPsec SAs: %u\n", LIST_NUM(ike->IPsecSaList));
+ IPsecLog(ike, NULL, NULL, NULL, "LI_NUM_IPSEC_SA", LIST_NUM(ike->IPsecSaList));
+
+ for (i = 0;i < LIST_NUM(ike->IPsecSaList);i++)
+ {
+ IPSECSA *sa = LIST_DATA(ike->IPsecSaList, i);
+
+ FreeIPsecSa(sa);
+ }
+
+ ReleaseList(ike->IPsecSaList);
+
+ Debug("Num of IKE SAs: %u\n", LIST_NUM(ike->IkeSaList));
+ IPsecLog(ike, NULL, NULL, NULL, "LI_NUM_IKE_SA", LIST_NUM(ike->IkeSaList));
+
+ for (i = 0;i < LIST_NUM(ike->IkeSaList);i++)
+ {
+ IKE_SA *sa = LIST_DATA(ike->IkeSaList, i);
+
+ FreeIkeSa(sa);
+ }
+
+ ReleaseList(ike->IkeSaList);
+
+ Debug("Num of IKE_CLIENTs: %u\n", LIST_NUM(ike->ClientList));
+ IPsecLog(ike, NULL, NULL, NULL, "LI_NUM_IKE_CLIENTS", LIST_NUM(ike->ClientList));
+
+ for (i = 0;i < LIST_NUM(ike->ClientList);i++)
+ {
+ IKE_CLIENT *c = LIST_DATA(ike->ClientList, i);
+
+ FreeIkeClient(ike, c);
+ }
+
+ ReleaseList(ike->ClientList);
+
+ ReleaseSockEvent(ike->SockEvent);
+
+ IPsecLog(ike, NULL, NULL, NULL, "LI_STOP");
+
+ ReleaseCedar(ike->Cedar);
+
+ FreeIkeEngine(ike->Engine);
+
+ Debug("FreeThreadList()...\n");
+ FreeThreadList(ike->ThreadList);
+ Debug("FreeThreadList() Done.\n");
+
+ Free(ike);
+}
+
+// Create a new IKE server
+IKE_SERVER *NewIKEServer(CEDAR *cedar, IPSEC_SERVER *ipsec)
+{
+ IKE_SERVER *ike;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ ike = ZeroMalloc(sizeof(IKE_SERVER));
+
+ ike->Cedar = cedar;
+ AddRef(cedar->ref);
+
+ ike->IPsec = ipsec;
+
+ ike->Now = Tick64();
+
+ ike->SendPacketList = NewList(NULL);
+
+ ike->IkeSaList = NewList(CmpIkeSa);
+
+ ike->IPsecSaList = NewList(CmpIPsecSa);
+
+ ike->ClientList = NewList(CmpIkeClient);
+
+ ike->Engine = NewIkeEngine();
+
+ ike->ThreadList = NewThreadList();
+
+ IPsecLog(ike, NULL, NULL, NULL, "LI_START");
+
+ return ike;
+}
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_IKE.h b/src/Cedar/IPsec_IKE.h
new file mode 100644
index 00000000..85e319b1
--- /dev/null
+++ b/src/Cedar/IPsec_IKE.h
@@ -0,0 +1,450 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_IKE.h
+// Header of IPsec_IKE.c
+
+#ifndef IPSEC_IKE_H
+#define IPSEC_IKE_H
+
+//// Macro
+
+//// Constants
+
+// State
+#define IKE_SA_MAIN_MODE 0 // Main mode
+#define IKE_SA_AGRESSIVE_MODE 1 // Aggressive mode
+
+#define IKE_SA_MM_STATE_1_SA 0 // Main mode state 1 (SA exchange is complete. Wait for key exchange)
+#define IKE_SA_MM_STATE_2_KEY 1 // Main mode state 2 (Key exchange is complete. Wait for exchange ID)
+#define IKE_SA_MM_STATE_3_ESTABLISHED 2 // Main mode state 3 (ID exchange is complete. Established)
+
+#define IKE_SA_AM_STATE_1_SA 0 // Aggressive mode state 1 (SA exchange is completed. Wait for hash)
+#define IKE_SA_AM_STATE_2_ESTABLISHED 1 // Aggressive mode state 2 (Hash exchange is completed. Established)
+
+#define IKE_SA_RESEND_INTERVAL (2 * 1000) // IKE SA packet retransmission interval
+#define IKE_SA_RAND_SIZE 16 // Size of the random number
+
+// ESP
+#define IKE_ESP_HASH_SIZE 12 // The hash size for the ESP packet
+
+// Type of UDP packet
+#define IKE_UDP_TYPE_ISAKMP 0 // ISAKMP packet (destination 500)
+#define IKE_UDP_TYPE_ESP 1 // ESP packet (destination 4500)
+#define IKE_UDP_KEEPALIVE 2 // KeepAlive packet
+#define IKE_UDP_SPECIAL 3 // Special packet
+
+// String for Vendor ID
+#define IKE_VENDOR_ID_RFC3947_NAT_T "0x4a131c81070358455c5728f20e95452f"
+#define IKE_VENDOR_ID_IPSEC_NAT_T_IKE_03 "0x7d9419a65310ca6f2c179d9215529d56"
+#define IKE_VENDOR_ID_IPSEC_NAT_T_IKE_02 "0x90cb80913ebb696e086381b5ec427b1f"
+#define IKE_VENDOR_ID_IPSEC_NAT_T_IKE_02_2 "0xcd60464335df21f87cfdb2fc68b6a448"
+#define IKE_VENDOR_ID_IPSEC_NAT_T_IKE_00 "0x4485152d18b6bbcd0be8a8469579ddcc"
+#define IKE_VENDOR_ID_RFC3706_DPD "0xafcad71368a1f1c96b8696fc77570100"
+#define IKE_VENDOR_ID_MICROSOFT_L2TP "0x4048b7d56ebce88525e7de7f00d6c2d3"
+#define IKE_VENDOR_ID_MS_NT5_ISAKMPOAKLEY "0x1e2b516905991c7d7c96fcbfb587e461"
+#define IKE_VENDOR_ID_MS_VID_INITIALCONTACT "0x26244d38eddb61b3172a36e3d0cfb819"
+
+// Quota
+#define IKE_QUOTA_MAX_NUM_CLIENTS_PER_IP 1000 // The number of IKE_CLIENT per IP address
+#define IKE_QUOTA_MAX_NUM_CLIENTS 30000 // Limit number of IKE_CLIENT
+#define IKE_QUOTA_MAX_SA_PER_CLIENT 100 // The limit number of SA for each IKE_CLIENT
+
+// Time-out
+#define IKE_TIMEOUT_FOR_IKE_CLIENT 150000 // IKE_CLIENT non-communication disconnect time
+#define IKE_TIMEOUT_FOR_IKE_CLIENT_FOR_NOT_ESTABLISHED 10000 // IKE_CLIENT non-communication disconnect time (connection incomplete)
+#define IKE_INTERVAL_UDP_KEEPALIVE 5000 // UDP KeepAlive transmission interval
+#define IKE_QUICKMODE_START_INTERVAL 2000 // QuickMode start interval
+#define IKE_QUICKMODE_FAILED_TIMEOUT 10000 // Maximum time to tolerant that to fail to establish a QuickMode
+#define IKE_INTERVAL_DPD_KEEPALIVE 10000 // DPD KeepAlive transmission interval
+
+// Expiration margin
+#define IKE_SOFT_EXPIRES_MARGIN 1000 // Expiration margin
+
+
+//// Type
+
+// IKE SA transform data
+struct IKE_SA_TRANSFORM_SETTING
+{
+ IKE_CRYPTO *Crypto;
+ UINT CryptoKeySize;
+ IKE_HASH *Hash;
+ IKE_DH *Dh;
+ UINT CryptoId;
+ UINT HashId;
+ UINT DhId;
+ UINT LifeKilobytes;
+ UINT LifeSeconds;
+};
+
+// IPsec SA transforms data
+struct IPSEC_SA_TRANSFORM_SETTING
+{
+ IKE_CRYPTO *Crypto;
+ UINT CryptoKeySize;
+ IKE_HASH *Hash;
+ IKE_DH *Dh;
+ UINT CryptoId;
+ UINT HashId;
+ UINT DhId;
+ UINT LifeKilobytes;
+ UINT LifeSeconds;
+ UINT SpiServerToClient;
+ UINT CapsuleMode;
+ bool OnlyCapsuleModeIsInvalid;
+};
+
+// Function support information
+struct IKE_CAPS
+{
+ // Support Information
+ bool NatTraversalRfc3947; // RFC 3947 Negotiation of NAT-Traversal in the IKE
+ bool NatTraversalDraftIetf; // draft-ietf-ipsec-nat-t-ike
+ bool DpdRfc3706; // RFC 3706 A Traffic-Based Method of Detecting Dead Internet Key Exchange (IKE) Peers
+ bool MS_L2TPIPSecVPNClient; // Vendor ID: Microsoft L2TP/IPSec VPN Client
+ bool MS_NT5_ISAKMP_OAKLEY; // Vendor ID: MS NT5 ISAKMPOAKLEY
+ bool MS_Vid_InitialContact; // Vendor ID: Microsoft Vid-Initial-Contact
+
+ // Use information
+ bool UsingNatTraversalRfc3947;
+ bool UsingNatTraversalDraftIetf;
+};
+
+// IKE / IPsec client
+struct IKE_CLIENT
+{
+ UINT Id;
+ IP ClientIP;
+ UINT ClientPort;
+ IP ServerIP;
+ UINT ServerPort;
+ IKE_SA *CurrentIkeSa; // IKE SA to be used currently
+ IPSECSA *CurrentIpSecSaRecv; // IPsec SA to be used currently (receive direction)
+ IPSECSA *CurrentIpSecSaSend; // IPsec SA to be currently in use (transmit direction)
+ UINT64 FirstCommTick; // Time the first data communication
+ UINT64 LastCommTick; // Time that made the last communication (received data) time
+ bool Deleting; // Deleting
+ UINT64 NextKeepAliveSendTick; // Time to send the next KeepAlive
+ UINT64 NextDpdSendTick; // Time to send the next DPD
+ UINT DpdSeqNo; // DPD sequence number
+ char ClientId[128]; // ID presented by the client
+ char Secret[MAX_SIZE]; // Secret value of the authentication is successful
+
+ bool IsMicrosoft; // Whether the client is Microsoft's
+
+ IPSEC_SA_TRANSFORM_SETTING CachedTransformSetting; // Cached transform attribute value
+ UINT64 CurrentExpiresSoftTick_StoC; // The maximum value of the flexible expiration date of the current (server -> client)
+ UINT64 CurrentExpiresSoftTick_CtoS; // The maximum value of the flexible expiration date of the current (client -> server)
+ UINT CurrentNumEstablishedIPsecSA_StoC; // The number of IPsec SA currently active (server -> client)
+ UINT CurrentNumEstablishedIPsecSA_CtoS; // The number of IPsec SA currently active (client -> server)
+ UINT CurrentNumHealtyIPsecSA_CtoS; // The number of currently available IPsec SA which expiration well within (client -> server)
+ UINT CurrentNumHealtyIPsecSA_StoC; // The number of currently available IPsec SA which expiration well within (server -> client)
+ bool SendID1andID2; // Whether to send the ID in QM
+ UCHAR SendID1_Type, SendID2_Type;
+ UCHAR SendID1_Protocol, SendID2_Protocol;
+ USHORT SendID1_Port, SendID2_Port;
+ BUF *SendID1_Buf, *SendID2_Buf;
+ bool SendNatOaDraft1, SendNatOaDraft2, SendNatOaRfc; // Whether to send the NAT-OA in QM
+ bool StartQuickModeAsSoon; // Flag to indicate to the start of the Quick Mode as soon as possible
+ UINT64 LastQuickModeStartTick; // Time which the last QuickMode started
+ UINT64 NeedQmBeginTick; // Time which a start-up of QuickMode is required
+
+ // L2TP related
+ L2TP_SERVER *L2TP; // L2TP server
+ UINT L2TPClientPort; // Client-side port number of L2TP
+ IP L2TPServerIP, L2TPClientIP; // IP address used by the L2TP processing
+ bool IsL2TPOnIPsecTunnelMode; // Whether the L2TP is working on IPsec tunnel mode
+
+ // EtherIP related
+ ETHERIP_SERVER *EtherIP; // EtherIP server
+ bool IsEtherIPOnIPsecTunnelMode; // Whether the EtherIP is working on IPsec tunnel mode
+
+ // Transport mode related
+ IP TransportModeServerIP;
+ IP TransportModeClientIP;
+ bool ShouldCalcChecksumForUDP; // Flag to calculate the checksum for the UDP packet
+
+ // Tunnel mode related
+ IP TunnelModeServerIP; // Server-side internal IP address
+ IP TunnelModeClientIP; // Client-side internal IP address
+ USHORT TunnelSendIpId; // ID of the transmission IP header
+};
+
+// IKE SA
+struct IKE_SA
+{
+ UINT Id;
+ IKE_CLIENT *IkeClient; // Pointer to the IKE client
+ UINT64 InitiatorCookie, ResponderCookie; // Cookie
+ UINT Mode; // Mode
+ UINT State; // State
+ BUF *SendBuffer; // Buffer during transmission
+ UINT64 NextSendTick; // Next transmission time
+ UINT64 FirstCommTick; // Time that the first data communication
+ UINT64 EstablishedTick; // Time that the SA has been established
+ UINT64 LastCommTick; // Time that made the last communication (received data) time
+ IKE_SA_TRANSFORM_SETTING TransformSetting; // Transform Configuration
+ IKE_CAPS Caps; // IKE Caps
+ BUF *InitiatorRand, *ResponderRand; // Random number
+ BUF *DhSharedKey; // DH common key
+ BUF *GXi, *GXr; // DH exchange data
+ BUF *SAi_b; // Data needed for authentication
+ BUF *YourIDPayloadForAM; // Copy the ID payload of the client-side
+ UCHAR SKEYID[IKE_MAX_HASH_SIZE]; // Key set
+ UCHAR SKEYID_d[IKE_MAX_HASH_SIZE];
+ UCHAR SKEYID_a[IKE_MAX_HASH_SIZE];
+ UCHAR SKEYID_e[IKE_MAX_HASH_SIZE];
+ UCHAR InitiatorHashForAM[IKE_MAX_HASH_SIZE];
+ IKE_CRYPTO_KEY *CryptoKey; // Common encryption key
+ UINT HashSize; // Hash size
+ UINT KeySize; // Key size
+ UINT BlockSize; // Block size
+ UCHAR Iv[IKE_MAX_BLOCK_SIZE]; // IV
+ bool IsIvExisting; // Whether an IV exists
+ bool Established; // Established flag
+ bool Deleting; // Deleting
+ UINT NumResends; // The number of retransmissions
+ char Secret[MAX_SIZE]; // Secret value of the authentication is successful
+};
+
+// IPsec SA
+struct IPSECSA
+{
+ UINT Id;
+ IKE_CLIENT *IkeClient; // Pointer to the IKE client
+ IKE_SA *IkeSa; // Pointer to IKE_SA to use for transmission
+ UCHAR Iv[IKE_MAX_BLOCK_SIZE]; // IV used in the Quick Mode exchange
+ bool IsIvExisting; // Whether the IV exists
+ UINT MessageId; // Message ID used in Quick Mode exchange
+ UINT Spi; // SPI
+ UINT CurrentSeqNo; // Send sequence number
+ BUF *SendBuffer; // Buffer during transmission
+ UINT NumResends; // The number of retransmissions
+ UINT64 NextSendTick; // Next transmission date and time
+ UINT64 FirstCommTick; // Time the last data sent
+ UINT64 EstablishedTick; // Time that the SA has been established
+ UINT64 LastCommTick; // Time that made the last communication (received data) time
+ UINT64 ExpiresHardTick; // Exact expiration time
+ UINT64 ExpiresSoftTick; // Flexible expiration time
+ UINT64 TotalSize; // Size sent to and received
+ IPSEC_SA_TRANSFORM_SETTING TransformSetting; // Transform Configuration
+ bool ServerToClient; // Whether is upload direction
+ IPSECSA *PairIPsecSa; // IPsec SA that are paired
+ bool Established; // Established flag
+ BUF *InitiatorRand, *ResponderRand; // Random number
+ BUF *SharedKey; // PFS shared key
+ UCHAR Hash3[IKE_MAX_HASH_SIZE]; // Hash 3
+ UCHAR KeyMat[IKE_MAX_KEY_SIZE + IKE_MAX_HASH_SIZE]; // Encryption key
+ UCHAR HashKey[IKE_MAX_HASH_SIZE]; // Hash key
+ IKE_CRYPTO_KEY *CryptoKey; // Key data
+ bool Deleting; // Deleting
+ UCHAR EspIv[IKE_MAX_BLOCK_SIZE]; // IV for ESP communication
+ bool Initiated; // The server-side is initiator
+ DH_CTX *Dh; // DH (only if the server-side is initiator)
+ bool StartQM_FlagSet; // Whether the flag to indicate to do the QM is set to the IKE_CLIENT
+ UCHAR SKEYID_d[IKE_MAX_HASH_SIZE];
+ UCHAR SKEYID_a[IKE_MAX_HASH_SIZE];
+ IKE_HASH *SKEYID_Hash;
+};
+
+// IKE server
+struct IKE_SERVER
+{
+ CEDAR *Cedar;
+ IPSEC_SERVER *IPsec;
+ UINT64 Now; // Current time
+ LIST *SendPacketList; // Transmission packet
+ INTERRUPT_MANAGER *Interrupts; // Interrupt manager
+ SOCK_EVENT *SockEvent; // SockEvent
+ IKE_ENGINE *Engine; // Encryption engine
+ LIST *ClientList; // Client list
+ LIST *IkeSaList; // SA list
+ LIST *IPsecSaList; // IPsec SA list
+ LIST *ThreadList; // L2TP thread list
+ bool StateHasChanged; // Flag whether the state has changed
+ UINT CurrentIkeSaId, CurrentIPsecSaId, CurrentIkeClientId, CurrentEtherId; // Serial number ID
+
+ // Setting data
+ char Secret[MAX_SIZE]; // Pre-shared key
+};
+
+
+//// Function prototype
+IKE_SERVER *NewIKEServer(CEDAR *cedar, IPSEC_SERVER *ipsec);
+void FreeIKEServer(IKE_SERVER *ike);
+void SetIKEServerSockEvent(IKE_SERVER *ike, SOCK_EVENT *e);
+void ProcIKEPacketRecv(IKE_SERVER *ike, UDPPACKET *p);
+void StopIKEServer(IKE_SERVER *ike);
+void ProcessIKEInterrupts(IKE_SERVER *ike);
+IKE_PACKET *ParseIKEPacketHeader(UDPPACKET *p);
+void ProcIkeMainModePacketRecv(IKE_SERVER *ike, UDPPACKET *p, IKE_PACKET *header);
+void ProcIkeQuickModePacketRecv(IKE_SERVER *ike, UDPPACKET *p, IKE_PACKET *header);
+void ProcIkeAggressiveModePacketRecv(IKE_SERVER *ike, UDPPACKET *p, IKE_PACKET *header);
+void ProcIkeInformationalExchangePacketRecv(IKE_SERVER *ike, UDPPACKET *p, IKE_PACKET *header);
+void FreeIkeSa(IKE_SA *sa);
+void FreeIkeClient(IKE_SERVER *ike, IKE_CLIENT *c);
+UINT64 GenerateNewResponserCookie(IKE_SERVER *ike);
+bool GetBestTransformSettingForIkeSa(IKE_SERVER *ike, IKE_PACKET *pr, IKE_SA_TRANSFORM_SETTING *setting);
+bool TransformPayloadToTransformSettingForIkeSa(IKE_SERVER *ike, IKE_PACKET_TRANSFORM_PAYLOAD *transform, IKE_SA_TRANSFORM_SETTING *setting);
+IKE_CLIENT *SearchIkeClientForIkePacket(IKE_SERVER *ike, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, IKE_PACKET *pr);
+IKE_CLIENT *SearchOrCreateNewIkeClientForIkePacket(IKE_SERVER *ike, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, IKE_PACKET *pr);
+UINT GetNumberOfIkeClientsFromIP(IKE_SERVER *ike, IP *client_ip);
+UINT GetNumberOfIPsecSaOfIkeClient(IKE_SERVER *ike, IKE_CLIENT *c);
+UINT GetNumberOfIkeSaOfIkeClient(IKE_SERVER *ike, IKE_CLIENT *c);
+int CmpIkeClient(void *p1, void *p2);
+int CmpIkeSa(void *p1, void *p2);
+int CmpIPsecSa(void *p1, void *p2);
+IKE_SA *FindIkeSaByEndPointAndInitiatorCookie(IKE_SERVER *ike, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, UINT64 init_cookie, UINT mode);
+IKE_SA *FindIkeSaByResponderCookie(IKE_SERVER *ike, UINT64 responder_cookie);
+IKE_SA *FindIkeSaByResponderCookieAndClient(IKE_SERVER *ike, UINT64 responder_cookie, IKE_CLIENT *c);
+IKE_CLIENT *NewIkeClient(IKE_SERVER *ike, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port);
+IKE_CLIENT *SetIkeClientEndpoint(IKE_SERVER *ike, IKE_CLIENT *c, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port);
+IKE_SA *NewIkeSa(IKE_SERVER *ike, IKE_CLIENT *c, UINT64 init_cookie, UINT mode, IKE_SA_TRANSFORM_SETTING *setting);
+IKE_PACKET_PAYLOAD *TransformSettingToTransformPayloadForIke(IKE_SERVER *ike, IKE_SA_TRANSFORM_SETTING *setting);
+void IkeSaSendPacket(IKE_SERVER *ike, IKE_SA *sa, IKE_PACKET *p);
+IKE_PACKET *IkeSaRecvPacket(IKE_SERVER *ike, IKE_SA *sa, void *data, UINT size);
+void IkeSendUdpPacket(IKE_SERVER *ike, UINT type, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, void *data, UINT size);
+void IkeAddVendorIdPayloads(IKE_PACKET *p);
+BUF *IkeStrToVendorId(char *str);
+void IkeAddVendorId(IKE_PACKET *p, char *str);
+bool IkeIsVendorIdExists(IKE_PACKET *p, char *str);
+void IkeCheckCaps(IKE_CAPS *caps, IKE_PACKET *p);
+BUF *IkeCalcNatDetectHash(IKE_SERVER *ike, IKE_HASH *hash, UINT64 initiator_cookie, UINT64 responder_cookie, IP *ip, UINT port);
+void IkeCalcSaKeySet(IKE_SERVER *ike, IKE_SA *sa, char *secret);
+IKE_CRYPTO_KEY *IkeNewCryptoKeyFromK(IKE_SERVER *ike, void *k, UINT k_size, IKE_HASH *h, IKE_CRYPTO *c, UINT crypto_key_size);
+BUF *IkeExpandKeySize(IKE_HASH *h, void *k, UINT k_size, UINT target_size);
+void IkeSaUpdateIv(IKE_SA *sa, void *iv, UINT iv_size);
+IPSECSA *NewIPsecSa(IKE_SERVER *ike, IKE_CLIENT *c, IKE_SA *ike_sa, bool initiate, UINT message_id, bool server_to_client, void *iv, UINT spi, void *init_rand_data, UINT init_rand_size, void *res_rand_data, UINT res_rand_size, IPSEC_SA_TRANSFORM_SETTING *setting, void *shared_key_data, UINT shared_key_size);
+void IkeCalcPhase2InitialIv(void *iv, IKE_SA *sa, UINT message_id);
+bool GetBestTransformSettingForIPsecSa(IKE_SERVER *ike, IKE_PACKET *pr, IPSEC_SA_TRANSFORM_SETTING *setting, IP *server_ip);
+bool TransformPayloadToTransformSettingForIPsecSa(IKE_SERVER *ike, IKE_PACKET_TRANSFORM_PAYLOAD *transform, IPSEC_SA_TRANSFORM_SETTING *setting, IP *server_ip);
+IKE_PACKET_PAYLOAD *TransformSettingToTransformPayloadForIPsec(IKE_SERVER *ike, IPSEC_SA_TRANSFORM_SETTING *setting);
+UINT GenerateNewIPsecSaSpi(IKE_SERVER *ike, UINT counterpart_spi);
+IPSECSA *SearchClientToServerIPsecSaBySpi(IKE_SERVER *ike, UINT spi);
+IPSECSA *SearchIPsecSaBySpi(IKE_SERVER *ike, IKE_CLIENT *c, UINT spi);
+IPSECSA *SearchIPsecSaByMessageId(IKE_SERVER *ike, IKE_CLIENT *c, UINT message_id);
+void IPsecSaSendPacket(IKE_SERVER *ike, IPSECSA *sa, IKE_PACKET *p);
+IKE_PACKET *IPsecSaRecvPacket(IKE_SERVER *ike, IPSECSA *sa, void *data, UINT size);
+void IPsecSaUpdateIv(IPSECSA *sa, void *iv, UINT iv_size);
+void ProcDeletePayload(IKE_SERVER *ike, IKE_CLIENT *c, IKE_PACKET_DELETE_PAYLOAD *d);
+void MarkIPsecSaAsDeleted(IKE_SERVER *ike, IPSECSA *sa);
+void MarkIkeSaAsDeleted(IKE_SERVER *ike, IKE_SA *sa);
+void PurgeDeletingSAsAndClients(IKE_SERVER *ike);
+void PurgeIPsecSa(IKE_SERVER *ike, IPSECSA *sa);
+void PurgeIkeSa(IKE_SERVER *ike, IKE_SA *sa);
+void PurgeIkeClient(IKE_SERVER *ike, IKE_CLIENT *c);
+void FreeIPsecSa(IPSECSA *sa);
+void MarkIkeClientAsDeleted(IKE_SERVER *ike, IKE_CLIENT *c);
+IKE_SA *GetOtherLatestIkeSa(IKE_SERVER *ike, IKE_SA *sa);
+IPSECSA *GetOtherLatestIPsecSa(IKE_SERVER *ike, IPSECSA *sa);
+void SendInformationalExchangePacket(IKE_SERVER *ike, IKE_CLIENT *c, IKE_PACKET_PAYLOAD *payload);
+void SendInformationalExchangePacketEx(IKE_SERVER *ike, IKE_CLIENT *c, IKE_PACKET_PAYLOAD *payload, bool force_plain, UINT64 init_cookie, UINT64 resp_cookie);
+void SendDeleteIkeSaPacket(IKE_SERVER *ike, IKE_CLIENT *c, UINT64 init_cookie, UINT64 resp_cookie);
+void SendDeleteIPsecSaPacket(IKE_SERVER *ike, IKE_CLIENT *c, UINT spi);
+void IPsecCalcKeymat(IKE_SERVER *ike, IKE_HASH *h, void *dst, UINT dst_size, void *skeyid_d_data, UINT skeyid_d_size, UCHAR protocol, UINT spi, void *rand_init_data, UINT rand_init_size,
+ void *rand_resp_data, UINT rand_resp_size, void *df_key_data, UINT df_key_size);
+
+void ProcIPsecEspPacketRecv(IKE_SERVER *ike, UDPPACKET *p);
+void ProcIPsecUdpPacketRecv(IKE_SERVER *ike, IKE_CLIENT *c, UCHAR *data, UINT data_size);
+void IPsecSendPacketByIPsecSa(IKE_SERVER *ike, IPSECSA *sa, UCHAR *data, UINT data_size, UCHAR protocol_id);
+void IPsecSendPacketByIPsecSaInner(IKE_SERVER *ike, IPSECSA *sa, UCHAR *data, UINT data_size, UCHAR protocol_id);
+void IPsecSendPacketByIkeClient(IKE_SERVER *ike, IKE_CLIENT *c, UCHAR *data, UINT data_size, UCHAR protocol_id);
+void IPsecSendUdpPacket(IKE_SERVER *ike, IKE_CLIENT *c, UINT src_port, UINT dst_port, UCHAR *data, UINT data_size);
+void IPsecIkeClientManageL2TPServer(IKE_SERVER *ike, IKE_CLIENT *c);
+void IPsecIkeClientSendL2TPPackets(IKE_SERVER *ike, IKE_CLIENT *c, L2TP_SERVER *l2tp);
+void IPsecIkeSendUdpForDebug(UINT dst_port, UINT dst_ip, void *data, UINT size);
+void StartQuickMode(IKE_SERVER *ike, IKE_CLIENT *c);
+UINT GenerateNewMessageId(IKE_SERVER *ike);
+
+void IPsecIkeClientManageEtherIPServer(IKE_SERVER *ike, IKE_CLIENT *c);
+void IPsecIkeClientSendEtherIPPackets(IKE_SERVER *ike, IKE_CLIENT *c, ETHERIP_SERVER *s);
+void ProcIPsecEtherIPPacketRecv(IKE_SERVER *ike, IKE_CLIENT *c, UCHAR *data, UINT data_size, bool is_tunnel_mode);
+bool IsIPsecSaTunnelMode(IPSECSA *sa);
+void ProcL2TPv3PacketRecv(IKE_SERVER *ike, IKE_CLIENT *c, UCHAR *data, UINT data_size, bool is_tunnel_mode);
+
+IKE_SA *SearchIkeSaByCookie(IKE_SERVER *ike, UINT64 init_cookie, UINT64 resp_cookie);
+
+#endif // IPSEC_IKE_H
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_IPC.c b/src/Cedar/IPsec_IPC.c
new file mode 100644
index 00000000..de883ade
--- /dev/null
+++ b/src/Cedar/IPsec_IPC.c
@@ -0,0 +1,2028 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_IPC.c
+// In-process VPN client module
+
+#include "CedarPch.h"
+
+// Extract the MS-CHAP v2 authentication information by parsing the password string
+bool ParseAndExtractMsChapV2InfoFromPassword(IPC_MSCHAP_V2_AUTHINFO *d, char *password)
+{
+ TOKEN_LIST *t;
+ bool ret = false;
+ // Validate arguments
+ if (d == NULL || password == NULL)
+ {
+ return false;
+ }
+
+ Zero(d, sizeof(IPC_MSCHAP_V2_AUTHINFO));
+
+ if (StartWith(password, IPC_PASSWORD_MSCHAPV2_TAG) == false)
+ {
+ return false;
+ }
+
+ t = ParseTokenWithNullStr(password, ":");
+
+ if (t->NumTokens == 5)
+ {
+ BUF *b1, *b2, *b3;
+
+ b1 = StrToBin(t->Token[2]);
+ b2 = StrToBin(t->Token[3]);
+ b3 = StrToBin(t->Token[4]);
+
+ if (IsEmptyStr(t->Token[1]) == false && b1->Size == 16 && b2->Size == 16 && b3->Size == 24)
+ {
+ StrCpy(d->MsChapV2_PPPUsername, sizeof(d->MsChapV2_PPPUsername), t->Token[1]);
+ Copy(d->MsChapV2_ServerChallenge, b1->Buf, 16);
+ Copy(d->MsChapV2_ClientChallenge, b2->Buf, 16);
+ Copy(d->MsChapV2_ClientResponse, b3->Buf, 24);
+
+ ret = true;
+ }
+
+ FreeBuf(b1);
+ FreeBuf(b2);
+ FreeBuf(b3);
+ }
+
+ FreeToken(t);
+
+ return ret;
+}
+
+// Start an IPC connection asynchronously
+IPC_ASYNC *NewIPCAsync(CEDAR *cedar, IPC_PARAM *param, SOCK_EVENT *sock_event)
+{
+ IPC_ASYNC *a;
+ // Validate arguments
+ if (cedar == NULL || param == NULL)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(IPC_ASYNC));
+
+ a->TubeForDisconnect = NewTube(0);
+
+ a->Cedar = cedar;
+ AddRef(a->Cedar->ref);
+
+ Copy(&a->Param, param, sizeof(IPC_PARAM));
+
+ if (sock_event != NULL)
+ {
+ a->SockEvent = sock_event;
+ AddRef(a->SockEvent->ref);
+ }
+
+ a->Thread = NewThread(IPCAsyncThreadProc, a);
+
+ return a;
+}
+
+// asynchronous IPC connection creation thread
+void IPCAsyncThreadProc(THREAD *thread, void *param)
+{
+ IPC_ASYNC *a;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ a = (IPC_ASYNC *)param;
+
+ // Attempt to connect
+ a->Ipc = NewIPCByParam(a->Cedar, &a->Param, &a->ErrorCode);
+
+ if (a->Ipc != NULL)
+ {
+ if (a->Param.IsL3Mode)
+ {
+ DHCP_OPTION_LIST cao;
+
+ Zero(&cao, sizeof(cao));
+
+ // Get an IP address from the DHCP server in the case of L3 mode
+ Debug("IPCDhcpAllocateIPEx() start...\n");
+ if (IPCDhcpAllocateIPEx(a->Ipc, &cao, a->TubeForDisconnect, a->Param.IsOpenVPN))
+ {
+ UINT t;
+ IP ip, subnet, gw;
+
+ Debug("IPCDhcpAllocateIPEx() Ok.\n");
+
+ // Calculate the DHCP update interval
+ t = cao.LeaseTime;
+ if (t == 0)
+ {
+ t = 600;
+ }
+
+ t = t / 3;
+
+ if (t == 0)
+ {
+ t = 1;
+ }
+
+ // Save the options list
+ Copy(&a->L3ClientAddressOption, &cao, sizeof(DHCP_OPTION_LIST));
+ a->L3DhcpRenewInterval = t * 1000;
+
+ // Set the obtained IP address parameters to the IPC virtual host
+ UINTToIP(&ip, cao.ClientAddress);
+ UINTToIP(&subnet, cao.SubnetMask);
+ UINTToIP(&gw, cao.Gateway);
+
+ IPCSetIPv4Parameters(a->Ipc, &ip, &subnet, &gw);
+
+ a->L3NextDhcpRenewTick = Tick64() + a->L3DhcpRenewInterval;
+ }
+ else
+ {
+ Debug("IPCDhcpAllocateIPEx() Error.\n");
+
+ a->DhcpAllocFailed = true;
+
+ FreeIPC(a->Ipc);
+ a->Ipc = NULL;
+ }
+ }
+ }
+
+ // Procedure complete
+ a->Done = true;
+
+ if (a->SockEvent != NULL)
+ {
+ SetSockEvent(a->SockEvent);
+ }
+}
+
+// Release the IPC asynchronous connection object
+void FreeIPCAsync(IPC_ASYNC *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ TubeDisconnect(a->TubeForDisconnect);
+ WaitThread(a->Thread, INFINITE);
+ ReleaseThread(a->Thread);
+
+ if (a->Ipc != NULL)
+ {
+ FreeIPC(a->Ipc);
+ a->Ipc = NULL;
+ }
+
+ if (a->SockEvent != NULL)
+ {
+ ReleaseSockEvent(a->SockEvent);
+ }
+
+ ReleaseCedar(a->Cedar);
+
+ ReleaseTube(a->TubeForDisconnect);
+ Free(a);
+}
+
+// Start a new IPC connection by specifying the parameter structure
+IPC *NewIPCByParam(CEDAR *cedar, IPC_PARAM *param, UINT *error_code)
+{
+ IPC *ipc;
+ // Validate arguments
+ if (cedar == NULL || param == NULL)
+ {
+ return NULL;
+ }
+
+ ipc = NewIPC(cedar, param->ClientName, param->Postfix, param->HubName,
+ param->UserName, param->Password, error_code, &param->ClientIp,
+ param->ClientPort, &param->ServerIp, param->ServerPort,
+ param->ClientHostname, param->CryptName,
+ param->BridgeMode, param->Mss);
+
+ return ipc;
+}
+
+// Start a new IPC connection
+IPC *NewIPC(CEDAR *cedar, char *client_name, char *postfix, char *hubname, char *username, char *password,
+ UINT *error_code, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port,
+ char *client_hostname, char *crypt_name,
+ bool bridge_mode, UINT mss)
+{
+ IPC *ipc;
+ UINT dummy_int = 0;
+ SOCK *a;
+ SOCK *s;
+ PACK *p;
+ UINT err = ERR_INTERNAL_ERROR;
+ char server_str[MAX_SIZE];
+ char macstr[30];
+ UINT server_ver, server_build;
+ UCHAR unique[SHA1_SIZE];
+ NODE_INFO info;
+ BUF *b;
+ UCHAR mschap_v2_server_response_20[20];
+ // Validate arguments
+ if (cedar == NULL || username == NULL || password == NULL || client_hostname == NULL)
+ {
+ return NULL;
+ }
+ if (IsEmptyStr(client_name))
+ {
+ client_name = "InProc VPN Connection";
+ }
+ if (IsEmptyStr(crypt_name))
+ {
+ crypt_name = "";
+ }
+ if (error_code == NULL)
+ {
+ error_code = &dummy_int;
+ }
+
+ Zero(mschap_v2_server_response_20, sizeof(mschap_v2_server_response_20));
+
+ err = *error_code = ERR_INTERNAL_ERROR;
+
+ a = GetInProcListeningSock(cedar);
+ if (a == NULL)
+ {
+ return NULL;
+ }
+
+ ipc = ZeroMalloc(sizeof(IPC));
+
+ ipc->Cedar = cedar;
+ AddRef(cedar->ref);
+
+ ipc->FlushList = NewTubeFlushList();
+
+ StrCpy(ipc->ClientHostname, sizeof(ipc->ClientHostname), client_hostname);
+ StrCpy(ipc->HubName, sizeof(ipc->HubName), hubname);
+ StrCpy(ipc->UserName, sizeof(ipc->UserName), username);
+ StrCpy(ipc->Password, sizeof(ipc->Password), password);
+
+ // Connect the in-process socket
+ s = ConnectInProc(a, client_ip, client_port, server_ip, server_port);
+ if (s == NULL)
+ {
+ goto LABEL_ERROR;
+ }
+
+ // Protocol initialization process
+ if (ClientUploadSignature(s) == false)
+ {
+ err = ERR_DISCONNECTED;
+ goto LABEL_ERROR;
+ }
+
+ p = HttpClientRecv(s);
+ if (p == NULL)
+ {
+ err = ERR_DISCONNECTED;
+ goto LABEL_ERROR;
+ }
+
+ err = GetErrorFromPack(p);
+ if (err != ERR_NO_ERROR)
+ {
+ FreePack(p);
+ goto LABEL_ERROR;
+ }
+
+ if (GetHello(p, ipc->random, &server_ver, &server_build, server_str, sizeof(server_str)) == false)
+ {
+ FreePack(p);
+ err = ERR_DISCONNECTED;
+ goto LABEL_ERROR;
+ }
+
+ FreePack(p);
+
+ // Upload the authentication data
+ p = PackLoginWithPlainPassword(hubname, username, password);
+ PackAddInt64(p, "timestamp", SystemTime64());
+ PackAddStr(p, "hello", client_name);
+ PackAddInt(p, "client_ver", cedar->Version);
+ PackAddInt(p, "client_build", cedar->Build);
+ PackAddInt(p, "max_connection", 1);
+ PackAddInt(p, "use_encrypt", 0);
+ PackAddInt(p, "use_compress", 0);
+ PackAddInt(p, "half_connection", 0);
+ PackAddInt(p, "adjust_mss", mss);
+ PackAddBool(p, "require_bridge_routing_mode", bridge_mode);
+ PackAddBool(p, "require_monitor_mode", false);
+ PackAddBool(p, "qos", false);
+
+ // Unique ID is determined by the sum of the connecting client IP address and the client_name
+ b = NewBuf();
+ WriteBuf(b, client_ip, sizeof(IP));
+ WriteBufStr(b, client_name);
+ WriteBufStr(b, crypt_name);
+
+ HashSha1(unique, b->Buf, b->Size);
+
+ FreeBuf(b);
+
+ PackAddData(p, "unique_id", unique, SHA1_SIZE);
+
+ PackAddStr(p, "inproc_postfix", postfix);
+ PackAddStr(p, "inproc_cryptname", crypt_name);
+
+ // Node information
+ Zero(&info, sizeof(info));
+ StrCpy(info.ClientProductName, sizeof(info.ClientProductName), client_name);
+ info.ClientProductVer = Endian32(cedar->Version);
+ info.ClientProductBuild = Endian32(cedar->Build);
+ StrCpy(info.ServerProductName, sizeof(info.ServerProductName), server_str);
+ info.ServerProductVer = Endian32(server_ver);
+ info.ServerProductBuild = Endian32(server_build);
+ StrCpy(info.ClientOsName, sizeof(info.ClientOsName), client_name);
+ StrCpy(info.ClientOsVer, sizeof(info.ClientOsVer), "-");
+ StrCpy(info.ClientOsProductId, sizeof(info.ClientOsProductId), "-");
+ info.ClientIpAddress = IPToUINT(&s->LocalIP);
+ info.ClientPort = Endian32(s->LocalPort);
+ StrCpy(info.ClientHostname, sizeof(info.ClientHostname), ipc->ClientHostname);
+ IPToStr(info.ServerHostname, sizeof(info.ServerHostname), &s->RemoteIP);
+ info.ServerIpAddress = IPToUINT(&s->RemoteIP);
+ info.ServerPort = Endian32(s->RemotePort);
+ StrCpy(info.HubName, sizeof(info.HubName), hubname);
+ Copy(info.UniqueId, unique, 16);
+ if (IsIP6(&s->LocalIP))
+ {
+ Copy(info.ClientIpAddress6, s->LocalIP.ipv6_addr, 16);
+ }
+ if (IsIP6(&s->RemoteIP))
+ {
+ Copy(info.ServerIpAddress6, s->RemoteIP.ipv6_addr, 16);
+ }
+ OutRpcNodeInfo(p, &info);
+
+ if (HttpClientSend(s, p) == false)
+ {
+ FreePack(p);
+ err = ERR_DISCONNECTED;
+ goto LABEL_ERROR;
+ }
+
+ FreePack(p);
+
+ // Receive a Welcome packet
+ p = HttpClientRecv(s);
+ if (p == NULL)
+ {
+ err = ERR_DISCONNECTED;
+ goto LABEL_ERROR;
+ }
+
+ err = GetErrorFromPack(p);
+ if (err != ERR_NO_ERROR)
+ {
+ FreePack(p);
+ goto LABEL_ERROR;
+ }
+
+ if (ParseWelcomeFromPack(p, ipc->SessionName, sizeof(ipc->SessionName),
+ ipc->ConnectionName, sizeof(ipc->ConnectionName), &ipc->Policy) == false)
+ {
+ err = ERR_PROTOCOL_ERROR;
+ FreePack(p);
+ goto LABEL_ERROR;
+ }
+
+ if (PackGetData2(p, "IpcMacAddress", ipc->MacAddress, 6) == false || IsZero(ipc->MacAddress, 6))
+ {
+ err = ERR_PROTOCOL_ERROR;
+ FreePack(p);
+ goto LABEL_ERROR;
+ }
+
+ if (PackGetData2(p, "IpcMsChapV2ServerResponse", mschap_v2_server_response_20, sizeof(mschap_v2_server_response_20)))
+ {
+ Copy(ipc->MsChapV2_ServerResponse, mschap_v2_server_response_20, sizeof(mschap_v2_server_response_20));
+ }
+
+ PackGetStr(p, "IpcHubName", ipc->HubName, sizeof(ipc->HubName));
+ Debug("IPC Hub Name: %s\n", ipc->HubName);
+
+ MacToStr(macstr, sizeof(macstr), ipc->MacAddress);
+
+ Debug("IPC: Session = %s, Connection = %s, Mac = %s\n", ipc->SessionName, ipc->ConnectionName, macstr);
+
+ FreePack(p);
+
+ ReleaseSock(a);
+ ipc->Sock = s;
+
+ Debug("NewIPC() Succeed.\n");
+
+ ipc->Interrupt = NewInterruptManager();
+
+ // Create an ARP table
+ ipc->ArpTable = NewList(IPCCmpArpTable);
+
+ // Create an IPv4 reception queue
+ ipc->IPv4RecviedQueue = NewQueue();
+
+ return ipc;
+
+LABEL_ERROR:
+ Debug("NewIPC() Failed: Err = %u\n", err);
+ Disconnect(s);
+ ReleaseSock(s);
+ ReleaseSock(a);
+ FreeIPC(ipc);
+ *error_code = err;
+ return NULL;
+}
+
+// Create a new IPC based on SOCK
+IPC *NewIPCBySock(CEDAR *cedar, SOCK *s, void *mac_address)
+{
+ IPC *ipc;
+ // Validate arguments
+ if (cedar == NULL || mac_address == NULL || s == NULL)
+ {
+ return NULL;
+ }
+
+ ipc = ZeroMalloc(sizeof(IPC));
+
+ ipc->Cedar = cedar;
+ AddRef(cedar->ref);
+
+ ipc->Sock = s;
+ AddRef(s->ref);
+
+ Copy(ipc->MacAddress, mac_address, 6);
+
+ ipc->Interrupt = NewInterruptManager();
+
+ // Create an ARP table
+ ipc->ArpTable = NewList(IPCCmpArpTable);
+
+ // Create an IPv4 reception queue
+ ipc->IPv4RecviedQueue = NewQueue();
+
+ ipc->FlushList = NewTubeFlushList();
+
+ return ipc;
+}
+
+// Get whether the IPC is connected
+bool IsIPCConnected(IPC *ipc)
+{
+ // Validate arguments
+ if (ipc == NULL)
+ {
+ return false;
+ }
+
+ if (IsTubeConnected(ipc->Sock->RecvTube) == false || IsTubeConnected(ipc->Sock->SendTube) == false)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Get to hit the SOCK_EVENT when a new data has arrived in the IPC
+void IPCSetSockEventWhenRecvL2Packet(IPC *ipc, SOCK_EVENT *e)
+{
+ // Validate arguments
+ if (ipc == NULL || e == NULL)
+ {
+ return;
+ }
+
+ JoinSockToSockEvent(ipc->Sock, e);
+}
+
+// End of IPC connection
+void FreeIPC(IPC *ipc)
+{
+ UINT i;
+ // Validate arguments
+ if (ipc == NULL)
+ {
+ return;
+ }
+
+ FreeTubeFlushList(ipc->FlushList);
+
+ Disconnect(ipc->Sock);
+ ReleaseSock(ipc->Sock);
+
+ if (ipc->Policy != NULL)
+ {
+ Free(ipc->Policy);
+ }
+
+ ReleaseCedar(ipc->Cedar);
+
+ FreeInterruptManager(ipc->Interrupt);
+
+ for (i = 0;i < LIST_NUM(ipc->ArpTable);i++)
+ {
+ IPC_ARP *a = LIST_DATA(ipc->ArpTable, i);
+ IPCFreeARP(a);
+ }
+
+ ReleaseList(ipc->ArpTable);
+
+ while (true)
+ {
+ BLOCK *b = GetNext(ipc->IPv4RecviedQueue);
+ if (b == NULL)
+ {
+ break;
+ }
+
+ FreeBlock(b);
+ }
+
+ ReleaseQueue(ipc->IPv4RecviedQueue);
+
+ Free(ipc);
+}
+
+// Release the IP address from the DHCP server
+void IPCDhcpFreeIP(IPC *ipc, IP *dhcp_server)
+{
+ DHCP_OPTION_LIST req;
+ UINT tran_id = Rand32();
+ // Validate arguments
+ if (ipc == NULL || dhcp_server == NULL)
+ {
+ return;
+ }
+
+ Zero(&req, sizeof(req));
+ req.Opcode = DHCP_RELEASE;
+ req.ServerAddress = IPToUINT(dhcp_server);
+
+ FreeDHCPv4Data(IPCSendDhcpRequest(ipc, NULL, tran_id, &req, 0, 0, NULL));
+}
+
+// Update the IP address using the DHCP
+void IPCDhcpRenewIP(IPC *ipc, IP *dhcp_server)
+{
+ DHCP_OPTION_LIST req;
+ UINT tran_id = Rand32();
+ // Validate arguments
+ if (ipc == NULL || dhcp_server == NULL)
+ {
+ return;
+ }
+
+ // Send a DHCP Request
+ Zero(&req, sizeof(req));
+ req.Opcode = DHCP_REQUEST;
+ StrCpy(req.Hostname, sizeof(req.Hostname), ipc->ClientHostname);
+ req.RequestedIp = IPToUINT(&ipc->ClientIPAddress);
+
+ FreeDHCPv4Data(IPCSendDhcpRequest(ipc, dhcp_server, tran_id, &req, 0, 0, NULL));
+}
+
+// Get the information other than the IP address with using DHCP
+bool IPCDhcpRequestInformIP(IPC *ipc, DHCP_OPTION_LIST *opt, TUBE *discon_poll_tube, IP *client_ip)
+{
+ DHCP_OPTION_LIST req;
+ DHCPV4_DATA *d;
+ UINT tran_id = Rand32();
+ bool ok;
+ // Validate arguments
+ if (ipc == NULL || opt == NULL || client_ip == NULL)
+ {
+ return false;
+ }
+
+ // Send a DHCP Inform
+ Zero(&req, sizeof(req));
+ req.Opcode = DHCP_INFORM;
+ req.ClientAddress = IPToUINT(client_ip);
+ StrCpy(req.Hostname, sizeof(req.Hostname), ipc->ClientHostname);
+
+ d = IPCSendDhcpRequest(ipc, NULL, tran_id, &req, DHCP_ACK, IPC_DHCP_TIMEOUT, discon_poll_tube);
+ if (d == NULL)
+ {
+ return false;
+ }
+
+ // Analyze the DHCP Ack
+ ok = true;
+ if (d->ParsedOptionList->SubnetMask == 0)
+ {
+ ok = false;
+ }
+
+ if (ok == false)
+ {
+ FreeDHCPv4Data(d);
+ return false;
+ }
+
+ Copy(opt, d->ParsedOptionList, sizeof(DHCP_OPTION_LIST));
+
+ FreeDHCPv4Data(d);
+
+ return true;
+}
+
+// Make a request for IP addresses using DHCP
+bool IPCDhcpAllocateIP(IPC *ipc, DHCP_OPTION_LIST *opt, TUBE *discon_poll_tube)
+{
+ return IPCDhcpAllocateIPEx(ipc, opt, discon_poll_tube, false);
+}
+bool IPCDhcpAllocateIPEx(IPC *ipc, DHCP_OPTION_LIST *opt, TUBE *discon_poll_tube, bool openvpn_compatible)
+{
+ DHCP_OPTION_LIST req;
+ DHCPV4_DATA *d, *d2;
+ UINT tran_id = Rand32();
+ bool ok;
+ UINT request_ip = 0;
+ IP current_scanning_ip;
+ UCHAR current_scanning_addr8;
+ UCHAR begin_scanning_addr8;
+ UINT64 giveup = Tick64() + (UINT64)IPC_DHCP_TIMEOUT_TOTAL_GIVEUP;
+ LIST *release_list;
+ bool ret = false;
+ // Validate arguments
+ if (ipc == NULL || opt == NULL)
+ {
+ return false;
+ }
+
+ release_list = NewListFast(NULL);
+
+ Zero(&current_scanning_ip, sizeof(current_scanning_ip));
+ current_scanning_addr8 = 0;
+ begin_scanning_addr8 = 0;
+
+LABEL_RETRY_FOR_OPENVPN:
+ tran_id = Rand32();
+ // Send a DHCP Discover
+ Zero(&req, sizeof(req));
+ req.RequestedIp = request_ip;
+ req.Opcode = DHCP_DISCOVER;
+ StrCpy(req.Hostname, sizeof(req.Hostname), ipc->ClientHostname);
+
+ d = IPCSendDhcpRequest(ipc, NULL, tran_id, &req, DHCP_OFFER, IPC_DHCP_TIMEOUT, discon_poll_tube);
+ if (d == NULL)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ // Analyze the DHCP Offer
+ ok = true;
+ if (IsValidUnicastIPAddressUINT4(d->ParsedOptionList->ClientAddress) == false)
+ {
+ ok = false;
+ }
+ if (IsValidUnicastIPAddressUINT4(d->ParsedOptionList->ServerAddress) == false)
+ {
+ ok = false;
+ }
+ if (d->ParsedOptionList->SubnetMask == 0)
+ {
+ ok = false;
+ }
+ if (d->ParsedOptionList->LeaseTime == 0)
+ {
+ d->ParsedOptionList->LeaseTime = IPC_DHCP_DEFAULT_LEASE;
+ }
+ if (d->ParsedOptionList->LeaseTime <= IPC_DHCP_MIN_LEASE)
+ {
+ d->ParsedOptionList->LeaseTime = IPC_DHCP_MIN_LEASE;
+ }
+
+ if (ok == false)
+ {
+ FreeDHCPv4Data(d);
+ goto LABEL_CLEANUP;
+ }
+
+ if (openvpn_compatible)
+ {
+ UINT ip = d->ParsedOptionList->ClientAddress;
+
+ if (OvsIsCompatibleL3IP(ip) == false)
+ {
+ char tmp[64];
+
+ DHCP_OPTION_LIST req;
+ IPC_DHCP_RELESAE_QUEUE *q;
+
+ // If the offered IP address is not used, place the address
+ // in release memo list to release at the end of this function
+ Zero(&req, sizeof(req));
+ req.Opcode = DHCP_RELEASE;
+ req.ServerAddress = d->ParsedOptionList->ServerAddress;
+
+ q = ZeroMalloc(sizeof(IPC_DHCP_RELESAE_QUEUE));
+ Copy(&q->Req, &req, sizeof(DHCP_OPTION_LIST));
+ q->TranId = tran_id;
+ Copy(q->MacAddress, ipc->MacAddress, 6);
+
+ Add(release_list, q);
+
+ FreeDHCPv4Data(d);
+
+ if (Tick64() >= giveup)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ if (IsZero(&current_scanning_ip, sizeof(IP)))
+ {
+ UINTToIP(&current_scanning_ip, ip);
+ current_scanning_addr8 = current_scanning_ip.addr[3];
+
+ if ((current_scanning_addr8 % 4) != 1)
+ {
+ current_scanning_addr8 = (UCHAR)(((((UINT)current_scanning_addr8 - 1) / 4) + 1) * 4 + 1);
+ }
+
+ begin_scanning_addr8 = current_scanning_addr8;
+ }
+ else
+ {
+ current_scanning_addr8 += 4;
+
+ if (current_scanning_addr8 == begin_scanning_addr8)
+ {
+ goto LABEL_CLEANUP;
+ }
+ }
+
+ current_scanning_ip.addr[3] = current_scanning_addr8;
+
+ request_ip = IPToUINT(&current_scanning_ip);
+
+ IPToStr32(tmp, sizeof(tmp), request_ip);
+
+ // Generate another MAC address
+ ipc->MacAddress[5]++;
+
+ Debug("Trying Allocating IP for OpenVPN: %s\n", tmp);
+
+ goto LABEL_RETRY_FOR_OPENVPN;
+ }
+ }
+
+ // Send a DHCP Request
+ Zero(&req, sizeof(req));
+ req.Opcode = DHCP_REQUEST;
+ StrCpy(req.Hostname, sizeof(req.Hostname), ipc->ClientHostname);
+ req.ServerAddress = d->ParsedOptionList->ServerAddress;
+ req.RequestedIp = d->ParsedOptionList->ClientAddress;
+
+ d2 = IPCSendDhcpRequest(ipc, NULL, tran_id, &req, DHCP_ACK, IPC_DHCP_TIMEOUT, discon_poll_tube);
+ if (d2 == NULL)
+ {
+ FreeDHCPv4Data(d);
+ goto LABEL_CLEANUP;
+ }
+
+ // Analyze the DHCP Ack
+ ok = true;
+ if (IsValidUnicastIPAddressUINT4(d2->ParsedOptionList->ClientAddress) == false)
+ {
+ ok = false;
+ }
+ if (IsValidUnicastIPAddressUINT4(d2->ParsedOptionList->ServerAddress) == false)
+ {
+ ok = false;
+ }
+ if (d2->ParsedOptionList->SubnetMask == 0)
+ {
+ ok = false;
+ }
+ if (d2->ParsedOptionList->LeaseTime == 0)
+ {
+ d2->ParsedOptionList->LeaseTime = IPC_DHCP_DEFAULT_LEASE;
+ }
+ if (d2->ParsedOptionList->LeaseTime <= IPC_DHCP_MIN_LEASE)
+ {
+ d2->ParsedOptionList->LeaseTime = IPC_DHCP_MIN_LEASE;
+ }
+
+ if (ok == false)
+ {
+ FreeDHCPv4Data(d);
+ FreeDHCPv4Data(d2);
+ goto LABEL_CLEANUP;
+ }
+
+ Copy(opt, d2->ParsedOptionList, sizeof(DHCP_OPTION_LIST));
+
+ FreeDHCPv4Data(d);
+ FreeDHCPv4Data(d2);
+
+ ret = true;
+
+LABEL_CLEANUP:
+ if (release_list != NULL)
+ {
+ // Release the IP address that was acquired from the DHCP server to no avail on the way
+ UINT i;
+ UCHAR mac_backup[6];
+
+ Copy(mac_backup, ipc->MacAddress, 6);
+
+ for (i = 0;i < LIST_NUM(release_list);i++)
+ {
+ IPC_DHCP_RELESAE_QUEUE *q = LIST_DATA(release_list, i);
+
+ Copy(ipc->MacAddress, q->MacAddress, 6);
+ FreeDHCPv4Data(IPCSendDhcpRequest(ipc, NULL, q->TranId, &q->Req, 0, 0, NULL));
+
+ IPCProcessInterrupts(ipc);
+
+ Free(q);
+ }
+
+ Copy(ipc->MacAddress, mac_backup, 6);
+
+ ReleaseList(release_list);
+ }
+ return ret;
+}
+
+// Send out a DHCP request, and wait for a corresponding response
+DHCPV4_DATA *IPCSendDhcpRequest(IPC *ipc, IP *dest_ip, UINT tran_id, DHCP_OPTION_LIST *opt, UINT expecting_code, UINT timeout, TUBE *discon_poll_tube)
+{
+ UINT resend_interval;
+ UINT64 giveup_time;
+ UINT64 next_send_time = 0;
+ TUBE *tubes[3];
+ UINT num_tubes = 0;
+ // Validate arguments
+ if (ipc == NULL || opt == NULL || (expecting_code != 0 && timeout == 0))
+ {
+ return NULL;
+ }
+
+ // Retransmission interval
+ resend_interval = MAX(1, (timeout / 3) - 100);
+
+ // Time-out time
+ giveup_time = Tick64() + (UINT64)timeout;
+
+ AddInterrupt(ipc->Interrupt, giveup_time);
+
+ tubes[num_tubes++] = ipc->Sock->RecvTube;
+ tubes[num_tubes++] = ipc->Sock->SendTube;
+
+ if (discon_poll_tube != NULL)
+ {
+ tubes[num_tubes++] = discon_poll_tube;
+ }
+
+ while (true)
+ {
+ UINT64 now = Tick64();
+ BUF *dhcp_packet;
+
+ IPCFlushArpTable(ipc);
+
+ // Time-out inspection
+ if ((expecting_code != 0) && (now >= giveup_time))
+ {
+ return NULL;
+ }
+
+ // Send by building a DHCP packet periodically
+ if (next_send_time == 0 || next_send_time <= now)
+ {
+ dhcp_packet = IPCBuildDhcpRequest(ipc, dest_ip, tran_id, opt);
+ if (dhcp_packet == NULL)
+ {
+ return NULL;
+ }
+
+ IPCSendIPv4(ipc, dhcp_packet->Buf, dhcp_packet->Size);
+
+ FreeBuf(dhcp_packet);
+
+ if (expecting_code == 0)
+ {
+ return NULL;
+ }
+
+ next_send_time = now + (UINT64)resend_interval;
+
+ AddInterrupt(ipc->Interrupt, next_send_time);
+ }
+
+ // Happy processing
+ IPCProcessL3Events(ipc);
+
+ while (true)
+ {
+ // Receive a packet
+ BLOCK *b = IPCRecvIPv4(ipc);
+ PKT *pkt;
+ DHCPV4_DATA *dhcp;
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ // Parse the packet
+ pkt = ParsePacketIPv4WithDummyMacHeader(b->Buf, b->Size);
+
+ dhcp = ParseDHCPv4Data(pkt);
+
+ if (dhcp != NULL)
+ {
+ if (Endian32(dhcp->Header->TransactionId) == tran_id && dhcp->OpCode == expecting_code)
+ {
+ // Expected operation code and transaction ID are returned
+ FreePacketWithData(pkt);
+ FreeBlock(b);
+
+ return dhcp;
+ }
+
+ FreeDHCPv4Data(dhcp);
+ }
+
+ FreePacketWithData(pkt);
+
+ FreeBlock(b);
+ }
+
+ if (IsTubeConnected(ipc->Sock->RecvTube) == false || IsTubeConnected(ipc->Sock->SendTube) == false ||
+ (discon_poll_tube != NULL && IsTubeConnected(discon_poll_tube) == false))
+ {
+ // Session is disconnected
+ return NULL;
+ }
+
+ // Keep the CPU waiting
+ WaitForTubes(tubes, num_tubes, GetNextIntervalForInterrupt(ipc->Interrupt));
+ }
+
+ return NULL;
+}
+
+// Build a DHCP request packet
+BUF *IPCBuildDhcpRequest(IPC *ipc, IP *dest_ip, UINT tran_id, DHCP_OPTION_LIST *opt)
+{
+ IPV4_HEADER ip;
+ UDP_HEADER* udp;
+ DHCPV4_HEADER dhcp;
+ UINT blank_size = 128 + 64;
+ BUF *ret;
+ BUF *b;
+ UDPV4_PSEUDO_HEADER *ph;
+ UINT ph_size;
+ UINT udp_size;
+ UINT magic_number = Endian32(DHCP_MAGIC_COOKIE);
+ USHORT checksum;
+ // Validate arguments
+ if (ipc == NULL || opt == NULL)
+ {
+ return NULL;
+ }
+
+ // DHCPv4 Options
+ b = IPCBuildDhcpRequestOptions(ipc, opt);
+ if (b == NULL)
+ {
+ return NULL;
+ }
+
+ // DHCPv4 Header
+ Zero(&dhcp, sizeof(dhcp));
+ dhcp.OpCode = 1;
+ dhcp.HardwareType = ARP_HARDWARE_TYPE_ETHERNET;
+ dhcp.HardwareAddressSize = 6;
+ dhcp.Hops = 0;
+ dhcp.TransactionId = Endian32(tran_id);
+ dhcp.ClientIP = IPToUINT(&ipc->ClientIPAddress);
+ if (dhcp.ClientIP == 0)
+ {
+ dhcp.ClientIP = opt->ClientAddress;
+ }
+ Copy(dhcp.ClientMacAddress, ipc->MacAddress, 6);
+
+ // UDP pseudo header
+ ph_size = b->Size + sizeof(dhcp) + blank_size + sizeof(UINT) + sizeof(UDPV4_PSEUDO_HEADER);
+ udp_size = b->Size + sizeof(dhcp) + blank_size + sizeof(UINT) + sizeof(UDP_HEADER);
+
+ ph = ZeroMalloc(ph_size);
+ ph->SrcIP = IPToUINT(&ipc->ClientIPAddress);
+ ph->DstIP = IPToUINT(dest_ip);
+ ph->Protocol = IP_PROTO_UDP;
+ ph->PacketLength1 = Endian16(udp_size);
+ ph->SrcPort = Endian16(NAT_DHCP_CLIENT_PORT);
+ ph->DstPort = Endian16(NAT_DHCP_SERVER_PORT);
+ ph->PacketLength2 = Endian16(udp_size);
+
+ Copy(((UCHAR *)(ph)) + sizeof(UDPV4_PSEUDO_HEADER), &dhcp, sizeof(dhcp));
+ Copy(((UCHAR *)(ph)) + sizeof(UDPV4_PSEUDO_HEADER) + sizeof(dhcp) + blank_size, &magic_number, sizeof(UINT));
+ Copy(((UCHAR *)(ph)) + sizeof(UDPV4_PSEUDO_HEADER) + sizeof(dhcp) + blank_size + sizeof(UINT),
+ b->Buf, b->Size);
+
+ // UDP Header
+ udp = (UDP_HEADER *)(((UCHAR *)ph) + 12);
+
+ // Calculate the checksum
+ checksum = IpChecksum(ph, ph_size);
+ if (checksum == 0x0000)
+ {
+ checksum = 0xffff;
+ }
+ udp->Checksum = checksum;
+
+ // IP Header
+ Zero(&ip, sizeof(ip));
+ IPV4_SET_VERSION(&ip, 4);
+ IPV4_SET_HEADER_LEN(&ip, 5);
+ ip.Identification = Rand16();
+ ip.TimeToLive = 128;
+ ip.Protocol = IP_PROTO_UDP;
+ ip.SrcIP = IPToUINT(&ipc->ClientIPAddress);
+ if (dest_ip != NULL)
+ {
+ ip.DstIP = IPToUINT(dest_ip);
+ }
+ else
+ {
+ ip.DstIP = Endian32(0xffffffff);
+ }
+ ip.TotalLength = Endian16((USHORT)(sizeof(IPV4_HEADER) + udp_size));
+ ip.Checksum = IpChecksum(&ip, sizeof(IPV4_HEADER));
+
+ ret = NewBuf();
+
+ WriteBuf(ret, &ip, sizeof(IPV4_HEADER));
+ WriteBuf(ret, udp, udp_size);
+
+ FreeBuf(b);
+ Free(ph);
+
+ return ret;
+}
+
+// Build a option data in the DHCP request packet
+BUF *IPCBuildDhcpRequestOptions(IPC *ipc, DHCP_OPTION_LIST *opt)
+{
+ LIST *o;
+ UCHAR opcode;
+ UCHAR client_id[7];
+ BUF *ret;
+ // Validate arguments
+ if (ipc == NULL || opt == NULL)
+ {
+ return NULL;
+ }
+
+ o = NewListFast(NULL);
+
+ // Opcode
+ opcode = opt->Opcode;
+ Add(o, NewDhcpOption(DHCP_ID_MESSAGE_TYPE, &opcode, sizeof(opcode)));
+
+ // Server ID
+ if (opt->ServerAddress != 0)
+ {
+ Add(o, NewDhcpOption(DHCP_ID_SERVER_ADDRESS, &opt->ServerAddress, 4));
+ }
+
+ // Client MAC Address
+ client_id[0] = ARP_HARDWARE_TYPE_ETHERNET;
+ Copy(client_id + 1, ipc->MacAddress, 6);
+ Add(o, NewDhcpOption(DHCP_ID_CLIENT_ID, client_id, sizeof(client_id)));
+
+ // Requested IP Address
+ if (opt->RequestedIp != 0)
+ {
+ Add(o, NewDhcpOption(DHCP_ID_REQUEST_IP_ADDRESS, &opt->RequestedIp, 4));
+ }
+
+ // Hostname
+ if (IsEmptyStr(opt->Hostname) == false)
+ {
+ Add(o, NewDhcpOption(DHCP_ID_HOST_NAME, opt->Hostname, StrLen(opt->Hostname)));
+ }
+
+ // Vendor
+ Add(o, NewDhcpOption(DHCP_ID_VENDOR_ID, IPC_DHCP_VENDOR_ID, StrLen(IPC_DHCP_VENDOR_ID)));
+
+ // Parameter Request List
+ if (opcode == DHCP_DISCOVER || opcode == DHCP_REQUEST || opcode == DHCP_INFORM)
+ {
+ UCHAR param_list[12];
+
+ param_list[0] = 1;
+ param_list[1] = 15;
+ param_list[2] = 3;
+ param_list[3] = 6;
+ param_list[4] = 44;
+ param_list[5] = 46;
+ param_list[6] = 47;
+ param_list[7] = 31;
+ param_list[8] = 33;
+ param_list[9] = 121;
+ param_list[10] = 249;
+ param_list[11] = 43;
+
+ Add(o, NewDhcpOption(DHCP_ID_REQ_PARAM_LIST, param_list, sizeof(param_list)));
+ }
+
+ ret = BuildDhcpOptionsBuf(o);
+
+ FreeDhcpOptions(o);
+
+ return ret;
+}
+
+// Process the received ARP
+void IPCProcessArp(IPC *ipc, BLOCK *b)
+{
+ UCHAR *dest_mac;
+ UCHAR *src_mac;
+ ARPV4_HEADER *arp;
+ UCHAR *sender_mac;
+ IP sender_ip;
+ UCHAR *target_mac;
+ IP target_ip;
+ // Validate arguments
+ if (ipc == NULL || b == NULL || b->Size < (14 + sizeof(ARPV4_HEADER)))
+ {
+ return;
+ }
+
+ dest_mac = b->Buf + 0;
+ src_mac = b->Buf + 6;
+
+ arp = (ARPV4_HEADER *)(b->Buf + 14);
+
+ if (arp->HardwareType != Endian16(ARP_HARDWARE_TYPE_ETHERNET))
+ {
+ return;
+ }
+ if (arp->ProtocolType != Endian16(MAC_PROTO_IPV4))
+ {
+ return;
+ }
+ if (arp->HardwareSize != 6 || arp->ProtocolSize != 4)
+ {
+ return;
+ }
+
+ sender_mac = arp->SrcAddress;
+ UINTToIP(&sender_ip, arp->SrcIP);
+
+ target_mac = arp->TargetAddress;
+ UINTToIP(&target_ip, arp->TargetIP);
+
+ if (CmpIpAddr(&sender_ip, &ipc->ClientIPAddress) == 0)
+ {
+ // Source is myself
+ return;
+ }
+
+ IPCAssociateOnArpTable(ipc, &sender_ip, sender_mac);
+ IPCAssociateOnArpTable(ipc, &target_ip, target_mac);
+
+ if (Endian16(arp->Operation) == ARP_OPERATION_REQUEST)
+ {
+ // Received an ARP request
+ if (CmpIpAddr(&target_ip, &ipc->ClientIPAddress) == 0)
+ {
+ // Create a response since a request for its own IP address have received
+ if (IsValidUnicastMacAddress(sender_mac))
+ {
+ UCHAR tmp[14 + sizeof(ARPV4_HEADER)];
+ ARPV4_HEADER *arp = (ARPV4_HEADER *)(tmp + 14);
+
+ Copy(tmp + 0, sender_mac, 6);
+ Copy(tmp + 6, ipc->MacAddress, 6);
+ WRITE_USHORT(tmp + 12, MAC_PROTO_ARPV4);
+
+ arp->HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+ arp->ProtocolType = Endian16(MAC_PROTO_IPV4);
+ arp->HardwareSize = 6;
+ arp->ProtocolSize = 4;
+ arp->Operation = Endian16(ARP_OPERATION_RESPONSE);
+
+ Copy(arp->SrcAddress, ipc->MacAddress, 6);
+ arp->SrcIP = IPToUINT(&ipc->ClientIPAddress);
+
+ Copy(arp->TargetAddress, sender_mac, 6);
+ arp->TargetIP = IPToUINT(&sender_ip);
+
+ IPCSendL2(ipc, tmp, sizeof(tmp));
+ }
+ }
+ }
+}
+
+// Associate the MAC address and IP address on the ARP table
+void IPCAssociateOnArpTable(IPC *ipc, IP *ip, UCHAR *mac_address)
+{
+ IPC_ARP *a;
+ // Validate arguments
+ if (ipc == NULL || ip == NULL || IsValidUnicastIPAddress4(ip) == false || IsValidUnicastMacAddress(mac_address) == false)
+ {
+ return;
+ }
+ if (CmpIpAddr(&ipc->ClientIPAddress, ip) == 0 || Cmp(ipc->MacAddress, mac_address, 6) == 0)
+ {
+ return;
+ }
+ if (IsInSameNetwork4(ip, &ipc->ClientIPAddress, &ipc->SubnetMask) == false)
+ {
+ // Not to learn the IP address of outside the subnet
+ return;
+ }
+
+ if (CmpIpAddr(&ipc->BroadcastAddress, ip) == 0)
+ {
+ // Not to learn the broadcast IP address
+ return;
+ }
+
+ // Search whether there is ARP table entry already
+ a = IPCSearchArpTable(ipc, ip);
+ if (a == NULL)
+ {
+ // Add to the ARP table
+ a = IPCNewARP(ip, mac_address);
+
+ Insert(ipc->ArpTable, a);
+ }
+ else
+ {
+ Copy(a->MacAddress, mac_address, 6);
+
+ // There is the ARP table entry already
+ if (a->Resolved == false)
+ {
+ a->Resolved = true;
+ a->GiveupTime = 0;
+
+ // Send all the packets that are accumulated to be sent
+ while (true)
+ {
+ BLOCK *b = GetNext(a->PacketQueue);
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ IPCSendIPv4WithDestMacAddr(ipc, b->Buf, b->Size, a->MacAddress);
+
+ FreeBlock(b);
+ }
+ }
+
+ // Extend the expiration date
+ a->ExpireTime = Tick64() + (UINT64)IPC_ARP_LIFETIME;
+ }
+}
+
+// Identifiy whether the MAC address is a normal unicast address
+bool IsValidUnicastMacAddress(UCHAR *mac)
+{
+ // Validate arguments
+ if (mac == NULL)
+ {
+ return false;
+ }
+
+ if (mac[0] & 0x01)
+ {
+ return false;
+ }
+
+ if (IsZero(mac, 6))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Identify whether the IP address is a normal unicast address
+bool IsValidUnicastIPAddress4(IP *ip)
+{
+ UINT i;
+ // Validate arguments
+ if (IsIP4(ip) == false)
+ {
+ return false;
+ }
+
+ if (IsZeroIP(ip))
+ {
+ return false;
+ }
+
+ if (ip->addr[0] >= 224 && ip->addr[0] <= 239)
+ {
+ // IPv4 Multicast
+ return false;
+ }
+
+ for (i = 0;i < 4;i++)
+ {
+ if (ip->addr[i] != 255)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+bool IsValidUnicastIPAddressUINT4(UINT ip)
+{
+ IP a;
+
+ UINTToIP(&a, ip);
+
+ return IsValidUnicastIPAddress4(&a);
+}
+
+// Interrupt process (This is called periodically)
+void IPCProcessInterrupts(IPC *ipc)
+{
+ // Validate arguments
+ if (ipc == NULL)
+ {
+ return;
+ }
+
+ FlushTubeFlushList(ipc->FlushList);
+}
+
+// Process the L3 event by the IPC
+void IPCProcessL3Events(IPC *ipc)
+{
+ IPCProcessL3EventsEx(ipc, 0);
+}
+void IPCProcessL3EventsEx(IPC *ipc, UINT64 now)
+{
+ // Validate arguments
+ if (ipc == NULL)
+ {
+ return;
+ }
+ if (now == 0)
+ {
+ now = Tick64();
+ }
+
+ // Remove old ARP table entries
+ IPCFlushArpTableEx(ipc, now);
+
+ // Receive all the L2 packet
+ while (true)
+ {
+ BLOCK *b = IPCRecvL2(ipc);
+ if (b == NULL)
+ {
+ // All reception completed
+ break;
+ }
+
+ if (b->Size >= 14)
+ {
+ UCHAR *dest_mac = b->Buf + 0;
+ UCHAR *src_mac = b->Buf + 6;
+ USHORT protocol = READ_USHORT(b->Buf + 12);
+
+ // Confirm the destination MAC address
+ // (Receive if the destination MAC address is the IPC address or a broadcast address)
+ if (Cmp(dest_mac, ipc->MacAddress, 6) == 0 || dest_mac[0] & 0x01)
+ {
+ // If the source MAC address is itselves or invalid address, ignore the packet
+ if (Cmp(src_mac, ipc->MacAddress, 6) != 0 && IsValidUnicastMacAddress(src_mac))
+ {
+ if (protocol == MAC_PROTO_ARPV4)
+ {
+ // ARP receiving process
+ IPCProcessArp(ipc, b);
+ }
+ else if (protocol == MAC_PROTO_IPV4)
+ {
+ // IPv4 receiving process
+ if (b->Size >= (14 + 20))
+ {
+ UCHAR *data = Clone(b->Buf + 14, b->Size - 14);
+ UINT size = b->Size - 14;
+ IP ip_src, ip_dst;
+ bool ok = false;
+
+ // Extract the IP address portion
+ UINTToIP(&ip_src, *((UINT *)(((UCHAR *)data) + 12)));
+ UINTToIP(&ip_dst, *((UINT *)(((UCHAR *)data) + 16)));
+
+ // Receive only if the IPv4 destination address is its own
+ // or 255.255.255.255 or a multicast address or a broadcast address
+ if (CmpIpAddr(&ip_dst, &ipc->ClientIPAddress) == 0)
+ {
+ ok = true;
+ }
+ else if (ip_dst.addr[0] == 255 && ip_dst.addr[1] == 255 &&
+ ip_dst.addr[2] == 255 && ip_dst.addr[3] == 255)
+ {
+ ok = true;
+ }
+ else if (ip_dst.addr[0] >= 224 && ip_dst.addr[0] <= 239)
+ {
+ ok = true;
+ }
+ else
+ {
+ if (CmpIpAddr(&ipc->BroadcastAddress, &ip_dst) == 0)
+ {
+ ok = true;
+ }
+
+ if (IsZeroIP(&ipc->ClientIPAddress))
+ {
+ // Client IP address is undetermined
+ ok = true;
+ }
+ }
+
+ if (ok)
+ {
+ IPCAssociateOnArpTable(ipc, &ip_src, src_mac);
+
+ // Place in the reception queue
+ InsertQueue(ipc->IPv4RecviedQueue, NewBlock(data, size, 0));
+ }
+ else
+ {
+ // This packet is discarded because it is irrelevant for me
+ Free(data);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ FreeBlock(b);
+ }
+
+ IPCProcessInterrupts(ipc);
+}
+
+// Configure IPv4 parameters
+bool IPCSetIPv4Parameters(IPC *ipc, IP *ip, IP *subnet, IP *gw)
+{
+ bool changed = false;
+ // Validate arguments
+ if (ipc == NULL || ip == NULL || subnet == NULL)
+ {
+ return false;
+ }
+
+ if (CmpIpAddr(&ipc->ClientIPAddress, ip) != 0)
+ {
+ changed = true;
+ }
+ Copy(&ipc->ClientIPAddress, ip, sizeof(IP));
+
+ if (CmpIpAddr(&ipc->SubnetMask, subnet) != 0)
+ {
+ changed = true;
+ }
+ Copy(&ipc->SubnetMask, subnet, sizeof(IP));
+
+ if (gw != NULL)
+ {
+ if (CmpIpAddr(&ipc->DefaultGateway, gw) != 0)
+ {
+ changed = true;
+ }
+
+ Copy(&ipc->DefaultGateway, gw, sizeof(IP));
+ }
+ else
+ {
+ if (IsZeroIP(&ipc->DefaultGateway) == false)
+ {
+ changed = true;
+ }
+
+ Zero(&ipc->DefaultGateway, sizeof(IP));
+ }
+
+ GetBroadcastAddress4(&ipc->BroadcastAddress, ip, subnet);
+
+ return changed;
+}
+
+// Send an IPv4 packet (client -> server)
+void IPCSendIPv4(IPC *ipc, void *data, UINT size)
+{
+ IP ip_src, ip_dst;
+ IP ip_dst_local;
+ bool is_broadcast = false;
+ UCHAR uc;
+ // Validate arguments
+ if (ipc == NULL || data == NULL || size < 20 || size > 1500)
+ {
+ return;
+ }
+
+ uc = ((UCHAR *)data)[0];
+ if (((uc >> 4) & 0x0f) != 4)
+ {
+ // Not an IPv4
+ return;
+ }
+
+ // Extract the IP address portion
+ UINTToIP(&ip_src, *((UINT *)(((UCHAR *)data) + 12)));
+ UINTToIP(&ip_dst, *((UINT *)(((UCHAR *)data) + 16)));
+
+ // Filter the source IP address
+ if (CmpIpAddr(&ip_src, &ipc->ClientIPAddress) != 0)
+ {
+ // Cut off packets from illegal IP address
+ return;
+ }
+
+ if (IsZeroIP(&ip_dst))
+ {
+ // Illegal destination address
+ return;
+ }
+
+ if (CmpIpAddr(&ip_dst, &ipc->ClientIPAddress) == 0)
+ {
+ // Packet destined for myself
+ return;
+ }
+
+ // Get the IP address of the relayed destination
+ Copy(&ip_dst_local, &ip_dst, sizeof(IP));
+ if (ip_dst.addr[0]==8)
+ DoNothing();
+ if (IsInSameNetwork4(&ip_dst, &ipc->ClientIPAddress, &ipc->SubnetMask) == false)
+ {
+ Copy(&ip_dst_local, &ipc->DefaultGateway, sizeof(IP));
+ }
+
+ if (CmpIpAddr(&ipc->BroadcastAddress, &ip_dst) == 0)
+ {
+ // Local Broadcast
+ is_broadcast = true;
+ }
+
+ if (ip_dst.addr[0] == 255 && ip_dst.addr[1] == 255 && ip_dst.addr[2] == 255 && ip_dst.addr[3] == 255)
+ {
+ // Global Broadcast
+ is_broadcast = true;
+ }
+
+ if (ip_dst.addr[0] >= 224 && ip_dst.addr[0] <= 239)
+ {
+ // IPv4 Multicast
+ is_broadcast = true;
+ }
+
+ if (is_broadcast)
+ {
+ // Send a broadcast packet
+ UCHAR dest[6];
+ UINT i;
+
+ // Destination
+ for (i = 0;i < 6;i++)
+ {
+ dest[i] = 0xff;
+ }
+
+ // Send
+ IPCSendIPv4WithDestMacAddr(ipc, data, size, dest);
+
+ return;
+ }
+
+ if (IsZeroIP(&ip_dst_local))
+ {
+ return;
+ }
+
+ IPCSendIPv4Unicast(ipc, data, size, &ip_dst_local);
+}
+
+// Send an IPv4 packet with a specified destination MAC address
+void IPCSendIPv4WithDestMacAddr(IPC *ipc, void *data, UINT size, UCHAR *dest_mac_addr)
+{
+ UCHAR tmp[1514];
+ // Validate arguments
+ if (ipc == NULL || data == NULL || size < 20 || size > 1500 || dest_mac_addr == NULL)
+ {
+ return;
+ }
+
+ // Destination
+ Copy(tmp + 0, dest_mac_addr, 6);
+
+ // Source
+ Copy(tmp + 6, ipc->MacAddress, 6);
+
+ // Protocol number
+ WRITE_USHORT(tmp + 12, MAC_PROTO_IPV4);
+
+ // Data
+ Copy(tmp + 14, data, size);
+
+ // Send
+ IPCSendL2(ipc, tmp, size + 14);
+}
+
+// Remove old ARP table entries
+void IPCFlushArpTable(IPC *ipc)
+{
+ IPCFlushArpTableEx(ipc, 0);
+}
+void IPCFlushArpTableEx(IPC *ipc, UINT64 now)
+{
+ UINT i;
+ LIST *o = NULL;
+ // Validate arguments
+ if (ipc == NULL)
+ {
+ return;
+ }
+ if (now == 0)
+ {
+ now = Tick64();
+ }
+
+ for (i = 0;i < LIST_NUM(ipc->ArpTable);i++)
+ {
+ IPC_ARP *a = LIST_DATA(ipc->ArpTable, i);
+ bool b = false;
+
+ if (a->Resolved && a->ExpireTime <= now)
+ {
+ b = true;
+ }
+ else if (a->Resolved == false && a->GiveupTime <= now)
+ {
+ b = true;
+ }
+
+ if (b)
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Add(o, a);
+ }
+ }
+
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IPC_ARP *a = LIST_DATA(o, i);
+
+ IPCFreeARP(a);
+
+ Delete(ipc->ArpTable, a);
+ }
+
+ ReleaseList(o);
+ }
+}
+
+// Send an IPv4 unicast packet
+void IPCSendIPv4Unicast(IPC *ipc, void *data, UINT size, IP *next_ip)
+{
+ IPC_ARP *a;
+ // Validate arguments
+ if (ipc == NULL || data == NULL || size < 20 || size > 1500 || next_ip == NULL)
+ {
+ return;
+ }
+
+ a = IPCSearchArpTable(ipc, next_ip);
+
+ if (a != NULL)
+ {
+ // ARP entry is found
+ if (a->Resolved)
+ {
+ // Send
+ a->ExpireTime = Tick64() + (UINT64)IPC_ARP_LIFETIME;
+
+ IPCSendIPv4WithDestMacAddr(ipc, data, size, a->MacAddress);
+ }
+ else
+ {
+ // Undeliverable because of unresolved table. Accumulate in the queue
+ if (a->PacketQueue->num_item < IPC_MAX_PACKET_QUEUE_LEN)
+ {
+ InsertQueue(a->PacketQueue, NewBlock(Clone(data, size), size, false));
+ }
+ }
+ }
+ else
+ {
+ ARPV4_HEADER arp;
+ UCHAR tmp[14 + sizeof(ARPV4_HEADER)];
+ UINT i;
+
+ // Because there is no such ARP entry, create a new one
+ a = IPCNewARP(next_ip, NULL);
+
+ // Send an ARP request
+ Zero(&arp, sizeof(arp));
+ arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+ arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
+ arp.HardwareSize = 6;
+ arp.ProtocolSize = 4;
+ arp.Operation = Endian16(ARP_OPERATION_REQUEST);
+ Copy(&arp.SrcAddress, &ipc->MacAddress, 6);
+ arp.SrcIP = IPToUINT(&ipc->ClientIPAddress);
+ arp.TargetIP = IPToUINT(next_ip);
+
+ for (i = 0;i < 6;i++)
+ {
+ tmp[i] = 0xff;
+ }
+
+ Copy(tmp + 6, ipc->MacAddress, 6);
+
+ WRITE_USHORT(tmp + 12, MAC_PROTO_ARPV4);
+ Copy(tmp + 14, &arp, sizeof(ARPV4_HEADER));
+
+ IPCSendL2(ipc, tmp, 14 + sizeof(ARPV4_HEADER));
+
+ // Accumulate the IP packet to be transmitted in the queue
+ if (a->PacketQueue->num_item < IPC_MAX_PACKET_QUEUE_LEN)
+ {
+ InsertQueue(a->PacketQueue, NewBlock(Clone(data, size), size, false));
+ }
+
+ Insert(ipc->ArpTable, a);
+ }
+}
+
+// Search the ARP table
+IPC_ARP *IPCSearchArpTable(IPC *ipc, IP *ip)
+{
+ IPC_ARP t;
+ IPC_ARP *a;
+ // Validate arguments
+ if (ipc == NULL || ip == NULL)
+ {
+ return NULL;
+ }
+
+ Copy(&t.Ip, ip, sizeof(IP));
+
+ a = Search(ipc->ArpTable, &t);
+
+ return a;
+}
+
+// Release the ARP entry
+void IPCFreeARP(IPC_ARP *a)
+{
+ BLOCK *b;
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ b = GetNext(a->PacketQueue);
+ if (b == NULL)
+ {
+ break;
+ }
+
+ FreeBlock(b);
+ }
+
+ ReleaseQueue(a->PacketQueue);
+
+ Free(a);
+}
+
+// Create a new ARP entry
+IPC_ARP *IPCNewARP(IP *ip, UCHAR *mac_address)
+{
+ IPC_ARP *a;
+ // Validate arguments
+ if (ip == NULL)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(IPC_ARP));
+
+ Copy(&a->Ip, ip, sizeof(IP));
+ if (mac_address != NULL)
+ {
+ Copy(a->MacAddress, mac_address, 6);
+ a->Resolved = true;
+ a->ExpireTime = Tick64() + (UINT64)IPC_ARP_LIFETIME;
+ }
+ else
+ {
+ a->GiveupTime = Tick64() + (UINT64)IPC_ARP_GIVEUPTIME;
+ }
+
+ a->PacketQueue = NewQueueFast();
+
+ return a;
+}
+
+// Compare ARP entries
+int IPCCmpArpTable(void *p1, void *p2)
+{
+ IPC_ARP *a1, *a2;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ a1 = *(IPC_ARP **)p1;
+ a2 = *(IPC_ARP **)p2;
+ if (a1 == NULL || a2 == NULL)
+ {
+ return 0;
+ }
+
+ return CmpIpAddr(&a1->Ip, &a2->Ip);
+}
+
+// Send an Ethernet packet (client -> server)
+void IPCSendL2(IPC *ipc, void *data, UINT size)
+{
+ // Validate arguments
+ if (ipc == NULL || data == NULL || size == 0)
+ {
+ return;
+ }
+
+ if (ipc->Sock == NULL)
+ {
+ return;
+ }
+
+ TubeSendEx(ipc->Sock->SendTube, data, size, NULL, true);
+ AddTubeToFlushList(ipc->FlushList, ipc->Sock->SendTube);
+}
+
+// Receive an IPv4 packet (server -> client)
+BLOCK *IPCRecvIPv4(IPC *ipc)
+{
+ BLOCK *b;
+ // Validate arguments
+ if (ipc == NULL)
+ {
+ return NULL;
+ }
+
+ b = GetNext(ipc->IPv4RecviedQueue);
+
+ return b;
+}
+
+// Receive an Ethernet packet (server -> client)
+BLOCK *IPCRecvL2(IPC *ipc)
+{
+ TUBEDATA *d;
+ BLOCK *b;
+ // Validate arguments
+ if (ipc == NULL)
+ {
+ return NULL;
+ }
+
+ if (ipc->Sock == NULL)
+ {
+ return NULL;
+ }
+
+ d = TubeRecvAsync(ipc->Sock->RecvTube);
+
+ if (d == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBlock(d->Data, d->DataSize, 0);
+
+ Free(d->Header);
+ Free(d);
+
+ return b;
+}
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_IPC.h b/src/Cedar/IPsec_IPC.h
new file mode 100644
index 00000000..0861c13f
--- /dev/null
+++ b/src/Cedar/IPsec_IPC.h
@@ -0,0 +1,243 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_IPC.h
+// Header of IPsec_IPC.c
+
+#ifndef IPSEC_IPC
+#define IPSEC_IPC
+
+// Constants
+#define IPC_ARP_LIFETIME (3 * 60 * 1000)
+#define IPC_ARP_GIVEUPTIME (1 * 1000)
+#define IPC_DHCP_TIMEOUT (5 * 1000)
+#define IPC_DHCP_TIMEOUT_TOTAL_GIVEUP (20 * 1000)
+#define IPC_DHCP_MIN_LEASE 5
+#define IPC_DHCP_DEFAULT_LEASE 3600
+
+#define IPC_MAX_PACKET_QUEUE_LEN 10000
+
+#define IPC_DHCP_VENDOR_ID "MSFT 5.0"
+
+#define IPC_PASSWORD_MSCHAPV2_TAG "xH7DiNlurDhcYV4a:"
+
+// ARP table entry
+struct IPC_ARP
+{
+ IP Ip; // IP address
+ bool Resolved; // Whether the MAC address have been resolved
+ UCHAR MacAddress[6]; // MAC address
+ UINT64 GiveupTime; // Time to give up (in the case of unresolved)
+ UINT64 ExpireTime; // Expiration date (If resolved)
+ QUEUE *PacketQueue; // Transmission packet queue
+};
+
+// DHCP release queue
+struct IPC_DHCP_RELESAE_QUEUE
+{
+ DHCP_OPTION_LIST Req;
+ UINT TranId;
+ UCHAR MacAddress[6];
+};
+
+// IPC_PARAM
+struct IPC_PARAM
+{
+ char ClientName[MAX_SIZE];
+ char Postfix[MAX_SIZE];
+ char HubName[MAX_HUBNAME_LEN + 1];
+ char UserName[MAX_USERNAME_LEN + 1];
+ char Password[MAX_PASSWORD_LEN + 1];
+ IP ClientIp;
+ UINT ClientPort;
+ IP ServerIp;
+ UINT ServerPort;
+ char ClientHostname[MAX_SIZE];
+ char CryptName[MAX_SIZE];
+ bool BridgeMode;
+ UINT Mss;
+ bool IsL3Mode;
+ bool IsOpenVPN;
+};
+
+// IPC_ASYNC object
+struct IPC_ASYNC
+{
+ CEDAR *Cedar; // Cedar
+ IPC_PARAM Param; // Parameters for creating IPC
+ THREAD *Thread; // Thread
+ SOCK_EVENT *SockEvent; // Socket events that is set when the connection is completed
+ bool Done; // Processing completion flag
+ IPC *Ipc; // IPC object (if it fails to connect, the value is NULL)
+ TUBE *TubeForDisconnect; // Tube for disconnection notification
+ UINT ErrorCode; // Error code in the case of failing to connect
+ DHCP_OPTION_LIST L3ClientAddressOption; // Client IP address option (Only in the case of L3 mode)
+ UINT64 L3DhcpRenewInterval; // DHCP update interval
+ UINT64 L3NextDhcpRenewTick; // DHCP renewal time of the next
+ bool DhcpAllocFailed; // Failed to get IP address from the DHCP server
+};
+
+// IPC object
+struct IPC
+{
+ CEDAR *Cedar;
+ char HubName[MAX_HUBNAME_LEN + 1];
+ char UserName[MAX_USERNAME_LEN + 1];
+ char Password[MAX_PASSWORD_LEN + 1];
+ char ClientHostname[MAX_SIZE];
+ UCHAR random[SHA1_SIZE];
+ char SessionName[MAX_SESSION_NAME_LEN + 1];
+ char ConnectionName[MAX_CONNECTION_NAME_LEN + 1];
+ POLICY *Policy;
+ SOCK *Sock;
+ INTERRUPT_MANAGER *Interrupt; // Interrupt manager
+ IP ClientIPAddress; // IP address of the client
+ IP SubnetMask; // Subnet mask of the client
+ IP DefaultGateway; // Default gateway address
+ IP BroadcastAddress; // Broadcast address
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2];
+ LIST *ArpTable; // ARP table
+ QUEUE *IPv4RecviedQueue; // IPv4 reception queue
+ TUBE_FLUSH_LIST *FlushList; // Tube Flush List
+ UCHAR MsChapV2_ServerResponse[20]; // Server response
+};
+
+// MS-CHAPv2 authentication information
+struct IPC_MSCHAP_V2_AUTHINFO
+{
+ char MsChapV2_PPPUsername[MAX_SIZE]; // MS-CHAPv2 Username
+ UCHAR MsChapV2_ServerChallenge[16]; // MS-CHAPv2 Server Challenge
+ UCHAR MsChapV2_ClientChallenge[16]; // MS-CHAPv2 Client Challenge
+ UCHAR MsChapV2_ClientResponse[24]; // MS-CHAPv2 Client Response
+};
+
+IPC *NewIPC(CEDAR *cedar, char *client_name, char *postfix, char *hubname, char *username, char *password,
+ UINT *error_code, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port,
+ char *client_hostname, char *crypt_name,
+ bool bridge_mode, UINT mss);
+IPC *NewIPCByParam(CEDAR *cedar, IPC_PARAM *param, UINT *error_code);
+IPC *NewIPCBySock(CEDAR *cedar, SOCK *s, void *mac_address);
+void FreeIPC(IPC *ipc);
+bool IsIPCConnected(IPC *ipc);
+void IPCSetSockEventWhenRecvL2Packet(IPC *ipc, SOCK_EVENT *e);
+void IPCSendL2(IPC *ipc, void *data, UINT size);
+void IPCSendIPv4(IPC *ipc, void *data, UINT size);
+BLOCK *IPCRecvL2(IPC *ipc);
+BLOCK *IPCRecvIPv4(IPC *ipc);
+void IPCProcessInterrupts(IPC *ipc);
+void IPCProcessL3Events(IPC *ipc);
+void IPCProcessL3EventsEx(IPC *ipc, UINT64 now);
+bool IPCSetIPv4Parameters(IPC *ipc, IP *ip, IP *subnet, IP *gw);
+IPC_ARP *IPCNewARP(IP *ip, UCHAR *mac_address);
+void IPCFreeARP(IPC_ARP *a);
+int IPCCmpArpTable(void *p1, void *p2);
+void IPCSendIPv4Unicast(IPC *ipc, void *data, UINT size, IP *next_ip);
+IPC_ARP *IPCSearchArpTable(IPC *ipc, IP *ip);
+void IPCSendIPv4WithDestMacAddr(IPC *ipc, void *data, UINT size, UCHAR *dest_mac_addr);
+void IPCFlushArpTable(IPC *ipc);
+void IPCFlushArpTableEx(IPC *ipc, UINT64 now);
+void IPCProcessArp(IPC *ipc, BLOCK *b);
+void IPCAssociateOnArpTable(IPC *ipc, IP *ip, UCHAR *mac_address);
+bool IsValidUnicastMacAddress(UCHAR *mac);
+bool IsValidUnicastIPAddress4(IP *ip);
+bool IsValidUnicastIPAddressUINT4(UINT ip);
+DHCPV4_DATA *IPCSendDhcpRequest(IPC *ipc, IP *dest_ip, UINT tran_id, DHCP_OPTION_LIST *opt, UINT expecting_code, UINT timeout, TUBE *discon_poll_tube);
+BUF *IPCBuildDhcpRequest(IPC *ipc, IP *dest_ip, UINT tran_id, DHCP_OPTION_LIST *opt);
+BUF *IPCBuildDhcpRequestOptions(IPC *ipc, DHCP_OPTION_LIST *opt);
+bool IPCDhcpAllocateIP(IPC *ipc, DHCP_OPTION_LIST *opt, TUBE *discon_poll_tube);
+bool IPCDhcpAllocateIPEx(IPC *ipc, DHCP_OPTION_LIST *opt, TUBE *discon_poll_tube, bool openvpn_compatible);
+bool IPCDhcpRequestInformIP(IPC *ipc, DHCP_OPTION_LIST *opt, TUBE *discon_poll_tube, IP *client_ip);
+void IPCDhcpRenewIP(IPC *ipc, IP *dhcp_server);
+void IPCDhcpFreeIP(IPC *ipc, IP *dhcp_server);
+IPC_ASYNC *NewIPCAsync(CEDAR *cedar, IPC_PARAM *param, SOCK_EVENT *sock_event);
+void IPCAsyncThreadProc(THREAD *thread, void *param);
+void FreeIPCAsync(IPC_ASYNC *a);
+
+bool ParseAndExtractMsChapV2InfoFromPassword(IPC_MSCHAP_V2_AUTHINFO *d, char *password);
+
+#endif // IPSEC_IPC
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_IkePacket.c b/src/Cedar/IPsec_IkePacket.c
new file mode 100644
index 00000000..8fa02e90
--- /dev/null
+++ b/src/Cedar/IPsec_IkePacket.c
@@ -0,0 +1,3129 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_IkePacket.c
+// IKE (ISAKMP) packet processing
+
+#include "CedarPch.h"
+
+// Convert the string to a password
+BUF *IkeStrToPassword(char *str)
+{
+ BUF *b;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return NewBuf();
+ }
+
+ if (StartWith(str, "0x") == false)
+ {
+ // Accept the string as is
+ b = NewBuf();
+ WriteBuf(b, str, StrLen(str));
+ }
+ else
+ {
+ // Interpret as a hexadecimal value
+ b = StrToBin(str + 2);
+ }
+
+ return b;
+}
+
+// Phase 1: Convert the encryption algorithm name to key size
+UINT IkePhase1CryptIdToKeySize(UCHAR id)
+{
+ switch (id)
+ {
+ case IKE_P1_CRYPTO_3DES_CBC:
+ return DES3_KEY_SIZE;
+
+ case IKE_P1_CRYPTO_DES_CBC:
+ return DES_KEY_SIZE;
+ }
+
+ return 0;
+}
+
+// Phase 2: Convert the encryption algorithm name to key size
+UINT IkePhase2CryptIdToKeySize(UCHAR id)
+{
+ switch (id)
+ {
+ case IKE_TRANSFORM_ID_P2_ESP_3DES:
+ return DES3_KEY_SIZE;
+
+ case IKE_TRANSFORM_ID_P2_ESP_DES:
+ return DES_KEY_SIZE;
+ }
+
+ return 0;
+}
+
+// Convert a string to an algorithm name
+UCHAR IkeStrToPhase1CryptId(char *name)
+{
+ if (StartWith(name, "3DES") || StartWith("3DES", name))
+ {
+ return IKE_P1_CRYPTO_3DES_CBC;
+ }
+ else if (StartWith(name, "DES") || StartWith("DES", name))
+ {
+ return IKE_P1_CRYPTO_DES_CBC;
+ }
+ else
+ {
+ return 0;
+ }
+}
+UCHAR IkeStrToPhase1HashId(char *name)
+{
+ if (StartWith(name, "SHA-1") || StartWith("SHA-1", name))
+ {
+ return IKE_P1_HASH_SHA1;
+ }
+
+ return 0;
+}
+UCHAR IkeStrToPhase2CryptId(char *name)
+{
+ if (StartWith(name, "3DES") || StartWith("3DES", name))
+ {
+ return IKE_TRANSFORM_ID_P2_ESP_3DES;
+ }
+ else if (StartWith(name, "DES") || StartWith("DES", name))
+ {
+ return IKE_TRANSFORM_ID_P2_ESP_DES;
+ }
+ else
+ {
+ return 0;
+ }
+}
+UCHAR IkeStrToPhase2HashId(char *name)
+{
+ if (StartWith(name, "SHA-1") || StartWith("SHA-1", name))
+ {
+ return IKE_P2_HMAC_SHA1_96;
+ }
+
+ return 0;
+}
+
+// Build a data payload
+BUF *IkeBuildDataPayload(IKE_PACKET_DATA_PAYLOAD *t)
+{
+ BUF *b;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+ WriteBuf(b, t->Data->Buf, t->Data->Size);
+
+ return b;
+}
+
+// Build a SA payload
+BUF *IkeBuildSaPayload(IKE_PACKET_SA_PAYLOAD *t)
+{
+ IKE_SA_HEADER h;
+ BUF *ret;
+ BUF *b;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+ h.DoI = Endian32(IKE_SA_DOI_IPSEC);
+ h.Situation = Endian32(IKE_SA_SITUATION_IDENTITY);
+
+ ret = NewBuf();
+
+ WriteBuf(ret, &h, sizeof(h));
+
+ b = IkeBuildPayloadList(t->PayloadList);
+ WriteBufBuf(ret, b);
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Build a proposal payload
+BUF *IkeBuildProposalPayload(IKE_PACKET_PROPOSAL_PAYLOAD *t)
+{
+ IKE_PROPOSAL_HEADER h;
+ BUF *ret, *b;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+ h.Number = t->Number;
+ h.NumTransforms = LIST_NUM(t->PayloadList);
+ h.ProtocolId = t->ProtocolId;
+ h.SpiSize = t->Spi->Size;
+
+ ret = NewBuf();
+ WriteBuf(ret, &h, sizeof(h));
+ WriteBufBuf(ret, t->Spi);
+
+ b = IkeBuildPayloadList(t->PayloadList);
+ WriteBufBuf(ret, b);
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Build the transform value list
+BUF *IkeBuildTransformValueList(LIST *o)
+{
+ BUF *b;
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IKE_PACKET_TRANSFORM_VALUE *v = LIST_DATA(o, i);
+ BUF *tmp = IkeBuildTransformValue(v);
+
+ WriteBufBuf(b, tmp);
+
+ FreeBuf(tmp);
+ }
+
+ return b;
+}
+
+// Build a transform value
+BUF *IkeBuildTransformValue(IKE_PACKET_TRANSFORM_VALUE *v)
+{
+ BUF *b;
+ UCHAR af_bit, type;
+ USHORT size_or_value;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return NULL;
+ }
+
+ type = v->Type;
+
+ if (v->Value >= 65536)
+ {
+ // 32 bit
+ af_bit = 0;
+ size_or_value = Endian16(sizeof(UINT));
+ }
+ else
+ {
+ // 16 bit
+ af_bit = 0x80;
+ size_or_value = Endian16((USHORT)v->Value);
+ }
+
+ b = NewBuf();
+ WriteBuf(b, &af_bit, sizeof(af_bit));
+ WriteBuf(b, &type, sizeof(type));
+ WriteBuf(b, &size_or_value, sizeof(size_or_value));
+
+ if (af_bit == 0)
+ {
+ UINT value = Endian32(v->Value);
+ WriteBuf(b, &value, sizeof(UINT));
+ }
+
+ return b;
+}
+
+// Build a transform payload
+BUF *IkeBuildTransformPayload(IKE_PACKET_TRANSFORM_PAYLOAD *t)
+{
+ IKE_TRANSFORM_HEADER h;
+ BUF *ret, *b;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+ h.Number = t->Number;
+ h.TransformId = t->TransformId;
+
+ ret = NewBuf();
+ WriteBuf(ret, &h, sizeof(h));
+
+ b = IkeBuildTransformValueList(t->ValueList);
+ WriteBufBuf(ret, b);
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Get the value from the transform payload
+UINT IkeGetTransformValue(IKE_PACKET_TRANSFORM_PAYLOAD *t, UINT type, UINT index)
+{
+ UINT i;
+ UINT num;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return 0;
+ }
+
+ num = 0;
+
+ for (i = 0;i < LIST_NUM(t->ValueList);i++)
+ {
+ IKE_PACKET_TRANSFORM_VALUE *v = LIST_DATA(t->ValueList, i);
+
+ if (v->Type == type)
+ {
+ if (num == index)
+ {
+ return v->Value;
+ }
+
+ num++;
+ }
+ }
+
+ return 0;
+}
+
+// Get the number of values from the transform payload
+UINT IkeGetTransformValueNum(IKE_PACKET_TRANSFORM_PAYLOAD *t, UINT type)
+{
+ UINT i;
+ UINT num;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return 0;
+ }
+
+ num = 0;
+
+ for (i = 0;i < LIST_NUM(t->ValueList);i++)
+ {
+ IKE_PACKET_TRANSFORM_VALUE *v = LIST_DATA(t->ValueList, i);
+
+ if (v->Type == type)
+ {
+ num++;
+ }
+ }
+
+ return num;
+}
+
+// Build the ID payload
+BUF *IkeBuildIdPayload(IKE_PACKET_ID_PAYLOAD *t)
+{
+ IKE_ID_HEADER h;
+ BUF *ret;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+ h.IdType = t->Type;
+ h.Port = Endian16(t->Port);
+ h.ProtocolId = t->ProtocolId;
+
+ ret = NewBuf();
+ WriteBuf(ret, &h, sizeof(h));
+
+ WriteBufBuf(ret, t->IdData);
+
+ return ret;
+}
+
+// Build a certificate payload
+BUF *IkeBuildCertPayload(IKE_PACKET_CERT_PAYLOAD *t)
+{
+ IKE_CERT_HEADER h;
+ BUF *ret;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+ h.CertType = t->CertType;
+
+ ret = NewBuf();
+ WriteBuf(ret, &h, sizeof(h));
+ WriteBufBuf(ret, t->CertData);
+
+ return ret;
+}
+
+// Build a certificate request payload
+BUF *IkeBuildCertRequestPayload(IKE_PACKET_CERT_REQUEST_PAYLOAD *t)
+{
+ IKE_CERT_REQUEST_HEADER h;
+ BUF *ret;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+ h.CertType = t->CertType;
+
+ ret = NewBuf();
+ WriteBuf(ret, &h, sizeof(h));
+ WriteBufBuf(ret, t->Data);
+
+ return ret;
+}
+
+// Build a notification payload
+BUF *IkeBuildNoticePayload(IKE_PACKET_NOTICE_PAYLOAD *t)
+{
+ IKE_NOTICE_HEADER h;
+ BUF *ret;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+ h.DoI = Endian32(IKE_SA_DOI_IPSEC);
+ h.MessageType = Endian16(t->MessageType);
+ h.ProtocolId = t->ProtocolId;
+ h.SpiSize = t->Spi->Size;
+
+ ret = NewBuf();
+ WriteBuf(ret, &h, sizeof(h));
+ WriteBuf(ret, t->Spi->Buf, t->Spi->Size);
+
+ if (t->MessageData != NULL)
+ {
+ WriteBuf(ret, t->MessageData->Buf, t->MessageData->Size);
+ }
+
+ return ret;
+}
+
+// Build a NAT-OA payload
+BUF *IkeBuildNatOaPayload(IKE_PACKET_NAT_OA_PAYLOAD *t)
+{
+ IKE_NAT_OA_HEADER h;
+ BUF *ret;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+
+ if (IsIP6(&t->IpAddress))
+ {
+ h.IdType = IKE_ID_IPV6_ADDR;
+ }
+ else
+ {
+ h.IdType = IKE_ID_IPV4_ADDR;
+ }
+
+ ret = NewBuf();
+
+ WriteBuf(ret, &h, sizeof(h));
+
+ if (IsIP6(&t->IpAddress))
+ {
+ WriteBuf(ret, t->IpAddress.ipv6_addr, 16);
+ }
+ else
+ {
+ WriteBuf(ret, t->IpAddress.addr, 4);
+ }
+
+ return ret;
+}
+
+// Build a deletion payload
+BUF *IkeBuildDeletePayload(IKE_PACKET_DELETE_PAYLOAD *t)
+{
+ IKE_DELETE_HEADER h;
+ BUF *ret;
+ UINT i;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+ h.DoI = Endian32(IKE_SA_DOI_IPSEC);
+ h.NumSpis = Endian16(LIST_NUM(t->SpiList));
+ h.ProtocolId = t->ProtocolId;
+
+ if (LIST_NUM(t->SpiList) >= 1)
+ {
+ BUF *b = LIST_DATA(t->SpiList, 0);
+
+ h.SpiSize = b->Size;
+ }
+
+ ret = NewBuf();
+ WriteBuf(ret, &h, sizeof(h));
+
+ for (i = 0;i < LIST_NUM(t->SpiList);i++)
+ {
+ BUF *b = LIST_DATA(t->SpiList, i);
+
+ WriteBuf(ret, b->Buf, b->Size);
+ }
+
+ return ret;
+}
+
+// Build a bit array from the payload
+BUF *IkeBuildPayload(IKE_PACKET_PAYLOAD *p)
+{
+ BUF *b = NULL;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ switch (p->PayloadType)
+ {
+ case IKE_PAYLOAD_SA: // SA payload
+ b = IkeBuildSaPayload(&p->Payload.Sa);
+ break;
+
+ case IKE_PAYLOAD_PROPOSAL: // Proposal payload
+ b = IkeBuildProposalPayload(&p->Payload.Proposal);
+ break;
+
+ case IKE_PAYLOAD_TRANSFORM: // Transform payload
+ b = IkeBuildTransformPayload(&p->Payload.Transform);
+ break;
+
+ case IKE_PAYLOAD_ID: // ID payload
+ b = IkeBuildIdPayload(&p->Payload.Id);
+ break;
+
+ case IKE_PAYLOAD_CERT: // Certificate payload
+ b = IkeBuildCertPayload(&p->Payload.Cert);
+ break;
+
+ case IKE_PAYLOAD_CERT_REQUEST: // Certificate request payload
+ b = IkeBuildCertRequestPayload(&p->Payload.CertRequest);
+ break;
+
+ case IKE_PAYLOAD_NOTICE: // Notification Payload
+ b = IkeBuildNoticePayload(&p->Payload.Notice);
+ break;
+
+ case IKE_PAYLOAD_DELETE: // Deletion payload
+ b = IkeBuildDeletePayload(&p->Payload.Delete);
+ break;
+
+ case IKE_PAYLOAD_NAT_OA: // NAT-OA payload
+ case IKE_PAYLOAD_NAT_OA_DRAFT:
+ case IKE_PAYLOAD_NAT_OA_DRAFT_2:
+ b = IkeBuildNatOaPayload(&p->Payload.NatOa);
+ break;
+
+ case IKE_PAYLOAD_KEY_EXCHANGE: // Key exchange payload
+ case IKE_PAYLOAD_HASH: // Hash payload
+ case IKE_PAYLOAD_SIGN: // Signature payload
+ case IKE_PAYLOAD_RAND: // Random number payload
+ case IKE_PAYLOAD_VENDOR_ID: // Vendor ID payload
+ case IKE_PAYLOAD_NAT_D: // NAT-D payload
+ case IKE_PAYLOAD_NAT_D_DRAFT: // NAT-D payload (draft)
+ default:
+ b = IkeBuildDataPayload(&p->Payload.GeneralData);
+ break;
+ }
+
+ if (b != NULL)
+ {
+ if (p->BitArray != NULL)
+ {
+ FreeBuf(p->BitArray);
+ }
+ p->BitArray = CloneBuf(b);
+ }
+
+ return b;
+}
+
+// Get the payload type of the first item
+UCHAR IkeGetFirstPayloadType(LIST *o)
+{
+ IKE_PACKET_PAYLOAD *p;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return IKE_PAYLOAD_NONE;
+ }
+
+ if (LIST_NUM(o) == 0)
+ {
+ return IKE_PAYLOAD_NONE;
+ }
+
+ p = (IKE_PACKET_PAYLOAD *)LIST_DATA(o, 0);
+
+ return p->PayloadType;
+}
+
+// Build a bit array from the payload list
+BUF *IkeBuildPayloadList(LIST *o)
+{
+ BUF *b;
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IKE_PACKET_PAYLOAD *p = LIST_DATA(o, i);
+ IKE_PACKET_PAYLOAD *next = NULL;
+ IKE_COMMON_HEADER h;
+ BUF *tmp;
+
+ if (i < (LIST_NUM(o) - 1))
+ {
+ next = LIST_DATA(o, i + 1);
+ }
+
+ Zero(&h, sizeof(h));
+ if (next != NULL)
+ {
+ h.NextPayload = next->PayloadType;
+ }
+ else
+ {
+ h.NextPayload = IKE_PAYLOAD_NONE;
+ }
+
+ tmp = IkeBuildPayload(p);
+ if (tmp != NULL)
+ {
+ h.PayloadSize = Endian16(tmp->Size + (USHORT)sizeof(h));
+
+ WriteBuf(b, &h, sizeof(h));
+ WriteBuf(b, tmp->Buf, tmp->Size);
+
+ FreeBuf(tmp);
+ }
+ }
+
+ SeekBuf(b, 0, 0);
+
+ return b;
+}
+
+// Get the specified payload
+IKE_PACKET_PAYLOAD *IkeGetPayload(LIST *o, UINT payload_type, UINT index)
+{
+ UINT i, num;
+ IKE_PACKET_PAYLOAD *ret = NULL;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return 0;
+ }
+
+ num = 0;
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IKE_PACKET_PAYLOAD *p = LIST_DATA(o, i);
+
+ if (p->PayloadType == payload_type)
+ {
+ if (num == index)
+ {
+ ret = p;
+ break;
+ }
+
+ num++;
+ }
+ }
+
+ return ret;
+}
+
+// Get the number of the payload of the specified type
+UINT IkeGetPayloadNum(LIST *o, UINT payload_type)
+{
+ UINT i, num;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return 0;
+ }
+
+ num = 0;
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IKE_PACKET_PAYLOAD *p = LIST_DATA(o, i);
+
+ if (p->PayloadType == payload_type)
+ {
+ num++;
+ }
+ }
+
+ return num;
+}
+
+// Create a deletion payload
+IKE_PACKET_PAYLOAD *IkeNewDeletePayload(UCHAR protocol_id, LIST *spi_list)
+{
+ IKE_PACKET_PAYLOAD *p;
+ if (spi_list == NULL)
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(IKE_PAYLOAD_DELETE);
+ p->Payload.Delete.ProtocolId = protocol_id;
+ p->Payload.Delete.SpiList = spi_list;
+
+ return p;
+}
+
+// Create a Notification payload
+IKE_PACKET_PAYLOAD *IkeNewNoticePayload(UCHAR protocol_id, USHORT message_type,
+ void *spi, UINT spi_size,
+ void *message, UINT message_size)
+{
+ IKE_PACKET_PAYLOAD *p;
+ if (spi == NULL && spi_size != 0)
+ {
+ return NULL;
+ }
+ if (message == NULL && message_size != 0)
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(IKE_PAYLOAD_NOTICE);
+ p->Payload.Notice.MessageType = message_type;
+ p->Payload.Notice.MessageData = MemToBuf(message, message_size);
+ p->Payload.Notice.Spi = MemToBuf(spi, spi_size);
+ p->Payload.Notice.ProtocolId = protocol_id;
+
+ return p;
+}
+
+// Create a Invalid Cookie Payload
+IKE_PACKET_PAYLOAD *IkeNewNoticeErrorInvalidCookiePayload(UINT64 init_cookie, UINT64 resp_cookie)
+{
+ IKE_PACKET_PAYLOAD *ret;
+ BUF *b = NewBuf();
+
+ WriteBufInt64(b, init_cookie);
+ WriteBufInt64(b, resp_cookie);
+
+ ret = IkeNewNoticePayload(IKE_PROTOCOL_ID_IKE, IKE_NOTICE_ERROR_INVALID_COOKIE, b->Buf, b->Size,
+ b->Buf, b->Size);
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Create an Invalid Exchange Type Payload
+IKE_PACKET_PAYLOAD *IkeNewNoticeErrorInvalidExchangeTypePayload(UINT64 init_cookie, UINT64 resp_cookie, UCHAR exchange_type)
+{
+ IKE_PACKET_PAYLOAD *ret;
+ BUF *b = NewBuf();
+
+ WriteBufInt64(b, init_cookie);
+ WriteBufInt64(b, resp_cookie);
+
+ ret = IkeNewNoticePayload(IKE_PROTOCOL_ID_IKE, IKE_NOTICE_ERROR_INVALID_EXCHANGE_TYPE, b->Buf, b->Size,
+ &exchange_type, 1);
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Create an Invalid SPI payload
+IKE_PACKET_PAYLOAD *IkeNewNoticeErrorInvalidSpiPayload(UINT spi)
+{
+ IKE_PACKET_PAYLOAD *ret;
+ spi = Endian32(spi);
+
+ ret = IkeNewNoticePayload(IKE_PROTOCOL_ID_IPSEC_ESP, IKE_NOTICE_ERROR_INVALID_SPI, &spi, sizeof(UINT),
+ &spi, sizeof(UINT));
+
+ return ret;
+}
+
+// Create a No Proposal Chosen payload
+IKE_PACKET_PAYLOAD *IkeNewNoticeErrorNoProposalChosenPayload(bool quick_mode, UINT64 init_cookie, UINT64 resp_cookie)
+{
+ BUF *b = NewBuf();
+ IKE_PACKET_PAYLOAD *ret;
+
+ WriteBufInt64(b, init_cookie);
+ WriteBufInt64(b, resp_cookie);
+
+ ret = IkeNewNoticePayload((quick_mode ? IKE_PROTOCOL_ID_IPSEC_ESP : IKE_PROTOCOL_ID_IKE),
+ IKE_NOTICE_ERROR_NO_PROPOSAL_CHOSEN, b->Buf, b->Size,
+ NULL, 0);
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Create a DPD payload
+IKE_PACKET_PAYLOAD *IkeNewNoticeDpdPayload(bool ack, UINT64 init_cookie, UINT64 resp_cookie, UINT seq_no)
+{
+ IKE_PACKET_PAYLOAD *ret;
+ BUF *b = NewBuf();
+
+ seq_no = Endian32(seq_no);
+
+ WriteBufInt64(b, init_cookie);
+ WriteBufInt64(b, resp_cookie);
+
+ ret = IkeNewNoticePayload(IKE_PROTOCOL_ID_IKE, (ack ? IKE_NOTICE_DPD_RESPONSE : IKE_NOTICE_DPD_REQUEST),
+ b->Buf, b->Size,
+ &seq_no, sizeof(UINT));
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Create a Certificate Request Payload
+IKE_PACKET_PAYLOAD *IkeNewCertRequestPayload(UCHAR cert_type, void *data, UINT size)
+{
+ IKE_PACKET_PAYLOAD *p;
+ if (data == NULL && size != 0)
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(IKE_PAYLOAD_CERT_REQUEST);
+ p->Payload.CertRequest.CertType = cert_type;
+ p->Payload.CertRequest.Data = MemToBuf(data, size);
+
+ return p;
+}
+
+// Create a Certificate payload
+IKE_PACKET_PAYLOAD *IkeNewCertPayload(UCHAR cert_type, void *cert_data, UINT cert_size)
+{
+ IKE_PACKET_PAYLOAD *p;
+ if (cert_data == NULL && cert_size != 0)
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(IKE_PAYLOAD_CERT);
+ p->Payload.Cert.CertType = cert_type;
+ p->Payload.Cert.CertData = MemToBuf(cert_data, cert_size);
+
+ return p;
+}
+
+// Create an ID payload
+IKE_PACKET_PAYLOAD *IkeNewIdPayload(UCHAR id_type, UCHAR protocol_id, USHORT port, void *id_data, UINT id_size)
+{
+ IKE_PACKET_PAYLOAD *p;
+ if (id_data == NULL && id_size != 0)
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(IKE_PAYLOAD_ID);
+ p->Payload.Id.IdData = MemToBuf(id_data, id_size);
+ p->Payload.Id.Port = port;
+ p->Payload.Id.ProtocolId = protocol_id;
+ p->Payload.Id.Type = id_type;
+
+ return p;
+}
+
+// Create a transform payload
+IKE_PACKET_PAYLOAD *IkeNewTransformPayload(UCHAR number, UCHAR transform_id, LIST *value_list)
+{
+ IKE_PACKET_PAYLOAD *p;
+ if (value_list == NULL)
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(IKE_PAYLOAD_TRANSFORM);
+ p->Payload.Transform.Number = number;
+ p->Payload.Transform.TransformId = transform_id;
+ p->Payload.Transform.ValueList = value_list;
+
+ return p;
+}
+
+// Create a proposal payload
+IKE_PACKET_PAYLOAD *IkeNewProposalPayload(UCHAR number, UCHAR protocol_id, void *spi, UINT spi_size, LIST *payload_list)
+{
+ IKE_PACKET_PAYLOAD *p;
+ if (payload_list == NULL || (spi == NULL && spi_size != 0))
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(IKE_PAYLOAD_PROPOSAL);
+ p->Payload.Proposal.Number = number;
+ p->Payload.Proposal.ProtocolId = protocol_id;
+ p->Payload.Proposal.Spi = MemToBuf(spi, spi_size);
+ p->Payload.Proposal.PayloadList = payload_list;
+
+ return p;
+}
+
+// Create an SA payload
+IKE_PACKET_PAYLOAD *IkeNewSaPayload(LIST *payload_list)
+{
+ IKE_PACKET_PAYLOAD *p;
+ // Validate arguments
+ if (payload_list == NULL)
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(IKE_PAYLOAD_SA);
+ p->Payload.Sa.PayloadList = payload_list;
+
+ return p;
+}
+
+// Create a NAT-OA payload
+IKE_PACKET_PAYLOAD *IkeNewNatOaPayload(UCHAR payload_type, IP *ip)
+{
+ IKE_PACKET_PAYLOAD *p;
+ // Validate arguments
+ if (ip == NULL)
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(payload_type);
+ Copy(&p->Payload.NatOa.IpAddress, ip, sizeof(IP));
+ p->PayloadType = payload_type;
+
+ return p;
+}
+
+// Create a data payload
+IKE_PACKET_PAYLOAD *IkeNewDataPayload(UCHAR payload_type, void *data, UINT size)
+{
+ IKE_PACKET_PAYLOAD *p;
+ // Validate arguments
+ if (data == NULL)
+ {
+ return NULL;
+ }
+
+ p = IkeNewPayload(payload_type);
+ p->Payload.GeneralData.Data = MemToBuf(data, size);
+
+ return p;
+}
+
+// Create a new payload
+IKE_PACKET_PAYLOAD *IkeNewPayload(UINT payload_type)
+{
+ IKE_PACKET_PAYLOAD *p;
+
+ p = ZeroMalloc(sizeof(IKE_PACKET_PAYLOAD));
+
+ p->PayloadType = payload_type;
+
+ return p;
+}
+
+// Analyse the IKE payload body
+IKE_PACKET_PAYLOAD *IkeParsePayload(UINT payload_type, BUF *b)
+{
+ IKE_PACKET_PAYLOAD *p = NULL;
+ bool ok = true;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return NULL;
+ }
+
+ p = ZeroMalloc(sizeof(IKE_PACKET_PAYLOAD));
+ p->PayloadType = payload_type;
+
+ switch (p->PayloadType)
+ {
+ case IKE_PAYLOAD_SA: // SA payload
+ ok = IkeParseSaPayload(&p->Payload.Sa, b);
+ break;
+
+ case IKE_PAYLOAD_PROPOSAL: // Proposal payload
+ ok = IkeParseProposalPayload(&p->Payload.Proposal, b);
+ break;
+
+ case IKE_PAYLOAD_TRANSFORM: // Proposal payload
+ ok = IkeParseTransformPayload(&p->Payload.Transform, b);
+ break;
+
+ case IKE_PAYLOAD_ID: // ID payload
+ ok = IkeParseIdPayload(&p->Payload.Id, b);
+ break;
+
+ case IKE_PAYLOAD_CERT: // Certificate payload
+ ok = IkeParseCertPayload(&p->Payload.Cert, b);
+ break;
+
+ case IKE_PAYLOAD_CERT_REQUEST: // Certificate request payload
+ ok = IkeParseCertRequestPayload(&p->Payload.CertRequest, b);
+ break;
+
+ case IKE_PAYLOAD_NOTICE: // Notification Payload
+ ok = IkeParseNoticePayload(&p->Payload.Notice, b);
+ break;
+
+ case IKE_PAYLOAD_DELETE: // Deletion payload
+ ok = IkeParseDeletePayload(&p->Payload.Delete, b);
+ break;
+
+ case IKE_PAYLOAD_NAT_OA:
+ case IKE_PAYLOAD_NAT_OA_DRAFT:
+ case IKE_PAYLOAD_NAT_OA_DRAFT_2:
+ ok = IkeParseNatOaPayload(&p->Payload.NatOa, b);
+ break;
+
+ case IKE_PAYLOAD_KEY_EXCHANGE: // Key exchange payload
+ case IKE_PAYLOAD_HASH: // Hash payload
+ case IKE_PAYLOAD_SIGN: // Signature payload
+ case IKE_PAYLOAD_RAND: // Random number payload
+ case IKE_PAYLOAD_VENDOR_ID: // Vendor ID payload
+ case IKE_PAYLOAD_NAT_D: // NAT-D payload
+ case IKE_PAYLOAD_NAT_D_DRAFT: // NAT-D payload (draft)
+ default:
+ ok = IkeParseDataPayload(&p->Payload.GeneralData, b);
+ break;
+ }
+
+ if (ok == false)
+ {
+ Free(p);
+ p = NULL;
+ }
+ else
+ {
+ p->BitArray = CloneBuf(b);
+ }
+
+ return p;
+}
+
+// Parse the SA payload
+bool IkeParseSaPayload(IKE_PACKET_SA_PAYLOAD *t, BUF *b)
+{
+ IKE_SA_HEADER *h;
+ UCHAR *buf;
+ UINT size;
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ if (b->Size < sizeof(IKE_SA_HEADER))
+ {
+ return false;
+ }
+
+ h = (IKE_SA_HEADER *)b->Buf;
+ buf = (UCHAR *)b->Buf;
+ buf += sizeof(IKE_SA_HEADER);
+ size = b->Size - sizeof(IKE_SA_HEADER);
+
+ if (Endian32(h->DoI) != IKE_SA_DOI_IPSEC)
+ {
+ Debug("ISAKMP: Invalid DoI Value: 0x%x\n", Endian32(h->DoI));
+ return false;
+ }
+
+ if (Endian32(h->Situation) != IKE_SA_SITUATION_IDENTITY)
+ {
+ Debug("ISAKMP: Invalid Situation Value: 0x%x\n", Endian32(h->Situation));
+ return false;
+ }
+
+ t->PayloadList = IkeParsePayloadList(buf, size, IKE_PAYLOAD_PROPOSAL);
+
+ return true;
+}
+
+// Release the SA payload
+void IkeFreeSaPayload(IKE_PACKET_SA_PAYLOAD *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->PayloadList != NULL)
+ {
+ IkeFreePayloadList(t->PayloadList);
+ t->PayloadList = NULL;
+ }
+}
+
+// Parse the proposal payload
+bool IkeParseProposalPayload(IKE_PACKET_PROPOSAL_PAYLOAD *t, BUF *b)
+{
+ IKE_PROPOSAL_HEADER *h;
+ UCHAR *buf;
+ UINT size;
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ if (b->Size < sizeof(IKE_PROPOSAL_HEADER))
+ {
+ return false;
+ }
+
+ h = (IKE_PROPOSAL_HEADER *)b->Buf;
+
+ t->Number = h->Number;
+ t->ProtocolId = h->ProtocolId;
+
+ buf = (UCHAR *)b->Buf;
+ buf += sizeof(IKE_PROPOSAL_HEADER);
+ size = b->Size - sizeof(IKE_PROPOSAL_HEADER);
+
+ if (size < (UINT)h->SpiSize)
+ {
+ return false;
+ }
+
+ t->Spi = MemToBuf(buf, h->SpiSize);
+
+ buf += h->SpiSize;
+ size -= h->SpiSize;
+
+ t->PayloadList = IkeParsePayloadList(buf, size, IKE_PAYLOAD_TRANSFORM);
+
+ return true;
+}
+
+// Release the proposal payload
+void IkeFreeProposalPayload(IKE_PACKET_PROPOSAL_PAYLOAD *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->Spi != NULL)
+ {
+ FreeBuf(t->Spi);
+ t->Spi = NULL;
+ }
+
+ if (t->PayloadList != NULL)
+ {
+ IkeFreePayloadList(t->PayloadList);
+ t->PayloadList = NULL;
+ }
+}
+
+// Parse the transform payload
+bool IkeParseTransformPayload(IKE_PACKET_TRANSFORM_PAYLOAD *t, BUF *b)
+{
+ IKE_TRANSFORM_HEADER h;
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ if (ReadBuf(b, &h, sizeof(h)) != sizeof(h))
+ {
+ return false;
+ }
+
+ t->Number = h.Number;
+ t->TransformId = h.TransformId;
+ t->ValueList = IkeParseTransformValueList(b);
+
+ return true;
+}
+
+// Create a new transform value
+IKE_PACKET_TRANSFORM_VALUE *IkeNewTransformValue(UCHAR type, UINT value)
+{
+ IKE_PACKET_TRANSFORM_VALUE *v = ZeroMalloc(sizeof(IKE_PACKET_TRANSFORM_VALUE));
+
+ v->Type = type;
+ v->Value = value;
+
+ return v;
+}
+
+// Parse the transform value list
+LIST *IkeParseTransformValueList(BUF *b)
+{
+ LIST *o;
+ bool ok = true;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return NULL;
+ }
+
+ o = NewListFast(NULL);
+
+ while (b->Current < b->Size)
+ {
+ UCHAR af_bit, type;
+ USHORT size;
+ UINT value = 0;
+ IKE_PACKET_TRANSFORM_VALUE *v;
+
+ if (ReadBuf(b, &af_bit, sizeof(af_bit)) != sizeof(af_bit))
+ {
+ ok = false;
+ break;
+ }
+
+ if (ReadBuf(b, &type, sizeof(type)) != sizeof(type))
+ {
+ ok = false;
+ break;
+ }
+
+ if (ReadBuf(b, &size, sizeof(size)) != sizeof(size))
+ {
+ ok = false;
+ }
+
+ size = Endian16(size);
+
+ if (af_bit == 0)
+ {
+ UCHAR *tmp = Malloc(size);
+
+ if (ReadBuf(b, tmp, size) != size)
+ {
+ ok = false;
+ Free(tmp);
+ break;
+ }
+
+ switch (size)
+ {
+ case sizeof(UINT):
+ value = READ_UINT(tmp);
+ break;
+
+ case sizeof(USHORT):
+ value = READ_USHORT(tmp);
+ break;
+
+ case sizeof(UCHAR):
+ value = *((UCHAR *)tmp);
+ break;
+ }
+
+ Free(tmp);
+ }
+ else
+ {
+ value = (UINT)size;
+ }
+
+ v = ZeroMalloc(sizeof(IKE_PACKET_TRANSFORM_VALUE));
+ v->Type = type;
+ v->Value = value;
+
+ Add(o, v);
+ }
+
+ if (ok == false)
+ {
+ IkeFreeTransformValueList(o);
+ o = NULL;
+ }
+
+ return o;
+}
+
+// Release the transform value list
+void IkeFreeTransformValueList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IKE_PACKET_TRANSFORM_VALUE *v = LIST_DATA(o, i);
+
+ Free(v);
+ }
+
+ ReleaseList(o);
+}
+
+// Release the transform payload
+void IkeFreeTransformPayload(IKE_PACKET_TRANSFORM_PAYLOAD *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->ValueList != NULL)
+ {
+ IkeFreeTransformValueList(t->ValueList);
+ t->ValueList = NULL;
+ }
+}
+
+// Parse the ID payload
+bool IkeParseIdPayload(IKE_PACKET_ID_PAYLOAD *t, BUF *b)
+{
+ IKE_ID_HEADER h;
+ IP ip;
+ IP subnet;
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ if (ReadBuf(b, &h, sizeof(h)) != sizeof(h))
+ {
+ return false;
+ }
+
+ t->Type = h.IdType;
+ t->ProtocolId = h.ProtocolId;
+ t->Port = Endian16(h.Port);
+ t->IdData = ReadRemainBuf(b);
+ if (t->IdData == NULL)
+ {
+ return false;
+ }
+
+ Zero(&ip, sizeof(ip));
+ Zero(&subnet, sizeof(subnet));
+
+ // Convert to string
+ Zero(t->StrData, sizeof(t->StrData));
+ switch (t->Type)
+ {
+ case IKE_ID_FQDN:
+ case IKE_ID_USER_FQDN:
+ case IKE_ID_KEY_ID:
+ Copy(t->StrData, t->IdData->Buf, MIN(t->IdData->Size, sizeof(t->StrData) - 1));
+ break;
+
+ case IKE_ID_IPV4_ADDR:
+ if (t->IdData->Size == 4)
+ {
+ Copy(ip.addr, t->IdData->Buf, 4);
+
+ IPToStr(t->StrData, sizeof(t->StrData), &ip);
+ }
+ break;
+
+ case IKE_ID_IPV6_ADDR:
+ if (t->IdData->Size == 16)
+ {
+ SetIP6(&ip, t->IdData->Buf);
+
+ IPToStr(t->StrData, sizeof(t->StrData), &ip);
+ }
+ break;
+
+ case IKE_ID_IPV4_ADDR_SUBNET:
+ if (t->IdData->Size == 8)
+ {
+ char ipstr[MAX_SIZE];
+ char subnetstr[MAX_SIZE];
+ Copy(ip.addr, t->IdData->Buf, 4);
+ Copy(subnet.addr, ((UCHAR *)t->IdData->Buf) + 4, 4);
+
+ IPToStr(ipstr, sizeof(ipstr), &ip);
+ MaskToStr(subnetstr, sizeof(subnetstr), &subnet);
+
+ Format(t->StrData, sizeof(t->StrData), "%s/%s", ipstr, subnetstr);
+ }
+ break;
+
+ case IKE_ID_IPV6_ADDR_SUBNET:
+ if (t->IdData->Size == 32)
+ {
+ char ipstr[MAX_SIZE];
+ char subnetstr[MAX_SIZE];
+ SetIP6(&ip, t->IdData->Buf);
+ SetIP6(&subnet, ((UCHAR *)t->IdData->Buf) + 16);
+
+ IPToStr(ipstr, sizeof(ipstr), &ip);
+ MaskToStr(subnetstr, sizeof(subnetstr), &subnet);
+
+ Format(t->StrData, sizeof(t->StrData), "%s/%s", ipstr, subnetstr);
+ }
+ break;
+ }
+
+ return true;
+}
+
+// Release the ID payload
+void IkeFreeIdPayload(IKE_PACKET_ID_PAYLOAD *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->IdData != NULL)
+ {
+ FreeBuf(t->IdData);
+ t->IdData = NULL;
+ }
+}
+
+// Parse the certificate payload
+bool IkeParseCertPayload(IKE_PACKET_CERT_PAYLOAD *t, BUF *b)
+{
+ IKE_CERT_HEADER h;
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ if (ReadBuf(b, &h, sizeof(h)) != sizeof(h))
+ {
+ return false;
+ }
+
+ t->CertType = h.CertType;
+ t->CertData = ReadRemainBuf(b);
+ if (t->CertData == NULL)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Release the certificate payload
+void IkeFreeCertPayload(IKE_PACKET_CERT_PAYLOAD *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->CertData != NULL)
+ {
+ FreeBuf(t->CertData);
+ t->CertData = NULL;
+ }
+}
+
+// Parse the certificate request payload
+bool IkeParseCertRequestPayload(IKE_PACKET_CERT_REQUEST_PAYLOAD *t, BUF *b)
+{
+ IKE_CERT_REQUEST_HEADER h;
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ if (ReadBuf(b, &h, sizeof(h)) != sizeof(h))
+ {
+ return false;
+ }
+
+ t->CertType = h.CertType;
+ t->Data = ReadRemainBuf(b);
+ if (t->Data == NULL)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Release the certificate request payload
+void IkeFreeCertRequestPayload(IKE_PACKET_CERT_REQUEST_PAYLOAD *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->Data != NULL)
+ {
+ FreeBuf(t->Data);
+ t->Data = NULL;
+ }
+}
+
+// Parse the notification payload
+bool IkeParseNoticePayload(IKE_PACKET_NOTICE_PAYLOAD *t, BUF *b)
+{
+ IKE_NOTICE_HEADER h;
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ if (ReadBuf(b, &h, sizeof(h)) != sizeof(h))
+ {
+ return false;
+ }
+
+ if (Endian32(h.DoI) != IKE_SA_DOI_IPSEC)
+ {
+ Debug("ISAKMP: Invalid DoI Value: 0x%x\n", Endian32(h.DoI));
+ return false;
+ }
+
+ t->MessageType = Endian16(h.MessageType);
+ t->ProtocolId = h.ProtocolId;
+ t->Spi = ReadBufFromBuf(b, h.SpiSize);
+ if (t->Spi == NULL)
+ {
+ return false;
+ }
+ t->MessageData = ReadRemainBuf(b);
+
+ return true;
+}
+
+// Release the notification payload
+void IkeFreeNoticePayload(IKE_PACKET_NOTICE_PAYLOAD *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->MessageData != NULL)
+ {
+ FreeBuf(t->MessageData);
+ t->MessageData = NULL;
+ }
+
+ if (t->Spi != NULL)
+ {
+ FreeBuf(t->Spi);
+ t->Spi = NULL;
+ }
+}
+
+// Parse the NAT-OA payload
+bool IkeParseNatOaPayload(IKE_PACKET_NAT_OA_PAYLOAD *t, BUF *b)
+{
+ IKE_NAT_OA_HEADER h;
+ UCHAR ip4[4];
+ UCHAR ip6[16];
+ IP ip;
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ Zero(&ip, sizeof(ip));
+
+ if (ReadBuf(b, &h, sizeof(h)) != sizeof(h))
+ {
+ return false;
+ }
+
+ if (h.IdType != IKE_ID_IPV4_ADDR && h.IdType != IKE_ID_IPV6_ADDR)
+ {
+ return false;
+ }
+
+ switch (h.IdType)
+ {
+ case IKE_ID_IPV4_ADDR: // IPv4
+ if (ReadBuf(b, ip4, sizeof(ip4)) != sizeof(ip4))
+ {
+ return false;
+ }
+
+ SetIP(&ip, ip4[0], ip4[1], ip4[2], ip4[3]);
+
+ break;
+
+ case IKE_ID_IPV6_ADDR: // IPv6
+ if (ReadBuf(b, ip6, sizeof(ip6)) != sizeof(ip6))
+ {
+ return false;
+ }
+
+ SetIP6(&ip, ip6);
+
+ break;
+
+ default:
+ return false;
+ }
+
+ Copy(&t->IpAddress, &ip, sizeof(IP));
+
+ return true;
+}
+
+// Parse the deletion payload
+bool IkeParseDeletePayload(IKE_PACKET_DELETE_PAYLOAD *t, BUF *b)
+{
+ IKE_DELETE_HEADER h;
+ UINT num_spi;
+ UINT spi_size;
+ UINT i;
+ bool ok = true;
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ if (ReadBuf(b, &h, sizeof(h)) != sizeof(h))
+ {
+ return false;
+ }
+
+ if (Endian32(h.DoI) != IKE_SA_DOI_IPSEC)
+ {
+ Debug("ISAKMP: Invalid DoI Value: 0x%x\n", Endian32(h.DoI));
+ return false;
+ }
+
+ t->ProtocolId = h.ProtocolId;
+ t->SpiList = NewListFast(NULL);
+ num_spi = Endian16(h.NumSpis);
+ spi_size = h.SpiSize;
+
+ for (i = 0;i < num_spi;i++)
+ {
+ BUF *spi = ReadBufFromBuf(b, spi_size);
+
+ if (spi == NULL)
+ {
+ ok = false;
+ break;
+ }
+
+ Add(t->SpiList, spi);
+ }
+
+ if (ok == false)
+ {
+ IkeFreeDeletePayload(t);
+ return false;
+ }
+
+ return true;
+}
+
+// Release the deletion payload
+void IkeFreeDeletePayload(IKE_PACKET_DELETE_PAYLOAD *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->SpiList != NULL)
+ {
+ for (i = 0;i < LIST_NUM(t->SpiList);i++)
+ {
+ BUF *spi = LIST_DATA(t->SpiList, i);
+
+ FreeBuf(spi);
+ }
+
+ ReleaseList(t->SpiList);
+
+ t->SpiList = NULL;
+ }
+}
+
+// Check whether the hash matches
+bool IkeCompareHash(IKE_PACKET_PAYLOAD *hash_payload, void *hash_data, UINT hash_size)
+{
+ //char tmp1[MAX_SIZE], tmp2[MAX_SIZE];
+ // Validate arguments
+ if (hash_payload == NULL || hash_data == NULL || hash_size == 0)
+ {
+ return false;
+ }
+
+ if (hash_payload->PayloadType != IKE_PAYLOAD_HASH)
+ {
+ return false;
+ }
+
+ if (hash_payload->Payload.Hash.Data == NULL)
+ {
+ return false;
+ }
+
+ if (hash_payload->Payload.Hash.Data->Size != hash_size)
+ {
+ return false;
+ }
+
+ //BinToStrEx(tmp1, sizeof(tmp1), hash_payload->Payload.Hash.Data->Buf, hash_size);
+ //BinToStrEx(tmp2, sizeof(tmp2), hash_data, hash_size);
+
+ //Debug("IkeCompareHash\n 1: %s\n 2: %s\n", tmp1, tmp2);
+
+ if (Cmp(hash_payload->Payload.Hash.Data->Buf, hash_data, hash_size) != 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Parse the data payload
+bool IkeParseDataPayload(IKE_PACKET_DATA_PAYLOAD *t, BUF *b)
+{
+ // Validate arguments
+ if (t == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ t->Data = MemToBuf(b->Buf, b->Size);
+
+ return true;
+}
+
+// Release the data payload
+void IkeFreeDataPayload(IKE_PACKET_DATA_PAYLOAD *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FreeBuf(t->Data);
+}
+
+// Release the IKE payload body
+void IkeFreePayload(IKE_PACKET_PAYLOAD *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ switch (p->PayloadType)
+ {
+ case IKE_PAYLOAD_SA: // SA payload
+ IkeFreeSaPayload(&p->Payload.Sa);
+ break;
+
+ case IKE_PAYLOAD_PROPOSAL: // Proposal payload
+ IkeFreeProposalPayload(&p->Payload.Proposal);
+ break;
+
+ case IKE_PAYLOAD_TRANSFORM: // Proposal payload
+ IkeFreeTransformPayload(&p->Payload.Transform);
+ break;
+
+ case IKE_PAYLOAD_ID: // ID payload
+ IkeFreeIdPayload(&p->Payload.Id);
+ break;
+
+ case IKE_PAYLOAD_CERT: // Certificate payload
+ IkeFreeCertPayload(&p->Payload.Cert);
+ break;
+
+ case IKE_PAYLOAD_CERT_REQUEST: // Certificate request payload
+ IkeFreeCertRequestPayload(&p->Payload.CertRequest);
+ break;
+
+ case IKE_PAYLOAD_NOTICE: // Notification Payload
+ IkeFreeNoticePayload(&p->Payload.Notice);
+ break;
+
+ case IKE_PAYLOAD_DELETE: // Deletion payload
+ IkeFreeDeletePayload(&p->Payload.Delete);
+ break;
+
+ case IKE_PAYLOAD_NAT_OA: // NAT-OD payload
+ case IKE_PAYLOAD_NAT_OA_DRAFT:
+ case IKE_PAYLOAD_NAT_OA_DRAFT_2:
+ // Do Nothing
+ break;
+
+ case IKE_PAYLOAD_KEY_EXCHANGE: // Key exchange payload
+ case IKE_PAYLOAD_HASH: // Hash payload
+ case IKE_PAYLOAD_SIGN: // Signature payload
+ case IKE_PAYLOAD_RAND: // Random number payload
+ case IKE_PAYLOAD_VENDOR_ID: // Vendor ID payload
+ case IKE_PAYLOAD_NAT_D: // NAT-D payload
+ case IKE_PAYLOAD_NAT_D_DRAFT: // NAT-D payload (draft)
+ default:
+ IkeFreeDataPayload(&p->Payload.GeneralData);
+ break;
+ }
+
+ if (p->BitArray != NULL)
+ {
+ FreeBuf(p->BitArray);
+ }
+
+ Free(p);
+}
+
+// Analyse the IKE payload list
+LIST *IkeParsePayloadList(void *data, UINT size, UCHAR first_payload)
+{
+ return IkeParsePayloadListEx(data, size, first_payload, NULL);
+}
+LIST *IkeParsePayloadListEx(void *data, UINT size, UCHAR first_payload, UINT *total_read_size)
+{
+ LIST *o;
+ BUF *b;
+ UCHAR payload_type = first_payload;
+ UINT total = 0;
+ // Validate arguments
+ if (data == NULL)
+ {
+ return NULL;
+ }
+
+ o = NewListFast(NULL);
+ b = MemToBuf(data, size);
+
+ while (payload_type != IKE_PAYLOAD_NONE)
+ {
+ // Read the common header
+ IKE_COMMON_HEADER header;
+ USHORT payload_size;
+ BUF *payload_data;
+ IKE_PACKET_PAYLOAD *pay;
+
+ if (ReadBuf(b, &header, sizeof(header)) != sizeof(header))
+ {
+ Debug("ISAKMP: Broken Packet (Invalid Payload Size)\n");
+
+LABEL_ERROR:
+ // Header reading failure
+ IkeFreePayloadList(o);
+ o = NULL;
+
+ break;
+ }
+
+ total += sizeof(header);
+
+ // Get the payload size
+ payload_size = Endian16(header.PayloadSize);
+
+ if (payload_size < sizeof(header))
+ {
+ Debug("ISAKMP: Broken Packet (Invalid Payload Size)\n");
+ goto LABEL_ERROR;
+ }
+
+ payload_size -= sizeof(header);
+
+ // Read the payload data
+ payload_data = ReadBufFromBuf(b, payload_size);
+ if (payload_data == NULL)
+ {
+ // Data read failure
+ Debug("ISAKMP: Broken Packet (Invalid Payload Data)\n");
+ goto LABEL_ERROR;
+ }
+
+ total += payload_size;
+
+ // Analyse the payload body
+ if (IKE_IS_SUPPORTED_PAYLOAD_TYPE(payload_type))
+ {
+ // Supported payload type
+ pay = IkeParsePayload(payload_type, payload_data);
+
+ if (pay == NULL)
+ {
+ FreeBuf(payload_data);
+ Debug("ISAKMP: Broken Packet (Payload Data Parse Failed)\n");
+ goto LABEL_ERROR;
+ }
+
+ Add(o, pay);
+ }
+ else
+ {
+ // Unsupported payload type
+ Debug("ISAKMP: Ignored Payload Type: %u\n", payload_type);
+ pay = IkeParsePayload(payload_type, payload_data);
+
+ if (pay == NULL)
+ {
+ FreeBuf(payload_data);
+ Debug("ISAKMP: Broken Packet (Payload Data Parse Failed)\n");
+ goto LABEL_ERROR;
+ }
+
+ Add(o, pay);
+ }
+
+ payload_type = header.NextPayload;
+
+ FreeBuf(payload_data);
+ }
+
+ FreeBuf(b);
+
+ if (total_read_size != NULL)
+ {
+ *total_read_size = total;
+ }
+
+ return o;
+}
+
+// Release the IKE payload list
+void IkeFreePayloadList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IKE_PACKET_PAYLOAD *p = LIST_DATA(o, i);
+
+ IkeFreePayload(p);
+ }
+
+ ReleaseList(o);
+}
+
+// Build an IKE packet
+BUF *IkeBuild(IKE_PACKET *p, IKE_CRYPTO_PARAM *cparam)
+{
+ return IkeBuildEx(p, cparam, false);
+}
+BUF *IkeBuildEx(IKE_PACKET *p, IKE_CRYPTO_PARAM *cparam, bool use_original_decrypted)
+{
+ IKE_HEADER h;
+ BUF *msg_buf;
+ BUF *ret;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ if (p->PayloadList == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&h, sizeof(h));
+ h.InitiatorCookie = Endian64(p->InitiatorCookie);
+ h.ResponderCookie = Endian64(p->ResponderCookie);
+ h.NextPayload = IkeGetFirstPayloadType(p->PayloadList);
+ h.Version = IKE_VERSION;
+ h.ExchangeType = p->ExchangeType;
+ h.Flag = (p->FlagEncrypted ? IKE_HEADER_FLAG_ENCRYPTED : 0) |
+ (p->FlagCommit ? IKE_HEADER_FLAG_COMMIT : 0) |
+ (p->FlagAuthOnly ? IKE_HEADER_FLAG_AUTH_ONLY : 0);
+ h.MessageId = Endian32(p->MessageId);
+
+ if (p->DecryptedPayload != NULL && use_original_decrypted)
+ {
+ msg_buf = CloneBuf(p->DecryptedPayload);
+ }
+ else
+ {
+ msg_buf = IkeBuildPayloadList(p->PayloadList);
+ }
+
+ if (p->DecryptedPayload != NULL)
+ {
+ FreeBuf(p->DecryptedPayload);
+ }
+
+ p->DecryptedPayload = CloneBuf(msg_buf);
+
+ if (p->FlagEncrypted)
+ {
+ BUF *b;
+ // Encryption
+ b = IkeEncryptWithPadding(msg_buf->Buf, msg_buf->Size, cparam);
+
+ if (b == NULL)
+ {
+ Debug("ISAKMP: Packet Encrypt Failed\n");
+ FreeBuf(msg_buf);
+ return NULL;
+ }
+
+ FreeBuf(msg_buf);
+
+ msg_buf = b;
+ }
+
+ h.MessageSize = Endian32(msg_buf->Size + sizeof(h));
+
+ ret = NewBuf();
+ WriteBuf(ret, &h, sizeof(h));
+ WriteBufBuf(ret, msg_buf);
+
+ FreeBuf(msg_buf);
+
+ SeekBuf(ret, 0, 0);
+
+ return ret;
+}
+
+// Analyse the IKE packet
+IKE_PACKET *IkeParseEx(void *data, UINT size, IKE_CRYPTO_PARAM *cparam, bool header_only)
+{
+ IKE_PACKET *p = NULL;
+ BUF *b;
+ // Validate arguments
+ if (data == NULL)
+ {
+ return NULL;
+ }
+
+ b = MemToBuf(data, size);
+
+ if (b->Size < sizeof(IKE_HEADER))
+ {
+ Debug("ISAKMP: Invalid Packet Size\n");
+ }
+ else
+ {
+ // Header analysis
+ IKE_HEADER *h = (IKE_HEADER *)b->Buf;
+
+ p = ZeroMalloc(sizeof(IKE_PACKET));
+
+ p->MessageSize = Endian32(h->MessageSize);
+ p->InitiatorCookie = Endian64(h->InitiatorCookie);
+ p->ResponderCookie = Endian64(h->ResponderCookie);
+ p->ExchangeType = h->ExchangeType;
+ p->FlagEncrypted = (h->Flag & IKE_HEADER_FLAG_ENCRYPTED) ? true : false;
+ p->FlagCommit = (h->Flag & IKE_HEADER_FLAG_COMMIT) ? true : false;
+ p->FlagAuthOnly = (h->Flag & IKE_HEADER_FLAG_AUTH_ONLY) ? true : false;
+ p->MessageId = Endian32(h->MessageId);
+
+ if (b->Size < Endian32(h->MessageSize) ||
+ Endian32(h->MessageSize) < sizeof(IKE_HEADER))
+ {
+ Debug("ISAKMP: Invalid Packet Size\n");
+
+ IkeFree(p);
+ p = NULL;
+ }
+ else
+ {
+ if (header_only == false)
+ {
+ bool ok = false;
+ UCHAR *payload_data;
+ UINT payload_size;
+ BUF *buf = NULL;
+
+ payload_data = ((UCHAR *)h) + sizeof(IKE_HEADER);
+ payload_size = Endian32(h->MessageSize) - sizeof(IKE_HEADER);
+
+ // Decrypt if it is encrypted
+ if (p->FlagEncrypted)
+ {
+ buf = IkeDecrypt(payload_data, payload_size, cparam);
+
+ if (buf != NULL)
+ {
+ ok = true;
+
+ payload_data = buf->Buf;
+ payload_size = buf->Size;
+
+ p->DecryptedPayload = CloneBuf(buf);
+ }
+ }
+ else
+ {
+ ok = true;
+ }
+
+ if (ok == false)
+ {
+ Debug("ISAKMP: Decrypt Failed\n");
+
+ IkeFree(p);
+ p = NULL;
+ }
+ else
+ {
+ UINT total_read_size;
+
+ // Payload analysis
+ p->PayloadList = IkeParsePayloadListEx(payload_data,
+ payload_size,
+ h->NextPayload,
+ &total_read_size);
+
+ if (p->DecryptedPayload != NULL)
+ {
+ p->DecryptedPayload->Size = MIN(p->DecryptedPayload->Size, total_read_size);
+ }
+ else
+ {
+ p->DecryptedPayload = MemToBuf(payload_data, payload_size);
+ }
+ }
+
+ if (buf != NULL)
+ {
+ FreeBuf(buf);
+ }
+ }
+ }
+ }
+
+ FreeBuf(b);
+
+ return p;
+}
+IKE_PACKET *IkeParseHeader(void *data, UINT size, IKE_CRYPTO_PARAM *cparam)
+{
+ return IkeParseEx(data, size, cparam, true);
+}
+IKE_PACKET *IkeParse(void *data, UINT size, IKE_CRYPTO_PARAM *cparam)
+{
+ return IkeParseEx(data, size, cparam, false);
+}
+
+// Send packet for debugging by UDP (For debugging with Ethereal)
+void IkeDebugUdpSendRawPacket(IKE_PACKET *p)
+{
+ BUF *b;
+ IP ip;
+ SOCK *udp;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ p->FlagEncrypted = false;
+
+ b = NULL;
+
+ if (b == NULL)
+ {
+ b = IkeBuildEx(p, NULL, true);
+ }
+
+ if (b == NULL)
+ {
+ return;
+ }
+
+ Zero(&ip, sizeof(ip));
+ SetIP(&ip, 1, 2, 3, 4);
+
+ udp = NewUDP(0);
+
+ SendTo(udp, &ip, 500, b->Buf, b->Size);
+
+ ReleaseSock(udp);
+ FreeBuf(b);
+}
+
+// Output the payload list
+void IkeDebugPrintPayloads(LIST *o, UINT depth)
+{
+ UINT i;
+ char space[MAX_SIZE];
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ MakeCharArray2(space, ' ', depth * 2);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IKE_PACKET_PAYLOAD *payload = LIST_DATA(o, i);
+
+ Debug("%s%u: Type = %u, Size = %u\n", space, i, payload->PayloadType, payload->BitArray->Size);
+
+ switch (payload->PayloadType)
+ {
+ case IKE_PAYLOAD_SA:
+ IkeDebugPrintPayloads(payload->Payload.Sa.PayloadList, depth + 1);
+ break;
+
+ case IKE_PAYLOAD_PROPOSAL:
+ IkeDebugPrintPayloads(payload->Payload.Proposal.PayloadList, depth + 1);
+ break;
+ }
+ }
+}
+
+// Encryption (also with padding)
+BUF *IkeEncryptWithPadding(void *data, UINT size, IKE_CRYPTO_PARAM *cparam)
+{
+ UINT total_size;
+ UINT i;
+ UCHAR n = 0;
+ UCHAR *tmp;
+ BUF *ret;
+ UCHAR tmp1600[1600];
+ bool no_free = false;
+ // Validate arguments
+ if (data == NULL || cparam == NULL)
+ {
+ return NULL;
+ }
+
+ total_size = ((size / cparam->Key->Crypto->BlockSize) + ((size % cparam->Key->Crypto->BlockSize) == 0 ? 0 : 1))
+ * cparam->Key->Crypto->BlockSize;
+ if (total_size == 0)
+ {
+ total_size = cparam->Key->Crypto->BlockSize;
+ }
+
+ if (total_size > sizeof(tmp1600))
+ {
+ tmp = Malloc(total_size);
+ }
+ else
+ {
+ tmp = tmp1600;
+ no_free = true;
+ }
+
+ Copy(tmp, data, size);
+
+ for (i = size;i < total_size;i++)
+ {
+ tmp[i] = ++n;
+ }
+
+ ret = IkeEncrypt(tmp, total_size, cparam);
+
+ if (no_free == false)
+ {
+ Free(tmp);
+ }
+
+ return ret;
+}
+
+// Encryption
+BUF *IkeEncrypt(void *data, UINT size, IKE_CRYPTO_PARAM *cparam)
+{
+ void *tmp;
+ BUF *b;
+ UCHAR tmp1600[1600];
+ bool no_free = false;
+ // Validate arguments
+ if (data == NULL || cparam == NULL)
+ {
+ return NULL;
+ }
+
+ if ((size % cparam->Key->Crypto->BlockSize) != 0)
+ {
+ // Not an integral multiple of block size
+ return NULL;
+ }
+
+ if (size > sizeof(tmp1600))
+ {
+ tmp = Malloc(size);
+ }
+ else
+ {
+ tmp = tmp1600;
+ no_free = true;
+ }
+
+ IkeCryptoEncrypt(cparam->Key, tmp, data, size, cparam->Iv);
+
+ if (size >= cparam->Key->Crypto->BlockSize)
+ {
+ Copy(cparam->NextIv, ((UCHAR *)tmp) + (size - cparam->Key->Crypto->BlockSize), cparam->Key->Crypto->BlockSize);
+ }
+ else
+ {
+ Zero(cparam->NextIv, cparam->Key->Crypto->BlockSize);
+ }
+
+ b = MemToBuf(tmp, size);
+
+ if (no_free == false)
+ {
+ Free(tmp);
+ }
+
+ return b;
+}
+
+// Decryption
+BUF *IkeDecrypt(void *data, UINT size, IKE_CRYPTO_PARAM *cparam)
+{
+ void *tmp;
+ BUF *b;
+ UCHAR tmp1600[1600];
+ bool no_free = false;
+ // Validate arguments
+ if (data == NULL || cparam == NULL)
+ {
+ return NULL;
+ }
+
+ if ((size % cparam->Key->Crypto->BlockSize) != 0)
+ {
+ // Not an integral multiple of block size
+ return NULL;
+ }
+
+ if (size > sizeof(tmp1600))
+ {
+ tmp = Malloc(size);
+ }
+ else
+ {
+ tmp = tmp1600;
+ no_free = true;
+ }
+
+ IkeCryptoDecrypt(cparam->Key, tmp, data, size, cparam->Iv);
+
+ if (size >= cparam->Key->Crypto->BlockSize)
+ {
+ Copy(cparam->NextIv, ((UCHAR *)data) + (size - cparam->Key->Crypto->BlockSize), cparam->Key->Crypto->BlockSize);
+ }
+ else
+ {
+ Zero(cparam->NextIv, cparam->Key->Crypto->BlockSize);
+ }
+
+ b = MemToBuf(tmp, size);
+
+ if (no_free == false)
+ {
+ Free(tmp);
+ }
+
+ return b;
+}
+
+// Release the IKE packet
+void IkeFree(IKE_PACKET *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ if (p->PayloadList != NULL)
+ {
+ IkeFreePayloadList(p->PayloadList);
+ }
+
+ if (p->DecryptedPayload != NULL)
+ {
+ FreeBuf(p->DecryptedPayload);
+ }
+
+ Free(p);
+}
+
+// Create an IKE packet
+IKE_PACKET *IkeNew(UINT64 init_cookie, UINT64 resp_cookie, UCHAR exchange_type,
+ bool encrypted, bool commit, bool auth_only, UINT msg_id,
+ LIST *payload_list)
+{
+ IKE_PACKET *p = ZeroMalloc(sizeof(IKE_PACKET));
+
+ p->InitiatorCookie = init_cookie;
+ p->ResponderCookie = resp_cookie;
+ p->ExchangeType = exchange_type;
+ p->FlagEncrypted = encrypted;
+ p->FlagCommit = commit;
+ p->FlagAuthOnly = auth_only;
+ p->MessageId = msg_id;
+ p->PayloadList = payload_list;
+
+ return p;
+}
+
+// Create a new SPI value
+UINT IkeNewSpi()
+{
+ while (true)
+ {
+ UINT i = Rand32();
+
+ if (i >= 4096)
+ {
+ return i;
+ }
+ }
+}
+
+
+// Create an encryption engine for IKE
+IKE_ENGINE *NewIkeEngine()
+{
+ IKE_ENGINE *e = ZeroMalloc(sizeof(IKE_ENGINE));
+ IKE_CRYPTO *des, *des3, *aes;
+ IKE_HASH *sha1, *md5;
+ IKE_DH *dh1, *dh2, *dh5;
+ UINT des_key_sizes[] =
+ {
+ 8,
+ };
+ UINT des3_key_sizes[] =
+ {
+ 24,
+ };
+ UINT aes_key_sizes[] =
+ {
+ 16, 24, 32,
+ };
+
+ e->CryptosList = NewListFast(NULL);
+ e->HashesList = NewListFast(NULL);
+ e->DhsList = NewListFast(NULL);
+
+ //// Encryption algorithm
+ // DES
+ des = NewIkeCrypto(e, IKE_CRYPTO_DES_ID, IKE_CRYPTO_DES_STRING,
+ des_key_sizes, sizeof(des_key_sizes) / sizeof(UINT), 8);
+
+ // 3DES
+ des3 = NewIkeCrypto(e, IKE_CRYPTO_3DES_ID, IKE_CRYPTO_3DES_STRING,
+ des3_key_sizes, sizeof(des3_key_sizes) / sizeof(UINT), 8);
+
+ // AES
+ aes = NewIkeCrypto(e, IKE_CRYPTO_AES_ID, IKE_CRYPTO_AES_STRING,
+ aes_key_sizes, sizeof(aes_key_sizes) / sizeof(UINT), 16);
+
+ //// Hash algorithm
+ // SHA-1
+ sha1 = NewIkeHash(e, IKE_HASH_SHA1_ID, IKE_HASH_SHA1_STRING, 20);
+
+ // MD5
+ md5 = NewIkeHash(e, IKE_HASH_MD5_ID, IKE_HASH_MD5_STRING, 16);
+
+ //// DH algorithm
+ dh1 = NewIkeDh(e, IKE_DH_1_ID, IKE_DH_1_STRING, 96);
+ dh2 = NewIkeDh(e, IKE_DH_2_ID, IKE_DH_2_STRING, 128);
+ dh5 = NewIkeDh(e, IKE_DH_5_ID, IKE_DH_5_STRING, 192);
+
+ // Define the IKE algorithm
+ e->IkeCryptos[IKE_P1_CRYPTO_DES_CBC] = des;
+ e->IkeCryptos[IKE_P1_CRYPTO_3DES_CBC] = des3;
+ e->IkeCryptos[IKE_P1_CRYPTO_AES_CBC] = aes;
+ e->IkeHashes[IKE_P1_HASH_MD5] = md5;
+ e->IkeHashes[IKE_P1_HASH_SHA1] = sha1;
+
+ // Definition of ESP algorithm
+ e->EspCryptos[IKE_TRANSFORM_ID_P2_ESP_DES] = des;
+ e->EspCryptos[IKE_TRANSFORM_ID_P2_ESP_3DES] = des3;
+ e->EspCryptos[IKE_TRANSFORM_ID_P2_ESP_AES] = aes;
+ e->EspHashes[IKE_P2_HMAC_MD5_96] = md5;
+ e->EspHashes[IKE_P2_HMAC_SHA1_96] = sha1;
+
+ // Definition of the DH algorithm
+ e->IkeDhs[IKE_P1_DH_GROUP_768_MODP] = e->EspDhs[IKE_P2_DH_GROUP_768_MODP] = dh1;
+ e->IkeDhs[IKE_P1_DH_GROUP_1024_MODP] = e->EspDhs[IKE_P2_DH_GROUP_1024_MODP] = dh2;
+ e->IkeDhs[IKE_P1_DH_GROUP_1536_MODP] = e->EspDhs[IKE_P2_DH_GROUP_1536_MODP] = dh5;
+
+ return e;
+}
+
+// Release the encryption engine for IKE
+void FreeIkeEngine(IKE_ENGINE *e)
+{
+ UINT i;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(e->CryptosList);i++)
+ {
+ IKE_CRYPTO *c = LIST_DATA(e->CryptosList, i);
+
+ FreeIkeCrypto(c);
+ }
+
+ ReleaseList(e->CryptosList);
+
+ for (i = 0;i < LIST_NUM(e->HashesList);i++)
+ {
+ IKE_HASH *h = LIST_DATA(e->HashesList, i);
+
+ FreeIkeHash(h);
+ }
+ ReleaseList(e->HashesList);
+
+ for (i = 0;i < LIST_NUM(e->DhsList);i++)
+ {
+ IKE_DH *d = LIST_DATA(e->DhsList, i);
+
+ FreeIkeDh(d);
+ }
+ ReleaseList(e->DhsList);
+
+ Free(e);
+}
+
+// Definition of a new DH algorithm for IKE
+IKE_DH *NewIkeDh(IKE_ENGINE *e, UINT dh_id, char *name, UINT key_size)
+{
+ IKE_DH *d;
+ // Validate arguments
+ if (e == NULL || name == NULL || key_size == 0)
+ {
+ return NULL;
+ }
+
+ d = ZeroMalloc(sizeof(IKE_DH));
+
+ d->DhId = dh_id;
+ d->Name = name;
+ d->KeySize = key_size;
+
+ Add(e->DhsList, d);
+
+ return d;
+}
+
+// Definition of a new encryption algorithm for IKE
+IKE_CRYPTO *NewIkeCrypto(IKE_ENGINE *e, UINT crypto_id, char *name, UINT *key_sizes, UINT num_key_sizes, UINT block_size)
+{
+ IKE_CRYPTO *c;
+ UINT i;
+ // Validate arguments
+ if (e == NULL || name == NULL || key_sizes == NULL)
+ {
+ return NULL;
+ }
+
+ c = ZeroMalloc(sizeof(IKE_CRYPTO));
+
+ c->CryptoId = crypto_id;
+ c->Name = name;
+
+ for (i = 0;i < MIN(num_key_sizes, 16);i++)
+ {
+ c->KeySizes[i] = key_sizes[i];
+ }
+
+ if (num_key_sizes >= 2)
+ {
+ c->VariableKeySize = true;
+ }
+
+ c->BlockSize = block_size;
+
+ Add(e->CryptosList, c);
+
+ return c;
+}
+
+// Release the definition of Encryption algorithm for IKE
+void FreeIkeCrypto(IKE_CRYPTO *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ Free(c);
+}
+
+// Release the definition of IKE hash algorithm
+void FreeIkeHash(IKE_HASH *h)
+{
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ Free(h);
+}
+
+// Release the definition of the DH algorithm for IKE
+void FreeIkeDh(IKE_DH *d)
+{
+ // Validate arguments
+ if (d == NULL)
+ {
+ return;
+ }
+
+ Free(d);
+}
+
+// Definition of a new hash algorithm for IKE
+IKE_HASH *NewIkeHash(IKE_ENGINE *e, UINT hash_id, char *name, UINT size)
+{
+ IKE_HASH *h;
+ // Validate arguments
+ if (e == NULL || name == NULL || size == 0)
+ {
+ return NULL;
+ }
+
+ h = ZeroMalloc(sizeof(IKE_HASH));
+
+ h->HashId = hash_id;
+ h->Name = name;
+ h->HashSize = size;
+
+ Add(e->HashesList, h);
+
+ return h;
+}
+
+// Get the encryption algorithm that is used in IKE
+IKE_CRYPTO *GetIkeCrypto(IKE_ENGINE *e, bool for_esp, UINT i)
+{
+ // Validate arguments
+ if (e == NULL || i == 0 || i >= MAX_IKE_ENGINE_ELEMENTS)
+ {
+ return NULL;
+ }
+
+ if (for_esp)
+ {
+ return e->EspCryptos[i];
+ }
+ else
+ {
+ return e->IkeCryptos[i];
+ }
+}
+
+// Get the hash algorithm used in the IKE
+IKE_HASH *GetIkeHash(IKE_ENGINE *e, bool for_esp, UINT i)
+{
+ // Validate arguments
+ if (e == NULL || i == 0 || i >= MAX_IKE_ENGINE_ELEMENTS)
+ {
+ return NULL;
+ }
+
+ if (for_esp)
+ {
+ return e->EspHashes[i];
+ }
+ else
+ {
+ return e->IkeHashes[i];
+ }
+}
+
+// Get the DH algorithm used in the IKE
+IKE_DH *GetIkeDh(IKE_ENGINE *e, bool for_esp, UINT i)
+{
+ // Validate arguments
+ if (e == NULL || i == 0 || i >= MAX_IKE_ENGINE_ELEMENTS)
+ {
+ return NULL;
+ }
+
+ if (for_esp)
+ {
+ return e->EspDhs[i];
+ }
+ else
+ {
+ return e->IkeDhs[i];
+ }
+}
+
+// Perform encryption
+void IkeCryptoEncrypt(IKE_CRYPTO_KEY *k, void *dst, void *src, UINT size, void *ivec)
+{
+ // Validate arguments
+ if (k == NULL || dst == NULL || src == NULL || size == 0 || ivec == NULL)
+ {
+ Zero(dst, size);
+ return;
+ }
+
+ if ((size % k->Crypto->BlockSize) != 0)
+ {
+ Zero(dst, size);
+ return;
+ }
+
+ switch (k->Crypto->CryptoId)
+ {
+ case IKE_CRYPTO_DES_ID: // DES
+ DesEncrypt(dst, src, size, k->DesKey1, ivec);
+ break;
+
+ case IKE_CRYPTO_3DES_ID: // 3DES
+ Des3Encrypt2(dst, src, size, k->DesKey1, k->DesKey2, k->DesKey3, ivec);
+ break;
+
+ case IKE_CRYPTO_AES_ID: // AES
+ AesEncrypt(dst, src, size, k->AesKey, ivec);
+ break;
+
+ default:
+ // Unknown
+ Zero(dst, size);
+ break;
+ }
+}
+
+// Perform decryption
+void IkeCryptoDecrypt(IKE_CRYPTO_KEY *k, void *dst, void *src, UINT size, void *ivec)
+{
+ // Validate arguments
+ if (k == NULL || dst == NULL || src == NULL || size == 0 || ivec == NULL)
+ {
+ Zero(dst, size);
+ return;
+ }
+
+ if ((size % k->Crypto->BlockSize) != 0)
+ {
+ Zero(dst, size);
+ return;
+ }
+
+ switch (k->Crypto->CryptoId)
+ {
+ case IKE_CRYPTO_DES_ID: // DES
+ DesDecrypt(dst, src, size, k->DesKey1, ivec);
+ break;
+
+ case IKE_CRYPTO_3DES_ID: // 3DES
+ Des3Decrypt2(dst, src, size, k->DesKey1, k->DesKey2, k->DesKey3, ivec);
+ break;
+
+ case IKE_CRYPTO_AES_ID: // AES
+ AesDecrypt(dst, src, size, k->AesKey, ivec);
+ break;
+
+ default:
+ // Unknown
+ Zero(dst, size);
+ break;
+ }
+}
+
+// Calculate a hash
+void IkeHash(IKE_HASH *h, void *dst, void *src, UINT size)
+{
+ // Validate arguments
+ if (h == NULL || dst == NULL || (size != 0 && src == NULL))
+ {
+ Zero(dst, size);
+ return;
+ }
+
+ switch (h->HashId)
+ {
+ case IKE_HASH_MD5_ID:
+ // MD5
+ Md5(dst, src, size);
+ break;
+
+ case IKE_HASH_SHA1_ID:
+ // SHA-1
+ Sha1(dst, src, size);
+ break;
+
+ default:
+ // Unknown
+ Zero(dst, size);
+ break;
+ }
+}
+
+// Calculation of HMAC
+void IkeHMac(IKE_HASH *h, void *dst, void *key, UINT key_size, void *data, UINT data_size)
+{
+ UCHAR k[HMAC_BLOCK_SIZE];
+ UCHAR *data1;
+ UCHAR hash1[IKE_MAX_HASH_SIZE];
+ UINT data1_size;
+ UCHAR data2[IKE_MAX_HASH_SIZE + HMAC_BLOCK_SIZE];
+ UINT data2_size;
+ UCHAR tmp1600[1600];
+ bool no_free = false;
+ UINT i;
+ // Validate arguments
+ if (h == NULL || dst == NULL || (key == NULL && key_size != 0) || (data == NULL && data_size != 0))
+ {
+ return;
+ }
+
+ if (h->HashId == IKE_HASH_SHA1_ID)
+ {
+ // Use special function (fast) in the case of SHA-1
+ HMacSha1(dst, key, key_size, data, data_size);
+ return;
+ }
+ else if (h->HashId == IKE_HASH_MD5_ID)
+ {
+ // Use the special function (fast) in the case of MD5
+ HMacMd5(dst, key, key_size, data, data_size);
+ return;
+ }
+
+ // Creating a K
+ Zero(k, sizeof(k));
+ if (key_size <= HMAC_BLOCK_SIZE)
+ {
+ Copy(k, key, key_size);
+ }
+ else
+ {
+ IkeHash(h, k, key, key_size);
+ }
+
+ // Generation of data 1
+ data1_size = data_size + HMAC_BLOCK_SIZE;
+
+ if (data1_size > sizeof(tmp1600))
+ {
+ data1 = Malloc(data1_size);
+ }
+ else
+ {
+ data1 = tmp1600;
+ no_free = true;
+ }
+
+ for (i = 0;i < HMAC_BLOCK_SIZE;i++)
+ {
+ data1[i] = k[i] ^ 0x36;
+ }
+
+ Copy(data1 + HMAC_BLOCK_SIZE, data, data_size);
+
+ // Calculate the hash value
+ IkeHash(h, hash1, data1, data1_size);
+
+ if (no_free == false)
+ {
+ Free(data1);
+ }
+
+ // Generation of data 2
+ data2_size = h->HashSize + HMAC_BLOCK_SIZE;
+
+ for (i = 0;i < HMAC_BLOCK_SIZE;i++)
+ {
+ data2[i] = k[i] ^ 0x5c;
+ }
+
+ Copy(data2 + HMAC_BLOCK_SIZE, hash1, h->HashSize);
+
+ // Calculate the hash value
+ IkeHash(h, dst, data2, data2_size);
+}
+void IkeHMacBuf(IKE_HASH *h, void *dst, BUF *key, BUF *data)
+{
+ // Validate arguments
+ if (h == NULL || dst == NULL || key == NULL || data == NULL)
+ {
+ return;
+ }
+
+ IkeHMac(h, dst, key->Buf, key->Size, data->Buf, data->Size);
+}
+
+// Check whether the key size is valid
+bool IkeCheckKeySize(IKE_CRYPTO *c, UINT size)
+{
+ bool ok = false;
+ UINT i;
+ // Validate arguments
+ if (c == NULL || size == 0)
+ {
+ return false;
+ }
+
+ for (i = 0;i < sizeof(c->KeySizes) / sizeof(UINT);i++)
+ {
+ if (c->KeySizes[i] == size)
+ {
+ ok = true;
+ break;
+ }
+ }
+
+ return ok;
+}
+
+// Create a key
+IKE_CRYPTO_KEY *IkeNewKey(IKE_CRYPTO *c, void *data, UINT size)
+{
+ IKE_CRYPTO_KEY *k;
+ // Validate arguments
+ if (c == NULL || data == NULL || size == 0)
+ {
+ return NULL;
+ }
+
+ if (IkeCheckKeySize(c, size) == false)
+ {
+ return NULL;
+ }
+
+ k = ZeroMalloc(sizeof(IKE_CRYPTO_KEY));
+ k->Crypto = c;
+ k->Data = Clone(data, size);
+ k->Size = size;
+
+ switch (k->Crypto->CryptoId)
+ {
+ case IKE_CRYPTO_DES_ID:
+ // DES 64bit key
+ k->DesKey1 = DesNewKeyValue(data);
+ break;
+
+ case IKE_CRYPTO_3DES_ID:
+ // 3DES 192bit key
+ k->DesKey1 = DesNewKeyValue(((UCHAR *)data) + DES_KEY_SIZE * 0);
+ k->DesKey2 = DesNewKeyValue(((UCHAR *)data) + DES_KEY_SIZE * 1);
+ k->DesKey3 = DesNewKeyValue(((UCHAR *)data) + DES_KEY_SIZE * 2);
+ break;
+
+ case IKE_CRYPTO_AES_ID:
+ // AES variable length key
+ k->AesKey = AesNewKey(data, size);
+ break;
+ }
+
+ return k;
+}
+
+// Release the key
+void IkeFreeKey(IKE_CRYPTO_KEY *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ DesFreeKeyValue(k->DesKey1);
+ DesFreeKeyValue(k->DesKey2);
+ DesFreeKeyValue(k->DesKey3);
+
+ AesFreeKey(k->AesKey);
+
+ Free(k->Data);
+
+ Free(k);
+}
+
+// Create a DH object
+DH_CTX *IkeDhNewCtx(IKE_DH *d)
+{
+ // Validate arguments
+ if (d == NULL)
+ {
+ return NULL;
+ }
+
+ switch (d->DhId)
+ {
+ case IKE_DH_1_ID:
+ return DhNewGroup1();
+
+ case IKE_DH_2_ID:
+ return DhNewGroup2();
+
+ case IKE_DH_5_ID:
+ return DhNewGroup5();
+ }
+
+ return NULL;
+}
+
+// Release the DH object
+void IkeDhFreeCtx(DH_CTX *dh)
+{
+ // Validate arguments
+ if (dh == NULL)
+ {
+ return;
+ }
+
+ DhFree(dh);
+}
+
+
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_IkePacket.h b/src/Cedar/IPsec_IkePacket.h
new file mode 100644
index 00000000..98a10392
--- /dev/null
+++ b/src/Cedar/IPsec_IkePacket.h
@@ -0,0 +1,711 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_IkePacket.h
+// Header of IPsec_IkePacket.c
+
+#ifndef IPSEC_PACKET_H
+#define IPSEC_PACKET_H
+
+// Constants
+#ifdef OS_WIN32
+#pragma pack(push, 1)
+#endif // OS_WIN32
+
+// Maximum hash size
+#define IKE_MAX_HASH_SIZE 20 // Size of SHA-1 is the maximum for now
+
+// Maximum block size
+#define IKE_MAX_BLOCK_SIZE 16 // Size of AES is maximum at the moment
+
+// Maximum key size
+#define IKE_MAX_KEY_SIZE 32 // Size of AES-256 is the maximum for now
+
+// IKE version
+#define IKE_VERSION 0x10 // 1.0
+
+// IKE payload type
+#define IKE_PAYLOAD_NONE 0 // No payload
+#define IKE_PAYLOAD_SA 1 // SA payload
+#define IKE_PAYLOAD_PROPOSAL 2 // Proposal payload
+#define IKE_PAYLOAD_TRANSFORM 3 // Transform payload
+#define IKE_PAYLOAD_KEY_EXCHANGE 4 // Key exchange payload
+#define IKE_PAYLOAD_ID 5 // ID payload
+#define IKE_PAYLOAD_CERT 6 // Certificate payload
+#define IKE_PAYLOAD_CERT_REQUEST 7 // Certificate request payload
+#define IKE_PAYLOAD_HASH 8 // Hash payload
+#define IKE_PAYLOAD_SIGN 9 // Signature payload
+#define IKE_PAYLOAD_RAND 10 // Random number payload
+#define IKE_PAYLOAD_NOTICE 11 // Notification Payload
+#define IKE_PAYLOAD_DELETE 12 // Deletion payload
+#define IKE_PAYLOAD_VENDOR_ID 13 // Vendor ID payload
+#define IKE_PAYLOAD_NAT_D 20 // NAT-D payload
+#define IKE_PAYLOAD_NAT_OA 21 // NAT-OA payload
+#define IKE_PAYLOAD_NAT_D_DRAFT 130 // NAT-D payload draft
+#define IKE_PAYLOAD_NAT_OA_DRAFT 16 // NAT-OA payload draft
+#define IKE_PAYLOAD_NAT_OA_DRAFT_2 131 // NAT-OA payload draft 2
+
+// Macro to check whether the payload type is supported
+#define IKE_IS_SUPPORTED_PAYLOAD_TYPE(i) ((((i) >= IKE_PAYLOAD_SA) && ((i) <= IKE_PAYLOAD_VENDOR_ID)) || ((i) == IKE_PAYLOAD_NAT_D) || ((i) == IKE_PAYLOAD_NAT_OA) || ((i) == IKE_PAYLOAD_NAT_OA_DRAFT) || ((i) == IKE_PAYLOAD_NAT_OA_DRAFT_2) || ((i) == IKE_PAYLOAD_NAT_D_DRAFT))
+
+// IKE header flag
+#define IKE_HEADER_FLAG_ENCRYPTED 1 // Encryption
+#define IKE_HEADER_FLAG_COMMIT 2 // Commit
+#define IKE_HEADER_FLAG_AUTH_ONLY 4 // Only authentication
+
+// IKE payload common header
+struct IKE_COMMON_HEADER
+{
+ UCHAR NextPayload;
+ UCHAR Reserved;
+ USHORT PayloadSize;
+} GCC_PACKED;
+
+// IKE SA payload header
+struct IKE_SA_HEADER
+{
+ UINT DoI; // DOI value
+ UINT Situation; // Situation value
+} GCC_PACKED;
+
+// DOI value in the IKE SA payload
+#define IKE_SA_DOI_IPSEC 1 // IPsec
+
+// Situation value in the IKE SA payload
+#define IKE_SA_SITUATION_IDENTITY 1 // Only authentication
+
+// IKE proposal payload header
+struct IKE_PROPOSAL_HEADER
+{
+ UCHAR Number; // Number
+ UCHAR ProtocolId; // Protocol ID
+ UCHAR SpiSize; // Length of SPI
+ UCHAR NumTransforms; // Transform number
+} GCC_PACKED;
+
+// Protocol ID in the IKE proposal payload header
+#define IKE_PROTOCOL_ID_IKE 1 // IKE
+#define IKE_PROTOCOL_ID_IPSEC_AH 2 // AH
+#define IKE_PROTOCOL_ID_IPSEC_ESP 3 // ESP
+#define IKE_PROTOCOL_ID_IPV4 4 // IP
+#define IKE_PROTOCOL_ID_IPV6 41 // IPv6
+
+// IKE transform payload header
+struct IKE_TRANSFORM_HEADER
+{
+ UCHAR Number; // Number
+ UCHAR TransformId; // Transform ID
+ USHORT Reserved; // Reserved
+} GCC_PACKED;
+
+// Transform ID (Phase 1) in IKE transform payload header
+#define IKE_TRANSFORM_ID_P1_KEY_IKE 1 // IKE
+
+// Transform ID (Phase 2) in IKE transform payload header
+#define IKE_TRANSFORM_ID_P2_ESP_DES 2 // DES-CBC
+#define IKE_TRANSFORM_ID_P2_ESP_3DES 3 // 3DES-CBC
+#define IKE_TRANSFORM_ID_P2_ESP_CAST 6 // CAST
+#define IKE_TRANSFORM_ID_P2_ESP_BLOWFISH 7 // BLOWFISH
+#define IKE_TRANSFORM_ID_P2_ESP_AES 12 // AES
+
+// IKE transform value (fixed length)
+struct IKE_TRANSFORM_VALUE
+{
+ UCHAR AfBit; // AF bit (0: Fixed length, 1: Variable length)
+ UCHAR Type; // Type
+ USHORT Value; // Value data (16bit)
+} GCC_PACKED;
+
+// The Type value in IKE transform value (Phase 1)
+#define IKE_TRANSFORM_VALUE_P1_CRYPTO 1 // Encryption algorithm
+#define IKE_TRANSFORM_VALUE_P1_HASH 2 // Hash algorithm
+#define IKE_TRANSFORM_VALUE_P1_AUTH_METHOD 3 // Authentication method
+#define IKE_TRANSFORM_VALUE_P1_DH_GROUP 4 // DH group number
+#define IKE_TRANSFORM_VALUE_P1_LIFE_TYPE 11 // Expiration date type
+#define IKE_TRANSFORM_VALUE_P1_LIFE_VALUE 12 // Expiration date
+#define IKE_TRANSFORM_VALUE_P1_KET_SIZE 14 // Key size
+
+// The Type value in IKE transform values (Phase 2)
+#define IKE_TRANSFORM_VALUE_P2_LIFE_TYPE 1 // Expiration date type
+#define IKE_TRANSFORM_VALUE_P2_LIFE_VALUE 2 // Expiration date
+#define IKE_TRANSFORM_VALUE_P2_DH_GROUP 3 // DH group number
+#define IKE_TRANSFORM_VALUE_P2_CAPSULE 4 // Encapsulation mode
+#define IKE_TRANSFORM_VALUE_P2_HMAC 5 // HMAC algorithm
+#define IKE_TRANSFORM_VALUE_P2_KEY_SIZE 6 // Key size
+
+// Phase 1: The encryption algorithm in the IKE transform value
+#define IKE_P1_CRYPTO_DES_CBC 1
+#define IKE_P1_CRYPTO_BLOWFISH 3
+#define IKE_P1_CRYPTO_3DES_CBC 5
+#define IKE_P1_CRYPTO_CAST_CBC 6
+#define IKE_P1_CRYPTO_AES_CBC 7
+
+// Phase 1: The hash algorithm in IKE transform value
+#define IKE_P1_HASH_MD5 1
+#define IKE_P1_HASH_SHA1 2
+
+// Phase 1: The authentication method in the IKE transform value
+#define IKE_P1_AUTH_METHOD_PRESHAREDKEY 1
+#define IKE_P1_AUTH_METHOD_RSA_SIGN 3
+
+// Phase 1: The DH group number in the IKE transform value
+#define IKE_P1_DH_GROUP_768_MODP 1
+#define IKE_P1_DH_GROUP_1024_MODP 2
+#define IKE_P1_DH_GROUP_1536_MODP 5
+
+// Phase 1: The expiration date type in IKE transform value
+#define IKE_P1_LIFE_TYPE_SECONDS 1
+#define IKE_P1_LIFE_TYPE_KILOBYTES 2
+
+// Phase 2: The HMAC algorithm in IPsec transform value
+#define IKE_P2_HMAC_MD5_96 1
+#define IKE_P2_HMAC_SHA1_96 2
+
+// Phase 2: The DH group number in the IPsec transform value
+#define IKE_P2_DH_GROUP_768_MODP 1
+#define IKE_P2_DH_GROUP_1024_MODP 2
+#define IKE_P2_DH_GROUP_1536_MODP 5
+
+// Phase 2: The encapsulation mode in IPsec transform value
+#define IKE_P2_CAPSULE_TUNNEL 1
+#define IKE_P2_CAPSULE_TRANSPORT 2
+#define IKE_P2_CAPSULE_NAT_TUNNEL_1 3
+#define IKE_P2_CAPSULE_NAT_TUNNEL_2 61443
+#define IKE_P2_CAPSULE_NAT_TRANSPORT_1 4
+#define IKE_P2_CAPSULE_NAT_TRANSPORT_2 61444
+
+// Phase 2: The expiration date type in IPsec transform value
+#define IKE_P2_LIFE_TYPE_SECONDS 1
+#define IKE_P2_LIFE_TYPE_KILOBYTES 2
+
+
+// IKE ID payload header
+struct IKE_ID_HEADER
+{
+ UCHAR IdType; // Type of ID
+ UCHAR ProtocolId; // Protocol ID
+ USHORT Port; // Port
+} GCC_PACKED;
+
+// Type of ID in the IKE ID payload header
+#define IKE_ID_IPV4_ADDR 1 // IPv4 address (32 bit)
+#define IKE_ID_FQDN 2 // FQDN
+#define IKE_ID_USER_FQDN 3 // User FQDN
+#define IKE_ID_IPV4_ADDR_SUBNET 4 // IPv4 + subnet (64 bit)
+#define IKE_ID_IPV6_ADDR 5 // IPv6 address (128 bit)
+#define IKE_ID_IPV6_ADDR_SUBNET 6 // IPv6 + subnet (256 bit)
+#define IKE_ID_DER_ASN1_DN 9 // X.500 Distinguished Name
+#define IKE_ID_DER_ASN1_GN 10 // X.500 General Name
+#define IKE_ID_KEY_ID 11 // Key
+
+// The protocol ID in the IKE ID payload
+#define IKE_ID_PROTOCOL_UDP IP_PROTO_UDP // UDP
+
+// IKE certificate payload header
+struct IKE_CERT_HEADER
+{
+ UCHAR CertType; // Certificate Type
+} GCC_PACKED;
+
+// The certificate type in IKE certificate payload header
+#define IKE_CERT_TYPE_X509 4 // X.509 certificate (for digital signature)
+
+// IKE certificate payload header
+struct IKE_CERT_REQUEST_HEADER
+{
+ UCHAR CertType; // Certificate Type
+} GCC_PACKED;
+
+// IKE notification payload header
+struct IKE_NOTICE_HEADER
+{
+ UINT DoI; // DOI value
+ UCHAR ProtocolId; // Protocol ID
+ // Same to the protocol ID in the IKE proposal payload header
+ UCHAR SpiSize; // SPI size
+ USHORT MessageType; // Message type
+} GCC_PACKED;
+
+// IKE Deletion payload header
+struct IKE_DELETE_HEADER
+{
+ UINT DoI; // DOI value
+ UCHAR ProtocolId; // Protocol ID
+ // Same to the protocol ID in the IKE proposal payload header
+ UCHAR SpiSize; // SPI size
+ USHORT NumSpis; // SPI number
+} GCC_PACKED;
+
+// IKE NAT-OA payload header
+struct IKE_NAT_OA_HEADER
+{
+ UCHAR IdType; // Type of ID
+ UCHAR Reserved1;
+ USHORT Reserved2;
+} GCC_PACKED;
+
+
+#ifdef OS_WIN32
+#pragma pack(pop)
+#endif // OS_WIN32
+
+
+
+//
+// IKE internal data structure
+//
+
+// IKE packet SA payload
+struct IKE_PACKET_SA_PAYLOAD
+{
+ LIST *PayloadList; // Proposal payload list
+};
+
+// IKE proposal packet payload
+struct IKE_PACKET_PROPOSAL_PAYLOAD
+{
+ UCHAR Number; // Number
+ UCHAR ProtocolId; // Protocol ID
+ BUF *Spi; // SPI data
+
+ LIST *PayloadList; // Payload list
+};
+
+// IKE packet transform payload
+struct IKE_PACKET_TRANSFORM_PAYLOAD
+{
+ UCHAR Number; // Number
+ UCHAR TransformId; // Transform ID
+
+ LIST *ValueList; // Value list
+};
+
+// IKE packet transform value
+struct IKE_PACKET_TRANSFORM_VALUE
+{
+ UCHAR Type; // Type
+ UINT Value; // Value
+};
+
+// IKE generic data payload
+struct IKE_PACKET_DATA_PAYLOAD
+{
+ BUF *Data; // Generic data
+};
+
+// IKE packet ID payload
+struct IKE_PACKET_ID_PAYLOAD
+{
+ UCHAR Type; // Type
+ UCHAR ProtocolId; // Protocol ID
+ USHORT Port; // Port number
+ BUF *IdData; // ID data
+ char StrData[128]; // Data of the result of converting to a string
+};
+
+// IKE packet certificate payload
+struct IKE_PACKET_CERT_PAYLOAD
+{
+ UCHAR CertType; // Certificate type
+ BUF *CertData; // Certificate data
+};
+
+// IKE packet certificate request payload
+struct IKE_PACKET_CERT_REQUEST_PAYLOAD
+{
+ UCHAR CertType; // Certificate type
+ BUF *Data; // Request data
+};
+
+// IKE packet notification payload
+struct IKE_PACKET_NOTICE_PAYLOAD
+{
+ UCHAR ProtocolId; // Protocol ID
+ USHORT MessageType; // Message type
+ BUF *Spi; // SPI data
+ BUF *MessageData; // Message data
+};
+
+// IKE notification message type
+// Error
+#define IKE_NOTICE_ERROR_INVALID_COOKIE 4 // Invalid cookie
+#define IKE_NOTICE_ERROR_INVALID_EXCHANGE_TYPE 7 // Invalid exchange type
+#define IKE_NOTICE_ERROR_INVALID_SPI 11 // Invalid SPI
+#define IKE_NOTICE_ERROR_NO_PROPOSAL_CHOSEN 14 // There is nothing worth mentioning in the presented proposal
+
+// DPD
+#define IKE_NOTICE_DPD_REQUEST 36136 // R-U-THERE
+#define IKE_NOTICE_DPD_RESPONSE 36137 // R-U-THERE-ACK
+
+
+// IKE packet deletion payload
+struct IKE_PACKET_DELETE_PAYLOAD
+{
+ UCHAR ProtocolId; // Protocol ID
+ LIST *SpiList; // SPI list
+};
+
+// IKE NAT-OA payload
+struct IKE_PACKET_NAT_OA_PAYLOAD
+{
+ IP IpAddress; // IP address
+};
+
+// IKE packet payload
+struct IKE_PACKET_PAYLOAD
+{
+ UCHAR PayloadType; // Payload type
+ UCHAR Padding[3];
+ BUF *BitArray; // Bit array
+
+ union
+ {
+ IKE_PACKET_SA_PAYLOAD Sa; // SA payload
+ IKE_PACKET_PROPOSAL_PAYLOAD Proposal; // Proposal payload
+ IKE_PACKET_TRANSFORM_PAYLOAD Transform; // Transform payload
+ IKE_PACKET_DATA_PAYLOAD KeyExchange; // Key exchange payload
+ IKE_PACKET_ID_PAYLOAD Id; // ID payload
+ IKE_PACKET_CERT_PAYLOAD Cert; // Certificate payload
+ IKE_PACKET_CERT_REQUEST_PAYLOAD CertRequest; // Certificate request payload
+ IKE_PACKET_DATA_PAYLOAD Hash; // Hash payload
+ IKE_PACKET_DATA_PAYLOAD Sign; // Signature payload
+ IKE_PACKET_DATA_PAYLOAD Rand; // Random number payload
+ IKE_PACKET_NOTICE_PAYLOAD Notice; // Notification Payload
+ IKE_PACKET_DELETE_PAYLOAD Delete; // Deletion payload
+ IKE_PACKET_DATA_PAYLOAD VendorId; // Vendor ID payload
+ IKE_PACKET_NAT_OA_PAYLOAD NatOa; // NAT-OA payload
+ IKE_PACKET_DATA_PAYLOAD GeneralData; // Generic data payload
+ } Payload;
+};
+
+struct IKE_PACKET
+{
+ UINT64 InitiatorCookie; // Initiator cookie
+ UINT64 ResponderCookie; // Responder cookie
+ UCHAR ExchangeType; // Exchange type
+ bool FlagEncrypted; // Encryption flag
+ bool FlagCommit; // Commit flag
+ bool FlagAuthOnly; // Flag only authentication
+ UINT MessageId; // Message ID
+ LIST *PayloadList; // Payload list
+ BUF *DecryptedPayload; // Decrypted payload
+ UINT MessageSize; // Original size
+};
+
+// IKE P1 key set
+struct IKE_P1_KEYSET
+{
+ BUF *SKEYID_d; // IPsec SA key
+ BUF *SKEYID_a; // IKE SA authentication key
+ BUF *SKEYID_e; // IKE SA encryption key
+};
+
+// Number and name of the encryption algorithm for IKE
+#define IKE_CRYPTO_DES_ID 0
+#define IKE_CRYPTO_DES_STRING "DES-CBC"
+
+#define IKE_CRYPTO_3DES_ID 1
+#define IKE_CRYPTO_3DES_STRING "3DES-CBC"
+
+#define IKE_CRYPTO_AES_ID 2
+#define IKE_CRYPTO_AES_STRING "AES-CBC"
+
+#define IKE_CRYPTO_BLOWFISH_ID 3
+#define IKE_CRYPTO_BLOWFISH_STRING "Blowfish-CBC"
+
+#define IKE_CRYPTO_CAST_ID 4
+#define IKE_CRYPTO_CAST_STRING "CAST-128-CBC"
+
+// Number and name of the IKE hash algorithm
+#define IKE_HASH_MD5_ID 0
+#define IKE_HASH_MD5_STRING "MD5"
+
+#define IKE_HASH_SHA1_ID 1
+#define IKE_HASH_SHA1_STRING "SHA-1"
+
+// Number and name of DH algorithm for IKE
+#define IKE_DH_1_ID 0
+#define IKE_DH_1_STRING "MODP 768 (Group 1)"
+
+#define IKE_DH_2_ID 1
+#define IKE_DH_2_STRING "MODP 1024 (Group 2)"
+
+#define IKE_DH_5_ID 2
+#define IKE_DH_5_STRING "MODP 1536 (Group 5)"
+
+
+// Encryption algorithm for IKE
+struct IKE_CRYPTO
+{
+ UINT CryptoId; // ID
+ char *Name; // Name
+ UINT KeySizes[16]; // Key size candidate
+ UINT BlockSize; // Block size
+ bool VariableKeySize; // Whether the key size is variable
+};
+
+// IKE encryption key
+struct IKE_CRYPTO_KEY
+{
+ IKE_CRYPTO *Crypto;
+ void *Data; // Key data
+ UINT Size; // Key size
+
+ DES_KEY_VALUE *DesKey1, *DesKey2, *DesKey3; // DES key
+ AES_KEY_VALUE *AesKey; // AES key
+};
+
+// IKE hash algorithm
+struct IKE_HASH
+{
+ UINT HashId; // ID
+ char *Name; // Name
+ UINT HashSize; // Output size
+};
+
+// DH algorithm for IKE
+struct IKE_DH
+{
+ UINT DhId; // ID
+ char *Name; // Name
+ UINT KeySize; // Key size
+};
+
+#define MAX_IKE_ENGINE_ELEMENTS 16
+
+// Encryption engine for IKE
+struct IKE_ENGINE
+{
+ IKE_CRYPTO *IkeCryptos[MAX_IKE_ENGINE_ELEMENTS]; // Encryption algorithm list that is used in the IKE
+ IKE_HASH *IkeHashes[MAX_IKE_ENGINE_ELEMENTS]; // Hash algorithm list that is used in the IKE
+ IKE_DH *IkeDhs[MAX_IKE_ENGINE_ELEMENTS]; // DH algorithm list that is used in the IKE
+
+ IKE_CRYPTO *EspCryptos[MAX_IKE_ENGINE_ELEMENTS]; // Encryption algorithm list that is used by ESP
+ IKE_HASH *EspHashes[MAX_IKE_ENGINE_ELEMENTS]; // Hash algorithm list that is used by ESP
+ IKE_DH *EspDhs[MAX_IKE_ENGINE_ELEMENTS]; // DH algorithm list that is used by ESP
+
+ LIST *CryptosList;
+ LIST *HashesList;
+ LIST *DhsList;
+};
+
+// IKE encryption parameters
+struct IKE_CRYPTO_PARAM
+{
+ IKE_CRYPTO_KEY *Key; // Key
+ UCHAR Iv[IKE_MAX_BLOCK_SIZE]; // IV
+ UCHAR NextIv[IKE_MAX_BLOCK_SIZE]; // IV to be used next
+};
+
+
+// Function prototype
+IKE_PACKET *IkeParseHeader(void *data, UINT size, IKE_CRYPTO_PARAM *cparam);
+IKE_PACKET *IkeParse(void *data, UINT size, IKE_CRYPTO_PARAM *cparam);
+IKE_PACKET *IkeParseEx(void *data, UINT size, IKE_CRYPTO_PARAM *cparam, bool header_only);
+void IkeFree(IKE_PACKET *p);
+IKE_PACKET *IkeNew(UINT64 init_cookie, UINT64 resp_cookie, UCHAR exchange_type,
+ bool encrypted, bool commit, bool auth_only, UINT msg_id,
+ LIST *payload_list);
+
+void IkeDebugPrintPayloads(LIST *o, UINT depth);
+void IkeDebugUdpSendRawPacket(IKE_PACKET *p);
+
+BUF *IkeEncrypt(void *data, UINT size, IKE_CRYPTO_PARAM *cparam);
+BUF *IkeEncryptWithPadding(void *data, UINT size, IKE_CRYPTO_PARAM *cparam);
+BUF *IkeDecrypt(void *data, UINT size, IKE_CRYPTO_PARAM *cparam);
+
+LIST *IkeParsePayloadList(void *data, UINT size, UCHAR first_payload);
+LIST *IkeParsePayloadListEx(void *data, UINT size, UCHAR first_payload, UINT *total_read_size);
+void IkeFreePayloadList(LIST *o);
+UINT IkeGetPayloadNum(LIST *o, UINT payload_type);
+IKE_PACKET_PAYLOAD *IkeGetPayload(LIST *o, UINT payload_type, UINT index);
+
+IKE_PACKET_PAYLOAD *IkeParsePayload(UINT payload_type, BUF *b);
+void IkeFreePayload(IKE_PACKET_PAYLOAD *p);
+bool IkeParseDataPayload(IKE_PACKET_DATA_PAYLOAD *t, BUF *b);
+void IkeFreeDataPayload(IKE_PACKET_DATA_PAYLOAD *t);
+bool IkeParseSaPayload(IKE_PACKET_SA_PAYLOAD *t, BUF *b);
+void IkeFreeSaPayload(IKE_PACKET_SA_PAYLOAD *t);
+bool IkeParseProposalPayload(IKE_PACKET_PROPOSAL_PAYLOAD *t, BUF *b);
+void IkeFreeProposalPayload(IKE_PACKET_PROPOSAL_PAYLOAD *t);
+bool IkeParseTransformPayload(IKE_PACKET_TRANSFORM_PAYLOAD *t, BUF *b);
+void IkeFreeTransformPayload(IKE_PACKET_TRANSFORM_PAYLOAD *t);
+LIST *IkeParseTransformValueList(BUF *b);
+void IkeFreeTransformValueList(LIST *o);
+bool IkeParseIdPayload(IKE_PACKET_ID_PAYLOAD *t, BUF *b);
+void IkeFreeIdPayload(IKE_PACKET_ID_PAYLOAD *t);
+bool IkeParseCertPayload(IKE_PACKET_CERT_PAYLOAD *t, BUF *b);
+void IkeFreeCertPayload(IKE_PACKET_CERT_PAYLOAD *t);
+bool IkeParseCertRequestPayload(IKE_PACKET_CERT_REQUEST_PAYLOAD *t, BUF *b);
+void IkeFreeCertRequestPayload(IKE_PACKET_CERT_REQUEST_PAYLOAD *t);
+bool IkeParseNoticePayload(IKE_PACKET_NOTICE_PAYLOAD *t, BUF *b);
+void IkeFreeNoticePayload(IKE_PACKET_NOTICE_PAYLOAD *t);
+bool IkeParseDeletePayload(IKE_PACKET_DELETE_PAYLOAD *t, BUF *b);
+void IkeFreeDeletePayload(IKE_PACKET_DELETE_PAYLOAD *t);
+bool IkeParseNatOaPayload(IKE_PACKET_NAT_OA_PAYLOAD *t, BUF *b);
+
+
+bool IkeCompareHash(IKE_PACKET_PAYLOAD *hash_payload, void *hash_data, UINT hash_size);
+
+IKE_PACKET_PAYLOAD *IkeNewPayload(UINT payload_type);
+IKE_PACKET_PAYLOAD *IkeNewDataPayload(UCHAR payload_type, void *data, UINT size);
+IKE_PACKET_PAYLOAD *IkeNewNatOaPayload(UCHAR payload_type, IP *ip);
+IKE_PACKET_PAYLOAD *IkeNewSaPayload(LIST *payload_list);
+IKE_PACKET_PAYLOAD *IkeNewProposalPayload(UCHAR number, UCHAR protocol_id, void *spi, UINT spi_size, LIST *payload_list);
+IKE_PACKET_PAYLOAD *IkeNewTransformPayload(UCHAR number, UCHAR transform_id, LIST *value_list);
+IKE_PACKET_TRANSFORM_VALUE *IkeNewTransformValue(UCHAR type, UINT value);
+IKE_PACKET_PAYLOAD *IkeNewIdPayload(UCHAR id_type, UCHAR protocol_id, USHORT port, void *id_data, UINT id_size);
+IKE_PACKET_PAYLOAD *IkeNewCertPayload(UCHAR cert_type, void *cert_data, UINT cert_size);
+IKE_PACKET_PAYLOAD *IkeNewCertRequestPayload(UCHAR cert_type, void *data, UINT size);
+IKE_PACKET_PAYLOAD *IkeNewNoticePayload(UCHAR protocol_id, USHORT message_type,
+ void *spi, UINT spi_size,
+ void *message, UINT message_size);
+IKE_PACKET_PAYLOAD *IkeNewDeletePayload(UCHAR protocol_id, LIST *spi_list);
+
+IKE_PACKET_PAYLOAD *IkeNewNoticeErrorInvalidCookiePayload(UINT64 init_cookie, UINT64 resp_cookie);
+IKE_PACKET_PAYLOAD *IkeNewNoticeErrorInvalidExchangeTypePayload(UINT64 init_cookie, UINT64 resp_cookie, UCHAR exchange_type);
+IKE_PACKET_PAYLOAD *IkeNewNoticeErrorInvalidSpiPayload(UINT spi);
+IKE_PACKET_PAYLOAD *IkeNewNoticeErrorNoProposalChosenPayload(bool quick_mode, UINT64 init_cookie, UINT64 resp_cookie);
+IKE_PACKET_PAYLOAD *IkeNewNoticeDpdPayload(bool ack, UINT64 init_cookie, UINT64 resp_cookie, UINT seq_no);
+
+UCHAR IkeGetFirstPayloadType(LIST *o);
+BUF *IkeBuild(IKE_PACKET *p, IKE_CRYPTO_PARAM *cparam);
+BUF *IkeBuildEx(IKE_PACKET *p, IKE_CRYPTO_PARAM *cparam, bool use_original_decrypted);
+BUF *IkeBuildPayloadList(LIST *o);
+BUF *IkeBuildPayload(IKE_PACKET_PAYLOAD *p);
+BUF *IkeBuildDataPayload(IKE_PACKET_DATA_PAYLOAD *t);
+BUF *IkeBuildSaPayload(IKE_PACKET_SA_PAYLOAD *t);
+BUF *IkeBuildProposalPayload(IKE_PACKET_PROPOSAL_PAYLOAD *t);
+BUF *IkeBuildTransformPayload(IKE_PACKET_TRANSFORM_PAYLOAD *t);
+BUF *IkeBuildTransformValue(IKE_PACKET_TRANSFORM_VALUE *v);
+BUF *IkeBuildTransformValueList(LIST *o);
+BUF *IkeBuildIdPayload(IKE_PACKET_ID_PAYLOAD *t);
+BUF *IkeBuildCertPayload(IKE_PACKET_CERT_PAYLOAD *t);
+BUF *IkeBuildCertRequestPayload(IKE_PACKET_CERT_REQUEST_PAYLOAD *t);
+BUF *IkeBuildNoticePayload(IKE_PACKET_NOTICE_PAYLOAD *t);
+BUF *IkeBuildDeletePayload(IKE_PACKET_DELETE_PAYLOAD *t);
+
+BUF *IkeBuildTransformPayload(IKE_PACKET_TRANSFORM_PAYLOAD *t);
+UINT IkeGetTransformValue(IKE_PACKET_TRANSFORM_PAYLOAD *t, UINT type, UINT index);
+UINT IkeGetTransformValueNum(IKE_PACKET_TRANSFORM_PAYLOAD *t, UINT type);
+
+UCHAR IkeStrToPhase1CryptId(char *name);
+UCHAR IkeStrToPhase1HashId(char *name);
+UCHAR IkeStrToPhase2CryptId(char *name);
+UCHAR IkeStrToPhase2HashId(char *name);
+BUF *IkeStrToPassword(char *str);
+UINT IkePhase1CryptIdToKeySize(UCHAR id);
+UINT IkePhase2CryptIdToKeySize(UCHAR id);
+
+UINT IkeNewSpi();
+
+IKE_ENGINE *NewIkeEngine();
+IKE_CRYPTO *NewIkeCrypto(IKE_ENGINE *e, UINT crypto_id, char *name, UINT *key_sizes, UINT num_key_sizes, UINT block_size);
+IKE_HASH *NewIkeHash(IKE_ENGINE *e, UINT hash_id, char *name, UINT size);
+IKE_DH *NewIkeDh(IKE_ENGINE *e, UINT dh_id, char *name, UINT key_size);
+void FreeIkeEngine(IKE_ENGINE *e);
+void FreeIkeCrypto(IKE_CRYPTO *c);
+void FreeIkeHash(IKE_HASH *h);
+void FreeIkeDh(IKE_DH *d);
+IKE_CRYPTO *GetIkeCrypto(IKE_ENGINE *e, bool for_esp, UINT i);
+IKE_HASH *GetIkeHash(IKE_ENGINE *e, bool for_esp, UINT i);
+IKE_DH *GetIkeDh(IKE_ENGINE *e, bool for_esp, UINT i);
+
+void IkeHash(IKE_HASH *h, void *dst, void *src, UINT size);
+void IkeHMac(IKE_HASH *h, void *dst, void *key, UINT key_size, void *data, UINT data_size);
+void IkeHMacBuf(IKE_HASH *h, void *dst, BUF *key, BUF *data);
+
+IKE_CRYPTO_KEY *IkeNewKey(IKE_CRYPTO *c, void *data, UINT size);
+bool IkeCheckKeySize(IKE_CRYPTO *c, UINT size);
+void IkeFreeKey(IKE_CRYPTO_KEY *k);
+void IkeCryptoEncrypt(IKE_CRYPTO_KEY *k, void *dst, void *src, UINT size, void *ivec);
+void IkeCryptoDecrypt(IKE_CRYPTO_KEY *k, void *dst, void *src, UINT size, void *ivec);
+
+DH_CTX *IkeDhNewCtx(IKE_DH *d);
+void IkeDhFreeCtx(DH_CTX *dh);
+
+
+#endif // IPSEC_PACKET_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_L2TP.c b/src/Cedar/IPsec_L2TP.c
new file mode 100644
index 00000000..6a4ecf6a
--- /dev/null
+++ b/src/Cedar/IPsec_L2TP.c
@@ -0,0 +1,2498 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_L2TP.c
+// L2TP protocol stack
+
+#include "CedarPch.h"
+
+// Release the L2TP AVP value
+void FreeL2TPAVP(L2TP_AVP *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ if (a->Data != NULL)
+ {
+ Free(a->Data);
+ }
+
+ Free(a);
+}
+
+// Release the L2TP packet
+void FreeL2TPPacket(L2TP_PACKET *p)
+{
+ UINT i;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ if (p->AvpList != NULL)
+ {
+ for (i = 0;i < LIST_NUM(p->AvpList);i++)
+ {
+ L2TP_AVP *a = LIST_DATA(p->AvpList, i);
+
+ FreeL2TPAVP(a);
+ }
+
+ ReleaseList(p->AvpList);
+ }
+
+ if (p->Data != NULL)
+ {
+ Free(p->Data);
+ }
+
+ Free(p);
+}
+
+// Send an L2TP control packet
+void SendL2TPControlPacket(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, UINT session_id, L2TP_PACKET *p)
+{
+ BUF *buf;
+ L2TP_QUEUE *q;
+ // Validate arguments
+ if (l2tp == NULL || t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ p->IsControl = true;
+ p->TunnelId = t->TunnelId1;
+ p->SessionId = session_id;
+
+ p->Ns = t->NextNs;
+ t->NextNs++;
+
+ p->Nr = t->LastNr + 1;
+
+ buf = BuildL2TPPacketData(p);
+
+ q = ZeroMalloc(sizeof(L2TP_QUEUE));
+ q->Buf = buf;
+ q->Ns = p->Ns;
+ q->NextSendTick = l2tp->Now + (UINT64)L2TP_PACKET_RESEND_INTERVAL;
+ SendL2TPControlPacketMain(l2tp, t, q);
+
+ L2TPAddInterrupt(l2tp, q->NextSendTick);
+
+ Add(t->SendQueue, q);
+
+}
+
+// Specify the interrupt occurrence time of the next
+void L2TPAddInterrupt(L2TP_SERVER *l2tp, UINT64 next_tick)
+{
+ // Validate arguments
+ if (l2tp == NULL || next_tick == 0)
+ {
+ return;
+ }
+
+ AddInterrupt(l2tp->Interrupts, next_tick);
+}
+
+// Send a L2TP data packet
+void SendL2TPDataPacket(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s, void *data, UINT size)
+{
+ UDPPACKET *p;
+ UCHAR *buf;
+ UINT buf_size;
+ // Validate arguments
+ if (l2tp == NULL || t == NULL || s == NULL || (size != 0 && data == NULL))
+ {
+ return;
+ }
+
+ // Build a L2TP data packet
+ if (s->IsV3 == false)
+ {
+ // L2TP Ver 2
+ buf_size = 8 + size;
+ buf = Malloc(buf_size);
+ buf[0] = 0x40;
+ buf[1] = 0x02;
+
+ WRITE_USHORT(buf + 2, buf_size);
+ WRITE_USHORT(buf + 4, t->TunnelId1);
+ WRITE_USHORT(buf + 6, s->SessionId1);
+
+ Copy(buf + 8, data, size);
+
+ // Transmission
+ p = NewUdpPacket(&t->ServerIp, t->ServerPort, &t->ClientIp, t->ClientPort, buf, buf_size);
+ }
+ else
+ {
+ // L2TPv3
+ buf_size = 4 + size;
+ buf = Malloc(buf_size);
+
+ WRITE_UINT(buf, s->SessionId1);
+
+ Copy(buf + 4, data, size);
+
+ // Transmission
+ p = NewUdpPacket(&t->ServerIp, IPSEC_PORT_L2TPV3_VIRTUAL, &t->ClientIp, IPSEC_PORT_L2TPV3_VIRTUAL, buf, buf_size);
+ }
+
+ L2TPSendUDP(l2tp, p);
+}
+
+// L2TP packet transmission main
+void SendL2TPControlPacketMain(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_QUEUE *q)
+{
+ UDPPACKET *p;
+ // Validate arguments
+ if (l2tp == NULL || t == NULL || q == NULL)
+ {
+ return;
+ }
+
+ p = NewUdpPacket(&t->ServerIp, t->ServerPort, &t->ClientIp, t->ClientPort,
+ Clone(q->Buf->Buf, q->Buf->Size), q->Buf->Size);
+
+ // Update the received sequence number
+ WRITE_USHORT(((UCHAR *)p->Data) + (p->SrcPort == IPSEC_PORT_L2TPV3_VIRTUAL ? 14 : 10), t->LastNr + 1);
+
+ L2TPSendUDP(l2tp, p);
+}
+
+// Send a UDP packet
+void L2TPSendUDP(L2TP_SERVER *l2tp, UDPPACKET *p)
+{
+ // Validate arguments
+ if (l2tp == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Add(l2tp->SendPacketList, p);
+}
+
+// Build a L2TP packet
+BUF *BuildL2TPPacketData(L2TP_PACKET *pp)
+{
+ BUF *ret;
+ UCHAR c;
+ USHORT us;
+ UINT ui;
+ // Validate arguments
+ if (pp == NULL)
+ {
+ return NULL;
+ }
+
+ ret = NewBuf();
+
+ c = 0;
+
+ if (pp->Ver == 3)
+ {
+ if (pp->SessionId != 0)
+ {
+ // Add the Remote Session ID AVP
+ L2TP_AVP *a = GetAVPValue(pp, L2TP_AVP_TYPE_V3_SESSION_ID_REMOTE);
+ if (a == NULL || a->DataSize != sizeof(UINT))
+ {
+ UINT ui = Endian32(pp->SessionId);
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_V3_SESSION_ID_REMOTE, true, 0, &ui, sizeof(UINT)));
+
+ if (GetAVPValueEx(pp, L2TPV3_CISCO_AVP_SESSION_ID_LOCAL, L2TP_AVP_VENDOR_ID_CISCO) != NULL)
+ {
+ Add(pp->AvpList, NewAVP(L2TPV3_CISCO_AVP_SESSION_ID_REMOTE, true, L2TP_AVP_VENDOR_ID_CISCO, &ui, sizeof(UINT)));
+ }
+ }
+ }
+ }
+
+ if (pp->Ver == 3)
+ {
+ // Zero as Session ID
+ ui = 0;
+ WriteBuf(ret, &ui, sizeof(UINT));
+ }
+
+ // Flags
+ if (pp->IsControl)
+ {
+ c |= L2TP_HEADER_BIT_TYPE;
+ c |= L2TP_HEADER_BIT_LENGTH;
+ c |= L2TP_HEADER_BIT_SEQUENCE;
+ }
+ else
+ {
+ c |= L2TP_HEADER_BIT_OFFSET;
+ }
+
+ WriteBuf(ret, &c, 1);
+
+ // Ver
+ c = 2;
+ if (pp->Ver == 3)
+ {
+ c = 3;
+ }
+ WriteBuf(ret, &c, 1);
+
+ // Length
+ if (pp->IsControl)
+ {
+ us = 0;
+ WriteBuf(ret, &us, sizeof(USHORT));
+ }
+
+ // Tunnel ID
+ if (pp->Ver != 3)
+ {
+ us = Endian16((USHORT)pp->TunnelId);
+ WriteBuf(ret, &us, sizeof(USHORT));
+ }
+ else
+ {
+ ui = Endian32(pp->TunnelId);
+ WriteBuf(ret, &ui, sizeof(UINT));
+ }
+
+ // Session ID
+ if (pp->Ver != 3)
+ {
+ us = Endian16((USHORT)pp->SessionId);
+ WriteBuf(ret, &us, sizeof(USHORT));
+ }
+
+ if (pp->IsControl)
+ {
+ // Ns
+ us = Endian16(pp->Ns);
+ WriteBuf(ret, &us, sizeof(USHORT));
+
+ // Nr
+ us = Endian16(pp->Nr);
+ WriteBuf(ret, &us, sizeof(USHORT));
+ }
+ else
+ {
+ // Offset Size = 0
+ us = 0;
+ WriteBuf(ret, &us, sizeof(USHORT));
+ }
+
+ if (pp->IsControl)
+ {
+ // AVP
+ UINT i;
+ for (i = 0;i < LIST_NUM(pp->AvpList);i++)
+ {
+ L2TP_AVP *a = LIST_DATA(pp->AvpList, i);
+
+ // Length and Flags
+ us = Endian16(a->DataSize + 6);
+
+ if (a->Mandatory)
+ {
+ *((UCHAR *)&us) |= L2TP_AVP_BIT_MANDATORY;
+ }
+
+ WriteBuf(ret, &us, sizeof(USHORT));
+
+ // Vendor ID
+ us = Endian16(a->VendorID);
+ WriteBuf(ret, &us, sizeof(USHORT));
+
+ // Type
+ us = Endian16(a->Type);
+ WriteBuf(ret, &us, sizeof(USHORT));
+
+ // Data
+ WriteBuf(ret, a->Data, a->DataSize);
+ }
+ }
+ else
+ {
+ // Payload
+ WriteBuf(ret, pp->Data, pp->DataSize);
+ }
+
+ if (pp->IsControl)
+ {
+ // Update Length
+ WRITE_USHORT(((UCHAR *)ret->Buf) + 2 + (pp->Ver == 3 ? sizeof(UINT) : 0), (USHORT)(ret->Size - (pp->Ver == 3 ? sizeof(UINT) : 0)));
+ }
+
+ SeekBuf(ret, 0, 0);
+
+ return ret;
+}
+
+// Parse the L2TP packet
+L2TP_PACKET *ParseL2TPPacket(UDPPACKET *p)
+{
+ L2TP_PACKET *ret;
+ UCHAR *buf;
+ UINT size;
+ bool is_l2tpv3 = false;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ ret = ZeroMalloc(sizeof(L2TP_PACKET));
+
+ if (p->SrcPort == IPSEC_PORT_L2TPV3_VIRTUAL)
+ {
+ // It is L2TPv3
+ is_l2tpv3 = true;
+ }
+
+ buf = p->Data;
+ size = p->Size;
+
+ if (is_l2tpv3)
+ {
+ UINT session_id;
+ // In the case of L2TPv3
+ if (size < 4)
+ {
+ goto LABEL_ERROR;
+ }
+
+ session_id = READ_UINT(buf);
+
+ if (session_id != 0)
+ {
+ // L2TPv3 data packet reception
+ ret->SessionId = session_id;
+
+ buf += sizeof(UINT);
+ size -= sizeof(UINT);
+
+ ret->Data = Clone(buf, size);
+ ret->DataSize = size;
+
+ ret->Ver = 3;
+
+ return ret;
+ }
+ else
+ {
+ // L2TPv3 control packet reception
+ buf += sizeof(UINT);
+ size -= sizeof(UINT);
+ }
+ }
+
+ // L2TP
+ if (size < 6)
+ {
+ goto LABEL_ERROR;
+ }
+
+ if (*buf & L2TP_HEADER_BIT_TYPE)
+ {
+ ret->IsControl = true;
+ }
+
+ if (*buf & L2TP_HEADER_BIT_LENGTH)
+ {
+ ret->HasLength = true;
+ }
+
+ if (*buf & L2TP_HEADER_BIT_SEQUENCE)
+ {
+ ret->HasSequence = true;
+ }
+
+ if (is_l2tpv3 == false)
+ {
+ if (*buf & L2TP_HEADER_BIT_OFFSET)
+ {
+ ret->HasOffset = true;
+ }
+
+ if (*buf & L2TP_HEADER_BIT_PRIORITY)
+ {
+ ret->IsPriority = true;
+ }
+ }
+
+ buf++;
+ size--;
+
+ ret->Ver = *buf & L2TP_HEADER_BIT_VER;
+
+ buf++;
+ size--;
+
+ if (is_l2tpv3 == false)
+ {
+ // L2TP
+ if (ret->Ver != 2)
+ {
+ goto LABEL_ERROR;
+ }
+ }
+ else
+ {
+ // L2TPv3
+ if (ret->Ver != 3)
+ {
+ goto LABEL_ERROR;
+ }
+ }
+
+ if (ret->IsControl)
+ {
+ if (ret->HasLength == false || ret->HasSequence == false)
+ {
+ goto LABEL_ERROR;
+ }
+ }
+ else
+ {
+ /*if (ret->HasSequence)
+ {
+ goto LABEL_ERROR;
+ }*/
+ }
+
+ if (ret->HasLength)
+ {
+ // Length
+ if (size < 2)
+ {
+ goto LABEL_ERROR;
+ }
+ ret->Length = READ_USHORT(buf);
+ buf += 2;
+ size -= 2;
+
+ if (size < (ret->Length - 4))
+ {
+ goto LABEL_ERROR;
+ }
+
+ size = ret->Length - 4;
+ }
+
+ // Tunnel ID, Session ID
+ if (size < 4)
+ {
+ goto LABEL_ERROR;
+ }
+
+ if (is_l2tpv3 == false)
+ {
+ // L2TP
+ ret->TunnelId = READ_USHORT(buf);
+ buf += 2;
+ size -= 2;
+
+ ret->SessionId = READ_USHORT(buf);
+ buf += 2;
+ size -= 2;
+ }
+ else
+ {
+ // L2TPv3: Only tunnel ID is written in the header
+ ret->TunnelId = READ_UINT(buf);
+ buf += 4;
+ size -= 4;
+
+ // The session ID is not written in the header
+ ret->SessionId = 0;
+ }
+
+ if (ret->HasSequence)
+ {
+ // Ns, Nr
+ if (size < 4)
+ {
+ goto LABEL_ERROR;
+ }
+
+ ret->Ns = READ_USHORT(buf);
+ buf += 2;
+ size -= 2;
+
+ ret->Nr = READ_USHORT(buf);
+ buf += 2;
+ size -= 2;
+ }
+
+ if (ret->HasOffset)
+ {
+ // Offset
+ if (size < 2)
+ {
+ goto LABEL_ERROR;
+ }
+
+ ret->OffsetSize = READ_USHORT(buf);
+ buf += 2;
+ size -= 2;
+
+ if (size < ret->OffsetSize)
+ {
+ goto LABEL_ERROR;
+ }
+
+ buf += ret->OffsetSize;
+ size -= ret->OffsetSize;
+ }
+
+ ret->DataSize = size;
+ ret->Data = Clone(buf, ret->DataSize);
+
+ if (ret->IsControl == false)
+ {
+ if (ret->DataSize == 0)
+ {
+ goto LABEL_ERROR;
+ }
+ }
+
+ if (ret->IsControl)
+ {
+ if (ret->DataSize == 0)
+ {
+ ret->IsZLB = true;
+ }
+ }
+
+ if (ret->IsControl)
+ {
+ ret->AvpList = NewListFast(NULL);
+
+ // Parse the AVP field
+ while (size != 0)
+ {
+ L2TP_AVP a;
+
+ Zero(&a, sizeof(a));
+
+ // Header
+ if (size < 6)
+ {
+ goto LABEL_ERROR;
+ }
+
+ if (*buf & L2TP_AVP_BIT_MANDATORY)
+ {
+ a.Mandatory = true;
+ }
+
+ if (*buf & L2TP_AVP_BIT_HIDDEN)
+ {
+ goto LABEL_ERROR;
+ }
+
+ a.Length = READ_USHORT(buf) & L2TP_AVP_LENGTH;
+
+ if (a.Length < 6)
+ {
+ goto LABEL_ERROR;
+ }
+
+ buf += 2;
+ size -= 2;
+
+ a.VendorID = READ_USHORT(buf);
+ buf += 2;
+ size -= 2;
+
+ a.Type = READ_USHORT(buf);
+ buf += 2;
+ size -= 2;
+
+ a.DataSize = a.Length - 6;
+ a.Data = Clone(buf, a.DataSize);
+
+ buf += a.DataSize;
+ size -= a.DataSize;
+
+ Add(ret->AvpList, Clone(&a, sizeof(a)));
+ }
+ }
+
+ if (ret->IsControl && ret->IsZLB == false)
+ {
+ // Get the MessageType in the case of Control packet
+ L2TP_AVP *a = GetAVPValue(ret, L2TP_AVP_TYPE_MESSAGE_TYPE);
+ if (a == NULL || a->DataSize != 2)
+ {
+ goto LABEL_ERROR;
+ }
+
+ ret->MessageType = READ_USHORT(a->Data);
+ }
+
+ if (ret->Ver == 3)
+ {
+ // Get the Remote Session ID in the case of L2TPv3
+ L2TP_AVP *a = GetAVPValue(ret, L2TP_AVP_TYPE_V3_SESSION_ID_REMOTE);
+ if (a != NULL && a->DataSize == sizeof(UINT))
+ {
+ ret->SessionId = READ_UINT(a->Data);
+ }
+ }
+
+ return ret;
+
+LABEL_ERROR:
+ FreeL2TPPacket(ret);
+ return NULL;
+}
+
+// Get the AVP value
+L2TP_AVP *GetAVPValue(L2TP_PACKET *p, UINT type)
+{
+ return GetAVPValueEx(p, type, 0);
+}
+L2TP_AVP *GetAVPValueEx(L2TP_PACKET *p, UINT type, UINT vendor_id)
+{
+ UINT i;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(p->AvpList);i++)
+ {
+ L2TP_AVP *a = LIST_DATA(p->AvpList, i);
+
+ if (a->Type == type && a->VendorID == vendor_id)
+ {
+ return a;
+ }
+ }
+
+ return NULL;
+}
+
+// Release the L2TP transmission queue
+void FreeL2TPQueue(L2TP_QUEUE *q)
+{
+ // Validate arguments
+ if (q == NULL)
+ {
+ return;
+ }
+
+ FreeBuf(q->Buf);
+
+ FreeL2TPPacket(q->L2TPPacket);
+
+ Free(q);
+}
+
+// Sort function of L2TP reception queue
+int CmpL2TPQueueForRecv(void *p1, void *p2)
+{
+ L2TP_QUEUE *q1, *q2;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ q1 = *(L2TP_QUEUE **)p1;
+ q2 = *(L2TP_QUEUE **)p2;
+ if (q1 == NULL || q2 == NULL)
+ {
+ return 0;
+ }
+
+ if (L2TP_SEQ_LT(q1->Ns, q2->Ns))
+ {
+ return -1;
+ }
+ else if (q1->Ns == q2->Ns)
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+// Create a L2TP tunnel
+L2TP_TUNNEL *NewL2TPTunnel(L2TP_SERVER *l2tp, L2TP_PACKET *p, UDPPACKET *udp)
+{
+ L2TP_TUNNEL *t;
+ L2TP_AVP *a;
+ // Validate arguments
+ if (l2tp == NULL || p == NULL || udp == NULL)
+ {
+ return NULL;
+ }
+
+ t = ZeroMalloc(sizeof(L2TP_TUNNEL));
+
+ if (p->Ver == 3)
+ {
+ t->IsV3 = true;
+ }
+
+ t->SessionList = NewList(NULL);
+
+ Copy(&t->ClientIp, &udp->SrcIP, sizeof(IP));
+ t->ClientPort = udp->SrcPort;
+
+ Copy(&t->ServerIp, &udp->DstIP, sizeof(IP));
+ t->ServerPort = udp->DestPort;
+
+ // Hostname
+ a = GetAVPValue(p, L2TP_AVP_TYPE_HOST_NAME);
+ if (a != NULL && a->DataSize >= 1 && a->DataSize < sizeof(t->HostName))
+ {
+ Copy(t->HostName, a->Data, a->DataSize);
+ }
+ else
+ {
+ IPToStr(t->HostName, sizeof(t->HostName), &t->ClientIp);
+ }
+
+ // Vendor Name
+ a = GetAVPValue(p, L2TP_AVP_TYPE_VENDOR_NAME);
+ if (a != NULL && a->DataSize >= 1 && a->DataSize < sizeof(t->VendorName))
+ {
+ Copy(t->VendorName, a->Data, a->DataSize);
+ }
+
+ // Assigned Tunnel ID
+ a = GetAVPValue(p, (p->Ver == 3 ? L2TP_AVP_TYPE_V3_TUNNEL_ID : L2TP_AVP_TYPE_ASSIGNED_TUNNEL));
+ if (a == NULL || a->DataSize != (t->IsV3 ? sizeof(UINT) : sizeof(USHORT)))
+ {
+ goto LABEL_ERROR;
+ }
+
+ t->TunnelId1 = (t->IsV3 ? READ_UINT(a->Data) : READ_USHORT(a->Data));
+ t->TunnelId2 = GenerateNewTunnelIdEx(l2tp, &t->ClientIp, t->IsV3);
+
+ if (t->TunnelId2 == 0)
+ {
+ goto LABEL_ERROR;
+ }
+
+ if (p->Ver == 3)
+ {
+ // Identify whether it's Cisco
+ a = GetAVPValueEx(p, L2TPV3_CISCO_AVP_TUNNEL_ID, L2TP_AVP_VENDOR_ID_CISCO);
+ if (a != NULL)
+ {
+ t->IsCiscoV3 = true;
+ }
+ }
+
+ // Transmission queue
+ t->SendQueue = NewList(NULL);
+
+ // Reception queue
+ t->RecvQueue = NewList(CmpL2TPQueueForRecv);
+
+ t->LastRecvTick = l2tp->Now;
+ t->LastHelloSent = l2tp->Now;
+
+ return t;
+
+LABEL_ERROR:
+ FreeL2TPTunnel(t);
+ return NULL;
+}
+
+// Search a tunnel
+L2TP_TUNNEL *GetTunnelFromId(L2TP_SERVER *l2tp, IP *client_ip, UINT tunnel_id, bool is_v3)
+{
+ UINT i;
+ // Validate arguments
+ if (l2tp == NULL || client_ip == 0 || tunnel_id == 0)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(l2tp->TunnelList);i++)
+ {
+ L2TP_TUNNEL *t = LIST_DATA(l2tp->TunnelList, i);
+
+ if (t->TunnelId2 == tunnel_id && CmpIpAddr(&t->ClientIp, client_ip) == 0)
+ {
+ if (EQUAL_BOOL(t->IsV3, is_v3))
+ {
+ return t;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+// Search the tunnel by the tunnel ID that is assigned by the client
+L2TP_TUNNEL *GetTunnelFromIdOfAssignedByClient(L2TP_SERVER *l2tp, IP *client_ip, UINT tunnel_id)
+{
+ UINT i;
+ // Validate arguments
+ if (l2tp == NULL || client_ip == 0 || tunnel_id == 0)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(l2tp->TunnelList);i++)
+ {
+ L2TP_TUNNEL *t = LIST_DATA(l2tp->TunnelList, i);
+
+ if (t->TunnelId1 == tunnel_id && CmpIpAddr(&t->ClientIp, client_ip) == 0)
+ {
+ return t;
+ }
+ }
+
+ return NULL;
+}
+
+// Create a new tunnel ID
+UINT GenerateNewTunnelId(L2TP_SERVER *l2tp, IP *client_ip)
+{
+ return GenerateNewTunnelIdEx(l2tp, client_ip, false);
+}
+UINT GenerateNewTunnelIdEx(L2TP_SERVER *l2tp, IP *client_ip, bool is_32bit)
+{
+ UINT id;
+ UINT max_number = 0xffff;
+ // Validate arguments
+ if (l2tp == NULL || client_ip == NULL)
+ {
+ return 0;
+ }
+
+ if (is_32bit)
+ {
+ max_number = 0xfffffffe;
+ }
+
+ for (id = 1;id <= max_number;id++)
+ {
+ if (GetTunnelFromId(l2tp, client_ip, id, is_32bit) == NULL)
+ {
+ return id;
+ }
+ }
+
+ return 0;
+}
+
+// Release the L2TP tunnel
+void FreeL2TPTunnel(L2TP_TUNNEL *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(t->SessionList);i++)
+ {
+ L2TP_SESSION *s = LIST_DATA(t->SessionList, i);
+
+ FreeL2TPSession(s);
+ }
+
+ ReleaseList(t->SessionList);
+
+ for (i = 0;i < LIST_NUM(t->SendQueue);i++)
+ {
+ L2TP_QUEUE *q = LIST_DATA(t->SendQueue, i);
+
+ FreeL2TPQueue(q);
+ }
+
+ ReleaseList(t->SendQueue);
+
+ for (i = 0;i < LIST_NUM(t->RecvQueue);i++)
+ {
+ L2TP_QUEUE *q = LIST_DATA(t->RecvQueue, i);
+
+ FreeL2TPQueue(q);
+ }
+
+ ReleaseList(t->RecvQueue);
+
+ Free(t);
+}
+
+// Generate a new L2TP control packet
+L2TP_PACKET *NewL2TPControlPacket(UINT message_type, bool is_v3)
+{
+ L2TP_PACKET *p = ZeroMalloc(sizeof(L2TP_PACKET));
+
+ p->IsControl = true;
+ p->HasLength = true;
+ p->HasSequence = true;
+ p->Ver = (is_v3 ? 3 : 2);
+ p->MessageType = message_type;
+
+ p->AvpList = NewListFast(NULL);
+
+ if (message_type != 0)
+ {
+ L2TP_AVP *a;
+ USHORT us;
+
+ a = ZeroMalloc(sizeof(L2TP_AVP));
+
+ a->Type = L2TP_AVP_TYPE_MESSAGE_TYPE;
+ a->Mandatory = true;
+
+ us = Endian16(message_type);
+ a->Data = Clone(&us, sizeof(USHORT));
+ a->DataSize = sizeof(USHORT);
+
+ Add(p->AvpList, a);
+ }
+
+ return p;
+}
+
+// Create a new AVP value
+L2TP_AVP *NewAVP(USHORT type, bool mandatory, USHORT vendor_id, void *data, UINT data_size)
+{
+ L2TP_AVP *a;
+ // Validate arguments
+ if (data_size != 0 && data == NULL)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(L2TP_AVP));
+
+ a->Type = type;
+ a->Mandatory = mandatory;
+ a->VendorID = vendor_id;
+ a->Data = Clone(data, data_size);
+ a->DataSize = data_size;
+
+ return a;
+}
+
+// Process a received L2TP packet
+void L2TPProcessRecvControlPacket(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_PACKET *p)
+{
+ // Validate arguments
+ if (l2tp == NULL || t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (p->SessionId == 0)
+ {
+ if (p->MessageType == L2TP_MESSAGE_TYPE_SCCCN && l2tp->Halt == false)
+ {
+ // Tunnel establishment completed
+ if (t->Established == false)
+ {
+ if (t->Disconnecting == false)
+ {
+ t->Established = true;
+ t->LastHelloSent = l2tp->Now;
+ }
+ }
+ }
+
+ if (t->Established)
+ {
+ if (p->MessageType == L2TP_MESSAGE_TYPE_ICRQ && t->WantToDisconnect == false && l2tp->Halt == false)
+ {
+ // Request to establish a new session arrives
+ L2TP_AVP *a = GetAVPValue(p,
+ (t->IsV3 ? L2TP_AVP_TYPE_V3_SESSION_ID_LOCAL : L2TP_AVP_TYPE_ASSIGNED_SESSION));
+ if (a != NULL && a->DataSize == (t->IsV3 ? sizeof(UINT) : sizeof(USHORT)) && IsZero(a->Data, (t->IsV3 ? sizeof(UINT) : sizeof(USHORT))) == false)
+ {
+ UINT session_id = (t->IsV3 ? READ_UINT(a->Data) : READ_USHORT(a->Data));
+
+ // Check whether there is other same session ID
+ if (GetSessionFromIdAssignedByClient(t, session_id) == NULL)
+ {
+ // Create a session
+ L2TP_SESSION *s = NewL2TPSession(l2tp, t, session_id);
+
+ if (s != NULL)
+ {
+ L2TP_PACKET *pp;
+ USHORT us;
+ UINT ui;
+
+ // Get the PseudowireType
+ if (t->IsV3)
+ {
+ s->PseudowireType = L2TPV3_PW_TYPE_ETHERNET;
+
+ a = GetAVPValue(p, L2TP_AVP_TYPE_V3_PW_TYPE);
+
+ if (a != NULL && a->DataSize == sizeof(USHORT))
+ {
+ ui = READ_USHORT(a->Data);
+
+ s->PseudowireType = ui;
+ }
+ }
+
+ Add(t->SessionList, s);
+ Debug("L2TP New Session: ID = %u/%u on Tunnel %u/%u\n", s->SessionId1, s->SessionId2,
+ t->TunnelId1, t->TunnelId2);
+
+ // Respond the session creation completion notice
+ pp = NewL2TPControlPacket(L2TP_MESSAGE_TYPE_ICRP, s->IsV3);
+
+ // Assigned Session AVP
+ if (s->IsV3 == false)
+ {
+ us = Endian16(s->SessionId2);
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_ASSIGNED_SESSION, true, 0, &us, sizeof(USHORT)));
+ }
+ else
+ {
+ ui = Endian32(s->SessionId2);
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_V3_SESSION_ID_LOCAL, true, 0, &ui, sizeof(UINT)));
+
+ if (s->IsCiscoV3)
+ {
+ Add(pp->AvpList, NewAVP(L2TPV3_CISCO_AVP_SESSION_ID_LOCAL, true, L2TP_AVP_VENDOR_ID_CISCO, &ui, sizeof(UINT)));
+ }
+ }
+
+ if (s->IsV3)
+ {
+ // Pseudowire AVP
+ us = Endian16(s->PseudowireType);
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_V3_PW_TYPE, true, 0, &us, sizeof(USHORT)));
+
+ if (s->IsCiscoV3)
+ {
+ Add(pp->AvpList, NewAVP(L2TPV3_CISCO_AVP_PW_TYPE, true, L2TP_AVP_VENDOR_ID_CISCO, &us, sizeof(USHORT)));
+ }
+ }
+
+ SendL2TPControlPacket(l2tp, t, session_id, pp);
+
+ FreeL2TPPacket(pp);
+ }
+ }
+ }
+ }
+ else if (p->MessageType == L2TP_MESSAGE_TYPE_STOPCCN)
+ {
+ // Tunnel disconnect request arrives
+ L2TP_AVP *a = GetAVPValue(p, (t->IsV3 ? L2TP_AVP_TYPE_V3_TUNNEL_ID : L2TP_AVP_TYPE_ASSIGNED_TUNNEL));
+ if (a != NULL && a->DataSize == (t->IsV3 ? sizeof(UINT) : sizeof(USHORT)))
+ {
+ UINT ui = (t->IsV3 ? READ_UINT(a->Data) : READ_USHORT(a->Data));
+
+ if (ui == t->TunnelId1)
+ {
+ // Disconnect the tunnel
+ DisconnectL2TPTunnel(t);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Search a session
+ L2TP_SESSION *s = GetSessionFromId(t, p->SessionId);
+
+ if (s != NULL)
+ {
+ if (s->Established == false)
+ {
+ if (p->MessageType == L2TP_MESSAGE_TYPE_ICCN)
+ {
+ // Session establishment completed
+ if (s->Disconnecting == false)
+ {
+ s->Established = true;
+ }
+ }
+ }
+ else
+ {
+ if (p->MessageType == L2TP_MESSAGE_TYPE_CDN)
+ {
+ // Received a session disconnection request
+ L2TP_AVP *a = GetAVPValue(p,
+ (t->IsV3 ? L2TP_AVP_TYPE_V3_SESSION_ID_LOCAL : L2TP_AVP_TYPE_ASSIGNED_SESSION));
+ if (a != NULL && a->DataSize == (t->IsV3 ? sizeof(UINT) : sizeof(USHORT)))
+ {
+ UINT ui = (t->IsV3 ? READ_UINT(a->Data) : READ_USHORT(a->Data));
+
+ if (ui == s->SessionId1)
+ {
+ // Disconnect the session
+ DisconnectL2TPSession(t, s);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ Debug("Session ID %u not found in Tunnel ID %u/%u\n", p->SessionId, t->TunnelId1, t->TunnelId2);
+ }
+ }
+}
+
+// Disconnect the L2TP tunnel
+void DisconnectL2TPTunnel(L2TP_TUNNEL *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (/*t->Established && */t->Disconnecting == false && t->WantToDisconnect == false)
+ {
+ UINT i;
+
+ Debug("Trying to Disconnect Tunnel ID %u/%u\n", t->TunnelId1, t->TunnelId2);
+ t->WantToDisconnect = true;
+
+ // Disconnect all sessions within the tunnel
+ for (i = 0;i < LIST_NUM(t->SessionList);i++)
+ {
+ L2TP_SESSION *s = LIST_DATA(t->SessionList, i);
+
+ DisconnectL2TPSession(t, s);
+ }
+ }
+}
+
+// Disconnect the L2TP session
+void DisconnectL2TPSession(L2TP_TUNNEL *t, L2TP_SESSION *s)
+{
+ // Validate arguments
+ if (t == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (s->Established && s->Disconnecting == false && s->WantToDisconnect == false)
+ {
+ Debug("Trying to Disconnect Session ID %u/%u on Tunnel %u/%u\n", s->SessionId1, s->SessionId2,
+ t->TunnelId1, t->TunnelId2);
+ s->WantToDisconnect = true;
+ }
+}
+
+// Create a new session
+L2TP_SESSION *NewL2TPSession(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, UINT session_id_by_client)
+{
+ L2TP_SESSION *s;
+ UINT session_id_by_server;
+ // Validate arguments
+ if (l2tp == NULL || t == NULL || session_id_by_client == 0)
+ {
+ return NULL;
+ }
+
+ if (t->IsV3 == false)
+ {
+ session_id_by_server = GenerateNewSessionIdEx(t, t->IsV3);
+ }
+ else
+ {
+ session_id_by_server = GenerateNewSessionIdForL2TPv3(l2tp);
+ }
+ if (session_id_by_server == 0)
+ {
+ return NULL;
+ }
+
+ s = ZeroMalloc(sizeof(L2TP_SESSION));
+
+ s->SessionId1 = session_id_by_client;
+ s->SessionId2 = session_id_by_server;
+
+ s->IsV3 = t->IsV3;
+ s->IsCiscoV3 = t->IsCiscoV3;
+
+ s->Tunnel = t;
+
+ return s;
+}
+
+// Retrieve a session from L2TP session ID
+L2TP_SESSION *SearchL2TPSessionById(L2TP_SERVER *l2tp, bool is_v3, UINT id)
+{
+ UINT i, j;
+ // Validate arguments
+ if (l2tp == NULL || id == 0)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(l2tp->TunnelList);i++)
+ {
+ L2TP_TUNNEL *t = LIST_DATA(l2tp->TunnelList, i);
+
+ for (j = 0;j < LIST_NUM(t->SessionList);j++)
+ {
+ L2TP_SESSION *s = LIST_DATA(t->SessionList, j);
+
+ if (s->SessionId2 == id)
+ {
+ if (EQUAL_BOOL(s->IsV3, is_v3))
+ {
+ return s;
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+// Create a new session ID
+UINT GenerateNewSessionId(L2TP_TUNNEL *t)
+{
+ return GenerateNewSessionIdEx(t, false);
+}
+UINT GenerateNewSessionIdEx(L2TP_TUNNEL *t, bool is_32bit)
+{
+ UINT i;
+ UINT max_number = 0xffff;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return 0;
+ }
+
+ if (is_32bit)
+ {
+ max_number = 0xfffffffe;
+ }
+
+ for (i = 1;i <= max_number;i++)
+ {
+ if (GetSessionFromId(t, i) == NULL)
+ {
+ return i;
+ }
+ }
+
+ return 0;
+}
+UINT GenerateNewSessionIdForL2TPv3(L2TP_SERVER *l2tp)
+{
+ // Validate arguments
+ if (l2tp == NULL)
+ {
+ return 0;
+ }
+
+ while (true)
+ {
+ UINT id = Rand32();
+
+ if (id == 0 || id == 0xffffffff)
+ {
+ continue;
+ }
+
+ if (SearchL2TPSessionById(l2tp, true, id) == false)
+ {
+ return id;
+ }
+ }
+}
+
+// Release the session
+void FreeL2TPSession(L2TP_SESSION *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Free(s);
+}
+
+// Search a session from the session ID
+L2TP_SESSION *GetSessionFromId(L2TP_TUNNEL *t, UINT session_id)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || session_id == 0)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(t->SessionList);i++)
+ {
+ L2TP_SESSION *s = LIST_DATA(t->SessionList, i);
+
+ if (s->SessionId2 == session_id)
+ {
+ return s;
+ }
+ }
+
+ return NULL;
+}
+
+// Search a session from the session ID (Search by ID assigned from the client side)
+L2TP_SESSION *GetSessionFromIdAssignedByClient(L2TP_TUNNEL *t, UINT session_id)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || session_id == 0)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(t->SessionList);i++)
+ {
+ L2TP_SESSION *s = LIST_DATA(t->SessionList, i);
+
+ if (s->SessionId1 == session_id)
+ {
+ return s;
+ }
+ }
+
+ return NULL;
+}
+
+// Performs processing L2TP received packets.
+void ProcL2TPPacketRecv(L2TP_SERVER *l2tp, UDPPACKET *p)
+{
+ L2TP_PACKET *pp;
+ bool no_free = false;
+ // Validate arguments
+ if (l2tp == NULL || p == NULL)
+ {
+ return;
+ }
+
+ // Parse a packet.
+ pp = ParseL2TPPacket(p);
+ if (pp == NULL)
+ {
+ return;
+ }
+
+ if (pp->MessageType == L2TP_MESSAGE_TYPE_SCCRQ && pp->SessionId == 0 && pp->TunnelId == 0 &&
+ pp->Nr == 0 && pp->Ns == 0 && l2tp->Halt == false)
+ {
+ {
+ L2TP_AVP *a = GetAVPValue(pp, (pp->Ver == 3 ? L2TP_AVP_TYPE_V3_TUNNEL_ID : L2TP_AVP_TYPE_ASSIGNED_TUNNEL));
+ if (a != NULL && a->DataSize == (pp->Ver == 3 ? sizeof(UINT) : sizeof(USHORT)))
+ {
+ UINT client_assigned_id = (pp->Ver == 3 ? READ_UINT(a->Data) : READ_USHORT(a->Data));
+ if (GetTunnelFromIdOfAssignedByClient(l2tp, &p->SrcIP, client_assigned_id) == NULL)
+ {
+ char ipstr[MAX_SIZE];
+ L2TP_PACKET *pp2;
+ UCHAR protocol_version[2];
+ UCHAR caps_data[4];
+ USHORT us;
+ char hostname[MAX_SIZE];
+
+ // Begin Tunneling
+ L2TP_TUNNEL *t = NewL2TPTunnel(l2tp, pp, p);
+
+ if (t != NULL)
+ {
+ IPToStr(ipstr, sizeof(ipstr), &t->ClientIp);
+ Debug("L2TP New Tunnel From %s (%s, %s): New Tunnel ID = %u/%u\n", ipstr, t->HostName, t->VendorName,
+ t->TunnelId1, t->TunnelId2);
+
+ // Add the tunnel to the list
+ Add(l2tp->TunnelList, t);
+
+ // Respond with SCCEP to SCCRQ
+ pp2 = NewL2TPControlPacket(L2TP_MESSAGE_TYPE_SCCRP, t->IsV3);
+
+ // Protocol Version
+ protocol_version[0] = 1;
+ protocol_version[1] = 0;
+ Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_PROTOCOL_VERSION, true, 0, protocol_version, sizeof(protocol_version)));
+
+ // Framing Capabilities
+ Zero(caps_data, sizeof(caps_data));
+ if (t->IsV3 == false)
+ {
+ caps_data[3] = 3;
+ }
+ Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_FRAME_CAP, false, 0, caps_data, sizeof(caps_data)));
+
+ if (t->IsV3 == false)
+ {
+ // Bearer Capabilities
+ Zero(caps_data, sizeof(caps_data));
+ caps_data[3] = 3;
+ Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_BEARER_CAP, false, 0, caps_data, sizeof(caps_data)));
+ }
+
+ // Host Name
+ GetMachineHostName(hostname, sizeof(hostname));
+ if (IsEmptyStr(hostname))
+ {
+ StrCpy(hostname, sizeof(hostname), "vpn");
+ }
+ Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_HOST_NAME, true, 0, hostname, StrLen(hostname)));
+
+ // Vendor Name
+ Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_VENDOR_NAME, false, 0, L2TP_VENDOR_NAME, StrLen(L2TP_VENDOR_NAME)));
+
+ // Assigned Tunnel ID
+ if (t->IsV3 == false)
+ {
+ us = Endian16(t->TunnelId2);
+ Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_ASSIGNED_TUNNEL, true, 0, &us, sizeof(USHORT)));
+ }
+ else
+ {
+ UINT ui = Endian32(t->TunnelId2);
+ Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_V3_TUNNEL_ID, true, 0, &ui, sizeof(UINT)));
+
+ if (t->IsCiscoV3)
+ {
+ Add(pp2->AvpList, NewAVP(L2TPV3_CISCO_AVP_TUNNEL_ID, true, L2TP_AVP_VENDOR_ID_CISCO, &ui, sizeof(UINT)));
+ }
+ }
+
+ // Pseudowire Capabilities List
+ if (t->IsV3)
+ {
+ // Only Ethernet
+ USHORT cap_list[2];
+ cap_list[0] = Endian16(L2TPV3_PW_TYPE_ETHERNET);
+ cap_list[1] = Endian16(L2TPV3_PW_TYPE_ETHERNET_VLAN);
+ Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_V3_PW_CAP_LIST, true, 0, cap_list, sizeof(cap_list)));
+
+ if (t->IsCiscoV3)
+ {
+ Add(pp2->AvpList, NewAVP(L2TPV3_CISCO_AVP_PW_CAP_LIST, true, L2TP_AVP_VENDOR_ID_CISCO, cap_list, sizeof(cap_list)));
+ }
+ }
+
+ // Cisco AVP
+ if (t->IsCiscoV3)
+ {
+ USHORT us = Endian16(1);
+ Add(pp2->AvpList, NewAVP(L2TPV3_CISCO_AVP_DRAFT_AVP_VERSION, true, L2TP_AVP_VENDOR_ID_CISCO, &us, sizeof(USHORT)));
+ }
+
+ // Recv Window Size
+ us = Endian16(L2TP_WINDOW_SIZE);
+ Add(pp2->AvpList, NewAVP(L2TP_AVP_TYPE_RECV_WINDOW_SIZE, false, 0, &us, sizeof(USHORT)));
+
+ SendL2TPControlPacket(l2tp, t, 0, pp2);
+
+ FreeL2TPPacket(pp2);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Process related to the existing tunnel
+ // Find the tunnel
+ L2TP_TUNNEL *t = NULL;
+ L2TP_SESSION *l2tpv3_session = NULL;
+
+ if (pp->Ver != 3 || pp->IsControl)
+ {
+ t = GetTunnelFromId(l2tp, &p->SrcIP, pp->TunnelId, pp->Ver == 3);
+ }
+ else
+ {
+ l2tpv3_session = SearchL2TPSessionById(l2tp, true, pp->SessionId);
+ if (l2tpv3_session != NULL)
+ {
+ t = l2tpv3_session->Tunnel;
+
+ pp->TunnelId = t->TunnelId2;
+ }
+ }
+
+ if (t == NULL)
+ {
+ char ipstr[MAX_SIZE];
+
+ IPToStr(ipstr, sizeof(ipstr), &p->SrcIP);
+ Debug("L2TP Tunnel From %s ID=%u Not Found on the Table.\n", ipstr, pp->TunnelId);
+ }
+ else
+ {
+ // Update last reception time
+ t->LastRecvTick = l2tp->Now;
+
+ if (pp->IsControl)
+ {
+ // Control packet
+ UINT i;
+ LIST *o = NULL;
+ L2TP_QUEUE *q;
+ L2TP_QUEUE tt;
+
+ // Delete the queue that the other party has already received from the retransmission queue
+ for (i = 0;i < LIST_NUM(t->SendQueue);i++)
+ {
+ L2TP_QUEUE *q = LIST_DATA(t->SendQueue, i);
+ if (L2TP_SEQ_LT(q->Ns, pp->Nr))
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Add(o, q);
+ }
+ }
+
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ L2TP_QUEUE *q = LIST_DATA(o, i);
+
+ Delete(t->SendQueue, q);
+
+ FreeL2TPQueue(q);
+ }
+
+ ReleaseList(o);
+ }
+
+ if ((!L2TP_SEQ_LT(pp->Ns, t->LastNr)) && (pp->Ns != t->LastNr))
+ {
+ // Add the packet received from the opposite to the queue
+ if (LIST_NUM(t->RecvQueue) < L2TP_WINDOW_SIZE)
+ {
+ Zero(&tt, sizeof(tt));
+ tt.Ns = pp->Ns;
+
+ if (Search(t->RecvQueue, &tt) == NULL)
+ {
+ q = ZeroMalloc(sizeof(L2TP_QUEUE));
+ q->Ns = pp->Ns;
+ q->L2TPPacket = pp;
+ no_free = true;
+ Insert(t->RecvQueue, q);
+
+ // Read to the end of completed part from the head of the queue
+ while (TRUE)
+ {
+ L2TP_QUEUE *q;
+ if (LIST_NUM(t->RecvQueue) == 0)
+ {
+ break;
+ }
+
+ q = LIST_DATA(t->RecvQueue, 0);
+ if (!L2TP_SEQ_EQ(q->Ns, t->LastNr + 1))
+ {
+ break;
+ }
+
+ if (q->L2TPPacket->IsZLB == false)
+ {
+ t->LastNr = q->Ns;
+
+ // The packet other than ZLB is treated
+ t->StateChanged = true;
+ }
+
+ Delete(t->RecvQueue, q);
+
+ // Process the received packet
+ L2TPProcessRecvControlPacket(l2tp, t, q->L2TPPacket);
+
+ FreeL2TPQueue(q);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Data packet
+ L2TP_SESSION *s = GetSessionFromId(t, pp->SessionId);
+
+ if (s != NULL && s->Established)
+ {
+ if (s->IsV3 == false)
+ {
+ // Start the L2TP thread (If not already started)
+ StartL2TPThread(l2tp, t, s);
+
+ // Pass the data
+ TubeSendEx(s->TubeRecv, pp->Data, pp->DataSize, NULL, true);
+ AddTubeToFlushList(l2tp->FlushList, s->TubeRecv);
+ }
+ else
+ {
+ BLOCK *b;
+
+ // Start the EtherIP session (If it's not have yet started)
+ L2TPSessionManageEtherIPServer(l2tp, s);
+
+ // Pass the data
+ b = NewBlock(pp->Data, pp->DataSize, 0);
+
+ EtherIPProcRecvPackets(s->EtherIP, b);
+
+ Free(b);
+ }
+ }
+ }
+ }
+ }
+
+ if (no_free == false)
+ {
+ FreeL2TPPacket(pp);
+ }
+}
+
+// Manage the EtherIP server that is associated with the L2TP session
+void L2TPSessionManageEtherIPServer(L2TP_SERVER *l2tp, L2TP_SESSION *s)
+{
+ IKE_SERVER *ike;
+ IKE_CLIENT *c;
+ // Validate arguments
+ if (l2tp == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (l2tp->IkeClient == NULL || l2tp->IkeServer == NULL)
+ {
+ return;
+ }
+
+ ike = l2tp->IkeServer;
+ c = l2tp->IkeClient;
+
+ if (s->EtherIP == NULL)
+ {
+ char crypt_name[MAX_SIZE];
+ UINT crypt_block_size = IKE_MAX_BLOCK_SIZE;
+
+ Zero(crypt_name, sizeof(crypt_name));
+
+ if (c->CurrentIpSecSaRecv != NULL)
+ {
+ Format(crypt_name, sizeof(crypt_name),
+ "IPsec - %s (%u bits)",
+ c->CurrentIpSecSaRecv->TransformSetting.Crypto->Name,
+ c->CurrentIpSecSaRecv->TransformSetting.CryptoKeySize * 8);
+
+ crypt_block_size = c->CurrentIpSecSaRecv->TransformSetting.Crypto->BlockSize;
+ }
+
+ s->EtherIP = NewEtherIPServer(ike->Cedar, ike->IPsec, ike,
+ &c->ClientIP, c->ClientPort,
+ &c->ServerIP, c->ServerPort, crypt_name,
+ c->IsL2TPOnIPsecTunnelMode, crypt_block_size, c->ClientId,
+ ++ike->CurrentEtherId);
+
+ StrCpy(s->EtherIP->VendorName, sizeof(s->EtherIP->VendorName), s->Tunnel->VendorName);
+
+ s->EtherIP->L2TPv3 = true;
+
+ Debug("IKE_CLIENT 0x%X: EtherIP Server Started.\n", c);
+
+ IPsecLog(ike, c, NULL, NULL, NULL, "LI_ETHERIP_SERVER_STARTED", ike->CurrentEtherId);
+ }
+ else
+ {
+ StrCpy(s->EtherIP->ClientId, sizeof(s->EtherIP->ClientId), c->ClientId);
+ }
+
+ if (s->EtherIP->Interrupts == NULL)
+ {
+ s->EtherIP->Interrupts = l2tp->Interrupts;
+ }
+
+ if (s->EtherIP->SockEvent == NULL)
+ {
+ SetEtherIPServerSockEvent(s->EtherIP, l2tp->SockEvent);
+ }
+
+ s->EtherIP->Now = l2tp->Now;
+}
+
+// Calculate the appropriate MSS of the L2TP
+UINT CalcL2TPMss(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s)
+{
+ UINT ret;
+ // Validate arguments
+ if (l2tp == NULL || t == NULL || s == NULL)
+ {
+ return 0;
+ }
+
+ ret = MTU_FOR_PPPOE;
+
+ if (l2tp->IkeServer != NULL)
+ {
+ // On IPsec
+ if (l2tp->IsIPsecIPv6)
+ {
+ ret -= 40;
+ }
+ else
+ {
+ ret -= 20;
+ }
+
+ // UDP
+ ret -= 8;
+
+ // ESP
+ ret -= 20 + l2tp->CryptBlockSize * 2;
+ }
+ else
+ {
+ // Raw L2TP
+ if (IsIP6(&t->ClientIp))
+ {
+ ret -= 40;
+ }
+ else
+ {
+ ret -= 20;
+ }
+ }
+
+ // L2TP UDP
+ ret -= 8;
+
+ // L2TP
+ ret -= 8;
+
+ // PPP
+ ret -= 4;
+
+ // Target communication
+ ret -= 20;
+
+ // TCP header
+ ret -= 20;
+
+ return ret;
+}
+
+// Start the L2TP thread
+void StartL2TPThread(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s)
+{
+ // Validate arguments
+ if (l2tp == NULL || t == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (s->HasThread == false)
+ {
+ char tmp[MAX_SIZE];
+
+ Debug("Thread Created for Session %u/%u on Tunnel %u/%u\n",
+ s->SessionId1, s->SessionId2, t->TunnelId1, t->TunnelId2);
+
+ s->HasThread = true;
+
+ NewTubePair(&s->TubeSend, &s->TubeRecv, 0);
+ SetTubeSockEvent(s->TubeSend, l2tp->SockEvent);
+
+ if (IsEmptyStr(t->VendorName) == false)
+ {
+ Format(tmp, sizeof(tmp), L2TP_IPC_CLIENT_NAME_TAG, t->VendorName);
+ }
+ else
+ {
+ StrCpy(tmp, sizeof(tmp), L2TP_IPC_CLIENT_NAME_NO_TAG);
+ }
+
+ // Create a PPP thread
+ s->Thread = NewPPPSession(l2tp->Cedar, &t->ClientIp, t->ClientPort, &t->ServerIp, t->ServerPort,
+ s->TubeSend, s->TubeRecv, L2TP_IPC_POSTFIX, tmp, t->HostName, l2tp->CryptName,
+ CalcL2TPMss(l2tp, t, s));
+ }
+}
+
+// Stop the L2TP thread
+void StopL2TPThread(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s)
+{
+ THREAD *thread;
+ // Validate arguments
+ if (l2tp == NULL || t == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (s->IsV3)
+ {
+ // Process the L2TPv3
+ if (s->EtherIP != NULL)
+ {
+ // Release the EtherIP server
+ ReleaseEtherIPServer(s->EtherIP);
+ s->EtherIP = NULL;
+ }
+ return;
+ }
+
+ if (s->HasThread == false)
+ {
+ return;
+ }
+ thread = s->Thread;
+ s->Thread = NULL;
+ s->HasThread = false;
+
+ // Disconnect the tube
+ TubeDisconnect(s->TubeRecv);
+ TubeDisconnect(s->TubeSend);
+
+ // Release the tube
+ ReleaseTube(s->TubeRecv);
+ ReleaseTube(s->TubeSend);
+
+ s->TubeRecv = NULL;
+ s->TubeSend = NULL;
+
+ // Pass the thread to termination list
+ if (l2tp->IkeServer == NULL)
+ {
+ AddThreadToThreadList(l2tp->ThreadList, thread);
+ }
+ else
+ {
+ AddThreadToThreadList(l2tp->IkeServer->ThreadList, thread);
+ }
+
+ Debug("Thread Stopped for Session %u/%u on Tunnel %u/%u\n",
+ s->SessionId1, s->SessionId2, t->TunnelId1, t->TunnelId2);
+
+ // Release the thread
+ ReleaseThread(thread);
+}
+
+// Interrupt processing of L2TP server
+void L2TPProcessInterrupts(L2TP_SERVER *l2tp)
+{
+ UINT i, j;
+ LIST *delete_tunnel_list = NULL;
+ // Validate arguments
+ if (l2tp == NULL)
+ {
+ return;
+ }
+
+ if (l2tp->Halt)
+ {
+ if (l2tp->Halting == false)
+ {
+ l2tp->Halting = true;
+
+ // Disconnect all tunnels
+ for (i = 0;i < LIST_NUM(l2tp->TunnelList);i++)
+ {
+ L2TP_TUNNEL *t = LIST_DATA(l2tp->TunnelList, i);
+
+ DisconnectL2TPTunnel(t);
+ }
+ }
+ }
+
+ // Flush
+ FlushTubeFlushList(l2tp->FlushList);
+
+ // Enumerate all tunnels
+ for (i = 0;i < LIST_NUM(l2tp->TunnelList);i++)
+ {
+ L2TP_TUNNEL *t = LIST_DATA(l2tp->TunnelList, i);
+ LIST *delete_session_list = NULL;
+
+ if ((l2tp->Now >= (t->LastRecvTick + (UINT64)L2TP_TUNNEL_TIMEOUT)) && t->Timedout == false)
+ {
+ // Disconnect the tunnel forcibly if data can not be received for a certain period of time
+ t->Timedout = true;
+
+ Debug("L2TP Tunnel %u/%u Timed out.\n", t->TunnelId1, t->TunnelId2);
+ DisconnectL2TPTunnel(t);
+ }
+
+ if (t->Established && (l2tp->Now >= (t->LastHelloSent + (UINT64)L2TP_HELLO_INTERVAL)))
+ {
+ if (LIST_NUM(t->SendQueue) <= L2TP_HELLO_SUPRESS_MAX_THRETHORD_NUM_SEND_QUEUE)
+ {
+ L2TP_PACKET *pp = NewL2TPControlPacket(L2TP_MESSAGE_TYPE_HELLO, t->IsV3);
+
+ // Send a Hello message
+ t->LastHelloSent = l2tp->Now;
+ //Debug("L2TP Sending Hello %u/%u: tick=%I64u\n", t->TunnelId1, t->TunnelId2, l2tp->Now);
+
+ SendL2TPControlPacket(l2tp, t, 0, pp);
+
+ FreeL2TPPacket(pp);
+
+ L2TPAddInterrupt(l2tp, t->LastHelloSent + (UINT64)L2TP_HELLO_INTERVAL);
+ }
+ }
+
+ // Enumerate all sessions
+ for (j = 0;j < LIST_NUM(t->SessionList);j++)
+ {
+ L2TP_SESSION *s = LIST_DATA(t->SessionList, j);
+
+ if (s->HasThread)
+ {
+ // Send packet data
+ while (true)
+ {
+ TUBEDATA *d = TubeRecvAsync(s->TubeSend);
+
+ if (d == NULL)
+ {
+ break;
+ }
+
+ SendL2TPDataPacket(l2tp, t, s, d->Data, d->DataSize);
+
+ FreeTubeData(d);
+ }
+
+ if (IsTubeConnected(s->TubeSend) == false)
+ {
+ // Disconnect the this session because the PPP thread ends
+ DisconnectL2TPSession(t, s);
+ }
+ }
+
+ if (s->IsV3)
+ {
+ if (s->EtherIP != NULL)
+ {
+ UINT k;
+
+ L2TPSessionManageEtherIPServer(l2tp, s);
+
+ // Notify an interrupt to the EtherIP module
+ EtherIPProcInterrupts(s->EtherIP);
+
+ // Send an EtherIP packet data
+ for (k = 0;k < LIST_NUM(s->EtherIP->SendPacketList);k++)
+ {
+ BLOCK *b = LIST_DATA(s->EtherIP->SendPacketList, k);
+
+ SendL2TPDataPacket(l2tp, t, s, b->Buf, b->Size);
+
+ FreeBlock(b);
+ }
+
+ DeleteAll(s->EtherIP->SendPacketList);
+ }
+ }
+
+ if (s->WantToDisconnect && s->Disconnecting == false)
+ {
+ // Disconnect the session
+ UCHAR error_data[4];
+ USHORT us;
+ UINT ui;
+ UINT ppp_error_1 = 0, ppp_error_2 = 0;
+
+ // Send the session disconnection response
+ L2TP_PACKET *pp = NewL2TPControlPacket(L2TP_MESSAGE_TYPE_CDN, s->IsV3);
+
+ if (s->TubeRecv != NULL)
+ {
+ ppp_error_1 = s->TubeRecv->IntParam1;
+ ppp_error_2 = s->TubeRecv->IntParam2;
+ }
+
+ // Assigned Session ID
+ if (s->IsV3 == false)
+ {
+ us = Endian16(s->SessionId2);
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_ASSIGNED_SESSION, true, 0,
+ &us, sizeof(USHORT)));
+ }
+ else
+ {
+ ui = Endian16(s->SessionId2);
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_V3_SESSION_ID_LOCAL, true, 0,
+ &ui, sizeof(UINT)));
+
+ if (t->IsCiscoV3)
+ {
+ Add(pp->AvpList, NewAVP(L2TPV3_CISCO_AVP_SESSION_ID_LOCAL, true, L2TP_AVP_VENDOR_ID_CISCO,
+ &ui, sizeof(UINT)));
+ }
+ }
+
+ // Result-Error Code
+ Zero(error_data, sizeof(error_data));
+ error_data[1] = 0x03;
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_RESULT_CODE, true, 0,
+ error_data, sizeof(error_data)));
+
+ if (ppp_error_1 != 0)
+ {
+ // PPP Disconnect Cause Code AVP
+ BUF *b = NewBuf();
+ UCHAR uc;
+ USHORT us;
+
+ // Disconnect Code
+ us = Endian16(ppp_error_1);
+ WriteBuf(b, &us, sizeof(USHORT));
+
+ // Control Protocol Number
+ us = Endian16(0xc021);
+ WriteBuf(b, &us, sizeof(USHORT));
+
+ // Direction
+ uc = (UCHAR)ppp_error_2;
+ WriteBuf(b, &uc, sizeof(UCHAR));
+
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_PPP_DISCONNECT_CAUSE, false, 0,
+ b->Buf, b->Size));
+
+ FreeBuf(b);
+ }
+
+ SendL2TPControlPacket(l2tp, t, s->SessionId1, pp);
+
+ FreeL2TPPacket(pp);
+
+ // Disconnect the session
+ Debug("L2TP Session %u/%u on Tunnel %u/%u Disconnected.\n", s->SessionId1, s->SessionId2,
+ t->TunnelId1, t->TunnelId2);
+ s->Disconnecting = true;
+ s->Established = false;
+ s->DisconnectTimeout = l2tp->Now + (UINT64)L2TP_TUNNEL_DISCONNECT_TIMEOUT;
+
+ // Stop the thread
+ StopL2TPThread(l2tp, t, s);
+
+ L2TPAddInterrupt(l2tp, s->DisconnectTimeout);
+ }
+
+ if (s->Disconnecting && ((l2tp->Now >= s->DisconnectTimeout) || LIST_NUM(t->SendQueue) == 0))
+ {
+ // Delete the session if synchronization between the client
+ // and the server is complete or a time-out occurs
+ if (delete_session_list == NULL)
+ {
+ delete_session_list = NewListFast(NULL);
+ }
+
+ Add(delete_session_list, s);
+ }
+ }
+
+ if (delete_session_list != NULL)
+ {
+ // Session deletion process
+ for (j = 0;j < LIST_NUM(delete_session_list);j++)
+ {
+ L2TP_SESSION *s = LIST_DATA(delete_session_list, j);
+
+ Debug("L2TP Session %u/%u on Tunnel %u/%u Cleaned up.\n", s->SessionId1, s->SessionId2,
+ t->TunnelId1, t->TunnelId2);
+
+ FreeL2TPSession(s);
+ Delete(t->SessionList, s);
+ }
+
+ ReleaseList(delete_session_list);
+ }
+
+ if (t->WantToDisconnect && t->Disconnecting == false)
+ {
+ // Disconnect the tunnel
+ USHORT error_data[4];
+ USHORT us;
+ UINT ui;
+ // Reply the tunnel disconnection response
+ L2TP_PACKET *pp = NewL2TPControlPacket(L2TP_MESSAGE_TYPE_STOPCCN, t->IsV3);
+
+ // Assigned Tunnel ID
+ if (t->IsV3 == false)
+ {
+ us = Endian16(t->TunnelId2);
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_ASSIGNED_TUNNEL, true, 0,
+ &us, sizeof(USHORT)));
+ }
+ else
+ {
+ ui = Endian32(t->TunnelId2);
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_V3_TUNNEL_ID, true, 0,
+ &ui, sizeof(UINT)));
+
+ if (t->IsCiscoV3)
+ {
+ Add(pp->AvpList, NewAVP(L2TPV3_CISCO_AVP_TUNNEL_ID, true, L2TP_AVP_VENDOR_ID_CISCO,
+ &ui, sizeof(UINT)));
+ }
+ }
+
+ // Result-Error Code
+ Zero(error_data, sizeof(error_data));
+ error_data[1] = 0x06;
+ Add(pp->AvpList, NewAVP(L2TP_AVP_TYPE_RESULT_CODE, true, 0,
+ error_data, sizeof(error_data)));
+
+ SendL2TPControlPacket(l2tp, t, 0, pp);
+
+ FreeL2TPPacket(pp);
+
+ Debug("L2TP Tunnel %u/%u is Disconnected.\n", t->TunnelId1, t->TunnelId2);
+ t->Disconnecting = true;
+ t->Established = false;
+ t->DisconnectTimeout = l2tp->Now + (UINT64)L2TP_TUNNEL_DISCONNECT_TIMEOUT;
+ L2TPAddInterrupt(l2tp, t->DisconnectTimeout);
+ }
+
+ if (t->Disconnecting && (((LIST_NUM(t->SendQueue) == 0) && LIST_NUM(t->SessionList) == 0) || (l2tp->Now >= t->DisconnectTimeout)))
+ {
+ // Delete the tunnel if there is no session in the tunnel when synchronization
+ // between the client and the server has been completed or a time-out occurs
+ if (delete_tunnel_list == NULL)
+ {
+ delete_tunnel_list = NewListFast(NULL);
+ }
+
+ Add(delete_tunnel_list, t);
+ }
+ }
+
+ if (delete_tunnel_list != NULL)
+ {
+ for (i = 0;i < LIST_NUM(delete_tunnel_list);i++)
+ {
+ L2TP_TUNNEL *t = LIST_DATA(delete_tunnel_list, i);
+
+ Debug("L2TP Tunnel %u/%u Cleaned up.\n", t->TunnelId1, t->TunnelId2);
+
+ FreeL2TPTunnel(t);
+ Delete(l2tp->TunnelList, t);
+ }
+
+ ReleaseList(delete_tunnel_list);
+ }
+
+ // Re-transmit packets
+ for (i = 0;i < LIST_NUM(l2tp->TunnelList);i++)
+ {
+ L2TP_TUNNEL *t = LIST_DATA(l2tp->TunnelList, i);
+ UINT j;
+
+ if (LIST_NUM(t->SendQueue) >= 1)
+ {
+ // Packet to be transmitted exists one or more
+ for (j = 0;j < LIST_NUM(t->SendQueue);j++)
+ {
+ L2TP_QUEUE *q = LIST_DATA(t->SendQueue, j);
+
+ if (l2tp->Now >= q->NextSendTick)
+ {
+ q->NextSendTick = l2tp->Now + (UINT64)L2TP_PACKET_RESEND_INTERVAL;
+
+ L2TPAddInterrupt(l2tp, q->NextSendTick);
+
+ SendL2TPControlPacketMain(l2tp, t, q);
+ }
+ }
+ }
+ else
+ {
+ // There is no packet to be transmitted, but the state of the tunnel is changed
+ if (t->StateChanged)
+ {
+ // Send a ZLB
+ L2TP_QUEUE *q = ZeroMalloc(sizeof(L2TP_QUEUE));
+ L2TP_PACKET *pp = NewL2TPControlPacket(0, t->IsV3);
+
+ pp->TunnelId = t->TunnelId1;
+ pp->Ns = t->NextNs;
+ q->Buf = BuildL2TPPacketData(pp);
+
+ SendL2TPControlPacketMain(l2tp, t, q);
+
+ FreeL2TPQueue(q);
+ FreeL2TPPacket(pp);
+ }
+ }
+
+ t->StateChanged = false;
+ }
+
+ if (l2tp->Halting)
+ {
+ if (LIST_NUM(l2tp->TunnelList) == 0)
+ {
+ // Stop all the L2TP tunnel completed
+ if (l2tp->HaltCompleted == false)
+ {
+ l2tp->HaltCompleted = true;
+
+ Set(l2tp->HaltCompletedEvent);
+ }
+ }
+ }
+
+ // Maintenance the thread list
+ if (l2tp->IkeServer == NULL)
+ {
+ MainteThreadList(l2tp->ThreadList);
+ //Debug("l2tp->ThreadList: %u\n", LIST_NUM(l2tp->ThreadList));
+ }
+}
+
+// Create a new L2TP server
+L2TP_SERVER *NewL2TPServer(CEDAR *cedar)
+{
+ return NewL2TPServerEx(cedar, NULL, false, 0);
+}
+L2TP_SERVER *NewL2TPServerEx(CEDAR *cedar, IKE_SERVER *ike, bool is_ipv6, UINT crypt_block_size)
+{
+ L2TP_SERVER *l2tp;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ l2tp = ZeroMalloc(sizeof(L2TP_SERVER));
+
+ l2tp->FlushList = NewTubeFlushList();
+
+ l2tp->Cedar = cedar;
+ AddRef(l2tp->Cedar->ref);
+
+ l2tp->SendPacketList = NewList(NULL);
+ l2tp->TunnelList = NewList(NULL);
+
+ l2tp->HaltCompletedEvent = NewEvent();
+
+ l2tp->ThreadList = NewThreadList();
+
+ l2tp->IkeServer = ike;
+
+ l2tp->IsIPsecIPv6 = is_ipv6;
+ l2tp->CryptBlockSize = crypt_block_size;
+
+ return l2tp;
+}
+
+// Stop the L2TP server
+void StopL2TPServer(L2TP_SERVER *l2tp, bool no_wait)
+{
+ // Validate arguments
+ if (l2tp == NULL)
+ {
+ return;
+ }
+ if (l2tp->Halt)
+ {
+ return;
+ }
+
+ // Begin to shut down
+ l2tp->Halt = true;
+ Debug("Shutting down L2TP Server...\n");
+
+ // Hit the event
+ SetSockEvent(l2tp->SockEvent);
+
+ if (no_wait == false)
+ {
+ // Wait until complete stopping all tunnels
+ Wait(l2tp->HaltCompletedEvent, INFINITE);
+ }
+ else
+ {
+ UINT i, j;
+ // Kill the thread of all sessions
+ for (i = 0;i < LIST_NUM(l2tp->TunnelList);i++)
+ {
+ L2TP_TUNNEL *t = LIST_DATA(l2tp->TunnelList, i);
+
+ for (j = 0;j < LIST_NUM(t->SessionList);j++)
+ {
+ L2TP_SESSION *s = LIST_DATA(t->SessionList, j);
+
+ StopL2TPThread(l2tp, t, s);
+ }
+ }
+ }
+
+ // Thread stop
+ Debug("Stopping all L2TP PPP Threads...\n");
+ StopThreadList(l2tp->ThreadList);
+ Debug("L2TP Server Shutdown Completed.\n");
+}
+
+// Release the L2TP server
+void FreeL2TPServer(L2TP_SERVER *l2tp)
+{
+ UINT i;
+ // Validate arguments
+ if (l2tp == NULL)
+ {
+ return;
+ }
+
+ FreeThreadList(l2tp->ThreadList);
+
+ for (i = 0;i < LIST_NUM(l2tp->SendPacketList);i++)
+ {
+ UDPPACKET *p = LIST_DATA(l2tp->SendPacketList, i);
+
+ FreeUdpPacket(p);
+ }
+
+ ReleaseList(l2tp->SendPacketList);
+
+ for (i = 0;i < LIST_NUM(l2tp->TunnelList);i++)
+ {
+ L2TP_TUNNEL *t = LIST_DATA(l2tp->TunnelList, i);
+
+ FreeL2TPTunnel(t);
+ }
+
+ ReleaseList(l2tp->TunnelList);
+
+ ReleaseSockEvent(l2tp->SockEvent);
+
+ ReleaseEvent(l2tp->HaltCompletedEvent);
+
+ ReleaseCedar(l2tp->Cedar);
+
+ FreeTubeFlushList(l2tp->FlushList);
+
+ Free(l2tp);
+}
+
+// Set a SockEvent to the L2TP server
+void SetL2TPServerSockEvent(L2TP_SERVER *l2tp, SOCK_EVENT *e)
+{
+ // Validate arguments
+ if (l2tp == NULL)
+ {
+ return;
+ }
+
+ if (e != NULL)
+ {
+ AddRef(e->ref);
+ }
+
+ if (l2tp->SockEvent != NULL)
+ {
+ ReleaseSockEvent(l2tp->SockEvent);
+ l2tp->SockEvent = NULL;
+ }
+
+ l2tp->SockEvent = e;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_L2TP.h b/src/Cedar/IPsec_L2TP.h
new file mode 100644
index 00000000..1de1fe1d
--- /dev/null
+++ b/src/Cedar/IPsec_L2TP.h
@@ -0,0 +1,347 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_L2TP.h
+// Header of IPsec_L2TP.c
+
+#ifndef IPSEC_L2TP_H
+#define IPSEC_L2TP_H
+
+//// Macro
+
+// Check the sequence number
+#define L2TP_SEQ_LT(a, b) (((USHORT)(((USHORT)(a)) - ((USHORT)(b)))) & 0x8000)
+#define L2TP_SEQ_EQ(a, b) ((USHORT)(a) == (USHORT)(b))
+
+//// Constants
+
+// Client string
+#define L2TP_IPC_CLIENT_NAME_TAG "L2TP VPN Client - %s"
+#define L2TP_IPC_CLIENT_NAME_NO_TAG "L2TP VPN Client"
+#define L2TP_IPC_POSTFIX "L2TP"
+
+// L2TP vendor name
+#define L2TP_VENDOR_NAME "L2TP"
+
+// L2TP packet retransmission interval
+#define L2TP_PACKET_RESEND_INTERVAL 500
+
+// Timeout for L2TP tunnel disconnecting completion
+#define L2TP_TUNNEL_DISCONNECT_TIMEOUT 3000
+
+// Timeout for L2TP session disconnection completion
+#define L2TP_SESSION_DISCONNECT_TIMEOUT 3000
+
+// Time-out interval of L2TP tunnel
+#define L2TP_TUNNEL_TIMEOUT (60 * 1000)
+
+// Transmission interval of L2TP Hello
+#define L2TP_HELLO_INTERVAL (8801)
+
+// Threshold number of registered items in the transmission queue for suppressing the L2TP Hello transmission
+#define L2TP_HELLO_SUPRESS_MAX_THRETHORD_NUM_SEND_QUEUE 32
+
+// L2TP window size
+#define L2TP_WINDOW_SIZE 16
+
+// L2TP packet header bit mask
+#define L2TP_HEADER_BIT_TYPE 0x80 // Type
+#define L2TP_HEADER_BIT_LENGTH 0x40 // Length
+#define L2TP_HEADER_BIT_SEQUENCE 0x08 // Sequence
+#define L2TP_HEADER_BIT_OFFSET 0x02 // Offset
+#define L2TP_HEADER_BIT_PRIORITY 0x01 // Priority
+#define L2TP_HEADER_BIT_VER 0x0F // Version
+
+// L2TP AVP header bit mask
+#define L2TP_AVP_BIT_MANDATORY 0x80 // Mandatory
+#define L2TP_AVP_BIT_HIDDEN 0x40 // Hidden
+#define L2TP_AVP_LENGTH 0x3FF // Length
+
+// AVP value
+#define L2TP_AVP_TYPE_MESSAGE_TYPE 0 // Message Type
+#define L2TP_AVP_TYPE_RESULT_CODE 1 // Result Code
+#define L2TP_AVP_TYPE_PROTOCOL_VERSION 2 // Protocol Version
+#define L2TP_AVP_TYPE_FRAME_CAP 3 // Framing Capabilities
+#define L2TP_AVP_TYPE_BEARER_CAP 4 // Bearer Capabilities
+#define L2TP_AVP_TYPE_TIE_BREAKER 5 // Tie Breaker
+#define L2TP_AVP_TYPE_HOST_NAME 7 // Host Name
+#define L2TP_AVP_TYPE_VENDOR_NAME 8 // Vendor Name
+#define L2TP_AVP_TYPE_ASSIGNED_TUNNEL 9 // Assigned Tunnel
+#define L2TP_AVP_TYPE_RECV_WINDOW_SIZE 10 // Receive Window Size
+#define L2TP_AVP_TYPE_ASSIGNED_SESSION 14 // Assigned Session ID
+#define L2TP_AVP_TYPE_CALL_SERIAL 15 // Call Serial Number
+#define L2TP_AVP_TYPE_PPP_DISCONNECT_CAUSE 46 // PPP Disconnect Cause Code
+#define L2TP_AVP_TYPE_V3_ROUTER_ID 60 // Router ID
+#define L2TP_AVP_TYPE_V3_TUNNEL_ID 61 // Assigned Control Connection ID
+#define L2TP_AVP_TYPE_V3_PW_CAP_LIST 62 // Pseudowire Capabilities List
+#define L2TP_AVP_TYPE_V3_SESSION_ID_LOCAL 63 // Local Session ID
+#define L2TP_AVP_TYPE_V3_SESSION_ID_REMOTE 64 // Remote Session ID
+#define L2TP_AVP_TYPE_V3_PW_TYPE 68 // Pseudowire Type
+
+// Message Type value
+#define L2TP_MESSAGE_TYPE_SCCRQ 1 // Start-Control-Connection-Request
+#define L2TP_MESSAGE_TYPE_SCCRP 2 // Start-Control-Connection-Reply
+#define L2TP_MESSAGE_TYPE_SCCCN 3 // Start-Control-Connection-Connected
+#define L2TP_MESSAGE_TYPE_STOPCCN 4 // Stop-Control-Connection-Notification
+#define L2TP_MESSAGE_TYPE_HELLO 6 // Hello
+#define L2TP_MESSAGE_TYPE_ICRQ 10 // Incoming-Call-Request
+#define L2TP_MESSAGE_TYPE_ICRP 11 // Incoming-Call-Reply
+#define L2TP_MESSAGE_TYPE_ICCN 12 // Incoming-Call-Connected
+#define L2TP_MESSAGE_TYPE_CDN 14 // Call-Disconnect-Notify
+
+// Type of L2TPv3 virtual network
+#define L2TPV3_PW_TYPE_ETHERNET 5 // Ethernet
+#define L2TPV3_PW_TYPE_ETHERNET_VLAN 4 // Ethernet VLAN
+
+// L2TPv3 vendor unique value
+#define L2TP_AVP_VENDOR_ID_CISCO 9 // Cisco Systems
+#define L2TPV3_CISCO_AVP_TUNNEL_ID 1 // Assigned Connection ID
+#define L2TPV3_CISCO_AVP_PW_CAP_LIST 2 // Pseudowire Capabilities List
+#define L2TPV3_CISCO_AVP_SESSION_ID_LOCAL 3 // Local Session ID
+#define L2TPV3_CISCO_AVP_SESSION_ID_REMOTE 4 // Remote Session ID
+#define L2TPV3_CISCO_AVP_PW_TYPE 7 // Pseudowire Type
+#define L2TPV3_CISCO_AVP_DRAFT_AVP_VERSION 10 // Draft AVP Version
+
+
+
+//// Types
+
+// L2TP queue
+struct L2TP_QUEUE
+{
+ BUF *Buf; // Data
+ USHORT Ns; // Sequence number
+ UINT64 NextSendTick; // Scheduled time to be sent next
+ L2TP_PACKET *L2TPPacket; // L2TP packet data
+};
+
+// L2TP AVP value
+struct L2TP_AVP
+{
+ bool Mandatory; // Force bit
+ UINT Length; // Overall length
+ USHORT VendorID; // Vendor ID
+ USHORT Type; // Type
+ UINT DataSize; // Data size
+ void *Data; // Data body
+};
+
+// L2TP packet
+struct L2TP_PACKET
+{
+ bool IsControl; // Whether it's a control message
+ bool HasLength; // Whether there is length bit
+ bool HasSequence; // Whether there is sequence bit
+ bool HasOffset; // Whether there is offset bit
+ bool IsPriority; // Whether priority packet
+ bool IsZLB; // Zero Length Bit
+ UINT Ver; // Version
+ UINT Length; // Length
+ UINT TunnelId; // Tunnel ID
+ UINT SessionId; // Session ID
+ USHORT Ns, Nr; // Sequence number
+ UINT OffsetSize; // Offset size
+ UINT DataSize; // Data size
+ void *Data; // Data body
+ LIST *AvpList; // AVP list
+ UINT MessageType; // Message type
+};
+
+// L2TP session
+struct L2TP_SESSION
+{
+ L2TP_TUNNEL *Tunnel; // Parent L2TP tunnel
+ bool IsV3; // L2TPv3
+ bool IsCiscoV3; // L2TPv3 for Cisco
+ UINT SessionId1; // Session ID (server -> client direction)
+ UINT SessionId2; // Session ID (client -> server direction)
+ bool Established; // Established
+ bool WantToDisconnect; // Whether to want to disconnect
+ bool Disconnecting; // Whether disconnected
+ UINT64 DisconnectTimeout; // Disconnection completion time-out
+ bool HasThread; // Whether have a thread
+ THREAD *Thread; // Thread
+ TUBE *TubeSend; // Tube of PPP to L2TP direction
+ TUBE *TubeRecv; // Tube of L2TP to PPP direction
+ UINT PseudowireType; // Type of L2TPv3 virtual line
+ ETHERIP_SERVER *EtherIP; // EtherIP server
+};
+
+// L2TP tunnel
+struct L2TP_TUNNEL
+{
+ bool IsV3; // L2TPv3
+ bool IsCiscoV3; // L2TPv3 for Cisco
+ IP ClientIp; // Client IP address
+ UINT ClientPort; // Client port number
+ IP ServerIp; // Server IP address
+ UINT ServerPort; // Server port number
+ UINT TunnelId1; // Tunnel ID (server -> client direction)
+ UINT TunnelId2; // Tunnel ID (client -> server direction)
+ char HostName[MAX_SIZE]; // Destination host name
+ char VendorName[MAX_SIZE]; // Destination vendor name
+ LIST *SessionList; // L2TP session list
+ LIST *SendQueue; // Transmission queue
+ LIST *RecvQueue; // Reception queue
+ USHORT NextNs; // Value of Ns of the packet to be sent next
+ USHORT LastNr; // Value of NR received in the last
+ bool Established; // Whether the tunnel is established
+ bool StateChanged; // Whether the state have changed
+ bool WantToDisconnect; // Whether to want to disconnect
+ bool Disconnecting; // Whether disconnected
+ UINT64 DisconnectTimeout; // Disconnection completion time-out
+ UINT64 LastRecvTick; // Time which the data has been received at last
+ bool Timedout; // Whether the time-out
+ UINT64 LastHelloSent; // Time which the data has been sent at last
+};
+
+// L2TP server
+struct L2TP_SERVER
+{
+ CEDAR *Cedar;
+ UINT64 Now; // Current time
+ LIST *SendPacketList; // Transmission packet
+ LIST *TunnelList; // Tunnel list
+ INTERRUPT_MANAGER *Interrupts; // Interrupt manager
+ SOCK_EVENT *SockEvent; // SockEvent
+ bool Halt; // Start the shutdown
+ bool Halting; // During shutdown
+ bool HaltCompleted; // Shutdown is complete
+ EVENT *HaltCompletedEvent; // Stopping completion event
+ LIST *ThreadList; // Thread list
+ char CryptName[MAX_SIZE]; // Cipher algorithm name
+ IKE_SERVER *IkeServer; // IKE server (Only if associated)
+ IKE_CLIENT *IkeClient; // IKE client (Only if associated)
+ bool IsIPsecIPv6; // Whether it's IPv6
+ UINT CryptBlockSize; // Cipher block size of the upper layer
+ TUBE_FLUSH_LIST *FlushList; // Tube Flush List
+};
+
+
+//// Function prototype
+L2TP_SERVER *NewL2TPServer(CEDAR *cedar);
+L2TP_SERVER *NewL2TPServerEx(CEDAR *cedar, IKE_SERVER *ike, bool is_ipv6, UINT crypt_block_size);
+void SetL2TPServerSockEvent(L2TP_SERVER *l2tp, SOCK_EVENT *e);
+void FreeL2TPServer(L2TP_SERVER *l2tp);
+void StopL2TPServer(L2TP_SERVER *l2tp, bool no_wait);
+void ProcL2TPPacketRecv(L2TP_SERVER *l2tp, UDPPACKET *p);
+L2TP_PACKET *ParseL2TPPacket(UDPPACKET *p);
+BUF *BuildL2TPPacketData(L2TP_PACKET *pp);
+L2TP_AVP *GetAVPValue(L2TP_PACKET *p, UINT type);
+L2TP_AVP *GetAVPValueEx(L2TP_PACKET *p, UINT type, UINT vendor_id);
+L2TP_TUNNEL *NewL2TPTunnel(L2TP_SERVER *l2tp, L2TP_PACKET *p, UDPPACKET *udp);
+UINT GenerateNewTunnelId(L2TP_SERVER *l2tp, IP *client_ip);
+UINT GenerateNewTunnelIdEx(L2TP_SERVER *l2tp, IP *client_ip, bool is_32bit);
+void FreeL2TPTunnel(L2TP_TUNNEL *t);
+L2TP_TUNNEL *GetTunnelFromId(L2TP_SERVER *l2tp, IP *client_ip, UINT tunnel_id, bool is_v3);
+L2TP_TUNNEL *GetTunnelFromIdOfAssignedByClient(L2TP_SERVER *l2tp, IP *client_ip, UINT tunnel_id);
+void SendL2TPControlPacket(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, UINT session_id, L2TP_PACKET *p);
+void SendL2TPControlPacketMain(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_QUEUE *q);
+void SendL2TPDataPacket(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s, void *data, UINT size);
+void FreeL2TPQueue(L2TP_QUEUE *q);
+void L2TPAddInterrupt(L2TP_SERVER *l2tp, UINT64 next_tick);
+void L2TPSendUDP(L2TP_SERVER *l2tp, UDPPACKET *p);
+void L2TPProcessInterrupts(L2TP_SERVER *l2tp);
+L2TP_PACKET *NewL2TPControlPacket(UINT message_type, bool is_v3);
+L2TP_AVP *NewAVP(USHORT type, bool mandatory, USHORT vendor_id, void *data, UINT data_size);
+int CmpL2TPQueueForRecv(void *p1, void *p2);
+void L2TPProcessRecvControlPacket(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_PACKET *p);
+L2TP_SESSION *GetSessionFromId(L2TP_TUNNEL *t, UINT session_id);
+L2TP_SESSION *GetSessionFromIdAssignedByClient(L2TP_TUNNEL *t, UINT session_id);
+L2TP_SESSION *NewL2TPSession(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, UINT session_id_by_client);
+UINT GenerateNewSessionId(L2TP_TUNNEL *t);
+UINT GenerateNewSessionIdEx(L2TP_TUNNEL *t, bool is_32bit);
+void FreeL2TPSession(L2TP_SESSION *s);
+void DisconnectL2TPSession(L2TP_TUNNEL *t, L2TP_SESSION *s);
+void DisconnectL2TPTunnel(L2TP_TUNNEL *t);
+void StartL2TPThread(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s);
+void StopL2TPThread(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s);
+UINT CalcL2TPMss(L2TP_SERVER *l2tp, L2TP_TUNNEL *t, L2TP_SESSION *s);
+UINT GenerateNewSessionIdForL2TPv3(L2TP_SERVER *l2tp);
+L2TP_SESSION *SearchL2TPSessionById(L2TP_SERVER *l2tp, bool is_v3, UINT id);
+void L2TPSessionManageEtherIPServer(L2TP_SERVER *l2tp, L2TP_SESSION *s);
+
+#endif // IPSEC_L2TP_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_PPP.c b/src/Cedar/IPsec_PPP.c
new file mode 100644
index 00000000..26fa0d1d
--- /dev/null
+++ b/src/Cedar/IPsec_PPP.c
@@ -0,0 +1,2689 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_PPP.c
+// PPP protocol stack
+
+#include "CedarPch.h"
+
+// PPP thread
+void PPPThread(THREAD *thread, void *param)
+{
+ PPP_SESSION *p = (PPP_SESSION *)param;
+ UINT i;
+ PPP_LCP *c;
+ USHORT us;
+ UINT ui;
+ USHORT next_protocol = 0;
+ bool ret = false;
+ char ipstr1[128], ipstr2[128];
+ bool established = false;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Initialize
+ p->Mru1 = p->Mru2 = PPP_MRU_DEFAULT;
+ p->RecvPacketList = NewList(NULL);
+
+ //// Link establishment phase
+ IPToStr(ipstr1, sizeof(ipstr1), &p->ClientIP);
+ IPToStr(ipstr2, sizeof(ipstr2), &p->ServerIP);
+ PPPLog(p, "LP_CONNECTED", p->Postfix, ipstr1, p->ClientHostname, p->ClientPort, ipstr2, p->ServerPort,
+ p->ClientSoftwareName, p->AdjustMss);
+
+ // Request the use of PAP
+ c = NewPPPLCP(PPP_LCP_CODE_REQ, 0);
+ us = Endian16(PPP_LCP_AUTH_PAP);
+ Add(c->OptionList, NewPPPOption(PPP_LCP_OPTION_AUTH, &us, sizeof(USHORT)));
+ ret = PPPSendRequest(p, PPP_PROTOCOL_LCP, c);
+ FreePPPLCP(c);
+ if (ret == false)
+ {
+ if (IsTubeConnected(p->TubeRecv))
+ {
+ // PAP protocol is denied
+ p->DisconnectCauseCode = 15;
+ p->DisconnectCauseDirection = 1;
+ Debug("PPP: PAP Rejected.\n");
+
+ if (p->EnableMSCHAPv2)
+ {
+ // Try to request the use of MS-CHAPv2
+ UCHAR ms_chap_v2_code[3];
+ WRITE_USHORT(ms_chap_v2_code, PPP_LCP_AUTH_CHAP);
+ ms_chap_v2_code[2] = PPP_CHAP_ALG_MS_CHAP_V2;
+
+ c = NewPPPLCP(PPP_LCP_CODE_REQ, 0);
+ Add(c->OptionList, NewPPPOption(PPP_LCP_OPTION_AUTH, ms_chap_v2_code, sizeof(ms_chap_v2_code)));
+ ret = PPPSendRequest(p, PPP_PROTOCOL_LCP, c);
+ FreePPPLCP(c);
+
+ if (ret == false)
+ {
+ if (IsTubeConnected(p->TubeRecv))
+ {
+ // MS-CHAPv2 protocol was also rejected
+ p->DisconnectCauseCode = 15;
+ p->DisconnectCauseDirection = 1;
+ Debug("PPP: MS-CHAPv2 Rejected.\n");
+ PPPLog(p, "LP_PAP_MSCHAPV2_REJECTED");
+ }
+ }
+ else
+ {
+ // It is to be used for the MS-CHAPv2
+ p->AuthProtocol = PPP_PROTOCOL_CHAP;
+ }
+ }
+ else
+ {
+ PPPLog(p, "LP_PAP_REJECTED");
+ }
+ }
+
+ if (ret == false)
+ {
+ goto LABEL_CLEANUP;
+ }
+ }
+
+ //// Authentication phase
+
+ if (p->AuthProtocol == PPP_PROTOCOL_PAP)
+ {
+ // PAP
+ next_protocol = PPPContinueCurrentProtocolRequestListening(p, PPP_PROTOCOL_LCP);
+ if (next_protocol == 0)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ Debug("next_protocol = 0x%x\n", next_protocol);
+
+ if (next_protocol != PPP_PROTOCOL_PAP)
+ {
+ Debug("next_protocol is not PAP !!\n");
+ PPPLog(p, "LP_NEXT_PROTOCOL_IS_NOT_PAP", next_protocol);
+ goto LABEL_CLEANUP;
+ }
+
+ next_protocol = PPPContinueCurrentProtocolRequestListening(p, PPP_PROTOCOL_PAP);
+ if (next_protocol == 0 || p->AuthOk == false)
+ {
+ if (IsTubeConnected(p->TubeRecv))
+ {
+ // PAP authentication failed
+ p->DisconnectCauseCode = 15;
+ p->DisconnectCauseDirection = 1;
+ Debug("PPP: PAP Failed.\n");
+ PPPLog(p, "LP_PAP_FAILED");
+ }
+ goto LABEL_CLEANUP;
+ }
+ }
+ else
+ {
+ // MS-CHAP v2
+ PPP_PACKET *pp, *pp_ret;
+ BUF *b;
+ char machine_name[MAX_SIZE];
+ UINT64 start_tick = Tick64();
+ UINT64 timeout_tick = start_tick + (UINT64)PPP_PACKET_RECV_TIMEOUT;
+ UINT64 next_send_tick = 0;
+ USHORT pp_ret_protocol;
+
+ PPPContinueUntilFinishAllLCPOptionRequestsDetermined(p);
+
+ // Generate a Server Challenge packet of MS-CHAP v2
+ GetMachineHostName(machine_name, sizeof(machine_name));
+ MsChapV2Server_GenerateChallenge(p->MsChapV2_ServerChallenge);
+
+ pp = ZeroMalloc(sizeof(PPP_PACKET));
+ pp->Protocol = PPP_PROTOCOL_CHAP;
+ pp->IsControl = true;
+ pp->Lcp = NewPPPLCP(PPP_CHAP_CODE_CHALLENGE, 0);
+
+ b = NewBuf();
+ WriteBufChar(b, 16);
+ WriteBuf(b, p->MsChapV2_ServerChallenge, sizeof(p->MsChapV2_ServerChallenge));
+ WriteBuf(b, machine_name, StrLen(machine_name));
+ pp->Lcp->Data = Clone(b->Buf, b->Size);
+ pp->Lcp->DataSize = b->Size;
+ FreeBuf(b);
+
+ PPPSendPacket(p, pp);
+
+ pp_ret_protocol = 0;
+ pp_ret = PPPRecvResponsePacket(p, pp, 0, &pp_ret_protocol, false);
+
+ if (pp_ret != NULL)
+ {
+ FreePPPPacket(pp_ret);
+ }
+
+ FreePPPPacket(pp);
+
+ if (pp_ret_protocol == 0 || p->AuthOk == false)
+ {
+ if (IsTubeConnected(p->TubeRecv))
+ {
+ // MS-CHAPv2 authentication failed
+ p->DisconnectCauseCode = 15;
+ p->DisconnectCauseDirection = 1;
+ Debug("PPP: MS-CHAPv2 Failed.\n");
+ PPPLog(p, "LP_MSCHAPV2_FAILED");
+ }
+ goto LABEL_CLEANUP;
+ }
+
+ next_protocol = pp_ret_protocol;
+ }
+
+ Debug("next_protocol = 0x%x\n", next_protocol);
+
+ if (next_protocol != PPP_PROTOCOL_IPCP)
+ {
+ // Receive the protocol of non-IPCP
+ Debug("Not IPCP Protocol.\n");
+ PPPLog(p, "LP_NEXT_PROTOCOL_IS_NOT_IPCP", next_protocol);
+ goto LABEL_CLEANUP;
+ }
+
+ // Notify the IP address of the PPP server
+ c = NewPPPLCP(PPP_LCP_CODE_REQ, 0);
+ ui = Endian32(0x01000001); // 1.0.0.1
+ Add(c->OptionList, NewPPPOption(PPP_IPCP_OPTION_IP, &ui, sizeof(UINT)));
+ ret = PPPSendRequest(p, PPP_PROTOCOL_IPCP, c);
+ FreePPPLCP(c);
+ if (ret == false)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ next_protocol = PPPContinueCurrentProtocolRequestListening(p, PPP_PROTOCOL_IPCP);
+ Debug("next_protocol = 0x%x\n", next_protocol);
+
+ if (p->Ipc == NULL || IsZeroIP(&p->Ipc->ClientIPAddress))
+ {
+ // IP address is undetermined
+ PPPLog(p, "LP_IP_ADDRESS_NOT_DETERMIND");
+ goto LABEL_CLEANUP;
+ }
+
+ if (next_protocol == PPP_PROTOCOL_IP)
+ {
+ established = true;
+
+ // Do the IP communication
+ while (true)
+ {
+ TUBE *tubes[2];
+ UINT64 now = Tick64();
+ UINT r;
+
+ // Flush the ARP table of the IPC
+ IPCFlushArpTable(p->Ipc);
+
+ // Packet of client to server direction
+ while (true)
+ {
+ PPP_PACKET *pp = PPPRecvPacketForCommunication(p);
+ if (pp == NULL)
+ {
+ break;
+ }
+
+ if (pp->Protocol == PPP_PROTOCOL_IP)
+ {
+ // Since I want to send the IP packet, pass it to the IPC
+ IPCSendIPv4(p->Ipc, pp->Data, pp->DataSize);
+ }
+
+ FreePPPPacket(pp);
+ }
+
+ if (p->DhcpAllocated)
+ {
+ if (now >= p->DhcpNextRenewTime)
+ {
+ IP ip;
+
+ // DHCP renewal procedure
+ p->DhcpNextRenewTime = now + p->DhcpRenewInterval;
+
+ UINTToIP(&ip, p->ClientAddressOption.ServerAddress);
+
+ IPCDhcpRenewIP(p->Ipc, &ip);
+ }
+ }
+
+ // Happy procedure
+ IPCProcessL3Events(p->Ipc);
+
+ // Packet of server to client direction
+ while (true)
+ {
+ BLOCK *b = IPCRecvIPv4(p->Ipc);
+ PPP_PACKET *pp;
+ PPP_PACKET tmp;
+ if (b == NULL)
+ {
+ break;
+ }
+
+ // Since receiving the IP packet, send it to the client by PPP
+ pp = &tmp;
+ pp->IsControl = false;
+ pp->Protocol = PPP_PROTOCOL_IP;
+ pp->Lcp = NULL;
+ pp->Data = b->Buf;
+ pp->DataSize = b->Size;
+
+ PPPSendPacketEx(p, pp, true);
+
+ FreePPPPacketEx(pp, true);
+ Free(b);
+ }
+
+ FlushTubeFlushList(p->FlushList);
+
+ // PPP Echo Request
+ if (p->NextEchoSendTime == 0 || now >= p->NextEchoSendTime)
+ {
+ p->NextEchoSendTime = now + (UINT64)PPP_ECHO_SEND_INTERVAL;
+ AddInterrupt(p->Ipc->Interrupt, p->NextEchoSendTime);
+
+ PPPSendEchoRequest(p);
+ }
+
+ // Terminate if any tube is disconnected
+ if (IsTubeConnected(p->TubeRecv) == false || IsTubeConnected(p->TubeSend) == false)
+ {
+ // Higher-level protocol is disconnected
+ PPPLog(p, "LP_UPPER_PROTOCOL_DISCONNECTED", p->Postfix);
+ break;
+ }
+ if (IsIPCConnected(p->Ipc) == false)
+ {
+ // IPC VPN session is disconnected
+ PPPLog(p, "LP_VPN_SESSION_TERMINATED");
+ break;
+ }
+
+ // Time-out inspection
+ if ((p->LastRecvTime + (UINT64)PPP_DATA_TIMEOUT) <= now)
+ {
+ // Communication time-out occurs
+ PPPLog(p, "LP_DATA_TIMEOUT");
+ break;
+ }
+
+ // Terminate if the PPP disconnected
+ if (p->IsTerminateReceived)
+ {
+ PPPLog(p, "LP_NORMAL_TERMINATE");
+ break;
+ }
+
+ // Wait until the next packet arrives
+ tubes[0] = p->TubeRecv;
+ tubes[1] = p->Ipc->Sock->RecvTube;
+
+ r = GetNextIntervalForInterrupt(p->Ipc->Interrupt);
+ WaitForTubes(tubes, 2, MIN(r, 1234));
+ }
+
+ // Disconnected normally
+ PPPLog(p, "LP_DISCONNECTED");
+ }
+
+ if (p->DhcpAllocated)
+ {
+ // If any address is assigned from the DHCP, release it
+ IP ip;
+ char tmp[MAX_SIZE];
+
+ UINTToIP(&ip, p->ClientAddressOption.ServerAddress);
+
+ IPToStr(tmp, sizeof(tmp), &ip);
+ Debug("Releasing IP Address from DHCP Server %s...\n", tmp);
+
+ IPCDhcpFreeIP(p->Ipc, &ip);
+ IPCProcessL3Events(p->Ipc);
+
+ SleepThread(300);
+ }
+
+LABEL_CLEANUP:
+
+ if (established == false)
+ {
+ // Disconnected Abnormally
+ PPPLog(p, "LP_DISCONNECTED_ABNORMAL");
+ }
+
+ // Disconnection process
+ PPPCleanTerminate(p);
+
+ // Release the memory
+ for (i = 0;i < LIST_NUM(p->RecvPacketList);i++)
+ {
+ PPP_PACKET *pp = LIST_DATA(p->RecvPacketList, i);
+
+ FreePPPPacket(pp);
+ }
+ ReleaseList(p->RecvPacketList);
+
+ // Release the PPP session
+ FreePPPSession(p);
+}
+
+// Disconnect the PPP cleanly
+void PPPCleanTerminate(PPP_SESSION *p)
+{
+ PPP_PACKET *pp;
+ PPP_PACKET *res;
+ UINT64 giveup_tick = Tick64() + (UINT64)PPP_TERMINATE_TIMEOUT;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ // Send a Terminate Request
+ pp = ZeroMalloc(sizeof(PPP_PACKET));
+ pp->IsControl = true;
+ pp->Protocol = PPP_PROTOCOL_LCP;
+ pp->Lcp = NewPPPLCP(PPP_LCP_CODE_TERMINATE_REQ, p->NextId++);
+ Debug("PPP: Terminate Request is Sent.\n");
+ if (PPPSendPacket(p, pp) == false)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ // Wait for Terminate ACK
+ while (true)
+ {
+ UINT64 now = Tick64();
+ UINT interval;
+
+ if (now >= giveup_tick)
+ {
+ break;
+ }
+
+ while (true)
+ {
+ if (IsTubeConnected(p->TubeRecv) == false)
+ {
+ break;
+ }
+
+ res = PPPRecvPacket(p, true);
+
+ if (res == NULL)
+ {
+ break;
+ }
+
+ if (res->IsControl && res->Protocol == PPP_PROTOCOL_LCP && res->Lcp->Code == PPP_LCP_CODE_TERMINATE_ACK)
+ {
+ Debug("PPP: Terminate ACK is Received.\n");
+ FreePPPPacket(res);
+ goto LABEL_CLEANUP;
+ }
+
+ FreePPPPacket(res);
+ }
+
+ interval = (UINT)(giveup_tick - now);
+
+ Wait(p->TubeRecv->Event, interval);
+ }
+
+LABEL_CLEANUP:
+ FreePPPPacket(pp);
+}
+
+// Wait until all pending LCP option are determined
+bool PPPContinueUntilFinishAllLCPOptionRequestsDetermined(PPP_SESSION *p)
+{
+ USHORT received_protocol = 0;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return false;
+ }
+
+ PPPRecvResponsePacket(p, NULL, PPP_PROTOCOL_LCP, &received_protocol, true);
+
+ return p->ClientLCPOptionDetermined;
+}
+
+// Continue the processing of the request packet protocol on the current PPP
+USHORT PPPContinueCurrentProtocolRequestListening(PPP_SESSION *p, USHORT protocol)
+{
+ USHORT received_protocol = 0;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return 0;
+ }
+
+ PPPRecvResponsePacket(p, NULL, protocol, &received_protocol, false);
+
+ return received_protocol;
+}
+
+// Send the PPP Echo Request
+void PPPSendEchoRequest(PPP_SESSION *p)
+{
+ PPP_PACKET *pp;
+ char echo_data[]= "\0\0\0\0Aho Baka Manuke";
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ pp = ZeroMalloc(sizeof(PPP_PACKET));
+ pp->Protocol = PPP_PROTOCOL_LCP;
+ pp->IsControl = true;
+ pp->Lcp = NewPPPLCP(PPP_LCP_CODE_ECHO_REQUEST, p->NextId++);
+
+ pp->Lcp->Data = Clone(echo_data, sizeof(echo_data));
+ pp->Lcp->DataSize = sizeof(echo_data);
+
+ PPPSendPacket(p, pp);
+
+ FreePPPPacket(pp);
+}
+
+// Send a request packet in the PPP
+bool PPPSendRequest(PPP_SESSION *p, USHORT protocol, PPP_LCP *c)
+{
+ PPP_PACKET *pp;
+ PPP_PACKET *pp2;
+ bool ret = false;
+ // Validate arguments
+ if (p == NULL || c == NULL)
+ {
+ return false;
+ }
+
+ pp = ZeroMalloc(sizeof(PPP_PACKET));
+ pp->Protocol = protocol;
+ pp->IsControl = true;
+ pp->Lcp = c;
+ pp->Lcp->Id = p->NextId++;
+
+ // Send the PPP packet
+ if (PPPSendPacket(p, pp) == false)
+ {
+ goto LABEL_ERROR;
+ }
+
+ // Receive a corresponding PPP packet
+ pp2 = PPPRecvResponsePacket(p, pp, 0, NULL, false);
+
+ if (pp2 != NULL)
+ {
+ if (protocol == PPP_PROTOCOL_LCP || protocol == PPP_PROTOCOL_IPCP)
+ {
+ if (!PPP_LCP_CODE_IS_NEGATIVE(pp2->Lcp->Code))
+ {
+ // A positive response is received
+ ret = true;
+ }
+ }
+ }
+
+ FreePPPPacket(pp2);
+ Free(pp);
+
+ return ret;
+
+LABEL_ERROR:
+ Free(pp);
+ return false;
+}
+
+// Check whether the Virtual HUB with the specified name exist?
+bool IsHubExistsWithLock(CEDAR *cedar, char *hubname)
+{
+ bool ret = false;
+ // Validate arguments
+ if (cedar == NULL || hubname == NULL)
+ {
+ return false;
+ }
+
+ LockList(cedar->HubList);
+ {
+ ret = IsHub(cedar, hubname);
+ }
+ UnlockList(cedar->HubList);
+
+ return ret;
+}
+
+// Separate into the user name and the Virtual HUB name by analyzing the string
+bool PPPParseUsername(CEDAR *cedar, char *src_username, ETHERIP_ID *dst)
+{
+ UINT i, len, last_at, first_en;
+ char token1[MAX_SIZE]; // username
+ char token2[MAX_SIZE]; // hub_name
+ char src[MAX_SIZE];
+ // Validate arguments
+ Zero(dst, sizeof(ETHERIP_ID));
+ if (cedar == NULL || src == NULL || dst == NULL)
+ {
+ return false;
+ }
+
+ StrCpy(src, sizeof(src), src_username);
+ Trim(src);
+
+ // Search for the first "\\" in the string
+ len = StrLen(src);
+
+ first_en = SearchStrEx(src, "\\", 0, true);
+
+ if (first_en != INFINITE && first_en >= 1 && (first_en < (len - 1)))
+ {
+ StrCpy(token1, sizeof(token1), src + first_en + 1);
+ StrCpy(token2, sizeof(token2), src);
+ token2[first_en] = 0;
+
+ // Confirm whether the hubname exists if the virtual HUB name is
+ // specified like as hubname\username
+ if (IsHubExistsWithLock(cedar, token2) == false)
+ {
+ // If the hubname does not exist, restore to the original name
+ StrCpy(token1, sizeof(token1), src);
+ ClearStr(token2, sizeof(token2));
+ }
+ }
+ else
+ {
+ // Search for the last "@" in the string
+ len = StrLen(src);
+ last_at = INFINITE;
+ for (i = 0;i < len;i++)
+ {
+ char c = src[i];
+
+ if (c == '@')
+ {
+ last_at = i;
+ }
+ }
+
+ Zero(token1, sizeof(token1));
+ Zero(token2, sizeof(token2));
+
+ if (last_at == INFINITE)
+ {
+ // "@" is not specified
+ StrCpy(token1, sizeof(token1), src);
+ }
+ else
+ {
+ // Split with last "@"
+ StrCpy(token1, sizeof(token1), src);
+ token1[last_at] = 0;
+
+ StrCpy(token2, sizeof(token2), src + last_at + 1);
+ }
+
+ // Check whether such Virtual HUB exists If the virtual HUB name is specified
+ if (IsEmptyStr(token2) == false)
+ {
+ if (IsHubExistsWithLock(cedar, token2) == false)
+ {
+ // Because the specified virtual HUB name doesn't exist, it's considered to be a part of the user name
+ StrCpy(token1, sizeof(token1), src);
+
+ ClearStr(token2, sizeof(token2));
+ }
+ }
+ }
+
+ if (IsEmptyStr(token2))
+ {
+ // Select the default Virtual HUB if the Virtual HUB name is not specified
+ StrCpy(token2, sizeof(token2), SERVER_DEFAULT_HUB_NAME);
+ if (cedar->Server != NULL && cedar->Server->IPsecServer != NULL)
+ {
+ Lock(cedar->Server->IPsecServer->LockSettings);
+ {
+ IPsecNormalizeServiceSetting(cedar->Server->IPsecServer);
+
+ StrCpy(token2, sizeof(token2), cedar->Server->IPsecServer->Services.L2TP_DefaultHub);
+ }
+ Unlock(cedar->Server->IPsecServer->LockSettings);
+ }
+
+ }
+
+ // Return the results
+ StrCpy(dst->HubName, sizeof(dst->HubName), token2);
+ StrCpy(dst->UserName, sizeof(dst->UserName), token1);
+
+ return true;
+}
+
+// Process the PPP request packet
+PPP_PACKET *PPPProcessRequestPacket(PPP_SESSION *p, PPP_PACKET *req)
+{
+ UINT i;
+ PPP_PACKET *ret = NULL;
+ UINT num_not_supported = 0;
+ UINT num_not_accepted = 0;
+ bool no_return_option_list = false;
+ UINT return_code = 0;
+ BUF *lcp_ret_data = NULL;
+ // Validate arguments
+ if (p == NULL || req == NULL || req->Lcp == NULL)
+ {
+ return NULL;
+ }
+
+ // Initialize
+ for (i = 0;i < LIST_NUM(req->Lcp->OptionList);i++)
+ {
+ PPP_OPTION *t = LIST_DATA(req->Lcp->OptionList, i);
+
+ t->IsAccepted = false;
+ t->IsSupported = false;
+ t->AltDataSize = 0;
+ Zero(t->AltData, sizeof(t->AltData));
+ }
+
+ // Process by scanning the specified option value
+ if (req->Protocol == PPP_PROTOCOL_LCP)
+ {
+ // LCP
+ if (req->Lcp == NULL)
+ {
+ return NULL;
+ }
+ for (i = 0;i < LIST_NUM(req->Lcp->OptionList);i++)
+ {
+ PPP_OPTION *t = LIST_DATA(req->Lcp->OptionList, i);
+
+ switch (t->Type)
+ {
+ case PPP_LCP_OPTION_MRU:
+ // MRU
+ t->IsSupported = true;
+ if (t->DataSize == sizeof(USHORT))
+ {
+ UINT value = READ_USHORT(t->Data);
+ if (value < PPP_MRU_MIN || value > PPP_MRU_MAX)
+ {
+ t->IsAccepted = false;
+ value = MAKESURE(value, PPP_MRU_MIN, PPP_MRU_MAX);
+ WRITE_USHORT(t->AltData, value);
+ t->AltDataSize = sizeof(USHORT);
+ }
+ else
+ {
+ p->Mru1 = value;
+ Debug("PPP: Client set %u as MRU\n", p->Mru1);
+ t->IsAccepted = true;
+ }
+ }
+ break;
+ }
+ }
+ }
+ else if (req->Protocol == PPP_PROTOCOL_CHAP)
+ {
+ bool ok = false;
+ char ret_str[MAX_SIZE];
+
+ no_return_option_list = true;
+
+ if (p->Ipc == NULL)
+ {
+ // MS-CHAPv2
+ if (req->Lcp->DataSize >= 51)
+ {
+ BUF *b;
+
+ b = NewBuf();
+
+ WriteBuf(b, req->Lcp->Data, req->Lcp->DataSize);
+ SeekBuf(b, 0, 0);
+
+ if (ReadBufChar(b) == 49)
+ {
+ UCHAR client_response_buffer[49];
+ UCHAR *client_challenge_16;
+ UCHAR *client_response_24;
+ char username_tmp[MAX_SIZE];
+ IPC *ipc = NULL;
+ char id[MAX_SIZE];
+ char hub[MAX_SIZE];
+ char password[MAX_SIZE];
+ char server_challenge_hex[MAX_SIZE];
+ char client_challenge_hex[MAX_SIZE];
+ char client_response_hex[MAX_SIZE];
+ ETHERIP_ID d;
+ UINT error_code;
+
+ ReadBuf(b, client_response_buffer, 49);
+
+ Zero(username_tmp, sizeof(username_tmp));
+ ReadBuf(b, username_tmp, sizeof(username_tmp));
+
+ client_challenge_16 = client_response_buffer + 0;
+ client_response_24 = client_response_buffer + 16 + 8;
+
+ Copy(p->MsChapV2_ClientChallenge, client_challenge_16, 16);
+ Copy(p->MsChapV2_ClientResponse, client_response_24, 24);
+
+ Debug("MS-CHAPv2: id=%s\n", username_tmp);
+
+ Zero(id, sizeof(id));
+ Zero(hub, sizeof(hub));
+
+ // The user name is divided into the ID and the virtual HUB name
+ Zero(&d, sizeof(d));
+ PPPParseUsername(p->Cedar, username_tmp, &d);
+
+ StrCpy(id, sizeof(id), d.UserName);
+ StrCpy(hub, sizeof(hub), d.HubName);
+
+ // Convert the MS-CHAPv2 data to a password string
+ BinToStr(server_challenge_hex, sizeof(server_challenge_hex),
+ p->MsChapV2_ServerChallenge, sizeof(p->MsChapV2_ServerChallenge));
+ BinToStr(client_challenge_hex, sizeof(client_challenge_hex),
+ p->MsChapV2_ClientChallenge, sizeof(p->MsChapV2_ClientChallenge));
+ BinToStr(client_response_hex, sizeof(client_response_hex),
+ p->MsChapV2_ClientResponse, sizeof(p->MsChapV2_ClientResponse));
+
+ Format(password, sizeof(password), "%s%s:%s:%s:%s",
+ IPC_PASSWORD_MSCHAPV2_TAG,
+ username_tmp,
+ server_challenge_hex,
+ client_challenge_hex,
+ client_response_hex);
+
+ // Attempt to connect with IPC
+ ipc = NewIPC(p->Cedar, p->ClientSoftwareName, p->Postfix, hub, id, password,
+ &error_code, &p->ClientIP, p->ClientPort, &p->ServerIP, p->ServerPort,
+ p->ClientHostname, p->CryptName, false, p->AdjustMss);
+
+ if (ipc != NULL)
+ {
+ p->Ipc = ipc;
+
+ Copy(p->MsChapV2_ServerResponse, ipc->MsChapV2_ServerResponse, 20);
+
+ ok = true;
+ }
+ else
+ {
+ switch (error_code)
+ {
+ default:
+ // Normal authentication error
+ p->MsChapV2_ErrorCode = 691;
+ break;
+
+ case ERR_MSCHAP2_PASSWORD_NEED_RESET:
+ // Authentication errors due to compatibility issues of the password
+ p->MsChapV2_ErrorCode = 942;
+ break;
+ }
+ }
+ }
+
+ FreeBuf(b);
+ }
+ }
+ else
+ {
+ // Return success for a request from the second time when it is successfully authenticated once
+ ok = true;
+ }
+
+ // Generate a response options string
+ if (ok == false)
+ {
+ // In the case of failure
+ char hex[MAX_SIZE];
+ BinToStr(hex, sizeof(hex), p->MsChapV2_ServerChallenge, 16);
+
+ Format(ret_str, sizeof(ret_str),
+ "E=%u R=0 C=%s V=3", p->MsChapV2_ErrorCode, hex);
+
+ return_code = PPP_CHAP_CODE_FAILURE;
+ }
+ else
+ {
+ // In the case of success
+ char hex[MAX_SIZE];
+ BinToStr(hex, sizeof(hex), p->MsChapV2_ServerResponse, 20);
+
+ Format(ret_str, sizeof(ret_str),
+ "S=%s", hex);
+
+ return_code = PPP_CHAP_CODE_SUCCESS;
+
+ p->AuthOk = true;
+ }
+
+ lcp_ret_data = NewBuf();
+ WriteBuf(lcp_ret_data, ret_str, StrLen(ret_str));
+ }
+ else if (req->Protocol == PPP_PROTOCOL_PAP)
+ {
+ UCHAR *data;
+ UINT size;
+ bool ok = false;
+
+ no_return_option_list = true;
+
+ if (p->Ipc == NULL)
+ {
+ // PAP
+
+ // Extract the ID and the password
+ data = req->Lcp->Data;
+ size = req->Lcp->DataSize;
+
+ if (size >= 1)
+ {
+ UCHAR len_id = data[0];
+ data++;
+ size--;
+
+ if (size >= len_id)
+ {
+ char username[256];
+ char password[256];
+
+ Zero(username, sizeof(username));
+ Zero(password, sizeof(password));
+
+ Copy(username, data, len_id);
+ data += len_id;
+ size -= len_id;
+
+ if (size >= 1)
+ {
+ UCHAR len_pass = data[0];
+ data++;
+ size--;
+
+ if (size >= len_pass)
+ {
+ IPC *ipc;
+ char id[MAX_SIZE];
+ char hub[MAX_SIZE];
+ ETHERIP_ID d;
+
+ Zero(id, sizeof(id));
+ Zero(hub, sizeof(hub));
+
+ Copy(password, data, len_pass);
+
+ Debug("PPP: id=%s, pw=%s\n", username, password);
+
+ // The user name is divided into the ID and the virtual HUB name
+ Zero(&d, sizeof(d));
+ PPPParseUsername(p->Cedar, username, &d);
+
+ StrCpy(id, sizeof(id), d.UserName);
+ StrCpy(hub, sizeof(hub), d.HubName);
+
+ if (IsEmptyStr(id) == false)
+ {
+ // Attempt to connect with IPC
+ UINT error_code;
+
+ ipc = NewIPC(p->Cedar, p->ClientSoftwareName, p->Postfix, hub, id, password,
+ &error_code, &p->ClientIP, p->ClientPort, &p->ServerIP, p->ServerPort,
+ p->ClientHostname, p->CryptName, false, p->AdjustMss);
+
+ if (ipc != NULL)
+ {
+ p->Ipc = ipc;
+ ok = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Return success for a request from the second time when it is successfully authenticated once
+ ok = true;
+ }
+
+ if (ok == false)
+ {
+ // Authentication failure
+ return_code = PPP_PAP_CODE_NAK;
+ }
+ else
+ {
+ // Authentication success
+ return_code = PPP_PAP_CODE_ACK;
+
+ p->AuthOk = true;
+ }
+ }
+ else if (req->Protocol == PPP_PROTOCOL_IPCP)
+ {
+ PPP_IPOPTION o;
+ // Get the IP options data from the request data
+ if (PPPGetIPOptionFromLCP(&o, req->Lcp))
+ {
+ PPP_IPOPTION res;
+ IP subnet;
+ IP gw;
+
+ if (IsZeroIP(&o.IpAddress) == false)
+ {
+ if (p->Ipc->Policy->DHCPForce == false)
+ {
+ if (p->DhcpAllocated == false)
+ {
+ if (p->UseStaticIPAddress == false)
+ {
+ DHCP_OPTION_LIST cao;
+
+ // The client specify an IP address
+ Zero(&cao, sizeof(cao));
+
+ cao.ClientAddress = IPToUINT(&o.IpAddress);
+
+ Copy(&p->ClientAddressOption, &cao, sizeof(cao));
+
+ p->UseStaticIPAddress = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ p->UseStaticIPAddress = false;
+ }
+
+ if (p->UseStaticIPAddress)
+ {
+ if (p->DhcpIpInformTried == false)
+ {
+ // Get additional information such as the subnet mask from the DHCP server
+ DHCP_OPTION_LIST cao;
+ IP client_ip;
+
+ IP subnet;
+ IP zero;
+
+ SetIP(&subnet, 255, 0, 0, 0);
+ Zero(&zero, sizeof(zero));
+
+ UINTToIP(&client_ip, p->ClientAddressOption.ClientAddress);
+
+ Zero(&cao, sizeof(cao));
+
+ IPCSetIPv4Parameters(p->Ipc, &client_ip, &subnet, &zero);
+
+ p->DhcpIpInformTried = true;
+
+ PPPLog(p, "LP_DHCP_INFORM_TRYING");
+
+ if (IPCDhcpRequestInformIP(p->Ipc, &cao, p->TubeRecv, &client_ip))
+ {
+ Debug("IPCDhcpRequestInformIP ok.\n");
+ Copy(&p->ClientAddressOption, &cao, sizeof(cao));
+ p->ClientAddressOption.ClientAddress = IPToUINT(&client_ip);
+
+ if (true)
+ {
+ char server_ip_str[64];
+ char subnet_str[64], defgw_str[64];
+ char dns1_str[64], dns2_str[64];
+ char wins1_str[64], wins2_str[64];
+
+ IPToStr32(server_ip_str, sizeof(server_ip_str), cao.ServerAddress);
+ IPToStr32(subnet_str, sizeof(subnet_str), cao.SubnetMask);
+ IPToStr32(defgw_str, sizeof(defgw_str), cao.Gateway);
+ IPToStr32(dns1_str, sizeof(dns1_str), cao.DnsServer);
+ IPToStr32(dns2_str, sizeof(dns2_str), cao.DnsServer2);
+ IPToStr32(wins1_str, sizeof(wins1_str), cao.WinsServer);
+ IPToStr32(wins2_str, sizeof(wins2_str), cao.WinsServer2);
+
+ PPPLog(p, "LP_DHCP_INFORM_OK",
+ subnet_str, defgw_str, cao.DomainName,
+ dns1_str, dns2_str, wins1_str, wins2_str,
+ server_ip_str);
+ }
+ }
+ else
+ {
+ Debug("IPCDhcpRequestInformIP failed.\n");
+
+ PPPLog(p, "LP_DHCP_INFORM_NG");
+ }
+
+ IPCSetIPv4Parameters(p->Ipc, &zero, &zero, &zero);
+ }
+ }
+ else
+ {
+ // Get an IP address from a DHCP server
+ if (p->DhcpIpAllocTried == false)
+ {
+ DHCP_OPTION_LIST cao;
+
+ Zero(&cao, sizeof(cao));
+ p->DhcpIpAllocTried = true;
+
+ PPPLog(p, "LP_DHCP_REQUEST_TRYING");
+
+ if (IPCDhcpAllocateIP(p->Ipc, &cao, p->TubeRecv))
+ {
+ UINT t;
+
+ Debug("IPCDhcpAllocateIP ok.\n");
+
+ // IP address has been determined
+ Copy(&p->ClientAddressOption, &cao, sizeof(cao));
+
+ p->DhcpAllocated = true;
+
+ // Determine the DHCP update interval
+ t = cao.LeaseTime;
+ if (t == 0)
+ {
+ t = 600;
+ }
+
+ t = t / 3;
+
+ if (t == 0)
+ {
+ t = 1;
+ }
+
+ p->DhcpRenewInterval = (UINT64)(t * 1000);
+ p->DhcpNextRenewTime = Tick64() + p->DhcpRenewInterval;
+
+ if (true)
+ {
+ char client_ip_str[64], server_ip_str[64];
+ char subnet_str[64], defgw_str[64];
+ char dns1_str[64], dns2_str[64];
+ char wins1_str[64], wins2_str[64];
+
+ IPToStr32(client_ip_str, sizeof(client_ip_str), cao.ClientAddress);
+ IPToStr32(server_ip_str, sizeof(server_ip_str), cao.ServerAddress);
+ IPToStr32(subnet_str, sizeof(subnet_str), cao.SubnetMask);
+ IPToStr32(defgw_str, sizeof(defgw_str), cao.Gateway);
+ IPToStr32(dns1_str, sizeof(dns1_str), cao.DnsServer);
+ IPToStr32(dns2_str, sizeof(dns2_str), cao.DnsServer2);
+ IPToStr32(wins1_str, sizeof(wins1_str), cao.WinsServer);
+ IPToStr32(wins2_str, sizeof(wins2_str), cao.WinsServer2);
+
+ PPPLog(p, "LP_DHCP_REQUEST_OK",
+ client_ip_str, subnet_str, defgw_str, cao.DomainName,
+ dns1_str, dns2_str, wins1_str, wins2_str,
+ server_ip_str, cao.LeaseTime);
+ }
+ }
+ else
+ {
+ Debug("IPCDhcpAllocateIP failed.\n");
+
+ PPPLog(p, "LP_DHCP_REQUEST_NG");
+ }
+ }
+ }
+
+ if (IsValidUnicastIPAddressUINT4(p->ClientAddressOption.ClientAddress) &&
+ p->ClientAddressOption.SubnetMask != 0)
+ {
+ // Success to determine the address
+ UINTToIP(&subnet, p->ClientAddressOption.SubnetMask);
+ UINTToIP(&gw, p->ClientAddressOption.Gateway);
+
+ Zero(&res, sizeof(res));
+ UINTToIP(&res.IpAddress, p->ClientAddressOption.ClientAddress);
+ UINTToIP(&res.DnsServer1, p->ClientAddressOption.DnsServer);
+ UINTToIP(&res.DnsServer2, p->ClientAddressOption.DnsServer2);
+ UINTToIP(&res.WinsServer1, p->ClientAddressOption.WinsServer);
+ UINTToIP(&res.WinsServer2, p->ClientAddressOption.WinsServer2);
+
+ if (IPCSetIPv4Parameters(p->Ipc, &res.IpAddress, &subnet, &gw))
+ {
+ char client_ip_str[64];
+ char subnet_str[64], defgw_str[64];
+ char dns1_str[64], dns2_str[64];
+ char wins1_str[64], wins2_str[64];
+
+ // IPv4 parameters have been set for the first time
+ Debug("Param First Set.\n");
+
+ IPToStr(client_ip_str, sizeof(client_ip_str), &res.IpAddress);
+ IPToStr(subnet_str, sizeof(subnet_str), &subnet);
+ IPToStr(defgw_str, sizeof(defgw_str), &gw);
+ IPToStr(dns1_str, sizeof(dns1_str), &res.DnsServer1);
+ IPToStr(dns2_str, sizeof(dns2_str), &res.DnsServer2);
+ IPToStr(wins1_str, sizeof(wins1_str), &res.WinsServer1);
+ IPToStr(wins2_str, sizeof(wins2_str), &res.WinsServer2);
+
+ PPPLog(p, "LP_SET_IPV4_PARAM", client_ip_str, subnet_str,
+ defgw_str, dns1_str, dns2_str, wins1_str, wins2_str);
+ }
+
+ PPPSetIPOptionToLCP(&res, req->Lcp, true);
+ }
+ else
+ {
+ // Failed to determine the address
+ Debug("IP Address Determination Failed.\n");
+
+ Zero(&res, sizeof(res));
+
+ PPPSetIPOptionToLCP(&res, req->Lcp, true);
+ }
+ }
+ }
+
+ // Assemble the LCP response packet based on the results
+ for (i = 0;i < LIST_NUM(req->Lcp->OptionList);i++)
+ {
+ PPP_OPTION *t = LIST_DATA(req->Lcp->OptionList, i);
+
+ if (t->IsSupported == false)
+ {
+ num_not_supported++;
+ }
+
+ if (t->IsAccepted == false)
+ {
+ num_not_accepted++;
+ }
+ }
+
+ // Create a PPP response packet
+ ret = ZeroMalloc(sizeof(PPP_PACKET));
+ ret->IsControl = true;
+ ret->Protocol = req->Protocol;
+
+ if (no_return_option_list == false)
+ {
+ // Response by attaching an optional list
+ if (num_not_supported >= 1)
+ {
+ // Return a Reject if there are unsupported parameters
+ ret->Lcp = NewPPPLCP(PPP_LCP_CODE_REJECT, req->Lcp->Id);
+
+ for (i = 0;i < LIST_NUM(req->Lcp->OptionList);i++)
+ {
+ PPP_OPTION *t = LIST_DATA(req->Lcp->OptionList, i);
+
+ if (t->IsSupported == false)
+ {
+ // Attach the original option value as is
+ Add(ret->Lcp->OptionList, NewPPPOption(t->Type, t->Data, t->DataSize));
+ }
+ }
+ }
+ else if (num_not_accepted >= 1)
+ {
+ // Return a NAK if there are any unacceptable parameter
+ // even that all parameters are supported
+ ret->Lcp = NewPPPLCP(PPP_LCP_CODE_NAK, req->Lcp->Id);
+
+ for (i = 0;i < LIST_NUM(req->Lcp->OptionList);i++)
+ {
+ PPP_OPTION *t = LIST_DATA(req->Lcp->OptionList, i);
+
+ if (t->IsAccepted == false)
+ {
+ // Replace the original option value with an acceptable value
+ Add(ret->Lcp->OptionList, NewPPPOption(t->Type, t->AltData, t->AltDataSize));
+ }
+ }
+ }
+ else
+ {
+ // Return an ACK if all parameters are accepted
+ ret->Lcp = NewPPPLCP(PPP_LCP_CODE_ACK, req->Lcp->Id);
+
+ for (i = 0;i < LIST_NUM(req->Lcp->OptionList);i++)
+ {
+ PPP_OPTION *t = LIST_DATA(req->Lcp->OptionList, i);
+
+ // Attach the original option value as is
+ Add(ret->Lcp->OptionList, NewPPPOption(t->Type, t->Data, t->DataSize));
+ }
+
+ if (req->Protocol == PPP_PROTOCOL_LCP)
+ {
+ p->ClientLCPOptionDetermined = true;
+ }
+ }
+ }
+ else
+ {
+ // Response without attaching a list of options
+ ret->Lcp = NewPPPLCP(return_code, req->Lcp->Id);
+
+ if (lcp_ret_data != NULL && lcp_ret_data->Size >= 1)
+ {
+ ret->Lcp->Data = Clone(lcp_ret_data->Buf, lcp_ret_data->Size);
+ ret->Lcp->DataSize = lcp_ret_data->Size;
+ }
+ }
+
+ if (lcp_ret_data != NULL)
+ {
+ FreeBuf(lcp_ret_data);
+ }
+
+ return ret;
+}
+
+// Set the IP options of PPP to LCP
+bool PPPSetIPOptionToLCP(PPP_IPOPTION *o, PPP_LCP *c, bool only_modify)
+{
+ bool ret = false;
+ // Validate arguments
+ if (c == NULL || o == NULL)
+ {
+ return false;
+ }
+
+ ret = PPPSetIPAddressValueToLCP(c, PPP_IPCP_OPTION_IP, &o->IpAddress, only_modify);
+
+ PPPSetIPAddressValueToLCP(c, PPP_IPCP_OPTION_DNS1, &o->DnsServer1, only_modify);
+ PPPSetIPAddressValueToLCP(c, PPP_IPCP_OPTION_DNS2, &o->DnsServer2, only_modify);
+ PPPSetIPAddressValueToLCP(c, PPP_IPCP_OPTION_WINS1, &o->WinsServer1, only_modify);
+ PPPSetIPAddressValueToLCP(c, PPP_IPCP_OPTION_WINS2, &o->WinsServer2, only_modify);
+
+ return ret;
+}
+
+// Get the IP options of PPP from LCP
+bool PPPGetIPOptionFromLCP(PPP_IPOPTION *o, PPP_LCP *c)
+{
+ bool ret;
+ // Validate arguments
+ if (c == NULL || o == NULL)
+ {
+ return false;
+ }
+
+ Zero(o, sizeof(PPP_IPOPTION));
+
+ ret = PPPGetIPAddressValueFromLCP(c, PPP_IPCP_OPTION_IP, &o->IpAddress);
+
+ PPPGetIPAddressValueFromLCP(c, PPP_IPCP_OPTION_DNS1, &o->DnsServer1);
+ PPPGetIPAddressValueFromLCP(c, PPP_IPCP_OPTION_DNS2, &o->DnsServer2);
+ PPPGetIPAddressValueFromLCP(c, PPP_IPCP_OPTION_WINS1, &o->WinsServer1);
+ PPPGetIPAddressValueFromLCP(c, PPP_IPCP_OPTION_WINS2, &o->WinsServer2);
+
+ return ret;
+}
+
+// Set the IP address data to the option list of the LCP
+bool PPPSetIPAddressValueToLCP(PPP_LCP *c, UINT type, IP *ip, bool only_modify)
+{
+ IP ip2;
+ UINT ui;
+ // Validate arguments
+ if (c == NULL || ip == NULL)
+ {
+ return false;
+ }
+
+ ui = IPToUINT(ip);
+
+ if (PPPGetIPAddressValueFromLCP(c, type, &ip2))
+ {
+ PPP_OPTION *opt;
+ opt = GetOptionValue(c, type);
+
+ if (opt != NULL)
+ {
+ if (IsZeroIP(ip) == false)
+ {
+ if (CmpIpAddr(&ip2, ip) == 0)
+ {
+ // No change
+ opt->IsAccepted = true;
+ opt->IsSupported = true;
+ }
+ else
+ {
+ // Changed
+ opt->IsAccepted = false;
+ opt->IsSupported = true;
+ opt->AltDataSize = 4;
+ Copy(opt->AltData, &ui, 4);
+ }
+ }
+ else
+ {
+ // The parameter itself is not supported
+ // (if the IP address is 0.0.0.0)
+ opt->IsSupported = false;
+ opt->IsAccepted = false;
+ }
+ }
+
+ return true;
+ }
+ else
+ {
+ if (IsZeroIP(ip) == false)
+ {
+ // Add as a new item
+ if (only_modify != false)
+ {
+ return false;
+ }
+ else
+ {
+ PPP_OPTION *opt2 = NewPPPOption(type, &ui, 4);
+ opt2->IsAccepted = opt2->IsSupported = true;
+
+ Add(c->OptionList, opt2);
+
+ return true;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+}
+
+// Get the IP address data from the option list of the LCP
+bool PPPGetIPAddressValueFromLCP(PPP_LCP *c, UINT type, IP *ip)
+{
+ PPP_OPTION *opt;
+ UINT ui;
+ // Validate arguments
+ if (c == NULL || ip == NULL)
+ {
+ return false;
+ }
+
+ opt = GetOptionValue(c, type);
+ if (opt == NULL)
+ {
+ return false;
+ }
+
+ if (opt->DataSize != 4)
+ {
+ return false;
+ }
+
+ opt->IsSupported = true;
+
+ ui = *((UINT *)opt->Data);
+
+ UINTToIP(ip, ui);
+
+ return true;
+}
+
+// Process corresponding to the incoming request while receiving a PPP packet corresponding to the transmitted request.
+// (If req == NULL, process on that protocol while the protocol specified in expected_protocol have received.
+//If other protocols has arrived, without further processing, and then store that packet in the session context once,
+// return NULL by setting the received_protocol.)
+PPP_PACKET *PPPRecvResponsePacket(PPP_SESSION *p, PPP_PACKET *req, USHORT expected_protocol, USHORT *received_protocol, bool finish_when_all_lcp_acked)
+{
+ UINT64 giveup_tick = Tick64() + (UINT64)PPP_PACKET_RECV_TIMEOUT;
+ UINT64 next_resend = Tick64() + (UINT64)PPP_PACKET_RESEND_INTERVAL;
+ PPP_PACKET *ret = NULL;
+ USHORT tmp_us = 0;
+ // Validate arguments
+ if (p == NULL || req != NULL && req->Lcp == NULL)
+ {
+ return NULL;
+ }
+
+ if (received_protocol == NULL)
+ {
+ received_protocol = &tmp_us;
+ }
+
+ if (req != NULL)
+ {
+ expected_protocol = req->Protocol;
+ }
+
+ *received_protocol = 0;
+
+ // Receive the next packet (Retransmission repeatedly the last packet until the reception is completed)
+ while (true)
+ {
+ UINT64 now = Tick64();
+ UINT interval;
+
+ if (IsTubeConnected(p->TubeRecv) == false)
+ {
+ return NULL;
+ }
+
+ while (true)
+ {
+ PPP_PACKET *pp;
+ PPP_PACKET *response;
+
+ if (p->LastStoredPacket != NULL)
+ {
+ pp = p->LastStoredPacket;
+ p->LastStoredPacket = NULL;
+ }
+ else
+ {
+ pp = PPPRecvPacketWithLowLayerProcessing(p, true);
+ }
+
+ if (pp == NULL)
+ {
+ break;
+ }
+
+ if (req != NULL)
+ {
+ // Determine whether the packet is corresponding to the request that was sent at the last
+ if (pp->IsControl && pp->Protocol == req->Protocol && pp->Lcp->Id == req->Lcp->Id &&
+ PPP_CODE_IS_RESPONSE(pp->Protocol, pp->Lcp->Code))
+ {
+ return pp;
+ }
+ }
+
+ // Return a response immediately without processing if a protocol other than the expected received
+ if ((pp->IsControl && pp->Protocol != expected_protocol) || pp->IsControl == false)
+ {
+ if (PPP_IS_SUPPORTED_PROTOCOL(pp->Protocol))
+ {
+ // This is another supported protocol
+ // Store this packet
+ PPPStoreLastPacket(p, pp);
+
+ *received_protocol = pp->Protocol;
+ return NULL;
+ }
+ else
+ {
+ // Unsupported protocol
+ Debug("Unsupported Protocol: 0x%x\n", pp->Protocol);
+ FreePPPPacket(pp);
+
+ return NULL;
+ }
+ }
+
+ if (pp->IsControl && PPP_CODE_IS_REQUEST(pp->Protocol, pp->Lcp->Code))
+ {
+ // Process when the received packet is a request packet
+ response = PPPProcessRequestPacket(p, pp);
+ FreePPPPacket(pp);
+
+ if (response == NULL)
+ {
+ return NULL;
+ }
+ else
+ {
+ bool is_pap_and_disconnect_now = false;
+ bool is_chap_and_disconnect_now = false;
+
+ if (PPPSendPacket(p, response) == false)
+ {
+ FreePPPPacket(response);
+ return NULL;
+ }
+
+ if (response->Protocol == PPP_PROTOCOL_PAP && response->IsControl &&
+ response->Lcp->Code != PPP_PAP_CODE_ACK)
+ {
+ is_pap_and_disconnect_now = true;
+ }
+
+ if (response->Protocol == PPP_PROTOCOL_CHAP && response->IsControl &&
+ response->Lcp->Code == PPP_CHAP_CODE_FAILURE)
+ {
+ is_chap_and_disconnect_now = true;
+ }
+
+ FreePPPPacket(response);
+
+ if (is_pap_and_disconnect_now)
+ {
+ // Disconnect immediately if user authentication fails at least once in the PAP authentication protocol
+ Debug("Disconnecting because PAP failed.\n");
+ SleepThread(300);
+ return NULL;
+ }
+
+ if (is_chap_and_disconnect_now)
+ {
+ // Disconnect immediately if it fails to user authentication at least once in the CHAP authentication protocol
+ Debug("Disconnecting because CHAP failed.\n");
+ SleepThread(300);
+ return NULL;
+ }
+ }
+ }
+ else
+ {
+ // Ignore in the case of the other packets
+ FreePPPPacket(pp);
+ }
+ }
+
+ // Packet retransmission
+ if (req != NULL)
+ {
+ if (now >= next_resend)
+ {
+ next_resend = now + PPP_PACKET_RESEND_INTERVAL;
+
+ if (PPPSendPacket(p, req) == false)
+ {
+ return NULL;
+ }
+ }
+ }
+
+ if (req == NULL)
+ {
+ giveup_tick = now + (UINT64)PPP_PACKET_RECV_TIMEOUT;
+ }
+
+ // Time-out decision
+ if (now >= giveup_tick)
+ {
+ PPPLog(p, "LP_CONTROL_TIMEOUT");
+ return NULL;
+ }
+
+ // Wait
+ if (req != NULL)
+ {
+ interval = MIN((UINT)(giveup_tick - now), (UINT)(next_resend - now));
+ }
+ else
+ {
+ interval = (UINT)(giveup_tick - now);
+ }
+
+ if (finish_when_all_lcp_acked && p->ClientLCPOptionDetermined)
+ {
+ return NULL;
+ }
+
+ Wait(p->TubeRecv->Event, interval);
+ }
+}
+
+// Store the last packet in the session (to be read the next time)
+void PPPStoreLastPacket(PPP_SESSION *p, PPP_PACKET *pp)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ if (p->LastStoredPacket != NULL)
+ {
+ FreePPPPacket(p->LastStoredPacket);
+ }
+
+ p->LastStoredPacket = pp;
+}
+
+// Receive a PPP communication packet
+PPP_PACKET *PPPRecvPacketForCommunication(PPP_SESSION *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ if (p->LastStoredPacket != NULL)
+ {
+ PPP_PACKET *pp = p->LastStoredPacket;
+ p->LastStoredPacket = NULL;
+ return pp;
+ }
+
+ return PPPRecvPacketWithLowLayerProcessing(p, true);
+}
+
+// Receive a PPP packet (Also performs low layer processing)
+PPP_PACKET *PPPRecvPacketWithLowLayerProcessing(PPP_SESSION *p, bool async)
+{
+ PPP_PACKET *pp = NULL;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+LABEL_LOOP:
+ pp = PPPRecvPacket(p, async);
+ if (pp == NULL)
+ {
+ return NULL;
+ }
+
+ if (PPP_IS_SUPPORTED_PROTOCOL(pp->Protocol) == false)
+ {
+ // Unsupported algorithm
+ PPP_PACKET *pp2 = ZeroMalloc(sizeof(PPP_PACKET));
+ BUF *buf;
+ UCHAR c;
+ USHORT us;
+
+ pp2->Protocol = PPP_PROTOCOL_LCP;
+ pp2->IsControl = false;
+
+ buf = NewBuf();
+
+ // Code
+ c = PPP_LCP_CODE_PROTOCOL_REJECT;
+ WriteBuf(buf, &c, 1);
+
+ // ID
+ c = p->NextId++;
+ WriteBuf(buf, &c, 1);
+
+ // Length
+ us = Endian16(pp->DataSize + 6);
+ WriteBuf(buf, &us, 2);
+
+ // Rejected Protocol
+ us = Endian16(pp->Protocol);
+ WriteBuf(buf, &us, 2);
+
+ // Packet Data
+ WriteBuf(buf, pp->Data, pp->DataSize);
+
+ pp2->Data = Clone(buf->Buf, buf->Size);
+ pp2->DataSize = buf->Size;
+
+ FreePPPPacket(pp);
+
+ FreeBuf(buf);
+
+ if (PPPSendPacket(p, pp2) == false)
+ {
+ FreePPPPacket(pp2);
+ return NULL;
+ }
+
+ FreePPPPacket(pp2);
+ goto LABEL_LOOP;
+ }
+
+ if (pp->IsControl && pp->Protocol == PPP_PROTOCOL_LCP)
+ {
+ if (pp->Lcp->Code == PPP_LCP_CODE_ECHO_REQUEST)
+ {
+ // Immediately return the echo response to the echo request
+ PPP_PACKET *pp2 = ZeroMalloc(sizeof(PPP_PACKET));
+
+ pp2->IsControl = true;
+ pp2->Protocol = PPP_PROTOCOL_LCP;
+ pp2->Lcp = NewPPPLCP(PPP_LCP_CODE_ECHO_RESPONSE, pp->Lcp->Id);
+ pp2->Lcp->Data = Clone(pp->Lcp->Data, pp->Lcp->DataSize);
+ pp2->Lcp->DataSize = pp->Lcp->DataSize;
+
+ FreePPPPacket(pp);
+
+ if (PPPSendPacket(p, pp2) == false)
+ {
+ FreePPPPacket(pp2);
+ return NULL;
+ }
+
+ FreePPPPacket(pp2);
+ goto LABEL_LOOP;
+ }
+ else if (pp->Lcp->Code == PPP_LCP_CODE_ECHO_RESPONSE)
+ {
+ // Ignore the Echo response packet
+ FreePPPPacket(pp);
+ goto LABEL_LOOP;
+ }
+ else if (pp->Lcp->Code == PPP_LCP_CODE_DROP)
+ {
+ // Ignore the Drop packet
+ FreePPPPacket(pp);
+ goto LABEL_LOOP;
+ }
+ else if (pp->Lcp->Code == PPP_LCP_CODE_IDENTIFICATION)
+ {
+ // Ignore the Identification packet
+ FreePPPPacket(pp);
+ WHERE;
+ goto LABEL_LOOP;
+ }
+ else if (pp->Lcp->Code == PPP_LCP_CODE_TERMINATE_REQ)
+ {
+ // Return the Terminate ACK If a Terminate Request has been received
+ PPP_PACKET *pp2 = ZeroMalloc(sizeof(PPP_PACKET));
+
+ pp2->IsControl = true;
+ pp2->Protocol = PPP_PROTOCOL_LCP;
+ pp2->Lcp = NewPPPLCP(PPP_LCP_CODE_TERMINATE_ACK, pp->Lcp->Id);
+ pp2->Lcp->Data = Clone(pp->Lcp->Data, pp->Lcp->DataSize);
+ pp2->Lcp->DataSize = pp->Lcp->DataSize;
+
+ p->IsTerminateReceived = true;
+
+ FreePPPPacket(pp);
+
+ if (PPPSendPacket(p, pp2) == false)
+ {
+ FreePPPPacket(pp2);
+ return NULL;
+ }
+
+ SleepThread(100);
+
+ FreePPPPacket(pp2);
+ goto LABEL_LOOP;
+ }
+ }
+
+ return pp;
+}
+
+// Receive a PPP packet
+PPP_PACKET *PPPRecvPacket(PPP_SESSION *p, bool async)
+{
+ TUBEDATA *d;
+ PPP_PACKET *pp;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+LABEL_LOOP:
+
+ if (async == false)
+ {
+ d = TubeRecvSync(p->TubeRecv, PPP_PACKET_RECV_TIMEOUT);
+ }
+ else
+ {
+ d = TubeRecvAsync(p->TubeRecv);
+ }
+
+ if (d == NULL)
+ {
+ return NULL;
+ }
+
+ pp = ParsePPPPacket(d->Data, d->DataSize);
+ FreeTubeData(d);
+
+ if (pp == NULL)
+ {
+ // A broken packet is received
+ goto LABEL_LOOP;
+ }
+
+ p->LastRecvTime = Tick64();
+
+ return pp;
+}
+
+// Send the PPP packet
+bool PPPSendPacket(PPP_SESSION *p, PPP_PACKET *pp)
+{
+ return PPPSendPacketEx(p, pp, false);
+}
+bool PPPSendPacketEx(PPP_SESSION *p, PPP_PACKET *pp, bool no_flush)
+{
+ bool ret = false;
+ BUF *b;
+ // Validate arguments
+ if (p == NULL || pp == NULL)
+ {
+ return false;
+ }
+
+ b = BuildPPPPacketData(pp);
+ if (b == NULL)
+ {
+ return false;
+ }
+
+ ret = TubeSendEx(p->TubeSend, b->Buf, b->Size, NULL, no_flush);
+
+ if (no_flush)
+ {
+ AddTubeToFlushList(p->FlushList, p->TubeSend);
+ }
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Create a new PPP options
+PPP_OPTION *NewPPPOption(UCHAR type, void *data, UINT size)
+{
+ PPP_OPTION *o;
+ // Validate arguments
+ if (size != 0 && data == NULL)
+ {
+ return NULL;
+ }
+
+ o = ZeroMalloc(sizeof(PPP_OPTION));
+
+ o->Type = type;
+ Copy(o->Data, data, size);
+ o->DataSize = size;
+
+ return o;
+}
+
+// Analyse the PPP packet
+PPP_PACKET *ParsePPPPacket(void *data, UINT size)
+{
+ PPP_PACKET *pp;
+ UCHAR *buf;
+ // Validate arguments
+ if (data == NULL || size == 0)
+ {
+ return NULL;
+ }
+
+ pp = ZeroMalloc(sizeof(PPP_PACKET));
+
+ buf = (UCHAR *)data;
+
+ // Address
+ if (size < 1)
+ {
+ goto LABEL_ERROR;
+ }
+ if (buf[0] != 0xff)
+ {
+ goto LABEL_ERROR;
+ }
+ size--;
+ buf++;
+
+ // Control
+ if (size < 1)
+ {
+ goto LABEL_ERROR;
+ }
+ if (buf[0] != 0x03)
+ {
+ goto LABEL_ERROR;
+ }
+ size--;
+ buf++;
+
+ // Protocol
+ if (size < 2)
+ {
+ goto LABEL_ERROR;
+ }
+ pp->Protocol = READ_USHORT(buf);
+ size -= 2;
+ buf += 2;
+
+ if (pp->Protocol == PPP_PROTOCOL_LCP || pp->Protocol == PPP_PROTOCOL_PAP || pp->Protocol == PPP_PROTOCOL_CHAP || pp->Protocol == PPP_PROTOCOL_IPCP)
+ {
+ pp->IsControl = true;
+ }
+
+ pp->Data = Clone(buf, size);
+ pp->DataSize = size;
+
+ if (pp->IsControl)
+ {
+ pp->Lcp = ParseLCP(pp->Protocol, pp->Data, pp->DataSize);
+ if (pp->Lcp == NULL)
+ {
+ goto LABEL_ERROR;
+ }
+ }
+
+ return pp;
+
+LABEL_ERROR:
+ FreePPPPacket(pp);
+ return NULL;
+}
+
+// Build a PPP packet data
+BUF *BuildPPPPacketData(PPP_PACKET *pp)
+{
+ BUF *ret;
+ UCHAR c;
+ USHORT us;
+ // Validate arguments
+ if (pp == NULL)
+ {
+ return NULL;
+ }
+
+ ret = NewBuf();
+
+ // Address
+ c = 0xff;
+ WriteBuf(ret, &c, 1);
+
+ // Control
+ c = 0x03;
+ WriteBuf(ret, &c, 1);
+
+ // Protocol
+ us = Endian16(pp->Protocol);
+ WriteBuf(ret, &us, 2);
+
+ if (pp->IsControl)
+ {
+ // LCP
+ BUF *b = BuildLCPData(pp->Lcp);
+
+ WriteBufBuf(ret, b);
+
+ FreeBuf(b);
+ }
+ else
+ {
+ // Data
+ WriteBuf(ret, pp->Data, pp->DataSize);
+ }
+
+ SeekBuf(ret, 0, 0);
+
+ return ret;
+}
+
+// Build the LCP packet data
+BUF *BuildLCPData(PPP_LCP *c)
+{
+ BUF *b;
+ UCHAR zero = 0;
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+
+ // Code
+ WriteBuf(b, &c->Code, 1);
+
+ // ID
+ WriteBuf(b, &c->Id, 1);
+
+ // Length (to be updated later)
+ zero = 0;
+ WriteBuf(b, &zero, 1);
+ WriteBuf(b, &zero, 1);
+
+ if (c->Data == NULL)
+ {
+ // Option List
+ for (i = 0;i < LIST_NUM(c->OptionList);i++)
+ {
+ PPP_OPTION *o = LIST_DATA(c->OptionList, i);
+ UCHAR sz = o->DataSize + 2;
+
+ WriteBuf(b, &o->Type, 1);
+ WriteBuf(b, &sz, 1);
+
+ WriteBuf(b, o->Data, o->DataSize);
+ }
+ }
+ else
+ {
+ // Data
+ WriteBuf(b, c->Data, c->DataSize);
+ }
+
+ SeekBuf(b, 0, 0);
+
+ // Update Length
+ WRITE_USHORT(((UCHAR *)b->Buf) + 2, b->Size);
+
+ return b;
+}
+
+// Analyse the LCP data
+PPP_LCP *ParseLCP(USHORT protocol, void *data, UINT size)
+{
+ UCHAR *buf;
+ PPP_LCP *c;
+ USHORT len;
+ bool has_option_list = false;
+ // Validate arguments
+ if (data == NULL || size == 0)
+ {
+ return NULL;
+ }
+
+ buf = (UCHAR *)data;
+ c = ZeroMalloc(sizeof(PPP_LCP));
+
+ c->OptionList = NewListFast(NULL);
+
+ // Code
+ if (size < 1)
+ {
+ goto LABEL_ERROR;
+ }
+ c->Code = buf[0];
+ buf++;
+ size--;
+
+ // ID
+ if (size < 1)
+ {
+ goto LABEL_ERROR;
+ }
+ c->Id = buf[0];
+ buf++;
+ size--;
+
+ // Length
+ if (size < 2)
+ {
+ goto LABEL_ERROR;
+ }
+ len = READ_USHORT(buf);
+ if (len < 4)
+ {
+ goto LABEL_ERROR;
+ }
+ len -= 4;
+ buf += 2;
+ size -= 2;
+
+ // Options or Data
+ if (size < len)
+ {
+ goto LABEL_ERROR;
+ }
+
+ has_option_list = PPP_CODE_IS_WITH_OPTION_LIST(protocol, c->Code);
+
+ if (has_option_list == false)
+ {
+ c->Data = Clone(buf, size);
+ c->DataSize = size;
+ }
+ else
+ {
+ // Option List
+ while (len >= 1)
+ {
+ PPP_OPTION o;
+
+ Zero(&o, sizeof(o));
+
+ // Type
+ if (len < 1)
+ {
+ goto LABEL_ERROR;
+ }
+ o.Type = buf[0];
+ buf++;
+ len--;
+
+ // Length
+ if (len < 1)
+ {
+ goto LABEL_ERROR;
+ }
+ o.DataSize = buf[0];
+ if (o.DataSize < 2)
+ {
+ goto LABEL_ERROR;
+ }
+ o.DataSize -= 2;
+ buf++;
+ len--;
+
+ // Data
+ if (len < o.DataSize)
+ {
+ goto LABEL_ERROR;
+ }
+ Copy(o.Data, buf, o.DataSize);
+ buf += o.DataSize;
+ len -= o.DataSize;
+
+ Add(c->OptionList, Clone(&o, sizeof(o)));
+ }
+ }
+
+ return c;
+
+LABEL_ERROR:
+ FreePPPLCP(c);
+ return NULL;
+}
+
+// Release the PPP packet
+void FreePPPPacket(PPP_PACKET *pp)
+{
+ FreePPPPacketEx(pp, false);
+}
+void FreePPPPacketEx(PPP_PACKET *pp, bool no_free_struct)
+{
+ // Validate arguments
+ if (pp == NULL)
+ {
+ return;
+ }
+
+ FreePPPLCP(pp->Lcp);
+
+ Free(pp->Data);
+
+ if (no_free_struct == false)
+ {
+ Free(pp);
+ }
+}
+
+// Release the PPP session
+void FreePPPSession(PPP_SESSION *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ if (p->TubeRecv != NULL)
+ {
+ // Record the PPP disconnect reason code for L2TP
+ p->TubeRecv->IntParam1 = p->DisconnectCauseCode;
+ p->TubeRecv->IntParam2 = p->DisconnectCauseDirection;
+ }
+
+ FreeTubeFlushList(p->FlushList);
+
+ TubeDisconnect(p->TubeRecv);
+ TubeDisconnect(p->TubeSend);
+
+ ReleaseCedar(p->Cedar);
+
+ ReleaseTube(p->TubeRecv);
+ ReleaseTube(p->TubeSend);
+
+ PPPStoreLastPacket(p, NULL);
+
+ if (p->Ipc != NULL)
+ {
+ FreeIPC(p->Ipc);
+ }
+
+ Free(p);
+}
+
+// Get the option value
+PPP_OPTION *GetOptionValue(PPP_LCP *c, UCHAR type)
+{
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(c->OptionList);i++)
+ {
+ PPP_OPTION *t = LIST_DATA(c->OptionList, i);
+
+ if (t->Type == type)
+ {
+ return t;
+ }
+ }
+
+ return NULL;
+}
+
+// Create the LCP
+PPP_LCP *NewPPPLCP(UCHAR code, UCHAR id)
+{
+ PPP_LCP *c = ZeroMalloc(sizeof(PPP_LCP));
+
+ c->Code = code;
+ c->Id = id;
+ c->OptionList = NewListFast(NULL);
+
+ return c;
+}
+
+// Release the LCP
+void FreePPPLCP(PPP_LCP *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ FreePPPOptionList(c->OptionList);
+
+ Free(c->Data);
+
+ Free(c);
+}
+
+// Release the PPP options list
+void FreePPPOptionList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ PPP_OPTION *t = LIST_DATA(o, i);
+
+ Free(t);
+ }
+
+ ReleaseList(o);
+}
+
+// Create a new PPP session
+THREAD *NewPPPSession(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, TUBE *send_tube, TUBE *recv_tube, char *postfix, char *client_software_name, char *client_hostname, char *crypt_name, UINT adjust_mss)
+{
+ PPP_SESSION *p;
+ THREAD *t;
+ // Validate arguments
+ if (cedar == NULL || client_ip == NULL || server_ip == NULL || send_tube == NULL || recv_tube == NULL)
+ {
+ return NULL;
+ }
+ if (IsEmptyStr(postfix))
+ {
+ postfix = "PPP";
+ }
+ if (IsEmptyStr(crypt_name))
+ {
+ crypt_name = "";
+ }
+ if (IsEmptyStr(client_software_name))
+ {
+ client_software_name = "PPP VPN Client";
+ }
+
+ // Data structure initialization
+ p = ZeroMalloc(sizeof(PPP_SESSION));
+
+ p->EnableMSCHAPv2 = true;
+ p->AuthProtocol = PPP_PROTOCOL_PAP;
+ p->MsChapV2_ErrorCode = 691;
+
+ p->Cedar = cedar;
+ AddRef(cedar->ref);
+
+ p->AdjustMss = adjust_mss;
+
+ StrCpy(p->CryptName, sizeof(p->CryptName), crypt_name);
+
+ Copy(&p->ClientIP, client_ip, sizeof(IP));
+ p->ClientPort = client_port;
+
+ Copy(&p->ServerIP, server_ip, sizeof(IP));
+ p->ServerPort = server_port;
+
+ p->TubeRecv = recv_tube;
+ p->TubeSend = send_tube;
+
+ AddRef(p->TubeRecv->Ref);
+ AddRef(p->TubeSend->Ref);
+
+ StrCpy(p->Postfix, sizeof(p->Postfix), postfix);
+ StrCpy(p->ClientSoftwareName, sizeof(p->ClientSoftwareName), client_software_name);
+
+ if (IsEmptyStr(client_hostname))
+ {
+ IPToStr(p->ClientHostname, sizeof(p->ClientHostname), client_ip);
+ }
+ else
+ {
+ StrCpy(p->ClientHostname, sizeof(p->ClientHostname), client_hostname);
+ }
+
+ p->FlushList = NewTubeFlushList();
+
+ // Thread creation
+ t = NewThread(PPPThread, p);
+
+ return t;
+}
+
+// Generate the NT hash of the password
+void GenerateNtPasswordHash(UCHAR *dst, char *password)
+{
+ UCHAR *tmp;
+ UINT tmp_size;
+ UINT i, len;
+ // Validate arguments
+ if (dst == NULL || password == NULL)
+ {
+ return;
+ }
+
+ // Generate a Unicode password
+ len = StrLen(password);
+ tmp_size = len * 2;
+
+ tmp = ZeroMalloc(tmp_size);
+
+ for (i = 0;i < len;i++)
+ {
+ tmp[i * 2] = password[i];
+ }
+
+ // Hashing
+ HashMd4(dst, tmp, tmp_size);
+
+ Free(tmp);
+}
+
+// Generate the MS-CHAPv2 server-side challenge
+void MsChapV2Server_GenerateChallenge(UCHAR *dst)
+{
+ // Validate arguments
+ if (dst == NULL)
+ {
+ return;
+ }
+
+ Rand(dst, 16);
+}
+
+// Generate the MS-CHAPv2 client-side challenge
+void MsChapV2Client_GenerateChallenge(UCHAR *dst)
+{
+ // Validate arguments
+ if (dst == NULL)
+ {
+ return;
+ }
+
+ Rand(dst, 16);
+}
+
+// Generate a 8 bytes challenge
+void MsChapV2_GenerateChallenge8(UCHAR *dst, UCHAR *client_challenge, UCHAR *server_challenge, char *username)
+{
+ BUF *b;
+ UCHAR hash[SHA1_SIZE];
+ char username2[MAX_SIZE];
+ char domainname2[MAX_SIZE];
+ // Validate arguments
+ if (dst == NULL || client_challenge == NULL || server_challenge == NULL)
+ {
+ return;
+ }
+
+ b = NewBuf();
+
+ WriteBuf(b, client_challenge, 16);
+ WriteBuf(b, server_challenge, 16);
+
+ ParseNtUsername(username, username2, sizeof(username2), domainname2, sizeof(domainname2), true);
+
+ if (IsEmptyStr(username2) == false)
+ {
+ WriteBuf(b, username2, StrLen(username2));
+ }
+
+ HashSha1(hash, b->Buf, b->Size);
+
+ FreeBuf(b);
+
+ Copy(dst, hash, 8);
+}
+
+// Generate the MS-CHAPv2 client response
+void MsChapV2Client_GenerateResponse(UCHAR *dst, UCHAR *challenge8, UCHAR *nt_password_hash)
+{
+ UCHAR password_hash_2[21];
+ UCHAR key1[8], key2[8], key3[8];
+ // Validate arguments
+ if (dst == NULL || challenge8 == NULL || nt_password_hash == NULL)
+ {
+ return;
+ }
+
+ Zero(password_hash_2, sizeof(password_hash_2));
+ Copy(password_hash_2, nt_password_hash, 16);
+
+ Zero(key1, sizeof(key1));
+ Zero(key2, sizeof(key2));
+ Zero(key3, sizeof(key3));
+
+ Copy(key1, password_hash_2 + 0, 7);
+ Copy(key2, password_hash_2 + 7, 7);
+ Copy(key3, password_hash_2 + 14, 7);
+
+ DesEcbEncrypt(dst + 0, challenge8, key1);
+ DesEcbEncrypt(dst + 8, challenge8, key2);
+ DesEcbEncrypt(dst + 16, challenge8, key3);
+}
+
+// Generate a hash of the hash of the NT password
+void GenerateNtPasswordHashHash(UCHAR *dst_hash, UCHAR *src_hash)
+{
+ // Validate arguments
+ if (dst_hash == NULL || src_hash == NULL)
+ {
+ return;
+ }
+
+ HashMd4(dst_hash, src_hash, 16);
+}
+
+// Generate the MS-CHAPv2 server response
+void MsChapV2Server_GenerateResponse(UCHAR *dst, UCHAR *nt_password_hash_hash, UCHAR *client_response, UCHAR *challenge8)
+{
+ UCHAR digest[SHA1_SIZE];
+ BUF *b;
+ char *magic1 = "Magic server to client signing constant";
+ char *magic2 = "Pad to make it do more than one iteration";
+ // Validate arguments
+ if (dst == NULL || nt_password_hash_hash == NULL || client_response == NULL || challenge8 == NULL)
+ {
+ return;
+ }
+
+ b = NewBuf();
+ WriteBuf(b, nt_password_hash_hash, 16);
+ WriteBuf(b, client_response, 24);
+ WriteBuf(b, magic1, StrLen(magic1));
+ HashSha1(digest, b->Buf, b->Size);
+ FreeBuf(b);
+
+ b = NewBuf();
+ WriteBuf(b, digest, sizeof(digest));
+ WriteBuf(b, challenge8, 8);
+ WriteBuf(b, magic2, StrLen(magic2));
+ HashSha1(dst, b->Buf, b->Size);
+ FreeBuf(b);
+}
+
+// Verify whether the password matches one that is specified by the user in the MS-CHAPv2
+bool MsChapV2VerityPassword(IPC_MSCHAP_V2_AUTHINFO *d, char *password)
+{
+ UCHAR ntlm_hash[MD5_SIZE];
+ UCHAR challenge8[8];
+ UCHAR client_response[24];
+ // Validate arguments
+ if (d == NULL || password == NULL)
+ {
+ return false;
+ }
+
+ GenerateNtPasswordHash(ntlm_hash, password);
+ MsChapV2_GenerateChallenge8(challenge8, d->MsChapV2_ClientChallenge, d->MsChapV2_ServerChallenge, d->MsChapV2_PPPUsername);
+ MsChapV2Client_GenerateResponse(client_response, challenge8, ntlm_hash);
+
+ if (Cmp(client_response, d->MsChapV2_ClientResponse, 24) != 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Estimate the password in the brute force for the request packet of MS-CHAPv2
+char *MsChapV2DoBruteForce(IPC_MSCHAP_V2_AUTHINFO *d, LIST *password_list)
+{
+ UINT i;
+ // Validate arguments
+ if (d == NULL || password_list == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(password_list);i++)
+ {
+ char *s = LIST_DATA(password_list, i);
+ char tmp[MAX_SIZE];
+ UINT j, max;
+ UINT len;
+
+ StrCpy(tmp, sizeof(tmp), s);
+
+ len = StrLen(tmp);
+ max = Power(2, MIN(len, 9));
+
+ for (j = 0;j < max;j++)
+ {
+ SetStrCaseAccordingToBits(tmp, j);
+ if (MsChapV2VerityPassword(d, tmp))
+ {
+ return CopyStr(tmp);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_PPP.h b/src/Cedar/IPsec_PPP.h
new file mode 100644
index 00000000..1534f1de
--- /dev/null
+++ b/src/Cedar/IPsec_PPP.h
@@ -0,0 +1,311 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_PPP.h
+// Header of IPsec_PPP.c
+
+#ifndef IPSEC_PPP_H
+#define IPSEC_PPP_H
+
+
+//// Macro
+#define PPP_LCP_CODE_IS_NEGATIVE(c) ((c) == PPP_LCP_CODE_NAK || (c) == PPP_LCP_CODE_REJECT || (c) == PPP_LCP_CODE_CODE_REJECT || (c) == PPP_LCP_CODE_PROTOCOL_REJECT)
+#define PPP_LCP_CODE_IS_REQUEST(c) ((c) == PPP_LCP_CODE_REQ)
+#define PPP_LCP_CODE_IS_RESPONSE(c) ((c) == PPP_LCP_CODE_ACK || (c) == PPP_LCP_CODE_NAK || (c) == PPP_LCP_CODE_REJECT || (c) == PPP_LCP_CODE_PROTOCOL_REJECT)
+#define PPP_LCP_CODE_IS_WITH_OPTION_LIST(c) ((c) == PPP_LCP_CODE_REQ || (c) == PPP_LCP_CODE_ACK || (c) == PPP_LCP_CODE_NAK)
+
+#define PPP_PAP_CODE_IS_REQUEST(c) ((c) == PPP_PAP_CODE_REQ)
+#define PPP_PAP_CODE_IS_RESPONSE(c) ((c) == PPP_PAP_CODE_ACK || (c) == PPP_PAP_CODE_NAK)
+
+#define PPP_CODE_IS_RESPONSE(protocol, c) ((((protocol) == PPP_PROTOCOL_LCP || (protocol) == PPP_PROTOCOL_IPCP) && PPP_LCP_CODE_IS_RESPONSE(c)) || (((protocol) == PPP_PROTOCOL_PAP) && PPP_PAP_CODE_IS_RESPONSE(c)))
+#define PPP_CODE_IS_REQUEST(protocol, c) ((((protocol) == PPP_PROTOCOL_LCP || (protocol) == PPP_PROTOCOL_IPCP) && PPP_LCP_CODE_IS_REQUEST(c)) || (((protocol) == PPP_PROTOCOL_PAP) && PPP_PAP_CODE_IS_REQUEST(c)) || ((protocol) == PPP_PROTOCOL_CHAP))
+#define PPP_CODE_IS_WITH_OPTION_LIST(protocol, c) ((((protocol) == PPP_PROTOCOL_LCP || (protocol) == PPP_PROTOCOL_IPCP) && PPP_LCP_CODE_IS_WITH_OPTION_LIST(c)) || false)
+
+#define PPP_IS_SUPPORTED_PROTOCOL(p) ((p) == PPP_PROTOCOL_LCP || (p) == PPP_PROTOCOL_PAP || (p) == PPP_PROTOCOL_CHAP || (p) == PPP_PROTOCOL_IPCP || (p) == PPP_PROTOCOL_IP)
+
+
+//// Constants
+
+// Time-out value
+#define PPP_PACKET_RECV_TIMEOUT 10000 // Timeout until the next packet is received
+#define PPP_PACKET_RESEND_INTERVAL 1000 // Retransmission interval of the last packet
+#define PPP_TERMINATE_TIMEOUT 2000 // Timeout value to complete disconnection after requesting to disconnect in the PPP
+#define PPP_ECHO_SEND_INTERVAL 4792 // Transmission interval of PPP Echo Request
+#define PPP_DATA_TIMEOUT (20 * 1000) // Communication time-out
+
+// MRU
+#define PPP_MRU_DEFAULT 1500 // Default value
+#define PPP_MRU_MIN 100 // Minimum value
+#define PPP_MRU_MAX 1500 // Maximum value
+
+// PPP protocol (for control)
+#define PPP_PROTOCOL_LCP 0xc021
+#define PPP_PROTOCOL_PAP 0xc023
+#define PPP_PROTOCOL_IPCP 0x8021
+#define PPP_PROTOCOL_CHAP 0xc223
+
+// PPP protocol (for transfer)
+#define PPP_PROTOCOL_IP 0x0021
+
+// LCP code
+#define PPP_LCP_CODE_REQ 1
+#define PPP_LCP_CODE_ACK 2
+#define PPP_LCP_CODE_NAK 3
+#define PPP_LCP_CODE_REJECT 4
+#define PPP_LCP_CODE_TERMINATE_REQ 5
+#define PPP_LCP_CODE_TERMINATE_ACK 6
+#define PPP_LCP_CODE_CODE_REJECT 7
+#define PPP_LCP_CODE_PROTOCOL_REJECT 8
+#define PPP_LCP_CODE_ECHO_REQUEST 9
+#define PPP_LCP_CODE_ECHO_RESPONSE 10
+#define PPP_LCP_CODE_DROP 11
+#define PPP_LCP_CODE_IDENTIFICATION 12
+
+// PAP Code
+#define PPP_PAP_CODE_REQ 1
+#define PPP_PAP_CODE_ACK 2
+#define PPP_PAP_CODE_NAK 3
+
+// CHAP code
+#define PPP_CHAP_CODE_CHALLENGE 1
+#define PPP_CHAP_CODE_RESPONSE 2
+#define PPP_CHAP_CODE_SUCCESS 3
+#define PPP_CHAP_CODE_FAILURE 4
+
+// LCP Option Type
+#define PPP_LCP_OPTION_MRU 1
+#define PPP_LCP_OPTION_AUTH 3
+
+// IPCP option type
+#define PPP_IPCP_OPTION_IP 3
+#define PPP_IPCP_OPTION_DNS1 129
+#define PPP_IPCP_OPTION_DNS2 131
+#define PPP_IPCP_OPTION_WINS1 130
+#define PPP_IPCP_OPTION_WINS2 132
+
+// Authentication protocol
+#define PPP_LCP_AUTH_PAP PPP_PROTOCOL_PAP
+#define PPP_LCP_AUTH_CHAP PPP_PROTOCOL_CHAP
+
+// Algorithm of CHAP
+#define PPP_CHAP_ALG_MS_CHAP_V2 0x81
+
+
+//// Type
+
+// IP options used in the PPP
+struct PPP_IPOPTION
+{
+ IP IpAddress; // IP address
+ IP DnsServer1, DnsServer2; // DNS server address
+ IP WinsServer1, WinsServer2; // WINS server address
+};
+
+// PPP packet
+struct PPP_PACKET
+{
+ USHORT Protocol; // Protocol
+ bool IsControl; // Whether or not the control packet
+ PPP_LCP *Lcp; // LCP packet data
+ UINT DataSize; // Data size
+ void *Data; // Data body
+};
+
+// PPP LCP packet
+struct PPP_LCP
+{
+ UCHAR Code; // Code
+ UCHAR Id; // ID
+ UCHAR MagicNumber[4]; // Magic number
+ LIST *OptionList; // PPP options list
+ void *Data; // Data
+ UINT DataSize; // Data size
+};
+
+// PPP Options
+struct PPP_OPTION
+{
+ UCHAR Type; // Type of option
+ UINT DataSize; // Data size
+ UCHAR Data[254]; // Data
+ bool IsSupported; // Flag of whether it is supported
+ bool IsAccepted; // Flag for whether accepted
+ UCHAR AltData[254]; // Alternate data when it isn't accepted
+ UINT AltDataSize; // Alternate data size
+};
+
+// PPP session
+struct PPP_SESSION
+{
+ CEDAR *Cedar; // Cedar
+ IP ClientIP; // Client IP address
+ UINT ClientPort; // Client port
+ IP ServerIP; // Server IP address
+ UINT ServerPort; // Server port
+ TUBE *TubeSend; // Sending tube
+ TUBE *TubeRecv; // Receiving tube
+ UCHAR NextId; // ID to be used next
+ UINT Mru1; // MRU (server -> client)
+ UINT Mru2; // MRU (client -> server)
+ LIST *RecvPacketList; // Received packet list
+ PPP_PACKET *LastStoredPacket; // Packet that is stored at the last
+ bool IsTerminateReceived; // Whether a Terminate has been received
+ UINT DisconnectCauseCode; // L2TP disconnect cause code
+ UINT DisconnectCauseDirection; // L2TP disconnect cause direction code
+ IPC *Ipc; // IPC
+ bool ClientLCPOptionDetermined; // LCP option from the client has been determined
+ char Postfix[MAX_SIZE]; // Postfix of the session name
+ char ClientHostname[MAX_SIZE]; // Client host name
+ char ClientSoftwareName[MAX_SIZE]; // Client software name
+ UINT64 NextEchoSendTime; // Time to send Echo Request next
+ UINT64 LastRecvTime; // Time which the data has been received last
+ DHCP_OPTION_LIST ClientAddressOption; // Client address option
+ bool DhcpIpAllocTried; // Whether the request for an IP address is already attempted by DHCP
+ bool DhcpIpInformTried; // Whether the acquirement for an IP information is already attempted by DHCP
+ bool DhcpAllocated; // IP address is assigned by DHCP
+ bool UseStaticIPAddress; // Use a static IP address that is specified by the client
+ UINT64 DhcpRenewInterval; // DHCP update interval
+ UINT64 DhcpNextRenewTime; // DHCP renewal time of the next
+ char CryptName[MAX_SIZE]; // Cipher algorithm name
+ UINT AdjustMss; // MSS value
+ TUBE_FLUSH_LIST *FlushList; // Tube Flush List
+ bool EnableMSCHAPv2; // Enable the MS-CHAP v2
+ USHORT AuthProtocol; // Authentication protocol
+ bool AuthOk; // Flag for whether the authentication was successful
+ UCHAR MsChapV2_ServerChallenge[16]; // MS-CHAPv2 Server Challenge
+ UCHAR MsChapV2_ClientChallenge[16]; // MS-CHAPv2 Client Challenge
+ UCHAR MsChapV2_ClientResponse[24]; // MS-CHAPv2 Client Response
+ UCHAR MsChapV2_ServerResponse[20]; // MS-CHAPv2 Server Response
+ UINT MsChapV2_ErrorCode; // Authentication failure error code of MS-CHAPv2
+};
+
+// Function prototype
+THREAD *NewPPPSession(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, TUBE *send_tube, TUBE *recv_tube, char *postfix, char *client_software_name, char *client_hostname, char *crypt_name, UINT adjust_mss);
+void PPPThread(THREAD *thread, void *param);
+void FreePPPSession(PPP_SESSION *p);
+void FreePPPOptionList(LIST *o);
+void FreePPPLCP(PPP_LCP *c);
+PPP_LCP *NewPPPLCP(UCHAR code, UCHAR id);
+PPP_LCP *ParseLCP(USHORT protocol, void *data, UINT size);
+BUF *BuildLCPData(PPP_LCP *c);
+PPP_OPTION *GetOptionValue(PPP_LCP *c, UCHAR type);
+PPP_PACKET *ParsePPPPacket(void *data, UINT size);
+void FreePPPPacket(PPP_PACKET *pp);
+void FreePPPPacketEx(PPP_PACKET *pp, bool no_free_struct);
+BUF *BuildPPPPacketData(PPP_PACKET *pp);
+PPP_OPTION *NewPPPOption(UCHAR type, void *data, UINT size);
+bool PPPSendPacket(PPP_SESSION *p, PPP_PACKET *pp);
+bool PPPSendPacketEx(PPP_SESSION *p, PPP_PACKET *pp, bool no_flush);
+PPP_PACKET *PPPRecvPacket(PPP_SESSION *p, bool async);
+PPP_PACKET *PPPRecvPacketWithLowLayerProcessing(PPP_SESSION *p, bool async);
+PPP_PACKET *PPPRecvPacketForCommunication(PPP_SESSION *p);
+void PPPStoreLastPacket(PPP_SESSION *p, PPP_PACKET *pp);
+void PPPCleanTerminate(PPP_SESSION *p);
+bool PPPGetIPOptionFromLCP(PPP_IPOPTION *o, PPP_LCP *c);
+bool PPPSetIPOptionToLCP(PPP_IPOPTION *o, PPP_LCP *c, bool only_modify);
+bool PPPGetIPAddressValueFromLCP(PPP_LCP *c, UINT type, IP *ip);
+bool PPPSetIPAddressValueToLCP(PPP_LCP *c, UINT type, IP *ip, bool only_modify);
+
+bool PPPSendRequest(PPP_SESSION *p, USHORT protocol, PPP_LCP *c);
+USHORT PPPContinueCurrentProtocolRequestListening(PPP_SESSION *p, USHORT protocol);
+bool PPPContinueUntilFinishAllLCPOptionRequestsDetermined(PPP_SESSION *p);
+PPP_PACKET *PPPRecvResponsePacket(PPP_SESSION *p, PPP_PACKET *req, USHORT expected_protocol, USHORT *received_protocol, bool finish_when_all_lcp_acked);
+PPP_PACKET *PPPProcessRequestPacket(PPP_SESSION *p, PPP_PACKET *req);
+void PPPSendEchoRequest(PPP_SESSION *p);
+bool PPPParseUsername(CEDAR *cedar, char *src, ETHERIP_ID *dst);
+bool IsHubExistsWithLock(CEDAR *cedar, char *hubname);
+
+void GenerateNtPasswordHash(UCHAR *dst, char *password);
+void GenerateNtPasswordHashHash(UCHAR *dst_hash, UCHAR *src_hash);
+void MsChapV2Server_GenerateChallenge(UCHAR *dst);
+void MsChapV2Client_GenerateChallenge(UCHAR *dst);
+void MsChapV2_GenerateChallenge8(UCHAR *dst, UCHAR *client_challenge, UCHAR *server_challenge, char *username);
+void MsChapV2Client_GenerateResponse(UCHAR *dst, UCHAR *challenge8, UCHAR *nt_password_hash);
+void MsChapV2Server_GenerateResponse(UCHAR *dst, UCHAR *nt_password_hash_hash, UCHAR *client_response, UCHAR *challenge8);
+bool MsChapV2VerityPassword(IPC_MSCHAP_V2_AUTHINFO *d, char *password);
+char *MsChapV2DoBruteForce(IPC_MSCHAP_V2_AUTHINFO *d, LIST *password_list);
+
+#endif // IPSEC_PPP_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_Win7.c b/src/Cedar/IPsec_Win7.c
new file mode 100644
index 00000000..e04a81e2
--- /dev/null
+++ b/src/Cedar/IPsec_Win7.c
@@ -0,0 +1,530 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_Win7.c
+// Initialize the helper module for Windows 7 / Windows 8 / Windows Vista / Windows Server 2008 / Windows Server 2008 R2 / Windows Server 2012
+
+#include <GlobalConst.h>
+
+#ifdef WIN32
+
+#define _WIN32_WINNT 0x0600
+#define WINVER 0x0600
+#define INITGUID
+#include <winsock2.h>
+#include <Ws2tcpip.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <wininet.h>
+#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#include <Fwpmu.h>
+#include <Fwpmtypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+#include "IPsec_Win7Inner.h"
+#include <Wfp/Wfp.h>
+
+static IPSEC_WIN7_FUNCTIONS *api = NULL;
+static HINSTANCE hDll = NULL;
+
+
+// Initialize the IPsec helper module for Windows 7
+IPSEC_WIN7 *IPsecWin7Init()
+{
+ IPSEC_WIN7 *w;
+ FWPM_SESSION0 session;
+ UINT ret;
+ FWPM_FILTER0 filter;
+ UINT64 weight = MAXUINT64;
+
+ Debug("IPsecWin7Init()\n");
+
+ if (MsIsVista() == false)
+ {
+ return NULL;
+ }
+
+ if (MsIsAdmin() == false)
+ {
+ return NULL;
+ }
+
+ if (IPsecWin7InitApi() == false)
+ {
+ return NULL;
+ }
+
+ // Driver Initialization
+ if (IPsecWin7InitDriver() == false)
+ {
+ return NULL;
+ }
+
+ // Open the WFP (Dynamic Session)
+ Zero(&session, sizeof(session));
+ session.flags = FWPM_SESSION_FLAG_DYNAMIC;
+
+ w = ZeroMalloc(sizeof(IPSEC_WIN7));
+ ret = api->FwpmEngineOpen0(NULL, RPC_C_AUTHN_DEFAULT, NULL, &session, &w->hEngine);
+ if (ret)
+ {
+ Debug("FwpmEngineOpen0 Failed.\n");
+ IPsecWin7Free(w);
+ return NULL;
+ }
+
+ // Create the Filter (IPv4)
+ Zero(&filter, sizeof(filter));
+ filter.flags = FWPM_FILTER_FLAG_PERMIT_IF_CALLOUT_UNREGISTERED;
+ filter.layerKey = FWPM_LAYER_INBOUND_IPPACKET_V4;
+ filter.weight.type = FWP_UINT64;
+ filter.weight.uint64 = &weight;
+ filter.action.type = FWP_ACTION_CALLOUT_UNKNOWN;
+ filter.action.calloutKey = GUID_WFP_CALLOUT_DRIVER_V4;
+ filter.displayData.name = IPSEC_WIN7_FILTER_TITLE_V4;
+ ret = api->FwpmFilterAdd0(w->hEngine, &filter, NULL, &w->FilterIPv4Id);
+ if (ret)
+ {
+ Debug("FwpmFilterAdd0 for IPv4 Failed: 0x%X\n", ret);
+ }
+ else
+ {
+ Debug("FwpmFilterAdd0 for IPv4 Ok.\n");
+ }
+
+ // Create the Filter (IPv6)
+ Zero(&filter, sizeof(filter));
+ filter.flags = FWPM_FILTER_FLAG_PERMIT_IF_CALLOUT_UNREGISTERED;
+ filter.layerKey = FWPM_LAYER_INBOUND_IPPACKET_V6;
+ filter.weight.type = FWP_UINT64;
+ filter.weight.uint64 = &weight;
+ filter.action.type = FWP_ACTION_CALLOUT_UNKNOWN;
+ filter.action.calloutKey = GUID_WFP_CALLOUT_DRIVER_V6;
+ filter.displayData.name = IPSEC_WIN7_FILTER_TITLE_V6;
+ ret = api->FwpmFilterAdd0(w->hEngine, &filter, NULL, &w->FilterIPv6Id);
+ if (ret)
+ {
+ Debug("FwpmFilterAdd0 for IPv6 Failed: 0x%X\n", ret);
+ }
+ else
+ {
+ Debug("FwpmFilterAdd0 for IPv6 Ok.\n");
+ }
+
+ // Open the device of the driver as a file
+ w->hDriverFile = CreateFileA(WFP_DEVICE_FILE_NAME, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (w->hDriverFile == NULL || w->hDriverFile == INVALID_HANDLE_VALUE)
+ {
+ Debug("CreateFileA(\"%s\") Failed.\n", WFP_DEVICE_FILE_NAME);
+ IPsecWin7Free(w);
+ return NULL;
+ }
+
+ IPsecWin7UpdateHostIPAddressList(w);
+
+ Debug("IPsecWin7Init() Ok.\n");
+
+ return w;
+}
+
+// Update the IP address list of the host
+void IPsecWin7UpdateHostIPAddressList(IPSEC_WIN7 *w)
+{
+ LIST *o;
+ UINT i;
+ BUF *buf;
+ UINT retsize;
+ // Validate arguments
+ if (w == NULL)
+ {
+ return;
+ }
+
+ o = GetHostIPAddressList();
+ if (o == NULL)
+ {
+ return;
+ }
+
+ buf = NewBuf();
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IP *ip = LIST_DATA(o, i);
+ WFP_LOCAL_IP a;
+
+ Zero(&a, sizeof(a));
+
+ // Exclude any IPs or localhost IP
+ if (IsZeroIP(ip) == false && IsLocalHostIP(ip) == false)
+ {
+ if (IsIP4(ip))
+ {
+ a.IpVersion = 4;
+ Copy(a.IpAddress.IPv4Address, ip->addr, 4);
+ }
+ else
+ {
+ a.IpVersion = 6;
+ Copy(a.IpAddress.IPv6Address, ip->ipv6_addr, 16);
+ }
+
+ WriteBuf(buf, &a, sizeof(WFP_LOCAL_IP));
+ }
+ }
+
+ if (WriteFile(w->hDriverFile, buf->Buf, buf->Size, &retsize, NULL) == false)
+ {
+ Debug("WriteFile to the driver failed. %u\n", GetLastError());
+ }
+
+ FreeHostIPAddressList(o);
+
+ FreeBuf(buf);
+}
+
+// Release the module
+void IPsecWin7Free(IPSEC_WIN7 *w)
+{
+ // Validate arguments
+ if (w == NULL)
+ {
+ return;
+ }
+
+ if (w->hEngine != NULL)
+ {
+ api->FwpmEngineClose0(w->hEngine);
+ }
+
+ if (w->hDriverFile != NULL && w->hDriverFile != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(w->hDriverFile);
+ }
+
+ Free(w);
+}
+
+// Initialize and start the driver
+bool IPsecWin7InitDriver()
+{
+ bool ret;
+ void *lock = MsInitGlobalLock("IPsecWin7InitDriver", false);
+ void *p = MsDisableWow64FileSystemRedirection();
+
+ MsGlobalLock(lock);
+ {
+ ret = IPsecWin7InitDriverInner();
+ }
+ MsGlobalUnlock(lock);
+
+ MsFreeGlobalLock(lock);
+
+ MsRestoreWow64FileSystemRedirection(p);
+
+ Debug("IPsecWin7InitDriver: %u\n", ret);
+
+ return ret;
+}
+bool IPsecWin7InitDriverInner()
+{
+ char sys_filename[MAX_PATH];
+ bool install_driver = true;
+ HANDLE hEngine;
+ UINT ret;
+ FWPM_SESSION0 session;
+ UINT id;
+ FWPM_CALLOUT0 callout;
+
+ Format(sys_filename, sizeof(sys_filename), IPSEC_WIN7_DST_SYS, MsGetSystem32Dir());
+
+ if (IsFileExists(sys_filename) && MsIsServiceInstalled(IPSEC_WIN7_DRIVER_NAME))
+ {
+ if (GetCurrentIPsecWin7DriverBuild() >= CEDAR_BUILD)
+ {
+ // Not to install since the latest version has been already installed
+ install_driver = false;
+ }
+ }
+
+ if (install_driver)
+ {
+ char *src_filename = IPSEC_WIN7_SRC_SYS_X86;
+ if (MsIsX64())
+ {
+ src_filename = IPSEC_WIN7_SRC_SYS_X64;
+ }
+
+ // Copy the driver
+ if (FileCopy(src_filename, sys_filename) == false)
+ {
+ Debug("%s copy failed.\n", sys_filename);
+ return false;
+ }
+ Debug("%s copied.\n", sys_filename);
+
+ // Set the build number
+ SetCurrentIPsecWin7DriverBuild();
+ }
+
+ // Get whether the device drivers is already installed
+ if (MsIsServiceInstalled(IPSEC_WIN7_DRIVER_NAME) == false)
+ {
+ wchar_t sys_filename_w[MAX_PATH];
+
+ StrToUni(sys_filename_w, sizeof(sys_filename_w), sys_filename);
+
+ // Run a new installation
+ if (MsInstallDeviceDriverW(IPSEC_WIN7_DRIVER_NAME, IPSEC_WIN7_DRIVER_TITLE,
+ sys_filename_w, NULL) == false)
+ {
+ // Installation failed
+ Debug("MsInstallDeviceDriverW failed.\n");
+ return false;
+ }
+ }
+
+ // Start if the device driver is stopped
+ if (MsIsServiceRunning(IPSEC_WIN7_DRIVER_NAME) == false)
+ {
+ if (MsStartService(IPSEC_WIN7_DRIVER_NAME) == false)
+ {
+ // Start failure
+ Debug("MsStartService failed.\n");
+ return false;
+ }
+
+ Debug("%s service started.\n", IPSEC_WIN7_DRIVER_NAME);
+ }
+ else
+ {
+ Debug("%s service was already started.\n", IPSEC_WIN7_DRIVER_NAME);
+ }
+
+ // Open the WFP
+ Zero(&session, sizeof(session));
+
+ ret = api->FwpmEngineOpen0(NULL, RPC_C_AUTHN_DEFAULT, NULL, &session, &hEngine);
+ if (ret)
+ {
+ Debug("FwpmEngineOpen0 failed.\n");
+ return false;
+ }
+
+ // Create the Callout Driver (IPv4)
+ Zero(&callout, sizeof(callout));
+ callout.calloutKey = GUID_WFP_CALLOUT_DRIVER_V4;
+ callout.applicableLayer = FWPM_LAYER_INBOUND_IPPACKET_V4;
+ callout.displayData.name = IPSEC_WIN7_DRIVER_TITLE_V4;
+ ret = api->FwpmCalloutAdd0(hEngine, &callout, NULL, &id);
+ if (ret)
+ {
+ Debug("FwpmCalloutAdd0 for IPv4 Failed: 0x%X\n", ret);
+ }
+ else
+ {
+ Debug("FwpmCalloutAdd0 for IPv4 Ok.\n");
+ }
+
+ // Create the Callout Driver (IPv6)
+ Zero(&callout, sizeof(callout));
+ callout.calloutKey = GUID_WFP_CALLOUT_DRIVER_V6;
+ callout.applicableLayer = FWPM_LAYER_INBOUND_IPPACKET_V6;
+ callout.displayData.name = IPSEC_WIN7_DRIVER_TITLE_V6;
+ ret = api->FwpmCalloutAdd0(hEngine, &callout, NULL, &id);
+ if (ret)
+ {
+ Debug("FwpmCalloutAdd0 for IPv6 Failed: 0x%X\n", ret);
+ }
+ else
+ {
+ Debug("FwpmCalloutAdd0 for IPv6 Ok.\n");
+ }
+
+ api->FwpmEngineClose0(hEngine);
+
+ return true;
+}
+
+// Write the build number of the current driver
+void SetCurrentIPsecWin7DriverBuild()
+{
+ MsRegWriteInt(REG_LOCAL_MACHINE, IPSEC_WIN7_DRIVER_REGKEY, IPSEC_WIN7_DRIVER_BUILDNUMBER, CEDAR_BUILD);
+}
+
+// Get the build number of the current driver
+UINT GetCurrentIPsecWin7DriverBuild()
+{
+ return MsRegReadInt(REG_LOCAL_MACHINE, IPSEC_WIN7_DRIVER_REGKEY, IPSEC_WIN7_DRIVER_BUILDNUMBER);
+}
+
+// Initialization of the API
+bool IPsecWin7InitApi()
+{
+ if (api != NULL)
+ {
+ return true;
+ }
+
+ if (hDll == NULL)
+ {
+ hDll = LoadLibraryA("FWPUCLNT.DLL");
+ }
+
+ if (hDll == NULL)
+ {
+ return false;
+ }
+
+ api = malloc(sizeof(IPSEC_WIN7_FUNCTIONS));
+ Zero(api, sizeof(IPSEC_WIN7_FUNCTIONS));
+
+ api->FwpmEngineOpen0 =
+ (DWORD (__stdcall *)(const wchar_t *,UINT32,SEC_WINNT_AUTH_IDENTITY_W *,const FWPM_SESSION0 *,HANDLE *))
+ GetProcAddress(hDll, "FwpmEngineOpen0");
+
+ api->FwpmEngineClose0 =
+ (DWORD (__stdcall *)(HANDLE))
+ GetProcAddress(hDll, "FwpmEngineClose0");
+
+ api->FwpmFreeMemory0 =
+ (void (__stdcall *)(void **))
+ GetProcAddress(hDll, "FwpmFreeMemory0");
+
+ api->FwpmFilterAdd0 =
+ (DWORD (__stdcall *)(HANDLE,const FWPM_FILTER0 *,PSECURITY_DESCRIPTOR,UINT64 *))
+ GetProcAddress(hDll, "FwpmFilterAdd0");
+
+ api->IPsecSaContextCreate0 =
+ (DWORD (__stdcall *)(HANDLE,const IPSEC_TRAFFIC0 *,UINT64 *,UINT64 *))
+ GetProcAddress(hDll, "IPsecSaContextCreate0");
+
+ api->IPsecSaContextGetSpi0 =
+ (DWORD (__stdcall *)(HANDLE,UINT64,const IPSEC_GETSPI0 *,IPSEC_SA_SPI *))
+ GetProcAddress(hDll, "IPsecSaContextGetSpi0");
+
+ api->IPsecSaContextAddInbound0 =
+ (DWORD (__stdcall *)(HANDLE,UINT64,const IPSEC_SA_BUNDLE0 *))
+ GetProcAddress(hDll, "IPsecSaContextAddInbound0");
+
+ api->IPsecSaContextAddOutbound0 =
+ (DWORD (__stdcall *)(HANDLE,UINT64,const IPSEC_SA_BUNDLE0 *))
+ GetProcAddress(hDll, "IPsecSaContextAddOutbound0");
+
+ api->FwpmCalloutAdd0 =
+ (DWORD (__stdcall *)(HANDLE,const FWPM_CALLOUT0 *,PSECURITY_DESCRIPTOR,UINT32 *))
+ GetProcAddress(hDll, "FwpmCalloutAdd0");
+
+ if (api->FwpmEngineOpen0 == NULL ||
+ api->FwpmEngineClose0 == NULL ||
+ api->FwpmFreeMemory0 == NULL ||
+ api->FwpmFilterAdd0 == NULL ||
+ api->IPsecSaContextCreate0 == NULL ||
+ api->IPsecSaContextGetSpi0 == NULL ||
+ api->IPsecSaContextAddInbound0 == NULL ||
+ api->IPsecSaContextAddOutbound0 == NULL ||
+ api->FwpmCalloutAdd0 == NULL)
+ {
+ free(api);
+ api = NULL;
+ return false;
+ }
+
+ return true;
+}
+
+#endif // WIN32
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_Win7.h b/src/Cedar/IPsec_Win7.h
new file mode 100644
index 00000000..35a8b664
--- /dev/null
+++ b/src/Cedar/IPsec_Win7.h
@@ -0,0 +1,121 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_Win7.h
+// Header of IPsec_Win7.c
+
+#ifndef IPSEC_WIN7_H
+#define IPSEC_WIN7_H
+
+// Constants
+#define IPSEC_WIN7_SRC_SYS_X86 "|pxwfp_x86.sys"
+#define IPSEC_WIN7_SRC_SYS_X64 "|pxwfp_x64.sys"
+#define IPSEC_WIN7_DST_SYS "%s\\drivers\\pxwfp.sys"
+
+#define IPSEC_WIN7_DRIVER_NAME "pxwfp"
+#define IPSEC_WIN7_DRIVER_TITLE L"SoftEther PacketiX VPN IPsec WFP Callout Driver"
+#define IPSEC_WIN7_DRIVER_TITLE_V4 L"SoftEther PacketiX VPN IPsec WFP Callout for IPv4"
+#define IPSEC_WIN7_DRIVER_TITLE_V6 L"SoftEther PacketiX VPN IPsec WFP Callout for IPv6"
+#define IPSEC_WIN7_FILTER_TITLE_V4 CEDAR_PRODUCT_STR_W L" VPN IPsec Filter for IPv4"
+#define IPSEC_WIN7_FILTER_TITLE_V6 CEDAR_PRODUCT_STR_W L" VPN IPsec Filter for IPv6"
+#define IPSEC_WIN7_DRIVER_REGKEY "SYSTEM\\CurrentControlSet\\services\\pxwfp"
+#define IPSEC_WIN7_DRIVER_BUILDNUMBER "CurrentInstalledBuild"
+
+
+// Function prototype
+IPSEC_WIN7 *IPsecWin7Init();
+void IPsecWin7Free(IPSEC_WIN7 *w);
+void IPsecWin7UpdateHostIPAddressList(IPSEC_WIN7 *w);
+
+bool IPsecWin7InitDriver();
+bool IPsecWin7InitDriverInner();
+UINT GetCurrentIPsecWin7DriverBuild();
+void SetCurrentIPsecWin7DriverBuild();
+bool IPsecWin7InitApi();
+
+
+#endif // IPSEC_WIN7_H
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/IPsec_Win7Inner.h b/src/Cedar/IPsec_Win7Inner.h
new file mode 100644
index 00000000..b57054b1
--- /dev/null
+++ b/src/Cedar/IPsec_Win7Inner.h
@@ -0,0 +1,160 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// IPsec_Win7.h
+// Internal header of IPsec_Win7.c
+
+#ifndef IPSEC_WIN7_INNER_H
+#define IPSEC_WIN7_INNER_H
+
+// API function
+typedef struct IPSEC_WIN7_FUNCTIONS
+{
+ DWORD (WINAPI *FwpmEngineOpen0)(
+ IN OPTIONAL const wchar_t* serverName,
+ IN UINT32 authnService,
+ IN OPTIONAL SEC_WINNT_AUTH_IDENTITY_W* authIdentity,
+ IN OPTIONAL const FWPM_SESSION0* session,
+ OUT HANDLE* engineHandle
+ );
+
+ DWORD (WINAPI *FwpmEngineClose0)(IN HANDLE engineHandle);
+
+ void (WINAPI *FwpmFreeMemory0)(IN OUT void** p);
+
+ DWORD (WINAPI *FwpmFilterAdd0)(
+ IN HANDLE engineHandle,
+ IN const FWPM_FILTER0* filter,
+ IN OPTIONAL PSECURITY_DESCRIPTOR sd,
+ OUT OPTIONAL UINT64* id
+ );
+
+ DWORD (WINAPI *IPsecSaContextCreate0)(
+ IN HANDLE engineHandle,
+ IN const IPSEC_TRAFFIC0* outboundTraffic,
+ OUT OPTIONAL UINT64* inboundFilterId,
+ OUT UINT64* id
+ );
+
+ DWORD (WINAPI *IPsecSaContextGetSpi0)(
+ IN HANDLE engineHandle,
+ IN UINT64 id,
+ IN const IPSEC_GETSPI0* getSpi,
+ OUT IPSEC_SA_SPI* inboundSpi
+ );
+
+ DWORD (WINAPI *IPsecSaContextAddInbound0)(
+ IN HANDLE engineHandle,
+ IN UINT64 id,
+ IN const IPSEC_SA_BUNDLE0* inboundBundle
+ );
+
+ DWORD (WINAPI *IPsecSaContextAddOutbound0)(
+ IN HANDLE engineHandle,
+ IN UINT64 id,
+ IN const IPSEC_SA_BUNDLE0* outboundBundle
+ );
+
+ DWORD (WINAPI *FwpmCalloutAdd0)(
+ IN HANDLE engineHandle,
+ IN const FWPM_CALLOUT0* callout,
+ IN OPTIONAL PSECURITY_DESCRIPTOR sd,
+ OUT OPTIONAL UINT32* id
+ );
+
+} IPSEC_WIN7_FUNCTIONS;
+
+// Instance
+struct IPSEC_WIN7
+{
+ HANDLE hEngine;
+ HANDLE hDriverFile;
+ UINT64 FilterIPv4Id, FilterIPv6Id;
+};
+
+
+#endif // IPSEC_WIN7_INNER_H
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Interop_OpenVPN.c b/src/Cedar/Interop_OpenVPN.c
new file mode 100644
index 00000000..48045333
--- /dev/null
+++ b/src/Cedar/Interop_OpenVPN.c
@@ -0,0 +1,2942 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Interop_OpenVPN.c
+// OpenVPN protocol stack
+
+#include "CedarPch.h"
+
+
+static bool g_no_openvpn_tcp = false;
+static bool g_no_openvpn_udp = false;
+
+// Ping signature of the OpenVPN protocol
+static UCHAR ping_signature[] =
+{
+ 0x2a, 0x18, 0x7b, 0xf3, 0x64, 0x1e, 0xb4, 0xcb,
+ 0x07, 0xed, 0x2d, 0x0a, 0x98, 0x1f, 0xc7, 0x48
+};
+
+// Set the OpenVPN over TCP disabling flag
+void OvsSetNoOpenVpnTcp(bool b)
+{
+ g_no_openvpn_tcp = b;
+}
+
+// Get the OpenVPN over TCP disabling flag
+bool OvsGetNoOpenVpnTcp()
+{
+ return g_no_openvpn_tcp;
+}
+
+// Set the OpenVPN over UDP disabling flag
+void OvsSetNoOpenVpnUdp(bool b)
+{
+ g_no_openvpn_udp = b;
+}
+
+// Get the OpenVPN over UDP disabling flag
+bool OvsGetNoOpenVpnUdp()
+{
+ return g_no_openvpn_udp;
+}
+
+
+// Write the OpenVPN log
+void OvsLog(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c, char *name, ...)
+{
+ wchar_t prefix[MAX_SIZE * 2];
+ wchar_t buf2[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+ if (se == NULL)
+ {
+ UniStrCpy(prefix, sizeof(prefix), _UU("LO_PREFIX_RAW"));
+ }
+ else
+ {
+ if (c == NULL)
+ {
+ UniFormat(prefix, sizeof(prefix), _UU("LO_PREFIX_SESSION"),
+ se->Id, &se->ClientIp, se->ClientPort, &se->ServerIp, se->ServerPort);
+ }
+ else
+ {
+ UniFormat(prefix, sizeof(prefix), _UU("LO_PREFIX_CHANNEL"),
+ se->Id, &se->ClientIp, se->ClientPort, &se->ServerIp, se->ServerPort,
+ c->KeyId);
+ }
+ }
+ va_start(args, name);
+ UniFormatArgs(buf2, sizeof(buf2), _UU(name), args);
+ va_end(args);
+
+ UniStrCat(prefix, sizeof(prefix), buf2);
+
+ WriteServerLog(s->Cedar, prefix);
+}
+
+// Process the received packet
+void OvsProceccRecvPacket(OPENVPN_SERVER *s, UDPPACKET *p, UINT protocol)
+{
+ OPENVPN_SESSION *se;
+ OPENVPN_PACKET *recv_packet;
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+
+ // Search for the session
+ se = OvsFindOrCreateSession(s, &p->DstIP, p->DestPort, &p->SrcIP, p->SrcPort, protocol);
+ if (se == NULL)
+ {
+ return;
+ }
+
+ // Parse the packet
+ recv_packet = OvsParsePacket(p->Data, p->Size);
+
+ if (recv_packet != NULL)
+ {
+ OPENVPN_CHANNEL *c = NULL;
+ if (recv_packet->OpCode != OPENVPN_P_DATA_V1 && recv_packet->MySessionId != 0)
+ {
+ Debug("RECV PACKET: %u %I64u\n", recv_packet->KeyId, recv_packet->MySessionId);
+ }
+ if (recv_packet->OpCode != OPENVPN_P_DATA_V1)
+ {
+ Debug(" PKT %u %u\n", recv_packet->OpCode, recv_packet->KeyId);
+ }
+
+ if (recv_packet->OpCode != OPENVPN_P_DATA_V1)
+ {
+ // Control packet
+ if (recv_packet->OpCode == OPENVPN_P_CONTROL_HARD_RESET_CLIENT_V2 ||
+ recv_packet->OpCode == OPENVPN_P_CONTROL_SOFT_RESET_V1)
+ {
+ // Connection request packet
+ if (se->Channels[recv_packet->KeyId] != NULL)
+ {
+ // Release when there is a channel data already
+ OvsFreeChannel(se->Channels[recv_packet->KeyId]);
+ se->Channels[recv_packet->KeyId] = NULL;
+ }
+
+ // Create a new channel
+ c = OvsNewChannel(se, recv_packet->KeyId);
+ if (se->ClientSessionId == 0)
+ {
+ se->ClientSessionId = recv_packet->MySessionId;
+ }
+ se->Channels[recv_packet->KeyId] = c;
+ Debug("OpenVPN New Channel :%u\n", recv_packet->KeyId);
+ OvsLog(s, se, c, "LO_NEW_CHANNEL");
+ }
+/* else if (recv_packet->OpCode == OPENVPN_P_CONTROL_SOFT_RESET_V1)
+ {
+ // Response to soft reset request packet
+ OPENVPN_PACKET *p;
+
+ p = OvsNewControlPacket(OPENVPN_P_CONTROL_SOFT_RESET_V1, recv_packet->KeyId, se->ServerSessionId,
+ 0, NULL, 0, 0, 0, NULL);
+
+ OvsSendPacketNow(s, se, p);
+
+ OvsFreePacket(p);
+ }*/
+ else
+ {
+ // Packet other than the connection request
+ if (se->Channels[recv_packet->KeyId] != NULL)
+ {
+ c = se->Channels[recv_packet->KeyId];
+ }
+ }
+
+ if (c != NULL)
+ {
+ // Delete the send packet list by looking the packet ID in the ACK list of arrived packet
+ OvsDeleteFromSendingControlPacketList(c, recv_packet->NumAck, recv_packet->AckPacketId);
+
+ if (recv_packet->OpCode != OPENVPN_P_ACK_V1)
+ {
+ // Add the Packet ID of arrived packet to the list
+ InsertIntDistinct(c->AckReplyList, recv_packet->PacketId);
+ Debug("Recv Packet ID (c=%u): %u\n", c->KeyId, recv_packet->PacketId);
+
+ if ((recv_packet->PacketId > c->MaxRecvPacketId)
+ || (recv_packet->OpCode == OPENVPN_P_CONTROL_HARD_RESET_CLIENT_V2)
+ || (recv_packet->OpCode == OPENVPN_P_CONTROL_SOFT_RESET_V1))
+ {
+ c->MaxRecvPacketId = recv_packet->PacketId;
+
+ // Process the received control packet
+ OvsProcessRecvControlPacket(s, se, c, recv_packet);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Data packet
+ if (se->Channels[recv_packet->KeyId] != NULL)
+ {
+ OPENVPN_CHANNEL *c = se->Channels[recv_packet->KeyId];
+ if (c->Status == OPENVPN_CHANNEL_STATUS_ESTABLISHED)
+ {
+ UCHAR *data;
+ UINT size;
+
+ data = recv_packet->Data;
+ size = recv_packet->DataSize;
+
+ if (size >= (c->MdRecv->Size + c->CipherDecrypt->IvSize + sizeof(UINT)))
+ {
+ UCHAR *hmac;
+ UCHAR *iv;
+ UCHAR hmac_test[128];
+
+ // HMAC
+ hmac = data;
+ data += c->MdRecv->Size;
+ size -= c->MdRecv->Size;
+
+ // Confirmation of HMAC
+ MdProcess(c->MdRecv, hmac_test, data, size);
+ if (Cmp(hmac_test, hmac, c->MdRecv->Size) == 0)
+ {
+ // Update of last communication time
+ se->LastCommTick = s->Now;
+
+ // IV
+ iv = data;
+ data += c->CipherDecrypt->IvSize;
+ size -= c->CipherDecrypt->IvSize;
+
+ // Payload
+ if (size >= 1 && (c->CipherDecrypt->BlockSize == 0 || (size % c->CipherDecrypt->BlockSize) == 0))
+ {
+ UINT data_packet_id;
+
+ // Decryption
+ size = CipherProcess(c->CipherDecrypt, iv, s->TmpBuf, data, size);
+
+ data = s->TmpBuf;
+
+ if (size >= sizeof(UINT))
+ {
+ data_packet_id = READ_UINT(data);
+
+ data += sizeof(UINT);
+ size -= sizeof(UINT);
+
+ if (size >= sizeof(ping_signature) &&
+ Cmp(data, ping_signature, sizeof(ping_signature)) == 0)
+ {
+ // Ignore since a ping packet has been received
+ DoNothing();
+ }
+ else
+ {
+ // Receive a packet!!
+ if (se->Ipc != NULL)
+ {
+ switch (se->Mode)
+ {
+ case OPENVPN_MODE_L2: // Send an Ethernet packet to a session
+ IPCSendL2(se->Ipc, data, size);
+ break;
+
+ case OPENVPN_MODE_L3: // Send an IPv4 packet to a session
+ IPCSendIPv4(se->Ipc, data, size);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+// Debug("HMAC Failed (c=%u)\n", c->KeyId);
+ }
+ }
+ }
+ }
+ }
+
+ OvsFreePacket(recv_packet);
+ }
+}
+
+// Remove a packet which the opponent has received from the transmission list
+void OvsDeleteFromSendingControlPacketList(OPENVPN_CHANNEL *c, UINT num_acks, UINT *acks)
+{
+ LIST *o;
+ UINT i;
+ // Validate arguments
+ if (c == NULL || num_acks == 0)
+ {
+ return;
+ }
+
+ o = NewListFast(NULL);
+ for (i = 0;i < num_acks;i++)
+ {
+ UINT ack = acks[i];
+ UINT j;
+
+ for (j = 0;j < LIST_NUM(c->SendControlPacketList);j++)
+ {
+ OPENVPN_CONTROL_PACKET *p = LIST_DATA(c->SendControlPacketList, j);
+
+ if (p->PacketId == ack)
+ {
+ AddDistinct(o, p);
+ }
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ OPENVPN_CONTROL_PACKET *p = LIST_DATA(o, i);
+
+ Delete(c->SendControlPacketList, p);
+
+ OvsFreeControlPacket(p);
+ }
+
+ ReleaseList(o);
+}
+
+// Process the received control packet
+void OvsProcessRecvControlPacket(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c, OPENVPN_PACKET *p)
+{
+ FIFO *recv_fifo = NULL;
+ FIFO *send_fifo = NULL;
+ // Validate arguments
+ if (s == NULL || se == NULL || c == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (p->OpCode == OPENVPN_P_CONTROL_V1)
+ {
+ Debug("SSL (c=%u): %u\n", c->KeyId, p->DataSize);
+
+ if (c->SslPipe == NULL)
+ {
+ // Create an SSL pipe
+ Lock(s->Cedar->lock);
+ {
+ c->SslPipe = NewSslPipe(true, s->Cedar->ServerX, s->Cedar->ServerK, s->Dh);
+ }
+ Unlock(s->Cedar->lock);
+
+ Debug("SSL Pipe Created (c=%u).\n", c->KeyId);
+ }
+
+ if (c->SslPipe->IsDisconnected == false)
+ {
+ // Pour the physically received data into SSL pipe
+ if (FifoSize(c->SslPipe->RawIn->SendFifo) < OPENVPN_MAX_SSL_RECV_BUF_SIZE)
+ {
+ Debug("SSL_Write: %u\n", p->DataSize);
+ WriteFifo(c->SslPipe->RawIn->SendFifo, p->Data, p->DataSize);
+ }
+ SyncSslPipe(c->SslPipe);
+ }
+ }
+
+ if (c->SslPipe != NULL && c->SslPipe->IsDisconnected == false)
+ {
+ recv_fifo = c->SslPipe->SslInOut->RecvFifo;
+ send_fifo = c->SslPipe->SslInOut->SendFifo;
+ }
+
+ Debug("SIZE: recv_fifo = %u, send_fifo = %u\n", FifoSize(recv_fifo), FifoSize(send_fifo));
+
+ switch (c->Status)
+ {
+ case OPENVPN_CHANNEL_STATUS_INIT:
+ switch (p->OpCode)
+ {
+ case OPENVPN_P_CONTROL_SOFT_RESET_V1:
+ // Key update (soft reset)
+ if (se->Established)
+ {
+ if (c->IsInitiatorServer == false)
+ {
+ OvsSendControlPacket(c, OPENVPN_P_CONTROL_SOFT_RESET_V1, NULL, 0);
+ }
+
+ c->Status = OPENVPN_CHANNEL_STATUS_TLS_WAIT_CLIENT_KEY;
+ c->IsRekeyChannel = true;
+ }
+ break;
+
+ case OPENVPN_P_CONTROL_HARD_RESET_CLIENT_V2:
+ // New connection (hard reset)
+ OvsSendControlPacket(c, OPENVPN_P_CONTROL_HARD_RESET_SERVER_V2, NULL, 0);
+
+ c->Status = OPENVPN_CHANNEL_STATUS_TLS_WAIT_CLIENT_KEY;
+ break;
+ }
+ break;
+
+ case OPENVPN_CHANNEL_STATUS_TLS_WAIT_CLIENT_KEY:
+ if (FifoSize(recv_fifo) >= 1)
+ {
+ OPENVPN_KEY_METHOD_2 data;
+ UCHAR *ptr = FifoPtr(recv_fifo);
+
+ // Parse OPENVPN_KEY_METHOD_2
+ UINT read_size = OvsParseKeyMethod2(&data, ptr, FifoSize(recv_fifo), true);
+ if (read_size != 0)
+ {
+ BUF *b;
+
+ // Success in parsing key information
+ ReadFifo(recv_fifo, NULL, read_size);
+
+ // Set session parameters
+ OvsSetupSessionParameters(s, se, c, &data);
+
+ // Build OPENVPN_KEY_METHOD_2 to respond
+ b = OvsBuildKeyMethod2(&c->ServerKey);
+
+ // Transmission of the response data
+ if (b != NULL)
+ {
+ WriteFifo(send_fifo, b->Buf, b->Size);
+
+ FreeBuf(b);
+ }
+
+ // State transition
+ c->Status = OPENVPN_CHANNEL_STATUS_TLS_WAIT_CLIENT_PUSH_REQUEST;
+ if (c->IsRekeyChannel)
+ {
+ c->Status = OPENVPN_CHANNEL_STATUS_ESTABLISHED;
+ c->EstablishedTick = s->Now;
+ Debug("OpenVPN Channel %u Established (re-key).\n", c->KeyId);
+ OvsLog(s, se, c, "LO_CHANNEL_ESTABLISHED_NEWKEY");
+ }
+ }
+ }
+ break;
+
+ case OPENVPN_CHANNEL_STATUS_TLS_WAIT_CLIENT_PUSH_REQUEST:
+ if (FifoSize(recv_fifo) >= 1)
+ {
+ char tmp[MAX_SIZE];
+ UINT read_size = OvsPeekStringFromFifo(recv_fifo, tmp, sizeof(tmp));
+
+ if (read_size >= 1)
+ {
+ Debug("Client->Server (c=%u): %s\n", c->KeyId, tmp);
+
+ ReadFifo(recv_fifo, NULL, read_size);
+
+ if (StartWith(tmp, "PUSH_REQUEST"))
+ {
+ // Since connection requested, start VPN connection
+ // When the IPC VPN connection has not been started yet, start it
+ OvsBeginIPCAsyncConnectionIfEmpty(s, se, c);
+
+ // State transition
+ c->Status = OPENVPN_CHANNEL_STATUS_TLS_VPN_CONNECTING;
+ }
+ }
+ }
+ break;
+
+ case OPENVPN_CHANNEL_STATUS_TLS_VPN_CONNECTING:
+ case OPENVPN_CHANNEL_STATUS_ESTABLISHED:
+ if (FifoSize(recv_fifo) >= 1)
+ {
+ char tmp[MAX_SIZE];
+ UINT read_size = OvsPeekStringFromFifo(recv_fifo, tmp, sizeof(tmp));
+
+ if (read_size >= 1)
+ {
+ Debug("Client->Server (c=%u): %s\n", c->KeyId, tmp);
+
+ ReadFifo(recv_fifo, NULL, read_size);
+
+ if (StartWith(tmp, "PUSH_REQUEST"))
+ {
+ WriteFifo(send_fifo, se->PushReplyStr, StrLen(se->PushReplyStr));
+ }
+ }
+ }
+ break;
+ }
+}
+
+// Calculate the proper MSS
+UINT OvsCalcTcpMss(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c)
+{
+ UINT ret = MTU_FOR_PPPOE;
+ // Validate arguments
+ if (s == NULL || se == NULL || c == NULL)
+ {
+ return 0;
+ }
+
+ if (c->MdSend == NULL || c->CipherEncrypt == NULL)
+ {
+ return 0;
+ }
+
+ if (se->Protocol == OPENVPN_PROTOCOL_TCP)
+ {
+ // Calculation is not required for TCP mode
+ return 0;
+ }
+
+ // IPv4 / IPv6
+ if (IsIP4(&se->ClientIp))
+ {
+ ret -= 20;
+ }
+ else
+ {
+ ret -= 40;
+ }
+
+ // UDP
+ ret -= 8;
+
+ // opcode
+ ret -= 1;
+
+ // HMAC
+ ret -= c->MdSend->Size;
+
+ // IV
+ ret -= c->CipherEncrypt->IvSize;
+
+ // Packet ID
+ ret -= 4;
+
+ if (c->CipherEncrypt->IsNullCipher == false)
+ {
+ // block
+ ret -= c->CipherEncrypt->BlockSize;
+ }
+
+ if (se->Mode == OPENVPN_MODE_L2)
+ {
+ // Inner Ethernet Header
+ ret -= 14;
+ }
+
+ // Inner IPv4
+ ret -= 20;
+
+ // Inner TCP
+ ret -= 20;
+
+ return ret;
+}
+
+// When the IPC VPN connection has not been started yet, start it
+void OvsBeginIPCAsyncConnectionIfEmpty(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c)
+{
+ // Validate arguments
+ if (s == NULL || se == NULL || c == NULL)
+ {
+ return;
+ }
+
+ if (IsIPCConnected(se->Ipc) == false)
+ {
+ FreeIPC(se->Ipc);
+
+ se->Ipc = NULL;
+ }
+
+ if (se->IpcAsync == NULL)
+ {
+ IPC_PARAM p;
+ ETHERIP_ID id;
+
+ Zero(&p, sizeof(p));
+ Zero(&id, sizeof(id));
+
+ // Parse the user name
+ PPPParseUsername(s->Cedar, c->ClientKey.Username, &id);
+
+
+ // Build IPC connection parameters
+ StrCpy(p.ClientName, sizeof(p.ClientName), OPENVPN_IPC_CLIENT_NAME);
+ StrCpy(p.Postfix, sizeof(p.Postfix), (se->Mode == OPENVPN_MODE_L3 ? OPENVPN_IPC_POSTFIX_L3 : OPENVPN_IPC_POSTFIX_L2));
+
+ StrCpy(p.UserName, sizeof(p.UserName), id.UserName);
+ StrCpy(p.HubName, sizeof(p.HubName), id.HubName);
+ StrCpy(p.Password, sizeof(p.Password), c->ClientKey.Password);
+
+ Copy(&p.ClientIp, &se->ClientIp, sizeof(IP));
+ p.ClientPort = se->ClientPort;
+
+ Copy(&p.ServerIp, &se->ServerIp, sizeof(IP));
+ p.ServerPort = se->ServerPort;
+
+ if (c->CipherEncrypt->IsNullCipher == false)
+ {
+ StrCpy(p.CryptName, sizeof(p.CryptName), c->CipherEncrypt->Name);
+ }
+
+ if (se->Mode == OPENVPN_MODE_L3)
+ {
+ // L3 Mode
+ p.IsL3Mode = true;
+ }
+ else
+ {
+ // L2 Mode
+ p.BridgeMode = true;
+ }
+
+ p.IsOpenVPN = true;
+
+ // Calculate the MSS
+ p.Mss = OvsCalcTcpMss(s, se, c);
+ Debug("MSS=%u\n", p.Mss);
+
+ // Start an IPC connection
+ se->IpcAsync = NewIPCAsync(s->Cedar, &p, s->SockEvent);
+ }
+}
+
+// Peek a NULL-terminated string from the FIFO
+UINT OvsPeekStringFromFifo(FIFO *f, char *str, UINT str_size)
+{
+ UINT i;
+ bool ok = false;
+ // Validate arguments
+ if (f == NULL || str == NULL || str_size == 0)
+ {
+ return 0;
+ }
+
+ StrCpy(str, str_size, "");
+
+ for (i = 0;i < MIN(str_size, FifoSize(f));i++)
+ {
+ char c = *(((char *)FifoPtr(f)) + i);
+
+ if (c != 0)
+ {
+ str[i] = c;
+ }
+ else
+ {
+ str[i] = 0;
+ i++;
+ ok = true;
+ break;
+ }
+ }
+
+ if (ok == false)
+ {
+ return 0;
+ }
+
+ return i;
+}
+
+// Set session parameters
+void OvsSetupSessionParameters(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c, OPENVPN_KEY_METHOD_2 *data)
+{
+ LIST *o;
+ BUF *b;
+ // Validate arguments
+ if (s == NULL || se == NULL || c == NULL || data == NULL)
+ {
+ return;
+ }
+
+ Copy(&c->ClientKey, data, sizeof(OPENVPN_KEY_METHOD_2));
+
+ // Parse the parameter string
+ Debug("Parsing Option Str: %s\n", data->OptionString);
+
+ OvsLog(s, se, c, "LO_OPTION_STR_RECV", data->OptionString);
+
+ o = OvsParseOptions(data->OptionString);
+
+ if (se->Mode == OPENVPN_MODE_UNKNOWN)
+ {
+ UINT mtu;
+ // Layer
+ if (StrCmpi(IniStrValue(o, "dev-type"), "tun") == 0)
+ {
+ // L3
+ se->Mode = OPENVPN_MODE_L3;
+ }
+ else
+ {
+ // L2
+ se->Mode = OPENVPN_MODE_L2;
+ }
+
+ // Link MTU
+ mtu = IniIntValue(o, "link-mtu");
+ if (mtu == 0)
+ {
+ mtu = OPENVPN_MTU_LINK;
+ }
+ se->LinkMtu = mtu;
+
+ // Tun MTU
+ mtu = IniIntValue(o, "tun-mtu");
+ if (mtu == 0)
+ {
+ mtu = OPENVPN_MTU_TUN;
+ }
+ se->TunMtu = mtu;
+ }
+
+ // Protocol
+ if (se->Protocol == OPENVPN_PROTOCOL_TCP)
+ {
+ // TCP
+ // UDP
+ if (IsIP6(&se->ClientIp) == false)
+ {
+ StrCpy(c->Proto, sizeof(c->Proto), "TCPv4_SERVER");
+ }
+ else
+ {
+ StrCpy(c->Proto, sizeof(c->Proto), "TCPv6_SERVER");
+ }
+ }
+ else
+ {
+ // UDP
+ if (IsIP6(&se->ClientIp) == false)
+ {
+ StrCpy(c->Proto, sizeof(c->Proto), "UDPv4");
+ }
+ else
+ {
+ StrCpy(c->Proto, sizeof(c->Proto), "UDPv6");
+ }
+ }
+
+ // Encryption algorithm
+ c->CipherEncrypt = OvsGetCipher(IniStrValue(o, "cipher"));
+ c->CipherDecrypt = NewCipher(c->CipherEncrypt->Name);
+
+ // Hash algorithm
+ c->MdSend = OvsGetMd(IniStrValue(o, "auth"));
+ c->MdRecv = NewMd(c->MdSend->Name);
+
+ // Random number generation
+ Rand(c->ServerKey.Random1, sizeof(c->ServerKey.Random1));
+ Rand(c->ServerKey.Random2, sizeof(c->ServerKey.Random2));
+
+ // Generate the Master Secret
+ b = NewBuf();
+ WriteBuf(b, OPENVPN_PREMASTER_LABEL, StrLen(OPENVPN_PREMASTER_LABEL));
+ WriteBuf(b, c->ClientKey.Random1, sizeof(c->ClientKey.Random1));
+ WriteBuf(b, c->ServerKey.Random1, sizeof(c->ServerKey.Random1));
+ Enc_tls1_PRF(b->Buf, b->Size,
+ c->ClientKey.PreMasterSecret, sizeof(c->ClientKey.PreMasterSecret),
+ c->MasterSecret, sizeof(c->MasterSecret));
+ FreeBuf(b);
+
+ // Generate an Expansion Key
+ b = NewBuf();
+ WriteBuf(b, OPENVPN_EXPANSION_LABEL, StrLen(OPENVPN_EXPANSION_LABEL));
+ WriteBuf(b, c->ClientKey.Random2, sizeof(c->ClientKey.Random2));
+ WriteBuf(b, c->ServerKey.Random2, sizeof(c->ServerKey.Random2));
+ WriteBufInt64(b, se->ClientSessionId);
+ WriteBufInt64(b, se->ServerSessionId);
+ Enc_tls1_PRF(b->Buf, b->Size, c->MasterSecret, sizeof(c->MasterSecret),
+ c->ExpansionKey, sizeof(c->ExpansionKey));
+ FreeBuf(b);
+
+ // Set the key
+ SetCipherKey(c->CipherDecrypt, c->ExpansionKey + 0, false);
+ SetCipherKey(c->CipherEncrypt, c->ExpansionKey + 128, true);
+ SetMdKey(c->MdRecv, c->ExpansionKey + 64, c->MdRecv->Size);
+ SetMdKey(c->MdSend, c->ExpansionKey + 192, c->MdSend->Size);
+
+ OvsFreeOptions(o);
+
+ // Generate the response option string
+ Format(c->ServerKey.OptionString, sizeof(c->ServerKey.OptionString),
+ "V4,dev-type %s,link-mtu %u,tun-mtu %u,proto %s,"
+ "cipher %s,auth %s,keysize %u,key-method 2,tls-server",
+ (se->Mode == OPENVPN_MODE_L2 ? "tap" : "tun"),
+ se->LinkMtu,
+ se->TunMtu,
+ c->Proto,
+ c->CipherEncrypt->Name, c->MdSend->Name, c->CipherEncrypt->KeySize * 8);
+ Debug("Building OptionStr: %s\n", c->ServerKey.OptionString);
+
+ OvsLog(s, se, c, "LO_OPTION_STR_SEND", c->ServerKey.OptionString);
+}
+
+// Get the encryption algorithm
+CIPHER *OvsGetCipher(char *name)
+{
+ CIPHER *c = NULL;
+
+ if (IsEmptyStr(name) == false && IsStrInStrTokenList(OPENVPN_CIPHER_LIST, name, NULL, false))
+ {
+ c = NewCipher(name);
+ }
+
+ if (c == NULL)
+ {
+ c = NewCipher(OPENVPN_DEFAULT_CIPHER);
+ }
+
+ return c;
+}
+
+// Get the hash algorithm
+MD *OvsGetMd(char *name)
+{
+ MD *m = NULL;
+
+ if (IsEmptyStr(name) == false && IsStrInStrTokenList(OPENVPN_MD_LIST, name, NULL, false))
+ {
+ m = NewMd(name);
+ }
+
+ if (m == NULL)
+ {
+ m = NewMd(OPENVPN_DEFAULT_MD);
+ }
+
+ return m;
+}
+
+// Parse the option string
+LIST *OvsParseOptions(char *str)
+{
+ LIST *o = NewListFast(NULL);
+ TOKEN_LIST *t;
+
+ t = ParseTokenWithoutNullStr(str, ",");
+ if (t != NULL)
+ {
+ UINT i;
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ char key[MAX_SIZE];
+ char value[MAX_SIZE];
+ char *line = t->Token[i];
+ Trim(line);
+
+ if (GetKeyAndValue(line, key, sizeof(key), value, sizeof(value), " \t"))
+ {
+ INI_ENTRY *e = ZeroMalloc(sizeof(INI_ENTRY));
+
+ e->Key = CopyStr(key);
+ e->Value = CopyStr(value);
+
+ Add(o, e);
+ }
+ }
+
+ FreeToken(t);
+ }
+
+ return o;
+}
+
+// Release the option list
+void OvsFreeOptions(LIST *o)
+{
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ FreeIni(o);
+}
+
+// Create an Option List
+LIST *OvsNewOptions()
+{
+ return NewListFast(NULL);
+}
+
+// Add a value to the option list
+void OvsAddOption(LIST *o, char *key, char *value)
+{
+ INI_ENTRY *e;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ e = GetIniEntry(o, key);
+ if (e != NULL)
+ {
+ // Overwrite existing keys
+ Free(e->Key);
+ e->Key = CopyStr(key);
+
+ Free(e->Value);
+ e->Value = CopyStr(value);
+ }
+ else
+ {
+ // Create a new key
+ e = ZeroMalloc(sizeof(INI_ENTRY));
+
+ e->Key = CopyStr(key);
+ e->Value = CopyStr(value);
+
+ Add(o, e);
+ }
+}
+
+// Confirm whether there is specified option key string
+bool OvsHasOption(LIST *o, char *key)
+{
+ // Validate arguments
+ if (o == NULL || key == NULL)
+ {
+ return false;
+ }
+
+ if (GetIniEntry(o, key) != NULL)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Build the data from KEY_METHOD2
+BUF *OvsBuildKeyMethod2(OPENVPN_KEY_METHOD_2 *d)
+{
+ BUF *b;
+ UCHAR uc;
+ // Validate arguments
+ if (d == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+
+ // Reserved
+ WriteBufInt(b, 0);
+
+ // Method
+ uc = 2;
+ WriteBuf(b, &uc, sizeof(UCHAR));
+
+ // Random1
+ WriteBuf(b, d->Random1, sizeof(d->Random1));
+
+ // Random2
+ WriteBuf(b, d->Random2, sizeof(d->Random2));
+
+ // Option String
+ OvsWriteStringToBuf(b, d->OptionString, sizeof(d->OptionString));
+
+ // Username
+ OvsWriteStringToBuf(b, d->Username, sizeof(d->Username));
+
+ // Password
+ OvsWriteStringToBuf(b, d->Password, sizeof(d->Password));
+
+ // PeerInfo
+ OvsWriteStringToBuf(b, d->PeerInfo, sizeof(d->PeerInfo));
+
+ return b;
+}
+
+// Append a string to buf
+void OvsWriteStringToBuf(BUF *b, char *str, UINT max_size)
+{
+ USHORT us;
+ UINT i;
+ char *tmp;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return;
+ }
+ if (str == NULL)
+ {
+ str = "";
+ }
+
+ if (StrLen(str) == 0)
+ {
+ us = 0;
+ WriteBuf(b, &us, sizeof(USHORT));
+ return;
+ }
+
+ i = StrSize(str);
+ i = MIN(i, max_size);
+ us = Endian16((USHORT)i);
+ WriteBuf(b, &us, sizeof(USHORT));
+
+ tmp = Malloc(i);
+ Copy(tmp, str, i);
+ tmp[i - 1] = 0;
+ WriteBuf(b, tmp, i);
+
+ Free(tmp);
+}
+
+// Parse the KEY_METHOD2
+UINT OvsParseKeyMethod2(OPENVPN_KEY_METHOD_2 *ret, UCHAR *data, UINT size, bool client_mode)
+{
+ BUF *b;
+ UINT read_size = 0;
+ UINT ui;
+ UCHAR uc;
+ // Validate arguments
+ Zero(ret, sizeof(OPENVPN_KEY_METHOD_2));
+ if (ret == NULL || data == NULL || size == 0)
+ {
+ return 0;
+ }
+
+ b = NewBuf();
+ WriteBuf(b, data, size);
+ SeekBuf(b, 0, 0);
+
+ // Reserved
+ if (ReadBuf(b, &ui, sizeof(UINT)) == sizeof(UINT))
+ {
+ // Method
+ if (ReadBuf(b, &uc, sizeof(UCHAR)) == sizeof(UCHAR) && uc == 2)
+ {
+ // Pre Master Secret
+ if (client_mode == false || ReadBuf(b, ret->PreMasterSecret, sizeof(ret->PreMasterSecret)) == sizeof(ret->PreMasterSecret))
+ {
+ // Random1
+ if (ReadBuf(b, ret->Random1, sizeof(ret->Random1)) == sizeof(ret->Random1))
+ {
+ // Random2
+ if (ReadBuf(b, ret->Random2, sizeof(ret->Random2)) == sizeof(ret->Random2))
+ {
+ // String
+ if (OvsReadStringFromBuf(b, ret->OptionString, sizeof(ret->OptionString)) &&
+ OvsReadStringFromBuf(b, ret->Username, sizeof(ret->Username)) &&
+ OvsReadStringFromBuf(b, ret->Password, sizeof(ret->Password)) &&
+ OvsReadStringFromBuf(b, ret->PeerInfo, sizeof(ret->PeerInfo)))
+ {
+ read_size = b->Current;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ FreeBuf(b);
+
+ return read_size;
+}
+
+// Read a string from BUF
+bool OvsReadStringFromBuf(BUF *b, char *str, UINT str_size)
+{
+ USHORT us;
+ // Validate arguments
+ if (b == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ if (ReadBuf(b, &us, sizeof(USHORT)) != sizeof(USHORT))
+ {
+ return false;
+ }
+
+ us = Endian16(us);
+
+ if (us == 0)
+ {
+ StrCpy(str, str_size, "");
+ return true;
+ }
+
+ if (us > str_size)
+ {
+ return false;
+ }
+
+ if (ReadBuf(b, str, us) != us)
+ {
+ return false;
+ }
+
+ if (str[us - 1] != 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Transmission of control packet (Automatic segmentation with the maximum size)
+void OvsSendControlPacketWithAutoSplit(OPENVPN_CHANNEL *c, UCHAR opcode, UCHAR *data, UINT data_size)
+{
+ BUF *b;
+ // Validate arguments
+ if (c == NULL || (data_size != 0 && data == NULL))
+ {
+ return;
+ }
+
+ b = NewBuf();
+ WriteBuf(b, data, data_size);
+ SeekBuf(b, 0, 0);
+
+ while (true)
+ {
+ UCHAR tmp[OPENVPN_CONTROL_PACKET_MAX_DATASIZE];
+ UINT size = ReadBuf(b, tmp, sizeof(tmp));
+
+ if (size == 0)
+ {
+ break;
+ }
+
+ OvsSendControlPacket(c, opcode, tmp, size);
+ //Debug(" *** CNT SEND %u\n", size);
+ }
+
+ FreeBuf(b);
+}
+
+// Send the control packet
+void OvsSendControlPacket(OPENVPN_CHANNEL *c, UCHAR opcode, UCHAR *data, UINT data_size)
+{
+ OPENVPN_CONTROL_PACKET *p;
+ // Validate arguments
+ if (c == NULL || (data_size != 0 && data == NULL))
+ {
+ return;
+ }
+
+ p = ZeroMalloc(sizeof(OPENVPN_CONTROL_PACKET));
+
+ p->OpCode = opcode;
+ p->PacketId = c->NextSendPacketId++;
+
+ if (data != NULL)
+ {
+ p->Data = Clone(data, data_size);
+ p->DataSize = data_size;
+ }
+
+ p->NextSendTime = 0;
+
+ Add(c->SendControlPacketList, p);
+}
+
+// Release the control packet being transmitted
+void OvsFreeControlPacket(OPENVPN_CONTROL_PACKET *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ if (p->Data != NULL)
+ {
+ Free(p->Data);
+ }
+
+ Free(p);
+}
+
+// Get a list of packet ID to be responded
+UINT OvsGetAckReplyList(OPENVPN_CHANNEL *c, UINT *ret)
+{
+ UINT i;
+ LIST *o = NULL;
+ UINT num;
+ // Validate arguments
+ if (c == NULL || ret == NULL)
+ {
+ return 0;
+ }
+
+ num = MIN(LIST_NUM(c->AckReplyList), OPENVPN_MAX_NUMACK);
+
+ for (i = 0;i < num;i++)
+ {
+ UINT *v = LIST_DATA(c->AckReplyList, i);
+
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Add(o, v);
+
+ ret[i] = *v;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ UINT *v = LIST_DATA(o, i);
+
+ Delete(c->AckReplyList, v);
+
+ Free(v);
+ }
+
+ ReleaseList(o);
+
+ return num;
+}
+
+// Release the channel
+void OvsFreeChannel(OPENVPN_CHANNEL *c)
+{
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ if (c->SslPipe != NULL)
+ {
+ FreeSslPipe(c->SslPipe);
+ }
+
+ ReleaseIntList(c->AckReplyList);
+
+ for (i = 0;i < LIST_NUM(c->SendControlPacketList);i++)
+ {
+ OPENVPN_CONTROL_PACKET *p = LIST_DATA(c->SendControlPacketList, i);
+
+ OvsFreeControlPacket(p);
+ }
+
+ ReleaseList(c->SendControlPacketList);
+
+ FreeCipher(c->CipherDecrypt);
+ FreeCipher(c->CipherEncrypt);
+
+ FreeMd(c->MdRecv);
+ FreeMd(c->MdSend);
+
+ Free(c);
+}
+
+// Create a new channel
+OPENVPN_CHANNEL *OvsNewChannel(OPENVPN_SESSION *se, UCHAR key_id)
+{
+ OPENVPN_CHANNEL *c;
+ // Validate arguments
+ if (se == NULL)
+ {
+ return NULL;
+ }
+
+ c = ZeroMalloc(sizeof(OPENVPN_CHANNEL));
+
+ c->Session = se;
+ c->Server = se->Server;
+
+ c->Status = OPENVPN_CHANNEL_STATUS_INIT;
+
+ c->AckReplyList = NewIntList(true);
+
+ c->SendControlPacketList = NewListFast(NULL);
+
+ c->KeyId = key_id;
+
+ Rand(c->NextIv, sizeof(c->NextIv));
+
+ //c->NextRekey = se->Server->Now + (UINT64)5000;
+
+ se->LastCreatedChannelIndex = key_id;
+
+ return c;
+}
+
+// Create a new server-side channel ID
+UINT64 OvsNewServerSessionId(OPENVPN_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return 0;
+ }
+
+ while (true)
+ {
+ UINT64 id = Rand64();
+ UINT i;
+ bool exists = false;
+
+ if (id == 0 || id == (UINT64)(0xFFFFFFFFFFFFFFFFULL))
+ {
+ continue;
+ }
+
+ for (i = 0;i < LIST_NUM(s->SessionList);i++)
+ {
+ OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
+ if (se->ServerSessionId == id)
+ {
+ exists = true;
+ }
+ }
+
+ if (exists == false)
+ {
+ return id;
+ }
+ }
+}
+
+// Build and submit the OpenVPN data packet
+void OvsSendDataPacket(OPENVPN_CHANNEL *c, UCHAR key_id, UINT data_packet_id, void *data, UINT data_size)
+{
+ UCHAR uc;
+ UCHAR *encrypted_data;
+ UINT encrypted_size;
+ UCHAR *dest_data;
+ UINT dest_size;
+ UINT r;
+
+ // Validate arguments
+ if (c == NULL || data == NULL || data_size == 0)
+ {
+ return;
+ }
+
+ uc = ((OPENVPN_P_DATA_V1 << 3) & 0xF8) | (key_id & 0x07);
+
+ // Generate the data to be encrypted
+
+ encrypted_size = sizeof(UINT) + data_size;
+ encrypted_data = ZeroMalloc(encrypted_size);
+
+ WRITE_UINT(encrypted_data, data_packet_id);
+ Copy(encrypted_data + sizeof(UINT), data, data_size);
+
+ // Prepare a buffer to store the results
+ dest_data = Malloc(sizeof(UCHAR) + c->MdSend->Size + c->CipherEncrypt->IvSize + encrypted_size + 256);
+
+ // Encrypt
+ r = CipherProcess(c->CipherEncrypt, c->NextIv, dest_data + sizeof(UCHAR) + c->MdSend->Size + c->CipherEncrypt->IvSize,
+ encrypted_data, encrypted_size);
+ dest_size = sizeof(UCHAR) + c->MdSend->Size + c->CipherEncrypt->IvSize + r;
+
+ // Copy the IV
+ Copy(dest_data + sizeof(UCHAR) + c->MdSend->Size, c->NextIv, c->CipherEncrypt->IvSize);
+
+ // Calculate the HMAC
+ MdProcess(c->MdSend, dest_data + sizeof(UCHAR), dest_data + sizeof(UCHAR) + c->MdSend->Size,
+ dest_size - sizeof(UCHAR) - c->MdSend->Size);
+
+ // Update the NextIV
+ Copy(c->NextIv, dest_data + dest_size - c->CipherEncrypt->IvSize, c->CipherEncrypt->IvSize);
+
+ // Op-code
+ dest_data[0] = uc;
+
+ OvsSendPacketRawNow(c->Server, c->Session, dest_data, dest_size);
+
+ Free(encrypted_data);
+}
+
+// Build an OpenVPN control packet
+BUF *OvsBuildPacket(OPENVPN_PACKET *p)
+{
+ BUF *b;
+ UCHAR uc;
+ UINT num_ack;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+
+ // OpCode + KeyID
+ uc = ((p->OpCode << 3) & 0xF8) | (p->KeyId & 0x07);
+ WriteBufChar(b, uc);
+
+ if (p->OpCode == OPENVPN_P_DATA_V1)
+ {
+ // Data Packet
+ WriteBuf(b, p->Data, p->DataSize);
+ SeekBuf(b, 0, 0);
+ return b;
+ }
+
+ // Sender Channel ID
+ WriteBufInt64(b, p->MySessionId);
+
+ // NumAck
+ num_ack = MIN(p->NumAck, OPENVPN_MAX_NUMACK);
+ WriteBufChar(b, (UCHAR)num_ack);
+
+ if (p->NumAck >= 1)
+ {
+ UINT i;
+
+ for (i = 0;i < num_ack;i++)
+ {
+ WriteBufInt(b, (UCHAR)p->AckPacketId[i]);
+ }
+
+ // Received Channel ID
+ WriteBufInt64(b, p->YourSessionId);
+ }
+
+ if (p->OpCode != OPENVPN_P_ACK_V1)
+ {
+ // Packet ID
+ WriteBufInt(b, p->PacketId);
+
+ // Payload
+ if (p->DataSize >= 1 && p->Data != NULL)
+ {
+ WriteBuf(b, p->Data, p->DataSize);
+ }
+ }
+
+ SeekBuf(b, 0, 0);
+
+ return b;
+}
+
+// Parse the OpenVPN packet
+OPENVPN_PACKET *OvsParsePacket(UCHAR *data, UINT size)
+{
+ UCHAR uc;
+ OPENVPN_PACKET *ret = NULL;
+ // Validate arguments
+ if (data == NULL || size == 0)
+ {
+ return NULL;
+ }
+
+ ret = ZeroMalloc(sizeof(OPENVPN_PACKET));
+
+ // OpCode + KeyID
+ if (size < 1)
+ {
+ goto LABEL_ERROR;
+ }
+ uc = *((UCHAR *)data);
+ data++;
+ size--;
+
+ ret->OpCode = ((uc & 0xF8) >> 3) & 0x1F;
+ ret->KeyId = uc & 0x07;
+
+ if (ret->OpCode == OPENVPN_P_DATA_V1)
+ {
+ // Data packet
+ ret->DataSize = size;
+ ret->Data = Clone(data, size);
+ return ret;
+ }
+
+ // Sender Channel ID
+ if (size < sizeof(UINT64))
+ {
+ goto LABEL_ERROR;
+ }
+ ret->MySessionId = READ_UINT64(data);
+ data += sizeof(UINT64);
+ size -= sizeof(UINT64);
+
+ // ACK
+ if (size < 1)
+ {
+ goto LABEL_ERROR;
+ }
+ uc = *((UCHAR *)data);
+ data++;
+ size--;
+
+ ret->NumAck = uc;
+
+ if (ret->NumAck > 4)
+ {
+ goto LABEL_ERROR;
+ }
+
+ if (ret->NumAck >= 1)
+ {
+ UINT i;
+
+ if (size < (sizeof(UINT) * (UINT)ret->NumAck + sizeof(UINT64)))
+ {
+ goto LABEL_ERROR;
+ }
+
+ for (i = 0;i < ret->NumAck;i++)
+ {
+ UINT ui;
+
+ ui = READ_UINT(data);
+
+ ret->AckPacketId[i] = ui;
+
+ data += sizeof(UINT);
+ size -= sizeof(UINT);
+ }
+
+ ret->YourSessionId = READ_UINT64(data);
+ data += sizeof(UINT64);
+ size -= sizeof(UINT64);
+ }
+
+ if (ret->OpCode != OPENVPN_P_ACK_V1)
+ {
+ // Read the Packet ID Because in the case of other than ACK
+ if (size < sizeof(UINT))
+ {
+ goto LABEL_ERROR;
+ }
+
+ ret->PacketId = READ_UINT(data);
+ data += sizeof(UINT);
+ size -= sizeof(UINT);
+
+ // Payload
+ ret->DataSize = size;
+ if (size >= 1)
+ {
+ ret->Data = Clone(data, size);
+ }
+ }
+
+ return ret;
+
+LABEL_ERROR:
+ Debug("OvsParsePacket Error.\n");
+ if (ret != NULL)
+ {
+ OvsFreePacket(ret);
+ }
+ return NULL;
+}
+
+// Release the OpenVPN packet
+void OvsFreePacket(OPENVPN_PACKET *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ if (p->Data != NULL)
+ {
+ Free(p->Data);
+ }
+
+ Free(p);
+}
+
+// If the session does not exist, create a session
+OPENVPN_SESSION *OvsFindOrCreateSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, UINT protocol)
+{
+ OPENVPN_SESSION *se;
+ // Validate arguments
+ if (s == NULL || server_ip == NULL || server_port == 0 || client_ip == NULL || client_port == 0)
+ {
+ return NULL;
+ }
+
+ se = OvsSearchSession(s, server_ip, server_port, client_ip, client_port, protocol);
+ if (se == NULL)
+ {
+ se = OvsNewSession(s, server_ip, server_port, client_ip, client_port, protocol);
+
+ if (se != NULL)
+ {
+ Insert(s->SessionList, se);
+ }
+ }
+
+ return se;
+}
+
+// Get the number of sessions currently connected from the IP address of the client
+UINT OvsGetNumSessionByClientIp(OPENVPN_SERVER *s, IP *ip)
+{
+ UINT i;
+ UINT ret = 0;
+ // Validate arguments
+ if (s == NULL || ip == NULL)
+ {
+ return 0;
+ }
+
+ for (i = 0;i < LIST_NUM(s->SessionList);i++)
+ {
+ OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
+
+ if (CmpIpAddr(&se->ClientIp, ip) == 0)
+ {
+ ret++;
+ }
+ }
+
+ return ret;
+}
+
+// Create a new session
+OPENVPN_SESSION *OvsNewSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, UINT protocol)
+{
+ OPENVPN_SESSION *se;
+ char server_ip_str[MAX_SIZE];
+ char client_ip_str[MAX_SIZE];
+ // Validate arguments
+ if (s == NULL || server_ip == NULL || server_port == 0 || client_ip == NULL || client_port == 0)
+ {
+ return NULL;
+ }
+
+
+ if (OvsGetNumSessionByClientIp(s, client_ip) > OPENVPN_QUOTA_MAX_NUM_SESSIONS_PER_IP)
+ {
+ // Number of sessions from the same IP address too many
+ return NULL;
+ }
+
+ if (LIST_NUM(s->SessionList) > OPENVPN_QUOTA_MAX_NUM_SESSIONS)
+ {
+ // Too many OpenVPN sessions
+ return NULL;
+ }
+
+ se = ZeroMalloc(sizeof(OPENVPN_SESSION));
+
+ se->Server = s;
+
+ Copy(&se->ClientIp, client_ip, sizeof(IP));
+ se->ClientPort = client_port;
+
+ Copy(&se->ServerIp, server_ip, sizeof(IP));
+ se->ServerPort = server_port;
+
+ se->LastCommTick = s->Now;
+
+ se->Protocol = protocol;
+
+ se->ServerSessionId = OvsNewServerSessionId(se->Server);
+
+ se->CreatedTick = s->Now;
+
+ se->Id = s->NextSessionId;
+ s->NextSessionId++;
+
+ IPToStr(server_ip_str, sizeof(server_ip_str), server_ip);
+ IPToStr(client_ip_str, sizeof(client_ip_str), client_ip);
+ Debug("OpenVPN New Session: %s:%u -> %s:%u Proto=%u\n", server_ip_str, server_port,
+ client_ip_str, client_port, protocol);
+
+ OvsLog(s, se, NULL, "LO_NEW_SESSION", (protocol == OPENVPN_PROTOCOL_UDP ? "UDP" : "TCP"));
+
+ return se;
+}
+
+// Release the session
+void OvsFreeSession(OPENVPN_SESSION *se)
+{
+ UINT i;
+ // Validate arguments
+ if (se == NULL)
+ {
+ return;
+ }
+
+ // If there is IP addresses which is got from a DHCP server in the session, release it
+ if (se->Ipc != NULL)
+ {
+ if (se->Mode == OPENVPN_MODE_L3)
+ {
+ if (se->IpcAsync != NULL)
+ {
+ IP dhcp_ip;
+
+ UINTToIP(&dhcp_ip, se->IpcAsync->L3ClientAddressOption.ServerAddress);
+
+ IPCDhcpFreeIP(se->Ipc, &dhcp_ip);
+ IPCProcessL3Events(se->Ipc);
+ }
+ }
+ }
+
+ // Release the channel
+ for (i = 0;i < OPENVPN_NUM_CHANNELS;i++)
+ {
+ OPENVPN_CHANNEL *c = se->Channels[i];
+
+ if (c != NULL)
+ {
+ OvsFreeChannel(c);
+ }
+ }
+
+ // Release the IPC
+ if (se->Ipc != NULL)
+ {
+ FreeIPC(se->Ipc);
+ }
+
+ if (se->IpcAsync != NULL)
+ {
+ FreeIPCAsync(se->IpcAsync);
+ }
+
+ Free(se);
+}
+
+// Search the session from the endpoint information
+OPENVPN_SESSION *OvsSearchSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, UINT protocol)
+{
+ OPENVPN_SESSION *se;
+ OPENVPN_SESSION t;
+ // Validate arguments
+ if (s == NULL || server_ip == NULL || server_port == 0 || client_ip == NULL || client_port == 0)
+ {
+ return NULL;
+ }
+
+ Copy(&t.ClientIp, client_ip, sizeof(IP));
+ t.ClientPort = client_port;
+ Copy(&t.ServerIp, server_ip, sizeof(IP));
+ t.ServerPort = server_port;
+ t.Protocol = protocol;
+
+ se = Search(s->SessionList, &t);
+
+ return se;
+}
+
+// Receive packets in the OpenVPN server
+void OvsRecvPacket(OPENVPN_SERVER *s, LIST *recv_packet_list, UINT protocol)
+{
+ UINT i, j;
+ LIST *delete_session_list = NULL;
+ // Validate arguments
+ if (s == NULL || recv_packet_list == NULL)
+ {
+ return;
+ }
+
+ s->Now = Tick64();
+
+ // Process for all sessions
+ for (i = 0;i < LIST_NUM(s->SessionList);i++)
+ {
+ OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
+
+ if (se->Ipc != NULL)
+ {
+ if (se->Mode == OPENVPN_MODE_L3)
+ {
+ // Flush the ARP table of the IPC
+ IPCFlushArpTableEx(se->Ipc, s->Now);
+ }
+ }
+ }
+
+ // Process received packets
+ for (i = 0;i < LIST_NUM(recv_packet_list);i++)
+ {
+ UDPPACKET *p = LIST_DATA(recv_packet_list, i);
+
+ OvsProceccRecvPacket(s, p, protocol);
+ }
+
+ // Treat for all sessions and all channels
+ for (i = 0;i < LIST_NUM(s->SessionList);i++)
+ {
+ OPENVPN_CHANNEL *latest_channel = NULL;
+ UINT64 max_tick = 0;
+ OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
+ bool is_disconnected = false;
+
+ if (se->Ipc != NULL)
+ {
+ if (se->Mode == OPENVPN_MODE_L3)
+ {
+ IPCProcessL3Events(se->Ipc);
+ }
+ }
+
+ for (j = 0;j < OPENVPN_NUM_CHANNELS;j++)
+ {
+ OPENVPN_CHANNEL *c = se->Channels[j];
+
+ if (c != NULL)
+ {
+ if (c->RekeyInitiated == false && ((c->NextRekey <= s->Now && c->NextRekey != 0) || (c->LastDataPacketId >= OPENVPN_MAX_PACKET_ID_FOR_TRIGGER_REKEY)))
+ {
+ OPENVPN_CHANNEL *c2;
+ // Send a soft reset by creating a new channel
+ UINT next_channel_id = se->LastCreatedChannelIndex + 1;
+ if (next_channel_id >= OPENVPN_NUM_CHANNELS)
+ {
+ next_channel_id = 1;
+ }
+ if (se->Channels[next_channel_id] != NULL)
+ {
+ // Release when there is a channel data already
+ OvsFreeChannel(se->Channels[next_channel_id]);
+ se->Channels[next_channel_id] = NULL;
+ }
+
+ // Create a new channel
+ c2 = OvsNewChannel(se, (UCHAR)next_channel_id);
+ c2->IsInitiatorServer = true;
+ se->Channels[next_channel_id] = c2;
+ Debug("OpenVPN New Channel for Re-Keying :%u\n", next_channel_id);
+ OvsLog(s, se, c, "LO_INITIATE_REKEY");
+
+ // Send a soft reset
+ OvsSendControlPacket(c2, OPENVPN_P_CONTROL_SOFT_RESET_V1, NULL, 0);
+
+ c->RekeyInitiated = true;
+ }
+ }
+
+ if (c != NULL)
+ {
+ switch (c->Status)
+ {
+ case OPENVPN_CHANNEL_STATUS_TLS_VPN_CONNECTING:
+ // Check whether the connection process completed if there is a channel running a VPN connection process
+ if (se->IpcAsync != NULL)
+ {
+ if (se->IpcAsync->Done)
+ {
+ if (se->IpcAsync->Ipc != NULL)
+ {
+ char option_str[MAX_SIZE];
+ char l3_options[MAX_SIZE];
+
+ // Successful in VPN connection
+ Debug("OpenVPN Channel %u Established (new key).\n", j);
+ OvsLog(s, se, c, "LO_CHANNEL_ESTABLISHED");
+
+ // 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));
+
+ if (se->Mode == OPENVPN_MODE_L3)
+ {
+ // Add such as the IP address that was acquired from the DHCP server
+ // if the L3 mode to the option character string
+ DHCP_OPTION_LIST *cao = &se->IpcAsync->L3ClientAddressOption;
+ char ip_client[64];
+ char ip_tunnel_endpoint[64];
+ UINT ip_tunnel_endpoint_32;
+ char ip_network[64];
+ char ip_subnet_mask[64];
+ char ip_dns1[64];
+ char ip_dns2[64];
+ char ip_wins1[64];
+ char ip_wins2[64];
+ char ip_defgw[64];
+
+ ClearStr(ip_dns1, sizeof(ip_dns1));
+ ClearStr(ip_dns2, sizeof(ip_dns2));
+ ClearStr(ip_wins1, sizeof(ip_wins1));
+ ClearStr(ip_wins2, sizeof(ip_wins2));
+ ClearStr(ip_defgw, sizeof(ip_defgw));
+
+ IPToStr32(ip_client, sizeof(ip_client),
+ cao->ClientAddress);
+
+ // Generate a virtual gateway address to be passed to the OpenVPN
+ ip_tunnel_endpoint_32 = Endian32(cao->ClientAddress);
+ ip_tunnel_endpoint_32++;
+ ip_tunnel_endpoint_32 = Endian32(ip_tunnel_endpoint_32);
+ IPToStr32(ip_tunnel_endpoint, sizeof(ip_tunnel_endpoint), ip_tunnel_endpoint_32);
+
+ // Create a subnet information for the LAN
+ IPToStr32(ip_network, sizeof(ip_network),
+ GetNetworkAddress(cao->ClientAddress,
+ cao->SubnetMask));
+
+ IPToStr32(ip_subnet_mask, sizeof(ip_subnet_mask),
+ cao->SubnetMask);
+
+ Format(l3_options, sizeof(l3_options),
+ ",ifconfig %s %s",
+// ",ifconfig %s %s,route %s %s %s 1",
+ ip_client, ip_tunnel_endpoint, ip_network, ip_subnet_mask,
+ ip_tunnel_endpoint);
+ StrCat(option_str, sizeof(option_str), l3_options);
+
+ // Domain name
+ if (IsEmptyStr(cao->DomainName) == false)
+ {
+ Format(l3_options, sizeof(l3_options),
+ ",dhcp-option DOMAIN %s", cao->DomainName);
+ StrCat(option_str, sizeof(option_str), l3_options);
+ }
+
+ // DNS server address 1
+ if (cao->DnsServer != 0)
+ {
+ char ip_str[64];
+ IPToStr32(ip_str, sizeof(ip_str), cao->DnsServer);
+ Format(l3_options, sizeof(l3_options),
+ ",dhcp-option DNS %s", ip_str);
+ StrCat(option_str, sizeof(option_str), l3_options);
+
+ StrCpy(ip_dns1, sizeof(ip_dns1), ip_str);
+ }
+
+ // DNS server address 2
+ if (cao->DnsServer2 != 0)
+ {
+ char ip_str[64];
+ IPToStr32(ip_str, sizeof(ip_str), cao->DnsServer2);
+ Format(l3_options, sizeof(l3_options),
+ ",dhcp-option DNS %s", ip_str);
+ StrCat(option_str, sizeof(option_str), l3_options);
+
+ StrCpy(ip_dns2, sizeof(ip_dns2), ip_str);
+ }
+
+ // WINS address 1
+ if (cao->WinsServer != 0)
+ {
+ char ip_str[64];
+ IPToStr32(ip_str, sizeof(ip_str), cao->WinsServer);
+ Format(l3_options, sizeof(l3_options),
+ ",dhcp-option WINS %s", ip_str);
+ StrCat(option_str, sizeof(option_str), l3_options);
+
+ StrCpy(ip_wins1, sizeof(ip_wins1), ip_str);
+ }
+
+ // WINS address 2
+ if (cao->WinsServer2 != 0)
+ {
+ char ip_str[64];
+ IPToStr32(ip_str, sizeof(ip_str), cao->WinsServer2);
+ Format(l3_options, sizeof(l3_options),
+ ",dhcp-option WINS %s", ip_str);
+ StrCat(option_str, sizeof(option_str), l3_options);
+
+ StrCpy(ip_wins2, sizeof(ip_wins2), ip_str);
+ }
+
+ // Default gateway
+ if (cao->Gateway != 0)
+ {
+ Format(l3_options, sizeof(l3_options),
+ ",route-gateway %s,redirect-gateway def1", ip_tunnel_endpoint);
+ StrCat(option_str, sizeof(option_str), l3_options);
+
+ IPToStr32(ip_defgw, sizeof(ip_defgw), cao->Gateway);
+ }
+
+ OvsLog(s, se, c, "LP_SET_IPV4_PARAM",
+ ip_client, ip_subnet_mask, ip_defgw, ip_dns1, ip_dns2, ip_wins1, ip_wins2);
+ }
+
+ WriteFifo(c->SslPipe->SslInOut->SendFifo, option_str, StrSize(option_str));
+
+ Debug("Push Str: %s\n", option_str);
+ OvsLog(s, se, c, "LO_PUSH_REPLY", option_str);
+
+ StrCpy(se->PushReplyStr, sizeof(se->PushReplyStr), option_str);
+
+ se->Ipc = se->IpcAsync->Ipc;
+ se->IpcAsync->Ipc = NULL;
+
+ s->SessionEstablishedCount++;
+
+ // Set a Sock Event of IPC to Sock Event of the UDP Listener
+ IPCSetSockEventWhenRecvL2Packet(se->Ipc, s->SockEvent);
+
+ // State transition
+ c->Status = OPENVPN_CHANNEL_STATUS_ESTABLISHED;
+ c->EstablishedTick = s->Now;
+ se->Established = true;
+ se->LastCommTick = Tick64();
+ }
+ else
+ {
+ char *str;
+
+ if (se->IpcAsync->DhcpAllocFailed)
+ {
+ OvsLog(s, se, c, "LP_DHCP_REQUEST_NG");
+ }
+
+ // Failed to connect VPN
+ Debug("OpenVPN Channel %u Failed.\n", j);
+ OvsLog(s, se, c, "LO_CHANNEL_FAILED");
+
+ // Return the AUTH_FAILED
+ str = "AUTH_FAILED";
+ WriteFifo(c->SslPipe->SslInOut->SendFifo, str, StrSize(str));
+
+ s->SessionEstablishedCount++;
+
+ // State transition
+ c->Status = OPENVPN_CHANNEL_STATUS_DISCONNECTED;
+
+ FreeIPCAsync(se->IpcAsync);
+ se->IpcAsync = NULL;
+ }
+ }
+ }
+ break;
+
+ case OPENVPN_CHANNEL_STATUS_ESTABLISHED:
+ // Monitor the IPC whether not disconnected when there is a VPN connection completed channel
+ if (IsIPCConnected(se->Ipc) == false)
+ {
+ // Send the RESTART since IPC is disconnected
+ char *str = "RESTART";
+ Debug("OpenVPN Channel %u Disconnected by HUB.\n", j);
+
+ OvsLog(s, se, c, "LO_CHANNEL_DISCONNECTED_BY_HUB");
+
+ WriteFifo(c->SslPipe->SslInOut->SendFifo, str, StrSize(str));
+
+ // State transition
+ c->Status = OPENVPN_CHANNEL_STATUS_DISCONNECTED;
+
+ // Set the session to disconnected state
+ se->Established = false;
+ se->LastCommTick = s->Now;
+ }
+ break;
+ }
+ }
+
+ if (c != NULL)
+ {
+ // If there is a packet to be transmitted physically in SSL, send it
+ if (c->SslPipe != NULL && SyncSslPipe(c->SslPipe))
+ {
+ if (FifoSize(c->SslPipe->RawOut->RecvFifo) >= 1)
+ {
+ Debug("RawOut Fifo Size (c=%u): %u\n", c->KeyId, FifoSize(c->SslPipe->RawOut->RecvFifo));
+
+ OvsSendControlPacketWithAutoSplit(c, OPENVPN_P_CONTROL_V1,
+ FifoPtr(c->SslPipe->RawOut->RecvFifo),
+ FifoSize(c->SslPipe->RawOut->RecvFifo));
+
+ ReadFifo(c->SslPipe->RawOut->RecvFifo, NULL, FifoSize(c->SslPipe->RawOut->RecvFifo));
+ }
+ }
+ }
+
+ if (c != NULL)
+ {
+ UINT num;
+ UINT acks[OPENVPN_MAX_NUMACK];
+ UINT k;
+
+ // Packet transmission
+ for (k = 0;k < LIST_NUM(c->SendControlPacketList);k++)
+ {
+ OPENVPN_CONTROL_PACKET *cp = LIST_DATA(c->SendControlPacketList, k);
+
+ if (cp->NextSendTime <= s->Now)
+ {
+ OPENVPN_PACKET *p;
+
+ num = OvsGetAckReplyList(c, acks);
+
+ p = OvsNewControlPacket(cp->OpCode, j, se->ServerSessionId, num, acks,
+ se->ClientSessionId, cp->PacketId, cp->DataSize, cp->Data);
+
+ OvsSendPacketNow(s, se, p);
+
+ OvsFreePacket(p);
+
+ cp->NextSendTime = s->Now + (UINT64)OPENVPN_CONTROL_PACKET_RESEND_INTERVAL;
+
+ AddInterrupt(s->Interrupt, cp->NextSendTime);
+ }
+ }
+
+ // If the response with an ACK-only packet is required, respond such that
+ num = OvsGetAckReplyList(c, acks);
+
+ if (num >= 1)
+ {
+ OPENVPN_PACKET *p = OvsNewControlPacket(OPENVPN_P_ACK_V1, j, se->ServerSessionId,
+ num, acks, se->ClientSessionId, 0, 0, NULL);
+
+ OvsSendPacketNow(s, se, p);
+
+ OvsFreePacket(p);
+ }
+ }
+ }
+
+ if (se->Ipc != NULL)
+ {
+ if (se->Mode == OPENVPN_MODE_L3)
+ {
+ if (se->IpcAsync != NULL)
+ {
+ // Update DHCP address
+ if (se->IpcAsync->L3NextDhcpRenewTick <= s->Now)
+ {
+ IP ip;
+
+ se->IpcAsync->L3NextDhcpRenewTick = s->Now + se->IpcAsync->L3DhcpRenewInterval;
+
+ UINTToIP(&ip, se->IpcAsync->L3ClientAddressOption.ServerAddress);
+
+ IPCDhcpRenewIP(se->Ipc, &ip);
+ }
+ }
+
+ IPCProcessL3Events(se->Ipc);
+ }
+
+ IPCProcessInterrupts(se->Ipc);
+ }
+
+ // Choose the latest channel in all established channels
+ for (j = 0;j < OPENVPN_NUM_CHANNELS;j++)
+ {
+ OPENVPN_CHANNEL *c = se->Channels[j];
+
+ if (c != NULL)
+ {
+ if (c->Status == OPENVPN_CHANNEL_STATUS_ESTABLISHED)
+ {
+ if (max_tick <= c->EstablishedTick)
+ {
+ max_tick = c->EstablishedTick;
+ latest_channel = c;
+ }
+ }
+ }
+ }
+
+ if (se->Established == false)
+ {
+ latest_channel = NULL;
+ }
+
+ // Send the data using the latest channel (when there is no transmission channel, suck out the queue simply)
+ if (se->Mode == OPENVPN_MODE_L2)
+ {
+ // Get an Ethernet frame from IPC
+ while (true)
+ {
+ BLOCK *b = IPCRecvL2(se->Ipc);
+ if (b == NULL)
+ {
+ break;
+ }
+
+ if (latest_channel != NULL && s->SupressSendPacket == false)
+ {
+ OvsSendDataPacket(latest_channel, latest_channel->KeyId, ++latest_channel->LastDataPacketId, b->Buf, b->Size);
+ }
+
+ FreeBlock(b);
+ }
+ }
+ else
+ {
+ // Get an IPv4 packet from IPC
+ while (true)
+ {
+ BLOCK *b = IPCRecvIPv4(se->Ipc);
+ if (b == NULL)
+ {
+ break;
+ }
+
+ if (latest_channel != NULL && s->SupressSendPacket == false)
+ {
+ OvsSendDataPacket(latest_channel, latest_channel->KeyId, ++latest_channel->LastDataPacketId, b->Buf, b->Size);
+ }
+
+ FreeBlock(b);
+ }
+ }
+
+ // Send a Ping
+ if (latest_channel != NULL)
+ {
+ if ((se->NextPingSendTick == 0) || (se->NextPingSendTick <= s->Now))
+ {
+ se->NextPingSendTick = s->Now + (UINT64)(OPENVPN_PING_SEND_INTERVAL);
+
+ OvsSendDataPacket(latest_channel, latest_channel->KeyId, ++latest_channel->LastDataPacketId,
+ ping_signature, sizeof(ping_signature));
+ //Debug(".");
+
+ AddInterrupt(s->Interrupt, se->NextPingSendTick);
+ }
+ }
+
+ if ((se->Established == false) && (s->Now >= (se->CreatedTick + (UINT64)OPENVPN_NEW_SESSION_DEADLINE_TIMEOUT)))
+ {
+ is_disconnected = true;
+ }
+
+ if (se->Established && (s->Now >= (se->LastCommTick + (UINT64)OPENVPN_RECV_TIMEOUT)))
+ {
+ is_disconnected = true;
+ }
+
+ if (is_disconnected)
+ {
+ if (delete_session_list == NULL)
+ {
+ delete_session_list = NewListFast(NULL);
+ }
+
+ Add(delete_session_list, se);
+ }
+ }
+
+ if (delete_session_list != NULL)
+ {
+ UINT i;
+
+ for (i = 0;i < LIST_NUM(delete_session_list);i++)
+ {
+ OPENVPN_SESSION *se = LIST_DATA(delete_session_list, i);
+
+ Debug("Deleting Session %p\n", se);
+ OvsLog(s, se, NULL, "LO_DELETE_SESSION");
+
+ OvsFreeSession(se);
+
+ s->DisconnectCount++;
+
+ Delete(s->SessionList, se);
+ }
+
+ ReleaseList(delete_session_list);
+ }
+}
+
+// Send the packet now
+void OvsSendPacketNow(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_PACKET *p)
+{
+ BUF *b;
+ UINT i;
+ // Validate arguments
+ if (s == NULL || se == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Debug("Sending Opcode=%u ", p->OpCode);
+ if (p->NumAck >= 1)
+ {
+ Debug("Sending ACK Packet IDs (c=%u): ", p->KeyId);
+ for (i = 0;i < p->NumAck;i++)
+ {
+ Debug("%u ", p->AckPacketId[i]);
+ }
+ }
+ Debug("\n");
+
+ b = OvsBuildPacket(p);
+
+ OvsSendPacketRawNow(s, se, b->Buf, b->Size);
+
+ Free(b);
+}
+void OvsSendPacketRawNow(OPENVPN_SERVER *s, OPENVPN_SESSION *se, void *data, UINT size)
+{
+ UDPPACKET *u;
+
+ // Validate arguments
+ if (s == NULL || se == NULL || data == NULL || size == 0)
+ {
+ Free(data);
+ return;
+ }
+
+ u = NewUdpPacket(&se->ServerIp, se->ServerPort, &se->ClientIp, se->ClientPort,
+ data, size);
+
+ Add(s->SendPacketList, u);
+}
+// Create a new OpenVPN control packet
+OPENVPN_PACKET *OvsNewControlPacket(UCHAR opcode, UCHAR key_id, UINT64 my_channel_id, UINT num_ack,
+ UINT *ack_packet_ids, UINT64 your_channel_id, UINT packet_id,
+ UINT data_size, UCHAR *data)
+{
+ OPENVPN_PACKET *p = ZeroMalloc(sizeof(OPENVPN_PACKET));
+ UINT i;
+
+ p->OpCode = opcode;
+ p->KeyId = key_id;
+ p->MySessionId = my_channel_id;
+ p->NumAck = num_ack;
+
+ for (i = 0;i < MIN(num_ack, OPENVPN_MAX_NUMACK);i++)
+ {
+ p->AckPacketId[i] = ack_packet_ids[i];
+ }
+
+ p->YourSessionId = your_channel_id;
+ p->PacketId = packet_id;
+
+ if (data_size != 0 && data != NULL)
+ {
+ p->Data = Clone(data, data_size);
+ p->DataSize = data_size;
+ }
+
+ return p;
+}
+
+// Comparison function of the entries in the session list
+int OvsCompareSessionList(void *p1, void *p2)
+{
+ OPENVPN_SESSION *s1, *s2;
+ int i;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ s1 = *(OPENVPN_SESSION **)p1;
+ s2 = *(OPENVPN_SESSION **)p2;
+ if (s1 == NULL || s2 == NULL)
+ {
+ return 0;
+ }
+
+ i = CmpIpAddr(&s1->Protocol, &s2->Protocol);
+ if (i != 0)
+ {
+ return i;
+ }
+
+ i = CmpIpAddr(&s1->ClientIp, &s2->ClientIp);
+ if (i != 0)
+ {
+ return i;
+ }
+
+ i = COMPARE_RET(s1->ClientPort, s2->ClientPort);
+ if (i != 0)
+ {
+ return i;
+ }
+
+ i = CmpIpAddr(&s1->ServerIp, &s2->ServerIp);
+ if (i != 0)
+ {
+ return i;
+ }
+
+ i = COMPARE_RET(s1->ServerPort, s2->ServerPort);
+ if (i != 0)
+ {
+ return i;
+ }
+
+ return 0;
+}
+
+// Identify whether the IP address is compatible to the tun device of OpenVPN
+bool OvsIsCompatibleL3IP(UINT ip)
+{
+ IP p;
+
+ UINTToIP(&p, ip);
+ if ((p.addr[3] % 4) == 1)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Get an IP address that is compatible to tun device of the OpenVPN after the specified IP address
+UINT OvsGetCompatibleL3IPNext(UINT ip)
+{
+ ip = Endian32(ip);
+
+ while (true)
+ {
+ if (OvsIsCompatibleL3IP(Endian32(ip)))
+ {
+ return Endian32(ip);
+ }
+
+ ip++;
+ }
+}
+
+// Create a new OpenVPN server
+OPENVPN_SERVER *NewOpenVpnServer(CEDAR *cedar, INTERRUPT_MANAGER *interrupt, SOCK_EVENT *sock_event)
+{
+ OPENVPN_SERVER *s;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ s = ZeroMalloc(sizeof(OPENVPN_SERVER));
+
+ s->Cedar = cedar;
+
+ AddRef(s->Cedar->ref);
+
+ s->Interrupt = interrupt;
+
+ s->SessionList = NewList(OvsCompareSessionList);
+ s->SendPacketList = NewListFast(NULL);
+
+ s->Now = Tick64();
+
+ s->NextSessionId = 1;
+
+ if (sock_event != NULL)
+ {
+ s->SockEvent = sock_event;
+ AddRef(s->SockEvent->ref);
+ }
+
+ OvsLog(s, NULL, NULL, "LO_START");
+
+ s->Dh = DhNewGroup2();
+
+ return s;
+}
+
+// Release the OpenVPN server
+void FreeOpenVpnServer(OPENVPN_SERVER *s)
+{
+ UINT i;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ OvsLog(s, NULL, NULL, "LO_STOP");
+
+ // Release the session list
+ for (i = 0;i < LIST_NUM(s->SessionList);i++)
+ {
+ OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
+
+ OvsFreeSession(se);
+ }
+
+ ReleaseList(s->SessionList);
+
+ // Release the packet which is attempting to send
+ for (i = 0;i < LIST_NUM(s->SendPacketList);i++)
+ {
+ UDPPACKET *p = LIST_DATA(s->SendPacketList, i);
+
+ FreeUdpPacket(p);
+ }
+
+ ReleaseList(s->SendPacketList);
+
+ ReleaseCedar(s->Cedar);
+
+ if (s->SockEvent != NULL)
+ {
+ ReleaseSockEvent(s->SockEvent);
+ }
+
+ DhFree(s->Dh);
+
+ Free(s);
+}
+
+// UDP reception procedure
+void OpenVpnServerUdpListenerProc(UDPLISTENER *u, LIST *packet_list)
+{
+ OPENVPN_SERVER_UDP *us;
+ UINT64 now = Tick64();
+ // Validate arguments
+ if (u == NULL || packet_list == NULL)
+ {
+ return;
+ }
+
+ us = (OPENVPN_SERVER_UDP *)u->Param;
+
+ if (OvsGetNoOpenVpnUdp())
+ {
+ // OpenVPN over UDP is disabled
+ return;
+ }
+
+ if (us->OpenVpnServer != NULL)
+ {
+ {
+ u->PollMyIpAndPort = false;
+
+ ClearStr(us->Cedar->OpenVPNPublicPorts, sizeof(us->Cedar->OpenVPNPublicPorts));
+ }
+
+ OvsRecvPacket(us->OpenVpnServer, packet_list, OPENVPN_PROTOCOL_UDP);
+
+ UdpListenerSendPackets(u, us->OpenVpnServer->SendPacketList);
+ DeleteAll(us->OpenVpnServer->SendPacketList);
+ }
+}
+
+// Create an OpenVPN server (UDP mode)
+OPENVPN_SERVER_UDP *NewOpenVpnServerUdp(CEDAR *cedar)
+{
+ OPENVPN_SERVER_UDP *u;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ u = ZeroMalloc(sizeof(OPENVPN_SERVER_UDP));
+
+ u->Cedar = cedar;
+
+ AddRef(u->Cedar->ref);
+
+ // Create a UDP listener
+ u->UdpListener = NewUdpListener(OpenVpnServerUdpListenerProc, u);
+
+ // Create an OpenVPN server
+ u->OpenVpnServer = NewOpenVpnServer(cedar, u->UdpListener->Interrupts, u->UdpListener->Event);
+
+ return u;
+}
+
+// Apply the port list to the OpenVPN server
+void OvsApplyUdpPortList(OPENVPN_SERVER_UDP *u, char *port_list)
+{
+ LIST *o;
+ UINT i;
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+
+ DeleteAllPortFromUdpListener(u->UdpListener);
+
+ o = StrToIntList(port_list, true);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ UINT port = *((UINT *)LIST_DATA(o, i));
+
+ if (port >= 1 && port <= 65535)
+ {
+ AddPortToUdpListener(u->UdpListener, port);
+ }
+ }
+
+ ReleaseIntList(o);
+}
+
+// Release the OpenVPN server (UDP mode)
+void FreeOpenVpnServerUdp(OPENVPN_SERVER_UDP *u)
+{
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+
+ // Stop the UDP listener
+ FreeUdpListener(u->UdpListener);
+
+ // Release the OpenVPN server
+ FreeOpenVpnServer(u->OpenVpnServer);
+
+ ReleaseCedar(u->Cedar);
+
+ Free(u);
+}
+
+// Check whether it's OpenSSL protocol by looking the first receive buffer of the TCP
+bool OvsCheckTcpRecvBufIfOpenVPNProtocol(UCHAR *buf, UINT size)
+{
+ if (buf == NULL || size != 2)
+ {
+ return false;
+ }
+
+ if (buf[0] == 0x00 && buf[1] == 0x0E)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Run the OpenVPN server in TCP mode
+bool OvsPerformTcpServer(CEDAR *cedar, SOCK *sock)
+{
+ OPENVPN_SERVER *s;
+ INTERRUPT_MANAGER *im;
+ SOCK_EVENT *se;
+ FIFO *tcp_recv_fifo;
+ FIFO *tcp_send_fifo;
+ UINT buf_size = (128 * 1024);
+ UCHAR *buf;
+ UINT64 giveup_time = Tick64() + (UINT64)OPENVPN_NEW_SESSION_DEADLINE_TIMEOUT;
+ LIST *ovs_recv_packet;
+ UINT i;
+ bool ret = false;
+ // Validate arguments
+ if (cedar == NULL || sock == NULL)
+ {
+ return false;
+ }
+
+ // Initialize
+ buf = Malloc(buf_size);
+ im = NewInterruptManager();
+ se = NewSockEvent();
+ SetTimeout(sock, TIMEOUT_INFINITE);
+ JoinSockToSockEvent(sock, se);
+
+ tcp_recv_fifo = NewFifoFast();
+ tcp_send_fifo = NewFifoFast();
+
+ ovs_recv_packet = NewListFast(NULL);
+
+ // Create an OpenVPN server
+ s = NewOpenVpnServer(cedar, im, se);
+
+ // Main loop
+ Debug("Entering OpenVPN TCP Server Main Loop.\n");
+ while (true)
+ {
+ UINT next_interval;
+ bool disconnected = false;
+ UINT64 now = Tick64();
+
+ // Receive data from a TCP socket
+ while (true)
+ {
+ UINT r = Recv(sock, buf, buf_size, false);
+ if (r == SOCK_LATER)
+ {
+ // Can not read any more
+ break;
+ }
+ else if (r == 0)
+ {
+ // Disconnected
+ disconnected = true;
+ break;
+ }
+ else
+ {
+ // Read
+ WriteFifo(tcp_recv_fifo, buf, r);
+ }
+ }
+
+ // Separate to a list of datagrams by interpreting the data received from the TCP socket
+ while (true)
+ {
+ UINT r = FifoSize(tcp_recv_fifo);
+ if (r >= sizeof(USHORT))
+ {
+ void *ptr = FifoPtr(tcp_recv_fifo);
+ USHORT packet_size = READ_USHORT(ptr);
+ if (packet_size <= OPENVPN_TCP_MAX_PACKET_SIZE)
+ {
+ UINT total_len = (UINT)packet_size + sizeof(USHORT);
+ if (r >= total_len)
+ {
+ if (ReadFifo(tcp_recv_fifo, buf, total_len) != total_len)
+ {
+ // Mismatch
+ disconnected = true;
+ break;
+ }
+ else
+ {
+ // Read one packet
+ UINT payload_len = packet_size;
+ UCHAR *payload_ptr = buf + sizeof(USHORT);
+
+ // Pass the packet to the OpenVPN server
+ Add(ovs_recv_packet, NewUdpPacket(&sock->RemoteIP, sock->RemotePort,
+ &sock->LocalIP, sock->LocalPort,
+ Clone(payload_ptr, payload_len), payload_len));
+ }
+ }
+ else
+ {
+ // Non-arrival
+ break;
+ }
+ }
+ else
+ {
+ // Invalid packet size
+ disconnected = true;
+ break;
+ }
+ }
+ else
+ {
+ // Non-arrival
+ break;
+ }
+ }
+
+ // Pass a list of received datagrams to the OpenVPN server
+ OvsRecvPacket(s, ovs_recv_packet, OPENVPN_PROTOCOL_TCP);
+
+ // Release the received packet list
+ for (i = 0;i < LIST_NUM(ovs_recv_packet);i++)
+ {
+ UDPPACKET *p = LIST_DATA(ovs_recv_packet, i);
+
+ FreeUdpPacket(p);
+ }
+
+ DeleteAll(ovs_recv_packet);
+
+ // Store in the queue by getting a list of the datagrams to be transmitted from the OpenVPN server
+ for (i = 0;i < LIST_NUM(s->SendPacketList);i++)
+ {
+ UDPPACKET *p = LIST_DATA(s->SendPacketList, i);
+ // Store the size to the TCP send queue first
+ USHORT us = (USHORT)p->Size;
+ //Debug(" *** TCP SEND %u\n", us);
+ us = Endian16(us);
+ WriteFifo(tcp_send_fifo, &us, sizeof(USHORT));
+
+ // Write the data body
+ WriteFifo(tcp_send_fifo, p->Data, p->Size);
+
+ // Packet release
+ FreeUdpPacket(p);
+ }
+ DeleteAll(s->SendPacketList);
+
+ // Send data to the TCP socket
+ while (FifoSize(tcp_send_fifo) >= 1)
+ {
+ UINT r = Send(sock, FifoPtr(tcp_send_fifo), FifoSize(tcp_send_fifo), false);
+
+ if (r == SOCK_LATER)
+ {
+ // Can not write any more
+ break;
+ }
+ else if (r == 0)
+ {
+ // Disconnected
+ disconnected = true;
+ break;
+ }
+ else
+ {
+ // Wrote out
+ ReadFifo(tcp_send_fifo, NULL, r);
+ }
+ }
+
+ if (FifoSize(tcp_send_fifo) > MAX_BUFFERING_PACKET_SIZE)
+ {
+ s->SupressSendPacket = true;
+ }
+ else
+ {
+ s->SupressSendPacket = false;
+ }
+
+ if (s->DisconnectCount >= 1)
+ {
+ // Session disconnection has occurred on OpenVPN server-side
+ disconnected = true;
+ }
+
+ if (giveup_time <= now)
+ {
+ UINT i;
+ UINT num_established_sessions = 0;
+ for (i = 0;i < LIST_NUM(s->SessionList);i++)
+ {
+ OPENVPN_SESSION *se = LIST_DATA(s->SessionList, i);
+
+ if (se->Established)
+ {
+ num_established_sessions++;
+ }
+ }
+
+ if (num_established_sessions == 0)
+ {
+ // If the number of sessions is 0 even if wait a certain period of time after the start of server, abort
+ disconnected = true;
+ }
+ }
+
+ if (disconnected)
+ {
+ // Error or disconnect occurs
+ Debug("Breaking OpenVPN TCP Server Main Loop.\n");
+ break;
+ }
+
+ // Wait until the next event occurs
+ next_interval = GetNextIntervalForInterrupt(im);
+ next_interval = MIN(next_interval, UDPLISTENER_WAIT_INTERVAL);
+ WaitSockEvent(se, next_interval);
+ }
+
+ if (s != NULL && s->SessionEstablishedCount != 0)
+ {
+ ret = true;
+ }
+
+ // Release the OpenVPN server
+ FreeOpenVpnServer(s);
+
+ // Release object
+ FreeInterruptManager(im);
+ ReleaseSockEvent(se);
+ ReleaseFifo(tcp_recv_fifo);
+ ReleaseFifo(tcp_send_fifo);
+ Free(buf);
+
+ // Release the received packet list
+ for (i = 0;i < LIST_NUM(ovs_recv_packet);i++)
+ {
+ UDPPACKET *p = LIST_DATA(ovs_recv_packet, i);
+
+ FreeUdpPacket(p);
+ }
+
+ ReleaseList(ovs_recv_packet);
+
+ return ret;
+}
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Interop_OpenVPN.h b/src/Cedar/Interop_OpenVPN.h
new file mode 100644
index 00000000..c60b6a60
--- /dev/null
+++ b/src/Cedar/Interop_OpenVPN.h
@@ -0,0 +1,362 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Interop_OpenVPN.h
+// Header of Interop_OpenVPN.c
+
+#ifndef INTEROP_OPENVPN_H
+#define INTEROP_OPENVPN_H
+
+
+//// Constants
+#define OPENVPN_UDP_PORT 1194 // OpenVPN default UDP port number
+#define OPENVPN_UDP_PORT_INCLUDE 1195 // OpenVPN default UDP port number (Operating within the client)
+
+#define OPENVPN_MAX_NUMACK 4 // The maximum number of ACKs
+#define OPENVPN_NUM_CHANNELS 8 // Maximum number of channels during a session
+#define OPENVPN_CONTROL_PACKET_RESEND_INTERVAL 500 // Control packet retransmission interval
+#define OPENVPN_CONTROL_PACKET_MAX_DATASIZE 1200 // Maximum data size that can be stored in one control packet
+
+#define OPENVPN_MAX_SSL_RECV_BUF_SIZE (256 * 1024) // SSL receive buffer maximum length
+
+#define OPENVPN_MAX_KEY_SIZE 64 // Maximum key size
+
+#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
+#define OPENVPN_TCP_MAX_PACKET_SIZE 2000 // The maximum packet size allowed in TCP mode
+
+
+// The default algorithm
+#define OPENVPN_DEFAULT_CIPHER "AES-128-CBC"
+#define OPENVPN_DEFAULT_MD "SHA1"
+
+// Encryption related
+#define OPENVPN_PREMASTER_LABEL "OpenVPN master secret"
+#define OPENVPN_EXPANSION_LABEL "OpenVPN key expansion"
+
+// IPC related
+#define OPENVPN_IPC_CLIENT_NAME "OpenVPN Client"
+#define OPENVPN_IPC_POSTFIX_L2 "OPENVPN_L2"
+#define OPENVPN_IPC_POSTFIX_L3 "OPENVPN_L3"
+
+// List of supported encryption algorithms
+#define OPENVPN_CIPHER_LIST "[NULL-CIPHER] NULL AES-128-CBC AES-192-CBC AES-256-CBC BF-CBC CAST-CBC CAST5-CBC DES-CBC DES-EDE-CBC DES-EDE3-CBC DESX-CBC RC2-40-CBC RC2-64-CBC RC2-CBC"
+
+// List of the supported hash algorithm
+#define OPENVPN_MD_LIST "SHA SHA1 MD5 MD4 RMD160"
+
+// MTU
+#define OPENVPN_MTU_LINK 1514 // Ethernet MTU
+#define OPENVPN_MTU_TUN 1500 // Tun MTU
+
+// Protocol
+#define OPENVPN_PROTOCOL_UDP 0 // UDP
+#define OPENVPN_PROTOCOL_TCP 1 // TCP
+
+// Op-code
+#define OPENVPN_P_CONTROL_SOFT_RESET_V1 3 // Soft reset request
+#define OPENVPN_P_CONTROL_V1 4 // SSL negotiation packet
+#define OPENVPN_P_ACK_V1 5 // Acknowledgment
+#define OPENVPN_P_DATA_V1 6 // Data packet
+#define OPENVPN_P_CONTROL_HARD_RESET_CLIENT_V2 7 // Connection request from client
+#define OPENVPN_P_CONTROL_HARD_RESET_SERVER_V2 8 // Connection response from server
+
+// State of OpenVPN channel
+#define OPENVPN_CHANNEL_STATUS_INIT 0 // Initialization phase
+#define OPENVPN_CHANNEL_STATUS_TLS_WAIT_CLIENT_KEY 1 // Waiting for the key information from the client
+#define OPENVPN_CHANNEL_STATUS_TLS_WAIT_CLIENT_PUSH_REQUEST 2 // Waiting for PUSH_REQUEST from the client
+#define OPENVPN_CHANNEL_STATUS_TLS_VPN_CONNECTING 3 // VPN connecting process is running
+#define OPENVPN_CHANNEL_STATUS_ESTABLISHED 4 // VPN connection established
+#define OPENVPN_CHANNEL_STATUS_DISCONNECTED 5 // Disconnected
+
+// Quota
+#define OPENVPN_QUOTA_MAX_NUM_SESSIONS_PER_IP 1000 // Number of OpenVPN sessions per IP address
+#define OPENVPN_QUOTA_MAX_NUM_SESSIONS 30000 // Limit of the number of sessions
+
+// Mode
+#define OPENVPN_MODE_UNKNOWN 0 // Unknown
+#define OPENVPN_MODE_L2 1 // TAP (Ethernet)
+#define OPENVPN_MODE_L3 2 // TUN (IP)
+
+
+//// Type
+
+// Data of OpenVPN Key Method 2
+struct OPENVPN_KEY_METHOD_2
+{
+ UCHAR PreMasterSecret[48]; // Pre Master Secret (client only)
+ UCHAR Random1[32]; // Random 1
+ UCHAR Random2[32]; // Random 2
+ char OptionString[512]; // Option string
+ char Username[512]; // User name
+ char Password[512]; // Password
+ char PeerInfo[1536]; // PeerInfo
+};
+
+// OpenVPN sending control packet
+struct OPENVPN_CONTROL_PACKET
+{
+ UCHAR OpCode; // Op-code
+ UINT PacketId; // Packet ID
+ UINT DataSize; // Data size
+ UCHAR *Data; // Data body
+ UINT64 NextSendTime; // Scheduled next transmission time
+};
+
+// OpenVPN packet
+struct OPENVPN_PACKET
+{
+ UCHAR OpCode; // Op-code
+ UCHAR KeyId; // Key ID
+ UINT64 MySessionId; // Channel ID of the sender
+ UCHAR NumAck; // Number of ACK
+ UINT AckPacketId[OPENVPN_MAX_NUMACK]; // ACK packet ID list
+ UINT64 YourSessionId; // Destination Channel ID (If there are one or more ACK)
+ UINT PacketId; // Packet ID
+ UINT DataSize; // Data size
+ UCHAR *Data; // Data body
+};
+
+// OpenVPN channel
+struct OPENVPN_CHANNEL
+{
+ OPENVPN_SERVER *Server;
+ OPENVPN_SESSION *Session;
+ UINT Status; // State
+ LIST *AckReplyList; // Response ACK list
+ UINT MaxRecvPacketId; // The maximum value of the arrived packet ID
+ UINT NextSendPacketId; // The value of a packet ID to be transmitted next
+ LIST *SendControlPacketList; // Sending control packet list
+ SSL_PIPE *SslPipe; // SSL pipe
+ OPENVPN_KEY_METHOD_2 ClientKey; // Key sent from the client
+ OPENVPN_KEY_METHOD_2 ServerKey; // Key sent from the server
+ char Proto[64]; // Protocol
+ CIPHER *CipherEncrypt; // Encryption algorithm
+ CIPHER *CipherDecrypt; // Decryption algorithm
+ MD *MdSend; // Transmission MD algorithm
+ MD *MdRecv; // Reception MD algorithm
+ UCHAR MasterSecret[48]; // Master Secret
+ UCHAR ExpansionKey[256]; // Expansion Key
+ UCHAR NextIv[64]; // Next IV
+ UINT LastDataPacketId; // Previous Data Packet ID
+ UINT64 EstablishedTick; // Established time
+ UCHAR KeyId; // KEY ID
+ bool IsRekeyChannel; // Whether it is a channel for key update
+ bool IsInitiatorServer; // Whether the channel was started from the server side
+ bool RekeyInitiated; // Whether re-keying has already started
+ UINT64 NextRekey;
+};
+
+// OpenVPN session
+struct OPENVPN_SESSION
+{
+ UINT Id; // ID
+ OPENVPN_SERVER *Server;
+ UINT64 ServerSessionId; // The session ID of the server-side
+ UINT64 ClientSessionId; // Session ID of the client side
+ UINT Protocol; // Protocol
+ IP ClientIp; // Client IP address
+ UINT ClientPort; // Client port number
+ IP ServerIp; // Server IP address
+ UINT ServerPort; // Server port number
+ OPENVPN_CHANNEL *Channels[OPENVPN_NUM_CHANNELS]; // Channels (up to 8)
+ UINT LastCreatedChannelIndex; // Channel number that is created in the last
+ UINT Mode; // Mode (L3 or L2)
+ UINT LinkMtu; // link-mtu
+ UINT TunMtu; // tun-mtu
+ IPC_ASYNC *IpcAsync; // Asynchronous IPC connection
+ IPC *Ipc; // Connected IPC connection
+ char PushReplyStr[MAX_SIZE]; // PUSH_REPLY string
+ UINT64 NextPingSendTick; // Next time to send a Ping
+ bool Established; // VPN communication established flag
+ UINT64 CreatedTick; // Creation date and time
+ UINT64 LastCommTick; // Last communication date and time
+};
+
+// OpenVPN server
+struct OPENVPN_SERVER
+{
+ CEDAR *Cedar;
+ INTERRUPT_MANAGER *Interrupt; // Interrupt manager
+ LIST *SendPacketList; // Transmission packet list
+ LIST *SessionList; // Session list
+ UINT64 Now; // Current time
+ SOCK_EVENT *SockEvent; // Socket event
+ UCHAR TmpBuf[OPENVPN_TMP_BUFFER_SIZE]; // Temporary buffer
+ UINT DisconnectCount; // The number of session lost that have occurred so far
+ bool SupressSendPacket; // Packet transmission suppression flag
+ UINT NextSessionId; // Next session ID
+ DH_CTX *Dh; // DH key
+ UINT SessionEstablishedCount; // Number of session establishment
+};
+
+// OpenVPN server (UDP mode)
+struct OPENVPN_SERVER_UDP
+{
+ CEDAR *Cedar;
+ UDPLISTENER *UdpListener; // UDP listener
+ OPENVPN_SERVER *OpenVpnServer; // OpenVPN server
+ UINT64 VgsNextGetPublicPortsTick;
+};
+
+
+//// Function prototype
+OPENVPN_SERVER_UDP *NewOpenVpnServerUdp(CEDAR *cedar);
+void FreeOpenVpnServerUdp(OPENVPN_SERVER_UDP *u);
+void OpenVpnServerUdpListenerProc(UDPLISTENER *u, LIST *packet_list);
+void OvsApplyUdpPortList(OPENVPN_SERVER_UDP *u, char *port_list);
+
+OPENVPN_SERVER *NewOpenVpnServer(CEDAR *cedar, INTERRUPT_MANAGER *interrupt, SOCK_EVENT *sock_event);
+void FreeOpenVpnServer(OPENVPN_SERVER *s);
+void OvsRecvPacket(OPENVPN_SERVER *s, LIST *recv_packet_list, UINT protocol);
+void OvsProceccRecvPacket(OPENVPN_SERVER *s, UDPPACKET *p, UINT protocol);
+int OvsCompareSessionList(void *p1, void *p2);
+OPENVPN_SESSION *OvsSearchSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, UINT protocol);
+OPENVPN_SESSION *OvsNewSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, UINT protocol);
+OPENVPN_SESSION *OvsFindOrCreateSession(OPENVPN_SERVER *s, IP *server_ip, UINT server_port, IP *client_ip, UINT client_port, UINT protocol);
+void OvsFreeSession(OPENVPN_SESSION *se);
+UINT OvsGetNumSessionByClientIp(OPENVPN_SERVER *s, IP *ip);
+
+OPENVPN_PACKET *OvsParsePacket(UCHAR *data, UINT size);
+void OvsFreePacket(OPENVPN_PACKET *p);
+BUF *OvsBuildPacket(OPENVPN_PACKET *p);
+OPENVPN_PACKET *OvsNewControlPacket(UCHAR opcode, UCHAR key_id, UINT64 my_channel_id, UINT num_ack,
+ UINT *ack_packet_ids, UINT64 your_channel_id, UINT packet_id,
+ UINT data_size, UCHAR *data);
+void OvsSendDataPacket(OPENVPN_CHANNEL *c, UCHAR key_id, UINT data_packet_id, void *data, UINT data_size);
+
+
+OPENVPN_CHANNEL *OvsNewChannel(OPENVPN_SESSION *se, UCHAR key_id);
+void OvsFreeChannel(OPENVPN_CHANNEL *c);
+UINT64 OvsNewServerSessionId(OPENVPN_SERVER *s);
+UINT OvsGetAckReplyList(OPENVPN_CHANNEL *c, UINT *ret);
+
+void OvsSendPacketNow(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_PACKET *p);
+void OvsSendPacketRawNow(OPENVPN_SERVER *s, OPENVPN_SESSION *se, void *data, UINT size);
+
+void OvsProcessRecvControlPacket(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c, OPENVPN_PACKET *p);
+void OvsSendControlPacket(OPENVPN_CHANNEL *c, UCHAR opcode, UCHAR *data, UINT data_size);
+void OvsSendControlPacketWithAutoSplit(OPENVPN_CHANNEL *c, UCHAR opcode, UCHAR *data, UINT data_size);
+void OvsFreeControlPacket(OPENVPN_CONTROL_PACKET *p);
+void OvsDeleteFromSendingControlPacketList(OPENVPN_CHANNEL *c, UINT num_acks, UINT *acks);
+UINT OvsParseKeyMethod2(OPENVPN_KEY_METHOD_2 *ret, UCHAR *data, UINT size, bool client_mode);
+bool OvsReadStringFromBuf(BUF *b, char *str, UINT str_size);
+void OvsSetupSessionParameters(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c, OPENVPN_KEY_METHOD_2 *data);
+BUF *OvsBuildKeyMethod2(OPENVPN_KEY_METHOD_2 *d);
+void OvsWriteStringToBuf(BUF *b, char *str, UINT max_size);
+
+LIST *OvsParseOptions(char *str);
+void OvsFreeOptions(LIST *o);
+LIST *OvsNewOptions();
+void OvsAddOption(LIST *o, char *key, char *value);
+bool OvsHasOption(LIST *o, char *key);
+UINT OvsPeekStringFromFifo(FIFO *f, char *str, UINT str_size);
+void OvsBeginIPCAsyncConnectionIfEmpty(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c);
+bool OvsIsCompatibleL3IP(UINT ip);
+UINT OvsGetCompatibleL3IPNext(UINT ip);
+UINT OvsCalcTcpMss(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_CHANNEL *c);
+
+CIPHER *OvsGetCipher(char *name);
+MD *OvsGetMd(char *name);
+bool OvsCheckTcpRecvBufIfOpenVPNProtocol(UCHAR *buf, UINT size);
+
+bool OvsPerformTcpServer(CEDAR *cedar, SOCK *sock);
+
+void OvsSetReplyForVgsPollEnable(bool b);
+
+void OvsSetNoOpenVpnTcp(bool b);
+bool OvsGetNoOpenVpnTcp();
+
+void OvsSetNoOpenVpnUdp(bool b);
+
+
+
+#endif // INTEROP_OPENVPN_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Interop_SSTP.c b/src/Cedar/Interop_SSTP.c
new file mode 100644
index 00000000..18065fae
--- /dev/null
+++ b/src/Cedar/Interop_SSTP.c
@@ -0,0 +1,1222 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Interop_SSTP.c
+// SSTP (Microsoft Secure Socket Tunneling Protocol) protocol stack
+
+#include "CedarPch.h"
+
+static bool g_no_sstp = false;
+
+// Get the SSTP disabling flag
+bool GetNoSstp()
+{
+ return g_no_sstp;
+}
+
+// Set the SSTP disabling flag
+void SetNoSstp(bool b)
+{
+ g_no_sstp = b;
+}
+
+// Process the SSTP control packet reception
+void SstpProcessControlPacket(SSTP_SERVER *s, SSTP_PACKET *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL || p->IsControl == false)
+ {
+ return;
+ }
+
+ Debug("SSTP Control Packet Recv: Msg = %u, Num = %u\n", p->MessageType, LIST_NUM(p->AttibuteList));
+
+ switch (p->MessageType)
+ {
+ case SSTP_MSG_CALL_CONNECT_REQUEST: // Receive a connection request from a client
+ if (s->Aborting == false && s->Disconnecting == false)
+ {
+ if (s->Status == SSTP_SERVER_STATUS_REQUEST_PENGING)
+ {
+ SSTP_ATTRIBUTE *protocol_id = SstpFindAttribute(p, SSTP_ATTRIB_ENCAPSULATED_PROTOCOL_ID);
+ if (protocol_id != NULL && protocol_id->DataSize == 2 &&
+ READ_USHORT(protocol_id->Data) == SSTP_ENCAPSULATED_PROTOCOL_PPP)
+ {
+ // Accept the connection request by the PPP protocol
+ SSTP_PACKET *ret;
+
+ // Generation of random numbers
+ Rand(s->SentNonce, SSTP_NONCE_SIZE);
+
+ ret = SstpNewControlPacketWithAnAttribute(SSTP_MSG_CALL_CONNECT_ACK,
+ SstpNewCryptoBindingRequestAttribute(CERT_HASH_PROTOCOL_SHA256, s->SentNonce));
+
+ SstpSendPacket(s, ret);
+
+ SstpFreePacket(ret);
+
+ s->Status = SSTP_SERVER_STATUS_CONNECTED_PENDING;
+
+ s->EstablishedCount++;
+ }
+ else
+ {
+ // Refuse to accept for a connection request other than the PPP protocol
+ SSTP_PACKET *ret = SstpNewControlPacketWithAnAttribute(SSTP_MSG_CALL_CONNECT_NAK,
+ SstpNewStatusInfoAttribute(SSTP_ATTRIB_ENCAPSULATED_PROTOCOL_ID, ATTRIB_STATUS_VALUE_NOT_SUPPORTED));
+
+ SstpSendPacket(s, ret);
+
+ SstpFreePacket(ret);
+ }
+ }
+ }
+ break;
+
+ case SSTP_MSG_CALL_CONNECTED: // Connection from the client complete
+ if (s->Aborting == false && s->Disconnecting == false)
+ {
+ if (s->Status == SSTP_SERVER_STATUS_CONNECTED_PENDING)
+ {
+ s->Status = SSTP_SERVER_STATUS_ESTABLISHED;
+
+ Debug("SSTP Connected.\n");
+ }
+ }
+ break;
+
+ case SSTP_MSG_CALL_DISCONNECT: // Receive a disconnect request from the client
+ case SSTP_MSG_CALL_DISCONNECT_ACK:
+ s->DisconnectRecved = true;
+ SstpDisconnect(s);
+ break;
+
+ case SSTP_MSG_CALL_ABORT: // Receive a disconnect request from the client
+ s->AbortReceived = true;
+ SstpAbort(s);
+ break;
+ }
+}
+
+// Process the SSTP received data packet
+void SstpProcessDataPacket(SSTP_SERVER *s, SSTP_PACKET *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL || p->IsControl)
+ {
+ return;
+ }
+
+ //Debug("SSTP Data Packet Recv: Size = %u\n", p->DataSize);
+
+ if (s->PPPThread == NULL)
+ {
+ // Create a thread to initialize the new PPP module
+ s->PPPThread = NewPPPSession(s->Cedar, &s->ClientIp, s->ClientPort, &s->ServerIp, s->ServerPort,
+ s->TubeSend, s->TubeRecv, SSTP_IPC_POSTFIX, SSTP_IPC_CLIENT_NAME,
+ s->ClientHostName, s->ClientCipherName, 0);
+ }
+
+ // Pass the received data to the PPP module
+ TubeSendEx(s->TubeRecv, p->Data, p->DataSize, NULL, true);
+ s->FlushRecvTube = true;
+}
+
+// Process the SSTP received packet
+void SstpProcessPacket(SSTP_SERVER *s, SSTP_PACKET *p)
+{
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ s->LastRecvTick = s->Now;
+
+ if (p->IsControl)
+ {
+ // Control packet
+ SstpProcessControlPacket(s, p);
+ }
+ else
+ {
+ // Data packet
+ SstpProcessDataPacket(s, p);
+ }
+}
+
+// Send a SSTP packet
+void SstpSendPacket(SSTP_SERVER *s, SSTP_PACKET *p)
+{
+ BUF *b;
+ BLOCK *block;
+ // Validate arguments
+ if (s == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (p->IsControl)
+ {
+ Debug("SSTP Control Packet Send: Msg = %u, Num = %u\n", p->MessageType, LIST_NUM(p->AttibuteList));
+ }
+ else
+ {
+ //Debug("SSTP Data Packet Send: Size=%u\n", p->DataSize);
+ }
+
+ b = SstpBuildPacket(p);
+ if (b == NULL)
+ {
+ return;
+ }
+
+ block = NewBlock(b->Buf, b->Size, 0);
+ block->PriorityQoS = p->IsControl;
+ Free(b);
+
+ InsertQueue(s->SendQueue, block);
+}
+
+// Process the timer interrupt
+void SstpProcessInterrupt(SSTP_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ s->Now = Tick64();
+
+ s->FlushRecvTube = false;
+
+ // Process the received packet
+ while (true)
+ {
+ BLOCK *b = GetNext(s->RecvQueue);
+ SSTP_PACKET *p;
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ p = SstpParsePacket(b->Buf, b->Size);
+ if (p == NULL)
+ {
+ // Disconnect the SSTP since a bad packet received
+ SstpAbort(s);
+ }
+ else
+ {
+ // Process the received packet
+ SstpProcessPacket(s, p);
+
+ SstpFreePacket(p);
+ }
+
+ FreeBlock(b);
+ }
+
+ if (s->FlushRecvTube)
+ {
+ TubeFlush(s->TubeRecv);
+ }
+
+ // Transmit a packet that the PPP module is trying to send via the SSTP
+ while (true)
+ {
+ TUBEDATA *d = TubeRecvAsync(s->TubeSend);
+ SSTP_PACKET *p;
+ if (d == NULL)
+ {
+ break;
+ }
+
+ p = SstpNewDataPacket(d->Data, d->DataSize);
+
+ SstpSendPacket(s, p);
+
+ SstpFreePacket(p);
+
+ FreeTubeData(d);
+ }
+
+ if (s->Status == SSTP_SERVER_STATUS_ESTABLISHED)
+ {
+ if (s->Disconnecting == false && s->Aborting == false)
+ {
+ // Periodic transmission of Echo Request
+ if (s->NextSendEchoRequestTick == 0 || s->NextSendEchoRequestTick <= s->Now)
+ {
+ UINT64 next_interval = (UINT64)(SSTP_ECHO_SEND_INTERVAL_MIN + Rand32() % (SSTP_ECHO_SEND_INTERVAL_MAX - SSTP_ECHO_SEND_INTERVAL_MIN));
+ SSTP_PACKET *p;
+
+ s->NextSendEchoRequestTick = s->Now + next_interval;
+ AddInterrupt(s->Interrupt, s->NextSendEchoRequestTick);
+
+ p = SstpNewControlPacket(SSTP_MSG_ECHO_REQUEST);
+
+ SstpSendPacket(s, p);
+
+ SstpFreePacket(p);
+ }
+ }
+ }
+
+ if ((s->LastRecvTick + (UINT64)SSTP_TIMEOUT) <= s->Now)
+ {
+ // Disconnect the SSTP because a timeout occurred
+ SstpAbort(s);
+ s->Disconnected = true;
+ }
+
+ if (IsTubeConnected(s->TubeRecv) == false || IsTubeConnected(s->TubeSend) == false)
+ {
+ // Disconnect the SSTP since the PPP module is disconnected
+ SstpDisconnect(s);
+ }
+
+ if (s->Disconnecting)
+ {
+ // Normal disconnection process
+ if (s->DisconnectSent == false)
+ {
+ // Send a Disconnect
+ SSTP_PACKET *ret = SstpNewControlPacket(s->DisconnectRecved ? SSTP_MSG_CALL_DISCONNECT_ACK : SSTP_MSG_CALL_DISCONNECT);
+
+ SstpSendPacket(s, ret);
+
+ SstpFreePacket(ret);
+
+ s->DisconnectSent = true;
+ }
+ }
+
+ if (s->Aborting)
+ {
+ // Abnormal disconnection processing
+ if (s->AbortSent == false)
+ {
+ // Send the Abort
+ SSTP_PACKET *ret = SstpNewControlPacket(SSTP_MSG_CALL_ABORT);
+
+ SstpSendPacket(s, ret);
+
+ SstpFreePacket(ret);
+
+ s->AbortSent = true;
+ }
+ }
+
+ if (s->DisconnectSent && s->DisconnectRecved)
+ {
+ // Disconnect after exchanging the Disconnect each other
+ s->Disconnected = true;
+ }
+
+ if (s->AbortSent && s->AbortReceived)
+ {
+ // Disconnect after exchanging the Abort each other
+ s->Disconnected = true;
+ }
+}
+
+// Create a new SSTP control packet with an Attribute
+SSTP_PACKET *SstpNewControlPacketWithAnAttribute(USHORT message_type, SSTP_ATTRIBUTE *a)
+{
+ SSTP_PACKET *p = SstpNewControlPacket(message_type);
+
+ if (a != NULL)
+ {
+ Add(p->AttibuteList, a);
+ }
+
+ return p;
+}
+
+// Create a new SSTP control packet
+SSTP_PACKET *SstpNewControlPacket(USHORT message_type)
+{
+ SSTP_PACKET *p = ZeroMalloc(sizeof(SSTP_PACKET));
+
+ p->IsControl = true;
+ p->MessageType = message_type;
+ p->Version = SSTP_VERSION_1;
+ p->AttibuteList = NewListFast(NULL);
+
+ return p;
+}
+
+// Create a new SSTP data packet
+SSTP_PACKET *SstpNewDataPacket(UCHAR *data, UINT size)
+{
+ SSTP_PACKET *p = ZeroMalloc(sizeof(SSTP_PACKET));
+
+ p->IsControl = false;
+ p->Data = Clone(data, size);
+ p->DataSize = size;
+
+ return p;
+}
+
+// Get the Attibute with the specified ID from SSTP packet
+SSTP_ATTRIBUTE *SstpFindAttribute(SSTP_PACKET *p, UCHAR attribute_id)
+{
+ UINT i;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(p->AttibuteList);i++)
+ {
+ SSTP_ATTRIBUTE *a = LIST_DATA(p->AttibuteList, i);
+
+ if (a->AttributeId == attribute_id)
+ {
+ return a;
+ }
+ }
+
+ return NULL;
+}
+
+// Disconnect the SSTP normally
+void SstpDisconnect(SSTP_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ s->Disconnecting = true;
+}
+
+// Disconnect the SSTP abnormally
+void SstpAbort(SSTP_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ s->Aborting = true;
+}
+
+// Create a Crypto Binding Request Attribute
+SSTP_ATTRIBUTE *SstpNewCryptoBindingRequestAttribute(UCHAR hash_protocol_bitmask, UCHAR *nonce_32bytes)
+{
+ SSTP_ATTRIBUTE *a;
+ UCHAR uc;
+ BUF *b = NewBuf();
+
+ uc = 0;
+ WriteBuf(b, &uc, 1);
+ WriteBuf(b, &uc, 1);
+ WriteBuf(b, &uc, 1);
+ WriteBuf(b, &hash_protocol_bitmask, 1);
+
+ WriteBuf(b, nonce_32bytes, SSTP_NONCE_SIZE);
+
+ a = SstpNewAttribute(SSTP_ATTRIB_CRYPTO_BINDING_REQ, b->Buf, b->Size);
+
+ FreeBuf(b);
+
+ return a;
+}
+
+// Create a Status Info Attribute
+SSTP_ATTRIBUTE *SstpNewStatusInfoAttribute(UCHAR attrib_id, UINT status)
+{
+ SSTP_ATTRIBUTE *a;
+ UCHAR uc;
+ BUF *b = NewBuf();
+
+ uc = 0;
+ WriteBuf(b, &uc, 1);
+ WriteBuf(b, &uc, 1);
+ WriteBuf(b, &uc, 1);
+ WriteBuf(b, &attrib_id, 1);
+
+ WriteBufInt(b, status);
+
+ a = SstpNewAttribute(SSTP_ATTRIB_STATUS_INFO, b->Buf, b->Size);
+
+ FreeBuf(b);
+
+ return a;
+}
+
+// Create a New Attribute
+SSTP_ATTRIBUTE *SstpNewAttribute(UCHAR attribute_id, UCHAR *data, UINT data_size)
+{
+ SSTP_ATTRIBUTE *a = ZeroMalloc(sizeof(SSTP_ATTRIBUTE));
+
+ a->AttributeId = attribute_id;
+ a->Data = Clone(data, data_size);
+ a->DataSize = data_size;
+
+ return a;
+}
+
+// Build the Attribute
+BUF *SstpBuildAttribute(SSTP_ATTRIBUTE *a)
+{
+ UCHAR uc;
+ USHORT us;
+ BUF *b;
+ // Validate arguments
+ if (a == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+
+ // Reserved
+ uc = 0;
+ WriteBuf(b, &uc, sizeof(UCHAR));
+
+ // Attribute ID
+ uc = a->AttributeId;
+ WriteBuf(b, &uc, sizeof(UCHAR));
+
+ // LengthPacket
+ a->TotalLength = a->DataSize + 4;
+ us = (USHORT)a->TotalLength;
+ us = Endian16(us);
+ WriteBuf(b, &us, sizeof(USHORT));
+
+ // Data
+ WriteBuf(b, a->Data, a->DataSize);
+
+ return b;
+}
+
+// Build the Attribute list
+BUF *SstpBuildAttributeList(LIST *o, USHORT message_type)
+{
+ UINT i;
+ BUF *b;
+ USHORT us;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+
+ us = Endian16(message_type);
+ WriteBuf(b, &us, sizeof(USHORT));
+
+ us = Endian16((USHORT)LIST_NUM(o));
+ WriteBuf(b, &us, sizeof(USHORT));
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ SSTP_ATTRIBUTE *a = LIST_DATA(o, i);
+ BUF *ab = SstpBuildAttribute(a);
+
+ if (ab != NULL)
+ {
+ WriteBufBuf(b, ab);
+
+ FreeBuf(ab);
+ }
+ }
+
+ return b;
+}
+
+// Building the SSTP packet
+BUF *SstpBuildPacket(SSTP_PACKET *p)
+{
+ BUF *b;
+ UCHAR uc;
+ USHORT us;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+
+ if (p->IsControl)
+ {
+ BUF *ab;
+
+ if (p->Data != NULL)
+ {
+ Free(p->Data);
+ }
+
+ ab = SstpBuildAttributeList(p->AttibuteList, p->MessageType);
+ p->Data = ab->Buf;
+ p->DataSize = ab->Size;
+ Free(ab);
+ }
+
+ // Version
+ uc = SSTP_VERSION_1;
+ WriteBuf(b, &uc, sizeof(UCHAR));
+
+ // Flag
+ uc = p->IsControl ? 1 : 0;
+ WriteBuf(b, &uc, sizeof(UCHAR));
+
+ // Length Packet
+ us = Endian16(p->DataSize + 4);
+ WriteBuf(b, &us, sizeof(USHORT));
+
+ // Data
+ WriteBuf(b, p->Data, p->DataSize);
+
+ return b;
+}
+
+// Parse the SSTP packet
+SSTP_PACKET *SstpParsePacket(UCHAR *data, UINT size)
+{
+ SSTP_PACKET *p;
+ USHORT len;
+ // Validate arguments
+ if (data == NULL || size == 0)
+ {
+ return NULL;
+ }
+
+ if (size < 4)
+ {
+ return NULL;
+ }
+
+ p = ZeroMalloc(sizeof(SSTP_PACKET));
+
+ // Version
+ p->Version = *((UCHAR *)data);
+ data++;
+ size--;
+
+ if (p->Version != SSTP_VERSION_1)
+ {
+ // Invalid version
+ SstpFreePacket(p);
+ return NULL;
+ }
+
+ // Flag
+ if ((*((UCHAR *)data)) & 0x01)
+ {
+ p->IsControl = true;
+ }
+ data++;
+ size--;
+
+ // Length
+ len = READ_USHORT(data) & 0xFFF;
+ data += sizeof(USHORT);
+ size -= sizeof(USHORT);
+
+ if (len < 4)
+ {
+ // Invalid size
+ SstpFreePacket(p);
+ return NULL;
+ }
+
+ if (((UINT)(len - 4)) > size)
+ {
+ // Oversized
+ SstpFreePacket(p);
+ return NULL;
+ }
+
+ // Data
+ p->DataSize = len - 4;
+ p->Data = Clone(data, p->DataSize);
+
+ if (p->IsControl)
+ {
+ // Parse the Attribute list
+ p->AttibuteList = SstpParseAttributeList(p->Data, p->DataSize, p);
+
+ if (p->AttibuteList == NULL)
+ {
+ // Failure of parsing list
+ SstpFreePacket(p);
+ return NULL;
+ }
+ }
+
+ return p;
+}
+
+// Parse the Attribute list
+LIST *SstpParseAttributeList(UCHAR *data, UINT size, SSTP_PACKET *p)
+{
+ LIST *o;
+ USHORT us;
+ UINT num;
+ // Validate arguments
+ if (size == 0 || data == NULL || p == NULL)
+ {
+ return NULL;
+ }
+
+ if (size < 4)
+ {
+ return NULL;
+ }
+
+ // Message Type
+ us = READ_USHORT(data);
+ p->MessageType = us;
+ data += sizeof(USHORT);
+ size -= sizeof(USHORT);
+
+ // Num Attributes
+ num = READ_USHORT(data);
+ data += sizeof(USHORT);
+ size -= sizeof(USHORT);
+
+ // Attibutes List
+ o = NewListFast(NULL);
+
+ while (LIST_NUM(o) < num)
+ {
+ SSTP_ATTRIBUTE *a = SstpParseAttribute(data, size);
+
+ if (a == NULL)
+ {
+ SstpFreeAttributeList(o);
+ return NULL;
+ }
+
+ if (a->TotalLength > size)
+ {
+ SstpFreeAttribute(a);
+ SstpFreeAttributeList(o);
+ return NULL;
+ }
+
+ Add(o, a);
+
+ data += a->TotalLength;
+ size -= a->TotalLength;
+ }
+
+ return o;
+}
+
+// Parse the Attribute
+SSTP_ATTRIBUTE *SstpParseAttribute(UCHAR *data, UINT size)
+{
+ SSTP_ATTRIBUTE *a;
+ // Validate arguments
+ if (data == NULL || size == 0)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(SSTP_ATTRIBUTE));
+
+ if (size < 4)
+ {
+ SstpFreeAttribute(a);
+ return NULL;
+ }
+
+ data++;
+ size--;
+
+ // Attribute ID
+ a->AttributeId = *((UCHAR *)data);
+ data++;
+ size--;
+
+ // Length
+ a->TotalLength = READ_USHORT(data) & 0xFFF;
+ data += sizeof(USHORT);
+ size -= sizeof(USHORT);
+
+ if (a->TotalLength < 4)
+ {
+ // Length fraud
+ SstpFreeAttribute(a);
+ return NULL;
+ }
+
+ a->DataSize = a->TotalLength - 4;
+ if (a->DataSize > size)
+ {
+ // Length excess
+ SstpFreeAttribute(a);
+ return NULL;
+ }
+
+ a->Data = Clone(data, a->DataSize);
+
+ return a;
+}
+
+// Release the Attibute
+void SstpFreeAttribute(SSTP_ATTRIBUTE *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ Free(a->Data);
+
+ Free(a);
+}
+
+// Release the Attribute list
+void SstpFreeAttributeList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ SSTP_ATTRIBUTE *a = LIST_DATA(o, i);
+
+ SstpFreeAttribute(a);
+ }
+
+ ReleaseList(o);
+}
+
+// Release the SSTP packet
+void SstpFreePacket(SSTP_PACKET *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ if (p->AttibuteList != NULL)
+ {
+ SstpFreeAttributeList(p->AttibuteList);
+ }
+
+ if (p->Data != NULL)
+ {
+ Free(p->Data);
+ }
+
+ Free(p);
+}
+
+// Create a SSTP server
+SSTP_SERVER *NewSstpServer(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ip,
+ UINT server_port, SOCK_EVENT *se,
+ char *client_host_name, char *crypt_name)
+{
+ SSTP_SERVER *s = ZeroMalloc(sizeof(SSTP_SERVER));
+
+ s->LastRecvTick = Tick64();
+
+ StrCpy(s->ClientHostName, sizeof(s->ClientHostName), client_host_name);
+ StrCpy(s->ClientCipherName, sizeof(s->ClientCipherName), crypt_name);
+
+ s->Cedar = cedar;
+ AddRef(s->Cedar->ref);
+
+ NewTubePair(&s->TubeSend, &s->TubeRecv, 0);
+ SetTubeSockEvent(s->TubeSend, se);
+
+ s->Now = Tick64();
+
+ Copy(&s->ClientIp, client_ip, sizeof(IP));
+ s->ClientPort = client_port;
+ Copy(&s->ServerIp, server_ip, sizeof(IP));
+ s->ServerPort = server_port;
+
+ s->SockEvent = se;
+
+ AddRef(s->SockEvent->ref);
+
+ s->RecvQueue = NewQueueFast();
+ s->SendQueue = NewQueueFast();
+
+ s->Interrupt = NewInterruptManager();
+
+ return s;
+}
+
+// Release the SSTP server
+void FreeSstpServer(SSTP_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ TubeDisconnect(s->TubeRecv);
+ TubeDisconnect(s->TubeSend);
+
+ WaitThread(s->PPPThread, INFINITE);
+ ReleaseThread(s->PPPThread);
+
+ while (true)
+ {
+ BLOCK *b = GetNext(s->RecvQueue);
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ FreeBlock(b);
+ }
+
+ while (true)
+ {
+ BLOCK *b = GetNext(s->SendQueue);
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ FreeBlock(b);
+ }
+
+ ReleaseQueue(s->RecvQueue);
+ ReleaseQueue(s->SendQueue);
+
+ ReleaseSockEvent(s->SockEvent);
+
+ FreeInterruptManager(s->Interrupt);
+
+ ReleaseCedar(s->Cedar);
+
+ ReleaseTube(s->TubeSend);
+ ReleaseTube(s->TubeRecv);
+
+ Free(s);
+}
+
+// Handle the communication of SSTP protocol
+bool ProcessSstpHttps(CEDAR *cedar, SOCK *s, SOCK_EVENT *se)
+{
+ UINT tmp_size = 65536;
+ UCHAR *tmp_buf;
+ FIFO *recv_fifo;
+ FIFO *send_fifo;
+ SSTP_SERVER *sstp;
+ bool ret = false;
+ // Validate arguments
+ if (cedar == NULL || s == NULL || se == NULL)
+ {
+ return false;
+ }
+
+ tmp_buf = Malloc(tmp_size);
+ recv_fifo = NewFifo();
+ send_fifo = NewFifo();
+
+ sstp = NewSstpServer(cedar, &s->RemoteIP, s->RemotePort, &s->LocalIP, s->LocalPort, se,
+ s->RemoteHostname, s->CipherName);
+
+ while (true)
+ {
+ UINT r;
+ bool is_disconnected = false;
+ bool state_changed = false;
+
+ // Receive data over SSL
+ while (true)
+ {
+ r = Recv(s, tmp_buf, tmp_size, true);
+ if (r == 0)
+ {
+ // SSL is disconnected
+ is_disconnected = true;
+ break;
+ }
+ else if (r == SOCK_LATER)
+ {
+ // Data is not received any more
+ break;
+ }
+ else
+ {
+ // Queue the received data
+ WriteFifo(recv_fifo, tmp_buf, r);
+ state_changed = true;
+ }
+ }
+
+ while (recv_fifo->size >= 4)
+ {
+ UCHAR *first4;
+ UINT read_size = 0;
+ bool ok = false;
+ // Read 4 bytes from the beginning of the receive queue
+ first4 = ((UCHAR *)recv_fifo->p) + recv_fifo->pos;
+ if (first4[0] == SSTP_VERSION_1)
+ {
+ USHORT len = READ_USHORT(first4 + 2) & 0xFFF;
+ if (len >= 4)
+ {
+ ok = true;
+
+ if (recv_fifo->size >= len)
+ {
+ UCHAR *data;
+ BLOCK *b;
+
+ read_size = len;
+ data = Malloc(read_size);
+
+ ReadFifo(recv_fifo, data, read_size);
+
+ b = NewBlock(data, read_size, 0);
+
+ InsertQueue(sstp->RecvQueue, b);
+ }
+ }
+ }
+
+ if (read_size == 0)
+ {
+ break;
+ }
+
+ if (ok == false)
+ {
+ // Disconnect the connection since a bad packet received
+ is_disconnected = true;
+ break;
+ }
+ }
+
+ // Process the timer interrupt
+ SstpProcessInterrupt(sstp);
+
+ if (sstp->Disconnected)
+ {
+ is_disconnected = true;
+ }
+
+ // Put the transmission data that SSTP module has generated into the transmission queue
+ while (true)
+ {
+ BLOCK *b = GetNext(sstp->SendQueue);
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ // When transmit a data packet, If there are packets of more than about
+ // 2.5 MB in the transmission queue of the TCP, discard without transmission
+ if (b->PriorityQoS || (send_fifo->size <= MAX_BUFFERING_PACKET_SIZE))
+ {
+ WriteFifo(send_fifo, b->Buf, b->Size);
+ }
+
+ FreeBlock(b);
+ }
+
+ // Data is transmitted over SSL
+ while (send_fifo->size != 0)
+ {
+ r = Send(s, ((UCHAR *)send_fifo->p) + send_fifo->pos, send_fifo->size, true);
+ if (r == 0)
+ {
+ // SSL is disconnected
+ is_disconnected = true;
+ break;
+ }
+ else if (r == SOCK_LATER)
+ {
+ // Can not send any more
+ break;
+ }
+ else
+ {
+ // Advance the transmission queue by the amount of the transmitted
+ ReadFifo(send_fifo, NULL, r);
+ state_changed = true;
+ }
+ }
+
+ if (is_disconnected)
+ {
+ // Disconnected
+ break;
+ }
+
+ // Wait for the next state change
+ if (state_changed == false)
+ {
+ UINT r = GetNextIntervalForInterrupt(sstp->Interrupt);
+ WaitSockEvent(se, MIN(r, SELECT_TIME));
+ }
+ }
+
+ if (sstp != NULL && sstp->EstablishedCount >= 1)
+ {
+ ret = true;
+ }
+
+ FreeSstpServer(sstp);
+
+ ReleaseFifo(recv_fifo);
+ ReleaseFifo(send_fifo);
+ Free(tmp_buf);
+
+ YieldCpu();
+ Disconnect(s);
+
+ return ret;
+}
+
+// Accept the SSTP connection
+bool AcceptSstp(CONNECTION *c)
+{
+ SOCK *s;
+ HTTP_HEADER *h;
+ char date_str[MAX_SIZE];
+ bool ret;
+ bool ret2 = false;
+ SOCK_EVENT *se;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ s = c->FirstSock;
+
+ GetHttpDateStr(date_str, sizeof(date_str), SystemTime64());
+
+ // Return a response
+ h = NewHttpHeader("HTTP/1.1", "200", "OK");
+ AddHttpValue(h, NewHttpValue("Content-Length", "18446744073709551615"));
+ AddHttpValue(h, NewHttpValue("Server", "Microsoft-HTTPAPI/2.0"));
+ AddHttpValue(h, NewHttpValue("Date", date_str));
+
+ ret = PostHttp(s, h, NULL, 0);
+
+ FreeHttpHeader(h);
+
+ if (ret)
+ {
+ SetTimeout(s, INFINITE);
+
+ se = NewSockEvent();
+
+ JoinSockToSockEvent(s, se);
+
+ Debug("ProcessSstpHttps Start.\n");
+ ret2 = ProcessSstpHttps(c->Cedar, s, se);
+ Debug("ProcessSstpHttps End.\n");
+
+ ReleaseSockEvent(se);
+ }
+
+ Disconnect(s);
+
+ return ret2;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Interop_SSTP.h b/src/Cedar/Interop_SSTP.h
new file mode 100644
index 00000000..dbf2d50c
--- /dev/null
+++ b/src/Cedar/Interop_SSTP.h
@@ -0,0 +1,238 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Interop_SSTP.h
+// Header of Interop_SSTP.c
+
+#ifndef INTEROP_SSTP_H
+#define INTEROP_SSTP_H
+
+//// Constants
+#define SSTP_URI "/sra_{BA195980-CD49-458b-9E23-C84EE0ADCD75}/" // SSTP HTTPS URI
+#define SSTP_VERSION_1 0x10 // SSTP Version 1.0
+#define MAX_SSTP_PACKET_SIZE 4096 // Maximum packet size
+#define SSTP_IPC_CLIENT_NAME "Microsoft SSTP VPN Client"
+#define SSTP_IPC_POSTFIX "SSTP"
+#define SSTP_ECHO_SEND_INTERVAL_MIN 2500 // Transmission interval of Echo Request (minimum)
+#define SSTP_ECHO_SEND_INTERVAL_MAX 4792 // Transmission interval of Echo Request (maximum)
+#define SSTP_TIMEOUT 10000 // Communication time-out of SSTP
+
+// SSTP Message Type
+#define SSTP_MSG_CALL_CONNECT_REQUEST 0x0001
+#define SSTP_MSG_CALL_CONNECT_ACK 0x0002
+#define SSTP_MSG_CALL_CONNECT_NAK 0x0003
+#define SSTP_MSG_CALL_CONNECTED 0x0004
+#define SSTP_MSG_CALL_ABORT 0x0005
+#define SSTP_MSG_CALL_DISCONNECT 0x0006
+#define SSTP_MSG_CALL_DISCONNECT_ACK 0x0007
+#define SSTP_MSG_ECHO_REQUEST 0x0008
+#define SSTP_MSG_ECHO_RESPONSE 0x0009
+
+// SSTP Attribute ID
+#define SSTP_ATTRIB_NO_ERROR 0x00
+#define SSTP_ATTRIB_ENCAPSULATED_PROTOCOL_ID 0x01
+#define SSTP_ATTRIB_STATUS_INFO 0x02
+#define SSTP_ATTRIB_CRYPTO_BINDING 0x03
+#define SSTP_ATTRIB_CRYPTO_BINDING_REQ 0x04
+
+// Protocol ID
+#define SSTP_ENCAPSULATED_PROTOCOL_PPP 0x0001
+
+// Hash Protocol Bitmask
+#define CERT_HASH_PROTOCOL_SHA1 0x01
+#define CERT_HASH_PROTOCOL_SHA256 0x02
+
+// Status
+#define ATTRIB_STATUS_NO_ERROR 0x00000000
+#define ATTRIB_STATUS_DUPLICATE_ATTRIBUTE 0x00000001
+#define ATTRIB_STATUS_UNRECOGNIZED_ATTRIBUTE 0x00000002
+#define ATTRIB_STATUS_INVALID_ATTRIB_VALUE_LENGTH 0x00000003
+#define ATTRIB_STATUS_VALUE_NOT_SUPPORTED 0x00000004
+#define ATTRIB_STATUS_UNACCEPTED_FRAME_RECEIVED 0x00000005
+#define ATTRIB_STATUS_RETRY_COUNT_EXCEEDED 0x00000006
+#define ATTRIB_STATUS_INVALID_FRAME_RECEIVED 0x00000007
+#define ATTRIB_STATUS_NEGOTIATION_TIMEOUT 0x00000008
+#define ATTRIB_STATUS_ATTRIB_NOT_SUPPORTED_IN_MSG 0x00000009
+#define ATTRIB_STATUS_REQUIRED_ATTRIBUTE_MISSING 0x0000000A
+#define ATTRIB_STATUS_STATUS_INFO_NOT_SUPPORTED_IN_MSG 0x0000000B
+
+// State of SSTP Server
+#define SSTP_SERVER_STATUS_REQUEST_PENGING 0 // Connection incomplete
+#define SSTP_SERVER_STATUS_CONNECTED_PENDING 1 // Connection completed. Authentication incomplete
+#define SSTP_SERVER_STATUS_ESTABLISHED 2 // Connection completed. Communication available
+
+// Length of Nonce
+#define SSTP_NONCE_SIZE 32 // 256 bits
+
+
+//// Type
+
+// SSTP Attibute
+struct SSTP_ATTRIBUTE
+{
+ UCHAR AttributeId;
+ UCHAR *Data;
+ UINT DataSize;
+ UINT TotalLength;
+};
+
+// SSTP Packet
+struct SSTP_PACKET
+{
+ UCHAR Version;
+ bool IsControl;
+ UCHAR *Data;
+ UINT DataSize;
+ USHORT MessageType;
+ LIST *AttibuteList;
+};
+
+// SSTP Server
+struct SSTP_SERVER
+{
+ CEDAR *Cedar;
+ UINT64 Now;
+ IP ClientIp, ServerIp;
+ UINT ClientPort, ServerPort;
+ char ClientHostName[MAX_HOST_NAME_LEN + 1];
+ char ClientCipherName[MAX_SIZE];
+ SOCK_EVENT *SockEvent;
+ QUEUE *RecvQueue; // Receive queue
+ QUEUE *SendQueue; // Transmission queue
+ INTERRUPT_MANAGER *Interrupt; // Interrupt manager
+ bool Aborting; // Forced disconnection flag
+ bool AbortSent; // Flag of whether to send the Abort
+ bool AbortReceived; // Flag of whether the Abort has been received
+ bool Disconnecting; // Disconnecting flag
+ bool DisconnectSent; // Flag of whether to send a Disconnect
+ bool DisconnectRecved; // Flag of whether a Disconnect has been received
+ bool Disconnected; // Flag as to disconnect
+ UINT Status; // State
+ UCHAR SentNonce[SSTP_NONCE_SIZE]; // Random data sent
+ TUBE *TubeRecv, *TubeSend; // Delivery tube of packets to PPP module
+ THREAD *PPPThread; // PPP module thread
+ UINT64 NextSendEchoRequestTick; // Time to send the next Echo Request
+ UINT64 LastRecvTick; // Tick when some data has received at the end
+ bool FlushRecvTube; // Flag whether to flush the reception tube
+ UINT EstablishedCount; // Number of session establishment
+};
+
+
+//// Function prototype
+bool AcceptSstp(CONNECTION *c);
+bool ProcessSstpHttps(CEDAR *cedar, SOCK *s, SOCK_EVENT *se);
+
+SSTP_SERVER *NewSstpServer(CEDAR *cedar, IP *client_ip, UINT client_port, IP *server_ip,
+ UINT server_port, SOCK_EVENT *se,
+ char *client_host_name, char *crypt_name);
+void FreeSstpServer(SSTP_SERVER *s);
+void SstpProcessInterrupt(SSTP_SERVER *s);
+SSTP_PACKET *SstpParsePacket(UCHAR *data, UINT size);
+LIST *SstpParseAttributeList(UCHAR *data, UINT size, SSTP_PACKET *p);
+SSTP_ATTRIBUTE *SstpParseAttribute(UCHAR *data, UINT size);
+void SstpFreeAttribute(SSTP_ATTRIBUTE *a);
+void SstpFreeAttributeList(LIST *o);
+void SstpFreePacket(SSTP_PACKET *p);
+BUF *SstpBuildPacket(SSTP_PACKET *p);
+BUF *SstpBuildAttributeList(LIST *o, USHORT message_type);
+BUF *SstpBuildAttribute(SSTP_ATTRIBUTE *a);
+void SstpAbort(SSTP_SERVER *s);
+void SstpDisconnect(SSTP_SERVER *s);
+void SstpProcessPacket(SSTP_SERVER *s, SSTP_PACKET *p);
+void SstpProcessControlPacket(SSTP_SERVER *s, SSTP_PACKET *p);
+void SstpProcessDataPacket(SSTP_SERVER *s, SSTP_PACKET *p);
+SSTP_ATTRIBUTE *SstpFindAttribute(SSTP_PACKET *p, UCHAR attribute_id);
+SSTP_ATTRIBUTE *SstpNewAttribute(UCHAR attribute_id, UCHAR *data, UINT data_size);
+SSTP_ATTRIBUTE *SstpNewStatusInfoAttribute(UCHAR attrib_id, UINT status);
+SSTP_ATTRIBUTE *SstpNewCryptoBindingRequestAttribute(UCHAR hash_protocol_bitmask, UCHAR *nonce_32bytes);
+SSTP_PACKET *SstpNewDataPacket(UCHAR *data, UINT size);
+SSTP_PACKET *SstpNewControlPacket(USHORT message_type);
+SSTP_PACKET *SstpNewControlPacketWithAnAttribute(USHORT message_type, SSTP_ATTRIBUTE *a);
+void SstpSendPacket(SSTP_SERVER *s, SSTP_PACKET *p);
+bool GetNoSstp();
+void SetNoSstp(bool b);
+
+#endif // INTEROP_SSTP_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Layer3.c b/src/Cedar/Layer3.c
new file mode 100644
index 00000000..3bb8ecbe
--- /dev/null
+++ b/src/Cedar/Layer3.c
@@ -0,0 +1,2173 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Layer3.c
+// Layer-3 switch module
+
+#include "CedarPch.h"
+
+static UCHAR broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+// Process the IP queue
+void L3PollingIpQueue(L3IF *f)
+{
+ L3PACKET *p;
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ // Process the packet came from another session
+ while (p = GetNext(f->IpPacketQueue))
+ {
+ PKT *pkt = p->Packet;
+
+ // Send as an IP packet
+ L3SendIp(f, p);
+ }
+}
+
+// Process IP packets
+void L3RecvIp(L3IF *f, PKT *p, bool self)
+{
+ IPV4_HEADER *ip;
+ UINT header_size;
+ UINT next_hop = 0;
+ L3IF *dst;
+ L3PACKET *packet;
+ UINT new_ttl = 0;
+ // Validate arguments
+ if (f == NULL || p == NULL)
+ {
+ return;
+ }
+
+ ip = p->L3.IPv4Header;
+ header_size = IPV4_GET_HEADER_LEN(p->L3.IPv4Header) * 4;
+
+ // Calculate the checksum
+ if (IpCheckChecksum(ip) == false)
+ {
+ // The checksum does not match
+ goto FREE_PACKET;
+ }
+
+ // Register in the ARP table
+ L3KnownArp(f, ip->SrcIP, p->MacAddressSrc);
+
+ if (p->BroadcastPacket)
+ {
+ // Not to route in the case of broadcast packet
+ goto FREE_PACKET;
+ }
+
+ // Calculate the TTL
+ if (ip->TimeToLive >= 1)
+ {
+ new_ttl = ip->TimeToLive - 1;
+ }
+ else
+ {
+ new_ttl = 0;
+ }
+
+ if (new_ttl == 0)
+ {
+ if (ip->DstIP != f->IpAddress)
+ {
+ UINT src_packet_size = p->PacketSize - sizeof(MAC_HEADER);
+ UINT icmp_packet_total_size = sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4 + header_size + 8;
+ UCHAR *buf;
+ IPV4_HEADER *ipv4;
+ ICMP_HEADER *icmpv4;
+ UCHAR *data;
+ PKT *pkt;
+ UINT data_size = MIN(p->PacketSize - header_size, header_size + 8);
+
+ // Generate an ICMP message that means that the TTL has expired
+ buf = ZeroMalloc(icmp_packet_total_size);
+ ipv4 = (IPV4_HEADER *)(buf + sizeof(MAC_HEADER));
+ icmpv4 = (ICMP_HEADER *)(buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER));
+ data = buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4;
+
+ IPV4_SET_VERSION(ipv4, 4);
+ IPV4_SET_HEADER_LEN(ipv4, sizeof(IPV4_HEADER) / 4);
+ ipv4->TotalLength = Endian16((USHORT)(icmp_packet_total_size - sizeof(MAC_HEADER)));
+ ipv4->TimeToLive = 0xff;
+ ipv4->Protocol = IP_PROTO_ICMPV4;
+ ipv4->SrcIP = f->IpAddress;
+ ipv4->DstIP = ip->SrcIP;
+ ipv4->Checksum = IpChecksum(ipv4, sizeof(IPV4_HEADER));
+
+ icmpv4->Type = 11;
+ Copy(data, ip, data_size);
+ icmpv4->Checksum = IpChecksum(icmpv4, sizeof(ICMP_HEADER) + data_size + 4);
+
+ buf[12] = 0x08;
+ buf[13] = 0x00;
+
+ pkt = ParsePacket(buf, icmp_packet_total_size);
+ if (pkt == NULL)
+ {
+ Free(buf);
+ }
+ else
+ {
+ L3RecvIp(f, pkt, true);
+ }
+
+ // Discard the packet body whose the TTL has expired
+ goto FREE_PACKET;
+ }
+ }
+
+ // Rewrite the TTL
+ p->L3.IPv4Header->TimeToLive = (UCHAR)new_ttl;
+
+ // Get the interface corresponding to the destination IP address
+ dst = L3GetNextIf(f->Switch, ip->DstIP, &next_hop);
+
+ if (dst == NULL && self == false)
+ {
+ UINT src_packet_size = p->PacketSize - sizeof(MAC_HEADER);
+ UINT icmp_packet_total_size = sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4 + header_size + 8;
+ UCHAR *buf;
+ IPV4_HEADER *ipv4;
+ ICMP_HEADER *icmpv4;
+ UCHAR *data;
+ PKT *pkt;
+ UINT data_size = MIN(p->PacketSize - header_size, header_size + 8);
+
+ // Respond with ICMP that indicates that no route can be found
+ buf = ZeroMalloc(icmp_packet_total_size);
+ ipv4 = (IPV4_HEADER *)(buf + sizeof(MAC_HEADER));
+ icmpv4 = (ICMP_HEADER *)(buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER));
+ data = buf + sizeof(MAC_HEADER) + sizeof(IPV4_HEADER) + sizeof(ICMP_HEADER) + 4;
+
+ IPV4_SET_VERSION(ipv4, 4);
+ IPV4_SET_HEADER_LEN(ipv4, sizeof(IPV4_HEADER) / 4);
+ ipv4->TotalLength = Endian16((USHORT)(icmp_packet_total_size - sizeof(MAC_HEADER)));
+ ipv4->TimeToLive = 0xff;
+ ipv4->Protocol = IP_PROTO_ICMPV4;
+ ipv4->SrcIP = f->IpAddress;
+ ipv4->DstIP = ip->SrcIP;
+ ipv4->Checksum = IpChecksum(ipv4, sizeof(IPV4_HEADER));
+
+ icmpv4->Type = 3;
+ Copy(data, ip, data_size);
+ icmpv4->Checksum = IpChecksum(icmpv4, sizeof(ICMP_HEADER) + data_size + 4);
+
+ buf[12] = 0x08;
+ buf[13] = 0x00;
+
+ pkt = ParsePacket(buf, icmp_packet_total_size);
+ if (pkt == NULL)
+ {
+ Free(buf);
+ }
+ else
+ {
+ L3RecvIp(f, pkt, true);
+ }
+
+ // Discard the packet body whose route can not be found
+ goto FREE_PACKET;
+ }
+
+ if (dst != NULL && ip->DstIP == dst->IpAddress)
+ {
+ bool free_packet = true;
+ // IP packet addressed to myself has arrived
+ if (p->TypeL4 == L4_ICMPV4)
+ {
+ ICMP_HEADER *icmp = p->L4.ICMPHeader;
+ if (icmp->Type == ICMP_TYPE_ECHO_REQUEST)
+ {
+ // Reply by rewriting the source and destination of the IP packet
+ UINT src_ip, dst_ip;
+ src_ip = p->L3.IPv4Header->DstIP;
+ dst_ip = p->L3.IPv4Header->SrcIP;
+
+ p->L3.IPv4Header->DstIP = dst_ip;
+ p->L3.IPv4Header->SrcIP = src_ip;
+
+ ip->TimeToLive = 0xff;
+
+ // Recalculates the checksum
+ ip->FlagsAndFlagmentOffset[0] = ip->FlagsAndFlagmentOffset[1] = 0;
+ icmp->Checksum = 0;
+ icmp->Type = ICMP_TYPE_ECHO_RESPONSE;
+ icmp->Checksum = IpChecksum(icmp, p->PacketSize - sizeof(MAC_HEADER) - header_size);
+
+ dst = L3GetNextIf(f->Switch, ip->DstIP, &next_hop);
+
+ free_packet = false;
+ }
+ }
+
+ if (free_packet)
+ {
+ goto FREE_PACKET;
+ }
+ }
+
+ if (dst == NULL)
+ {
+ // The destination does not exist
+ goto FREE_PACKET;
+ }
+
+ // Recalculate the IP checksum
+ ip->Checksum = 0;
+ ip->Checksum = IpChecksum(ip, header_size);
+
+ // Treat as a Layer-3 packet
+ packet = ZeroMalloc(sizeof(L3PACKET));
+ packet->Expire = Tick64() + IP_WAIT_FOR_ARP_TIMEOUT;
+ packet->NextHopIp = next_hop;
+ packet->Packet = p;
+
+ // Store to the destination session
+ L3StoreIpPacketToIf(f, dst, packet);
+
+ return;
+
+FREE_PACKET:
+ // Release the packet
+ Free(p->PacketData);
+ FreePacket(p);
+ return;
+}
+
+// Process the Layer 2 packet
+void L3RecvL2(L3IF *f, PKT *p)
+{
+ // Validate arguments
+ if (f == NULL || p == NULL)
+ {
+ return;
+ }
+
+ // Ignore any packets except a unicast packet which is destinated other
+ // or a packet which I sent
+ if (Cmp(p->MacAddressSrc, f->MacAddress, 6) == 0 ||
+ (p->BroadcastPacket == false && Cmp(p->MacAddressDest, f->MacAddress, 6) != 0))
+ {
+ // Release the packet
+ Free(p->PacketData);
+ FreePacket(p);
+ return;
+ }
+
+ if (p->TypeL3 == L3_ARPV4)
+ {
+ // Received an ARP packet
+ L3RecvArp(f, p);
+
+ // Release the packet
+ Free(p->PacketData);
+ FreePacket(p);
+ }
+ else if (p->TypeL3 == L3_IPV4)
+ {
+ // Received an IP packet
+ L3RecvIp(f, p, false);
+ }
+ else
+ {
+ // Release the packet
+ Free(p->PacketData);
+ FreePacket(p);
+ }
+}
+
+// Store the IP packet to a different interface
+void L3StoreIpPacketToIf(L3IF *src_if, L3IF *dst_if, L3PACKET *p)
+{
+ // Validate arguments
+ if (src_if == NULL || p == NULL || dst_if == NULL)
+ {
+ return;
+ }
+
+ // Add to the queue of store-destination session
+ InsertQueue(dst_if->IpPacketQueue, p);
+
+ // Hit the Cancel object of the store-destination session
+ AddCancelList(src_if->CancelList, dst_if->Session->Cancel1);
+}
+
+// Write the packet (Process because the packet was received)
+void L3PutPacket(L3IF *f, void *data, UINT size)
+{
+ PKT *p;
+ L3SW *s;
+ if (f == NULL)
+ {
+ return;
+ }
+
+ s = f->Switch;
+
+ if (data != NULL)
+ {
+ // Handle the next packet
+ if (f->CancelList == NULL)
+ {
+ f->CancelList = NewCancelList();
+ }
+
+ // Packet analysis
+ p = ParsePacket(data, size);
+
+ if (p == NULL)
+ {
+ // Packet analysis failure
+ Free(data);
+ }
+ else
+ {
+ // Packet analysis success
+ Lock(s->lock);
+ {
+ L3RecvL2(f, p);
+ }
+ Unlock(s->lock);
+ }
+ }
+ else
+ {
+ // Cancel for the cancellation list after all packet processing has been finished
+ if (f->CancelList != NULL)
+ {
+ CancelList(f->CancelList);
+ ReleaseCancelList(f->CancelList);
+ f->CancelList = NULL;
+ }
+ }
+}
+
+// Send the waiting IP packets whose destination MAC address has been resolved
+void L3SendWaitingIp(L3IF *f, UCHAR *mac, UINT ip, L3ARPENTRY *a)
+{
+ UINT i;
+ LIST *o = NULL;
+ // Validate arguments
+ if (f == NULL || mac == NULL || a == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(f->IpWaitList);i++)
+ {
+ L3PACKET *p = LIST_DATA(f->IpWaitList, i);
+
+ if (p->NextHopIp == ip)
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+ Add(o, p);
+ }
+ }
+
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ L3PACKET *p = LIST_DATA(o, i);
+
+ // Transmission
+ L3SendIpNow(f, a, p);
+
+ Delete(f->IpWaitList, p);
+ Free(p->Packet->PacketData);
+ FreePacket(p->Packet);
+ Free(p);
+ }
+
+ ReleaseList(o);
+ }
+}
+
+// Register in the ARP table
+void L3InsertArpTable(L3IF *f, UINT ip, UCHAR *mac)
+{
+ L3ARPENTRY *a, t;
+ // Validate arguments
+ if (f == NULL || ip == 0 || ip == 0xffffffff || mac == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ t.IpAddress = ip;
+
+ a = Search(f->ArpTable, &t);
+
+ if (a == NULL)
+ {
+ // Since this is not registered, register this
+ a = ZeroMalloc(sizeof(L3ARPENTRY));
+ a->IpAddress = ip;
+ Copy(a->MacAddress, mac, 6);
+ Insert(f->ArpTable, a);
+ }
+
+ // Extend the expiration date
+ a->Expire = Tick64() + ARP_ENTRY_EXPIRES;
+
+ // Send waiting IP packets
+ L3SendWaitingIp(f, mac, ip, a);
+}
+
+// Function to be called when the ARP resolved
+void L3KnownArp(L3IF *f, UINT ip, UCHAR *mac)
+{
+ L3ARPWAIT t, *w;
+ // Validate arguments
+ if (f == NULL || ip == 0 || ip == 0xffffffff || mac == NULL)
+ {
+ return;
+ }
+
+ // Delete an ARP query entry to this IP address
+ Zero(&t, sizeof(t));
+ t.IpAddress = ip;
+ w = Search(f->IpWaitList, &t);
+ if (w != NULL)
+ {
+ Delete(f->IpWaitList, w);
+ Free(w);
+ }
+
+ // Register in the ARP table
+ L3InsertArpTable(f, ip, mac);
+}
+
+// Issue an ARP query
+void L3SendArp(L3IF *f, UINT ip)
+{
+ L3ARPWAIT t, *w;
+ // Validate arguments
+ if (f == NULL || ip == 0 || ip == 0xffffffff)
+ {
+ return;
+ }
+
+ // Examine whether it has not already registered
+ Zero(&t, sizeof(t));
+ t.IpAddress = ip;
+ w = Search(f->ArpWaitTable, &t);
+
+ if (w != NULL)
+ {
+ // Do not do anything because it is already registered in the waiting list
+ return;
+ }
+ else
+ {
+ // Register in the waiting list newly
+ w = ZeroMalloc(sizeof(L3ARPWAIT));
+ w->Expire = Tick64() + ARP_REQUEST_GIVEUP;
+ w->IpAddress = ip;
+ Insert(f->ArpWaitTable, w);
+ }
+}
+
+// Received an ARP request
+void L3RecvArpRequest(L3IF *f, PKT *p)
+{
+ ARPV4_HEADER *a;
+ // Validate arguments
+ if (f == NULL || p == NULL)
+ {
+ return;
+ }
+
+ a = p->L3.ARPv4Header;
+
+ L3KnownArp(f, a->SrcIP, a->SrcAddress);
+
+ if (a->TargetIP == f->IpAddress)
+ {
+ // Respond only if the ARP packet addressed to myself
+ L3SendArpResponseNow(f, a->SrcAddress, a->SrcIP, f->IpAddress);
+ }
+}
+
+// Received an ARP response
+void L3RecvArpResponse(L3IF *f, PKT *p)
+{
+ ARPV4_HEADER *a;
+ // Validate arguments
+ if (f == NULL || p == NULL)
+ {
+ return;
+ }
+
+ a = p->L3.ARPv4Header;
+
+ L3KnownArp(f, a->SrcIP, a->SrcAddress);
+}
+
+// Received an ARP packet
+void L3RecvArp(L3IF *f, PKT *p)
+{
+ ARPV4_HEADER *a;
+ // Validate arguments
+ if (f == NULL || p == NULL)
+ {
+ return;
+ }
+
+ a = p->L3.ARPv4Header;
+
+ if (Endian16(a->HardwareType) != ARP_HARDWARE_TYPE_ETHERNET ||
+ Endian16(a->ProtocolType) != MAC_PROTO_IPV4 ||
+ a->HardwareSize != 6 || a->ProtocolSize != 4)
+ {
+ return;
+ }
+ if (Cmp(a->SrcAddress, p->MacAddressSrc, 6) != 0)
+ {
+ return;
+ }
+
+ switch (Endian16(a->Operation))
+ {
+ case ARP_OPERATION_REQUEST:
+ // ARP request arrives
+ L3RecvArpRequest(f, p);
+ break;
+
+ case ARP_OPERATION_RESPONSE:
+ // ARP response arrives
+ L3RecvArpResponse(f, p);
+ break;
+ }
+}
+
+// Send an IP packet
+void L3SendIp(L3IF *f, L3PACKET *p)
+{
+ L3ARPENTRY *a = NULL;
+ bool broadcast = false;
+ IPV4_HEADER *ip;
+ bool for_me = false;
+ // Validate arguments
+ if (f == NULL || p == NULL)
+ {
+ return;
+ }
+ if (p->Packet->TypeL3 != L3_IPV4)
+ {
+ return;
+ }
+
+ ip = p->Packet->L3.IPv4Header;
+
+ // Determining whether it's a broadcast
+ if (p->NextHopIp == 0xffffffff ||
+ ((p->NextHopIp & f->SubnetMask) == (f->IpAddress & f->SubnetMask)) &&
+ ((p->NextHopIp & (~f->SubnetMask)) == (~f->SubnetMask)))
+ {
+ broadcast = true;
+ }
+
+ if (broadcast == false && ip->DstIP == f->IpAddress)
+ {
+ // me?
+ }
+ else if (broadcast == false)
+ {
+ // Examine whether the ARP entry contains this in the case of unicast
+ a = L3SearchArpTable(f, p->NextHopIp);
+
+ if (a == NULL)
+ {
+ // Since It is not in the ARP table,
+ // insert it into the IP waiting list without sending immediately
+ p->Expire = Tick64() + IP_WAIT_FOR_ARP_TIMEOUT;
+
+ Insert(f->IpWaitList, p);
+
+ // Issue an ARP query
+ L3SendArp(f, p->NextHopIp);
+ return;
+ }
+ }
+
+ if (for_me == false)
+ {
+ // Send the IP packet
+ L3SendIpNow(f, a, p);
+ }
+
+ // Release the packet
+ Free(p->Packet->PacketData);
+ FreePacket(p->Packet);
+ Free(p);
+}
+
+// Send the IP packet immediately
+void L3SendIpNow(L3IF *f, L3ARPENTRY *a, L3PACKET *p)
+{
+ // Validate arguments
+ if (f == NULL || p == NULL)
+ {
+ return;
+ }
+
+ L3SendL2Now(f, a != NULL ? a->MacAddress : broadcast, f->MacAddress, Endian16(p->Packet->MacHeader->Protocol),
+ p->Packet->L3.PointerL3, p->Packet->PacketSize - sizeof(MAC_HEADER));
+}
+
+// Search in the ARP table
+L3ARPENTRY *L3SearchArpTable(L3IF *f, UINT ip)
+{
+ L3ARPENTRY *e, t;
+ // Validate arguments
+ if (f == NULL || ip == 0 || ip == 0xffffffff)
+ {
+ return NULL;
+ }
+
+ Zero(&t, sizeof(t));
+ t.IpAddress = ip;
+
+ e = Search(f->ArpTable, &t);
+
+ return e;
+}
+
+// Send an ARP request packet
+void L3SendArpRequestNow(L3IF *f, UINT dest_ip)
+{
+ ARPV4_HEADER arp;
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ // Build an ARP header
+ arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+ arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
+ arp.HardwareSize = 6;
+ arp.ProtocolSize = 4;
+ arp.Operation = Endian16(ARP_OPERATION_REQUEST);
+ Copy(arp.SrcAddress, f->MacAddress, 6);
+ arp.SrcIP = f->IpAddress;
+ Zero(&arp.TargetAddress, 6);
+ arp.TargetIP = dest_ip;
+
+ // Transmission
+ L3SendL2Now(f, broadcast, f->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
+}
+
+// Send an ARP response packet
+void L3SendArpResponseNow(L3IF *f, UCHAR *dest_mac, UINT dest_ip, UINT src_ip)
+{
+ ARPV4_HEADER arp;
+ // Validate arguments
+ if (f == NULL || dest_mac == NULL)
+ {
+ return;
+ }
+
+ // Build a header
+ arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+ arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
+ arp.HardwareSize = 6;
+ arp.ProtocolSize = 4;
+ arp.Operation = Endian16(ARP_OPERATION_RESPONSE);
+ Copy(arp.SrcAddress, f->MacAddress, 6);
+ Copy(arp.TargetAddress, dest_mac, 6);
+ arp.SrcIP = src_ip;
+ arp.TargetIP = dest_ip;
+
+ // Transmission
+ L3SendL2Now(f, dest_mac, f->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
+}
+
+// Generate a MAC address of the interface
+void L3GenerateMacAddress(L3IF *f)
+{
+ BUF *b;
+ UCHAR hash[SHA1_SIZE];
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ b = NewBuf();
+ WriteBuf(b, f->Switch->Name, StrLen(f->Switch->Name));
+ WriteBuf(b, f->HubName, StrLen(f->HubName));
+ WriteBuf(b, &f->IpAddress, sizeof(f->IpAddress));
+
+ GenMacAddress(f->MacAddress);
+ Hash(hash, b->Buf, b->Size, true);
+ Copy(f->MacAddress + 2, hash, 4);
+ f->MacAddress[1] = 0xA3;
+ FreeBuf(b);
+}
+
+// Send an L2 packet immediately
+void L3SendL2Now(L3IF *f, UCHAR *dest_mac, UCHAR *src_mac, USHORT protocol, void *data, UINT size)
+{
+ UCHAR *buf;
+ MAC_HEADER *mac_header;
+ PKT *p;
+ // Validate arguments
+ if (f == NULL || dest_mac == NULL || src_mac == NULL || data == NULL)
+ {
+ return;
+ }
+
+ // Buffer creation
+ buf = Malloc(MAC_HEADER_SIZE + size);
+
+ // MAC header
+ mac_header = (MAC_HEADER *)&buf[0];
+ Copy(mac_header->DestAddress, dest_mac, 6);
+ Copy(mac_header->SrcAddress, src_mac, 6);
+ mac_header->Protocol = Endian16(protocol);
+
+ // Copy data
+ Copy(&buf[sizeof(MAC_HEADER)], data, size);
+
+ // Size
+ size += sizeof(MAC_HEADER);
+
+ // Packet generation
+ p = ZeroMalloc(sizeof(PKT));
+ p->PacketData = buf;
+ p->PacketSize = size;
+
+ // Add to the queue
+ InsertQueue(f->SendQueue, p);
+}
+
+// Polling for the ARP resolution waiting list
+void L3PollingArpWaitTable(L3IF *f)
+{
+ UINT i;
+ LIST *o = NULL;
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(f->ArpWaitTable);i++)
+ {
+ L3ARPWAIT *w = LIST_DATA(f->ArpWaitTable, i);
+
+ if (w->Expire <= Tick64())
+ {
+ // The ARP request entry is expired
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Insert(o, w);
+ }
+ else if ((w->LastSentTime + ARP_REQUEST_TIMEOUT) <= Tick64())
+ {
+ // Send a next ARP request packet
+ w->LastSentTime = Tick64();
+
+ L3SendArpRequestNow(f, w->IpAddress);
+ }
+ }
+
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ L3ARPWAIT *w = LIST_DATA(o, i);
+
+ Delete(f->ArpWaitTable, w);
+ Free(w);
+ }
+
+ ReleaseList(o);
+ }
+}
+
+// Clear old ARP table entries
+void L3DeleteOldArpTable(L3IF *f)
+{
+ UINT i;
+ LIST *o = NULL;
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ if ((f->LastDeleteOldArpTable + ARP_ENTRY_POLLING_TIME) > Tick64())
+ {
+ return;
+ }
+ f->LastDeleteOldArpTable = Tick64();
+
+ for (i = 0;i < LIST_NUM(f->ArpTable);i++)
+ {
+ L3ARPENTRY *a = LIST_DATA(f->ArpTable, i);
+
+ if (a->Expire <= Tick64())
+ {
+ // Expired
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Insert(o, a);
+ }
+ }
+
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ L3ARPENTRY *a = LIST_DATA(o, i);
+
+ Delete(f->ArpTable, a);
+ Free(a);
+ }
+
+ ReleaseList(o);
+ }
+}
+
+// Clear the IP waiting list
+void L3DeleteOldIpWaitList(L3IF *f)
+{
+ UINT i;
+ LIST *o = NULL;
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(f->IpWaitList);i++)
+ {
+ L3PACKET *p = LIST_DATA(f->IpWaitList, i);
+
+ if (p->Expire <= Tick64())
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Insert(o, p);
+ }
+ }
+
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ L3PACKET *p = LIST_DATA(o, i);
+
+ Delete(f->IpWaitList, p);
+
+ Free(p->Packet->PacketData);
+ FreePacket(p->Packet);
+ Free(p);
+ }
+
+ ReleaseList(o);
+ }
+}
+
+// Beacon transmission
+void L3PollingBeacon(L3IF *f)
+{
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ if (f->LastBeaconSent == 0 ||
+ (f->LastBeaconSent + BEACON_SEND_INTERVAL) <= Tick64())
+ {
+ UINT dest_ip;
+ UCHAR *udp_buf;
+ UINT udp_buf_size;
+ ARPV4_HEADER arp;
+ IPV4_HEADER *ip;
+ UDP_HEADER *udp;
+ static char beacon_str[] =
+ "PacketiX VPN Virtual Layer-3 Switch Beacon";
+
+ // Send an UDP
+ dest_ip = (f->IpAddress & f->SubnetMask) | (~f->SubnetMask);
+ udp_buf_size = sizeof(IPV4_HEADER) + sizeof(UDP_HEADER) + sizeof(beacon_str);
+ udp_buf = ZeroMalloc(udp_buf_size);
+
+ ip = (IPV4_HEADER *)udp_buf;
+ udp = (UDP_HEADER *)(udp_buf + sizeof(IPV4_HEADER));
+ udp->DstPort = Endian16(7);
+ udp->SrcPort = Endian16(7);
+ udp->PacketLength = Endian16(sizeof(UDP_HEADER) + sizeof(beacon_str));
+
+ Copy(udp_buf + sizeof(IPV4_HEADER) + sizeof(UDP_HEADER), beacon_str, sizeof(beacon_str));
+
+ udp->Checksum = IpChecksum(udp, sizeof(UDP_HEADER) + sizeof(beacon_str));
+
+ ip->DstIP = dest_ip;
+ IPV4_SET_VERSION(ip, 4);
+ IPV4_SET_HEADER_LEN(ip, (IP_HEADER_SIZE / 4));
+ ip->TypeOfService = DEFAULT_IP_TOS;
+ ip->TotalLength = Endian16((USHORT)(udp_buf_size));
+ ip->TimeToLive = DEFAULT_IP_TTL;
+ ip->Protocol = IP_PROTO_UDP;
+ ip->SrcIP = f->IpAddress;
+ ip->Checksum = IpChecksum(ip, IP_HEADER_SIZE);
+
+ L3SendL2Now(f, broadcast, f->MacAddress, MAC_PROTO_IPV4, udp_buf, udp_buf_size);
+
+ Free(udp_buf);
+
+ // Build the ARP header
+ arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+ arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
+ arp.HardwareSize = 6;
+ arp.ProtocolSize = 4;
+ arp.Operation = Endian16(ARP_OPERATION_RESPONSE);
+ Copy(arp.SrcAddress, f->MacAddress, 6);
+ arp.SrcIP = f->IpAddress;
+ arp.TargetAddress[0] =
+ arp.TargetAddress[1] =
+ arp.TargetAddress[2] =
+ arp.TargetAddress[3] =
+ arp.TargetAddress[4] =
+ arp.TargetAddress[5] = 0xff;
+ arp.TargetIP = dest_ip;
+
+ // Transmission
+ L3SendL2Now(f, broadcast, f->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
+
+ f->LastBeaconSent = Tick64();
+ }
+}
+
+// Polling process
+void L3Polling(L3IF *f)
+{
+ L3SW *s;
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ s = f->Switch;
+
+ // Lock the entire switch in the middle of the polling process
+ Lock(s->lock);
+ {
+ // Beacon transmission
+ L3PollingBeacon(f);
+
+ // Process the IP queue
+ L3PollingIpQueue(f);
+
+ // Clear old ARP table entries
+ L3DeleteOldArpTable(f);
+
+ // Polling ARP resolution waiting list
+ L3PollingArpWaitTable(f);
+
+ // Clear the IP waiting list
+ L3DeleteOldIpWaitList(f);
+ }
+ Unlock(s->lock);
+}
+
+// Get the next packet
+UINT L3GetNextPacket(L3IF *f, void **data)
+{
+ UINT ret = 0;
+ // Validate arguments
+ if (f == NULL || data == NULL)
+ {
+ return 0;
+ }
+
+START:
+ // Examine the send queue
+ LockQueue(f->SendQueue);
+ {
+ PKT *p = GetNext(f->SendQueue);
+
+ if (p != NULL)
+ {
+ // There is a packet
+ ret = p->PacketSize;
+ *data = p->PacketData;
+ // Packet structure may be discarded
+ Free(p);
+ }
+ }
+ UnlockQueue(f->SendQueue);
+
+ if (ret == 0)
+ {
+ // Polling process
+ L3Polling(f);
+
+ // Examine whether a new packet is queued for results of the polling process
+ if (f->SendQueue->num_item != 0)
+ {
+ // Get the packet immediately if it's in the queue
+ goto START;
+ }
+ }
+
+ return ret;
+}
+
+// Determine the packet destined for the specified IP address should be sent to which interface
+L3IF *L3GetNextIf(L3SW *s, UINT ip, UINT *next_hop)
+{
+ UINT i;
+ L3IF *f;
+ UINT next_hop_ip = 0;
+ // Validate arguments
+ if (s == NULL || ip == 0 || ip == 0xffffffff)
+ {
+ return NULL;
+ }
+
+ f = NULL;
+
+ // Examine whether the specified IP address is contained
+ // in the networks which each interfaces belong to
+ for (i = 0;i < LIST_NUM(s->IfList);i++)
+ {
+ L3IF *ff = LIST_DATA(s->IfList, i);
+
+ if ((ff->IpAddress & ff->SubnetMask) == (ip & ff->SubnetMask))
+ {
+ f = ff;
+ next_hop_ip = ip;
+ break;
+ }
+ }
+
+ if (f == NULL)
+ {
+ // Find the routing table if it's not found
+ L3TABLE *t = L3GetBestRoute(s, ip);
+
+ if (t == NULL)
+ {
+ // Still not found
+ return NULL;
+ }
+ else
+ {
+ // Find the interface with the IP address of the router of
+ // NextHop of the found route
+ for (i = 0;i < LIST_NUM(s->IfList);i++)
+ {
+ L3IF *ff = LIST_DATA(s->IfList, i);
+
+ if ((ff->IpAddress & ff->SubnetMask) == (t->GatewayAddress & ff->SubnetMask))
+ {
+ f = ff;
+ next_hop_ip = t->GatewayAddress;
+ break;
+ }
+ }
+ }
+ }
+
+ if (f == NULL)
+ {
+ // Destination interface was unknown after all
+ return NULL;
+ }
+
+ if (next_hop != NULL)
+ {
+ *next_hop = next_hop_ip;
+ }
+
+ return f;
+}
+
+// Get the best routing table entry for the specified IP address
+L3TABLE *L3GetBestRoute(L3SW *s, UINT ip)
+{
+ UINT i;
+ UINT max_mask = 0;
+ UINT min_metric = INFINITE;
+ L3TABLE *ret = NULL;
+ // Validate arguments
+ if (s == NULL || ip == 0)
+ {
+ return NULL;
+ }
+
+ // 1st condition: Choose the one which have the largest subnet mask
+ // 2nd condition: Choose the one which have the smallest metric
+ for (i = 0;i < LIST_NUM(s->TableList);i++)
+ {
+ L3TABLE *t = LIST_DATA(s->TableList, i);
+
+ if ((t->NetworkAddress & t->SubnetMask) == (ip & t->SubnetMask))
+ {
+ if (t->SubnetMask >= max_mask)
+ {
+ max_mask = t->SubnetMask;
+ if (min_metric >= t->Metric)
+ {
+ min_metric = t->Metric;
+ ret = t;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+// Initialize the Layer-3 interface
+void L3InitInterface(L3IF *f)
+{
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ // MAC address generation
+ L3GenerateMacAddress(f);
+
+ // List generation
+ f->ArpTable = NewList(CmpL3ArpEntry);
+ f->ArpWaitTable = NewList(CmpL3ArpWaitTable);
+ f->IpPacketQueue = NewQueue();
+ f->IpWaitList = NewList(NULL);
+ f->SendQueue = NewQueue();
+}
+
+// Release the Layer-3 interface
+void L3FreeInterface(L3IF *f)
+{
+ UINT i;
+ L3PACKET *p;
+ PKT *pkt;
+ // Validate arguments
+ if (f == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(f->ArpTable);i++)
+ {
+ L3ARPENTRY *a = LIST_DATA(f->ArpTable, i);
+ Free(a);
+ }
+ ReleaseList(f->ArpTable);
+ f->ArpTable = NULL;
+
+ for (i = 0;i < LIST_NUM(f->ArpWaitTable);i++)
+ {
+ L3ARPWAIT *w = LIST_DATA(f->ArpWaitTable, i);
+ Free(w);
+ }
+ ReleaseList(f->ArpWaitTable);
+ f->ArpWaitTable = NULL;
+
+ while (p = GetNext(f->IpPacketQueue))
+ {
+ Free(p->Packet->PacketData);
+ FreePacket(p->Packet);
+ Free(p);
+ }
+ ReleaseQueue(f->IpPacketQueue);
+ f->IpPacketQueue = NULL;
+
+ for (i = 0;i < LIST_NUM(f->IpWaitList);i++)
+ {
+ L3PACKET *p = LIST_DATA(f->IpWaitList, i);
+ Free(p->Packet->PacketData);
+ FreePacket(p->Packet);
+ Free(p);
+ }
+ ReleaseList(f->IpWaitList);
+ f->IpWaitList = NULL;
+
+ while (pkt = GetNext(f->SendQueue))
+ {
+ Free(pkt->PacketData);
+ FreePacket(pkt);
+ }
+ ReleaseQueue(f->SendQueue);
+ f->SendQueue = NULL;
+}
+
+// Layer-3 interface thread
+void L3IfThread(THREAD *t, void *param)
+{
+ L3IF *f;
+ CONNECTION *c;
+ SESSION *s;
+ POLICY *policy;
+ char tmp[MAX_SIZE];
+ char name[MAX_SIZE];
+ char username[MAX_SIZE];
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ f = (L3IF *)param;
+
+ StrCpy(username, sizeof(username), L3_USERNAME);
+ if (f->Switch != NULL)
+ {
+ StrCat(username, sizeof(username), f->Switch->Name);
+ }
+
+ // Create a connection
+ c = NewServerConnection(f->Switch->Cedar, NULL, t);
+ c->Protocol = CONNECTION_HUB_LAYER3;
+
+ // Create a Session
+ policy = ClonePolicy(GetDefaultPolicy());
+ // Not to limit the number of broadcast by policy
+ policy->NoBroadcastLimiter = true;
+ s = NewServerSession(f->Switch->Cedar, c, f->Hub, username, policy);
+ c->Session = s;
+
+ ReleaseConnection(c);
+
+ // Determine the name of the session
+ GetMachineHostName(tmp, sizeof(tmp));
+ if (f->Switch->Cedar->Server->ServerType == SERVER_TYPE_STANDALONE)
+ {
+ Format(name, sizeof(name), "SID-L3-%s-%u", f->Switch->Name, Inc(f->Hub->SessionCounter));
+ }
+ else
+ {
+ Format(name, sizeof(name), "SID-L3-%s-%s-%u", tmp, f->Switch->Name, Inc(f->Hub->SessionCounter));
+ }
+ ConvertSafeFileName(name, sizeof(name), name);
+ StrUpper(name);
+
+ Free(s->Name);
+ s->Name = CopyStr(name);
+
+ s->L3SwitchMode = true;
+ s->L3If = f;
+
+ if (s->Username != NULL)
+ {
+ Free(s->Username);
+ }
+ s->Username = CopyStr(username);
+
+ StrCpy(s->UserNameReal, sizeof(s->UserNameReal), username);
+
+ f->Session = s;
+ AddRef(s->ref);
+
+ // Notify the initialization completion
+ NoticeThreadInit(t);
+
+ // Session main process
+ SessionMain(s);
+
+ // Release the session
+ ReleaseSession(s);
+}
+
+// Initialize all Layer-3 interfaces
+void L3InitAllInterfaces(L3SW *s)
+{
+ UINT i;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(s->IfList);i++)
+ {
+ L3IF *f = LIST_DATA(s->IfList, i);
+ THREAD *t;
+
+ L3InitInterface(f);
+
+ f->Hub = GetHub(s->Cedar, f->HubName);
+ t = NewThread(L3IfThread, f);
+ WaitThreadInit(t);
+ ReleaseThread(t);
+ }
+}
+
+// Release all Layer-3 interfaces
+void L3FreeAllInterfaces(L3SW *s)
+{
+ UINT i;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(s->IfList);i++)
+ {
+ L3IF *f = LIST_DATA(s->IfList, i);
+
+ ReleaseHub(f->Hub);
+ f->Hub = NULL;
+ ReleaseSession(f->Session);
+ f->Session = NULL;
+
+ L3FreeInterface(f);
+ }
+}
+
+// Layer-3 test
+void L3Test(SERVER *s)
+{
+ L3SW *ss = L3AddSw(s->Cedar, "TEST");
+ L3AddIf(ss, "DEFAULT", 0x0101a8c0, 0x00ffffff);
+ L3AddIf(ss, "DEFAULT2", 0x0102a8c0, 0x00ffffff);
+ L3SwStart(ss);
+ ReleaseL3Sw(ss);
+}
+
+// Layer-3 switch thread
+void L3SwThread(THREAD *t, void *param)
+{
+ L3SW *s;
+ bool shutdown_now = false;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ s = (L3SW *)param;
+
+ s->Active = true;
+
+ NoticeThreadInit(t);
+
+ // Operation start
+ SLog(s->Cedar, "L3_SWITCH_START", s->Name);
+
+ while (s->Halt == false)
+ {
+ if (s->Online == false)
+ {
+ // Because the L3 switch is off-line now,
+ // attempt to make it on-line periodically
+ LockList(s->Cedar->HubList);
+ {
+ Lock(s->lock);
+ {
+ UINT i;
+ UINT n = 0;
+ bool all_exists = true;
+ if (LIST_NUM(s->IfList) == 0)
+ {
+ // Don't operate if there is no interface
+ all_exists = false;
+ }
+ for (i = 0;i < LIST_NUM(s->IfList);i++)
+ {
+ L3IF *f = LIST_DATA(s->IfList, i);
+ HUB *h = GetHub(s->Cedar, f->HubName);
+
+ if (h != NULL)
+ {
+ if (h->Offline || h->Type == HUB_TYPE_FARM_DYNAMIC)
+ {
+ all_exists = false;
+ }
+ else
+ {
+ n++;
+ }
+ ReleaseHub(h);
+ }
+ else
+ {
+ all_exists = false;
+ }
+ }
+
+ if (all_exists && n >= 1)
+ {
+ // Start the operation because all Virtual HUBs for
+ // interfaces are enabled
+ SLog(s->Cedar, "L3_SWITCH_ONLINE", s->Name);
+ L3InitAllInterfaces(s);
+ s->Online = true;
+ }
+ }
+ Unlock(s->lock);
+ }
+ UnlockList(s->Cedar->HubList);
+ }
+ else
+ {
+ // Examine periodically whether all sessions terminated
+ UINT i;
+ bool any_halted = false;
+ LIST *o = NULL;
+
+SHUTDOWN:
+
+ Lock(s->lock);
+ {
+ for (i = 0;i < LIST_NUM(s->IfList);i++)
+ {
+ L3IF *f = LIST_DATA(s->IfList, i);
+ if (f->Session->Halt || f->Hub->Offline != false)
+ {
+ any_halted = true;
+ break;
+ }
+ }
+
+ if (shutdown_now)
+ {
+ any_halted = true;
+ }
+
+ if (any_halted)
+ {
+ SLog(s->Cedar, "L3_SWITCH_OFFLINE", s->Name);
+ o = NewListFast(NULL);
+ // If there is any terminated session, terminate all sessions
+ for (i = 0;i < LIST_NUM(s->IfList);i++)
+ {
+ L3IF *f = LIST_DATA(s->IfList, i);
+ Insert(o, f->Session);
+ }
+
+ // Restore to the offline
+ s->Online = false;
+ }
+ }
+ Unlock(s->lock);
+
+ if (o != NULL)
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ SESSION *s = LIST_DATA(o, i);
+ StopSession(s);
+ }
+ L3FreeAllInterfaces(s);
+ ReleaseList(o);
+ o = NULL;
+ }
+ }
+
+ SleepThread(50);
+ }
+
+ if (s->Online != false)
+ {
+ shutdown_now = true;
+ goto SHUTDOWN;
+ }
+
+ // Stop the operation
+ SLog(s->Cedar, "L3_SWITCH_STOP", s->Name);
+}
+
+// Start a Layer-3 switch
+void L3SwStart(L3SW *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Lock(s->lock);
+ {
+ if (s->Active == false)
+ {
+ // Start if there is registered interface
+ if (LIST_NUM(s->IfList) >= 1)
+ {
+ s->Halt = false;
+
+ // Create a thread
+ s->Thread = NewThread(L3SwThread, s);
+ WaitThreadInit(s->Thread);
+ }
+ }
+ }
+ Unlock(s->lock);
+}
+
+// Stop the Layer-3 switch
+void L3SwStop(L3SW *s)
+{
+ THREAD *t = NULL;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Lock(s->lock);
+ {
+ if (s->Active == false)
+ {
+ Unlock(s->lock);
+ return;
+ }
+
+ s->Halt = true;
+
+ t = s->Thread;
+
+ s->Active = false;
+ }
+ Unlock(s->lock);
+
+ WaitThread(t, INFINITE);
+ ReleaseThread(t);
+}
+
+// Add a Layer-3 switch
+L3SW *L3AddSw(CEDAR *c, char *name)
+{
+ L3SW *s = NULL;
+ // Validate arguments
+ if (c == NULL || name == NULL)
+ {
+ return NULL;
+ }
+
+ LockList(c->L3SwList);
+ {
+ s = L3GetSw(c, name);
+
+ if (s == NULL)
+ {
+ s = NewL3Sw(c, name);
+
+ Insert(c->L3SwList, s);
+
+ AddRef(s->ref);
+ }
+ else
+ {
+ ReleaseL3Sw(s);
+ s = NULL;
+ }
+ }
+ UnlockList(c->L3SwList);
+
+ return s;
+}
+
+// Delete the Layer-3 switch
+bool L3DelSw(CEDAR *c, char *name)
+{
+ L3SW *s;
+ bool ret = false;
+ // Validate arguments
+ if (c == NULL || name == NULL)
+ {
+ return false;
+ }
+
+ LockList(c->L3SwList);
+ {
+ s = L3GetSw(c, name);
+
+ if (s != NULL)
+ {
+ // Stop and delete
+ L3SwStop(s);
+ Delete(c->L3SwList, s);
+ ReleaseL3Sw(s);
+ ReleaseL3Sw(s);
+
+ ret = true;
+ }
+ }
+ UnlockList(c->L3SwList);
+
+ return ret;
+}
+
+
+// Delete the routing table
+bool L3DelTable(L3SW *s, L3TABLE *tbl)
+{
+ bool ret = false;
+ // Validate arguments
+ if (s == NULL || tbl == NULL)
+ {
+ return false;
+ }
+
+ Lock(s->lock);
+ {
+ if (s->Active == false)
+ {
+ L3TABLE *t = Search(s->TableList, tbl);
+
+ if (t != NULL)
+ {
+ Delete(s->TableList, t);
+ Free(t);
+
+ ret = true;
+ }
+ }
+ }
+ Unlock(s->lock);
+
+ return ret;
+}
+
+// Add to the routing table
+bool L3AddTable(L3SW *s, L3TABLE *tbl)
+{
+ bool ret = false;
+ // Validate arguments
+ if (s == NULL || tbl == NULL)
+ {
+ return false;
+ }
+
+ if (tbl->Metric == 0 || tbl->GatewayAddress == 0 || tbl->GatewayAddress == 0xffffffff)
+ {
+ return false;
+ }
+
+ Lock(s->lock);
+ {
+ if (LIST_NUM(s->TableList) >= GetServerCapsInt(s->Cedar->Server, "i_max_l3_table"))
+ {
+ // Too many
+ }
+ else
+ {
+ // Create
+ if (s->Active == false)
+ {
+ if (Search(s->TableList, tbl) == NULL)
+ {
+ L3TABLE *t = ZeroMalloc(sizeof(L3TABLE));
+
+ Copy(t, tbl, sizeof(L3TABLE));
+
+ Insert(s->TableList, t);
+
+ ret = true;
+ }
+ }
+ }
+ }
+ Unlock(s->lock);
+
+ return ret;
+}
+
+// Get the L3 switch
+L3SW *L3GetSw(CEDAR *c, char *name)
+{
+ L3SW t, *s;
+ // Validate arguments
+ if (c == NULL || name == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), name);
+
+ LockList(c->L3SwList);
+ {
+ s = Search(c->L3SwList, &t);
+ }
+ UnlockList(c->L3SwList);
+
+ if (s != NULL)
+ {
+ AddRef(s->ref);
+ }
+
+ return s;
+}
+
+// Get the interface that is connected to the specified Virtual HUB from the L3 switch
+L3IF *L3SearchIf(L3SW *s, char *hubname)
+{
+ L3IF t, *f;
+ // Validate arguments
+ if (s == NULL || hubname == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+ f = Search(s->IfList, &t);
+
+ return f;
+}
+
+// Delete the interface
+bool L3DelIf(L3SW *s, char *hubname)
+{
+ L3IF *f;
+ bool ret = false;
+ // Validate arguments
+ if (s == NULL || hubname == NULL)
+ {
+ return false;
+ }
+
+ Lock(s->lock);
+ {
+ if (s->Active == false)
+ {
+ f = L3SearchIf(s, hubname);
+
+ if (f != NULL)
+ {
+ // Remove
+ Delete(s->IfList, f);
+ Free(f);
+
+ ret = true;
+ }
+ }
+ }
+ Unlock(s->lock);
+
+ return ret;
+}
+
+// Add an interface
+bool L3AddIf(L3SW *s, char *hubname, UINT ip, UINT subnet)
+{
+ L3IF *f;
+ bool ret = false;
+ // Validate arguments
+ if (s == NULL || hubname == NULL || IsSafeStr(hubname) == false ||
+ ip == 0 || ip == 0xffffffff)
+ {
+ return false;
+ }
+
+ Lock(s->lock);
+ {
+ if (LIST_NUM(s->TableList) >= GetServerCapsInt(s->Cedar->Server, "i_max_l3_if"))
+ {
+ // Too many
+ }
+ else
+ {
+ if (s->Active == false)
+ {
+ // Examine whether the interface is already in the same Virtual HUB
+ if (L3SearchIf(s, hubname) == NULL)
+ {
+ // Add
+ f = ZeroMalloc(sizeof(L3IF));
+
+ f->Switch = s;
+ StrCpy(f->HubName, sizeof(f->HubName), hubname);
+ f->IpAddress = ip;
+ f->SubnetMask = subnet;
+
+ Insert(s->IfList, f);
+
+ ret = true;
+ }
+ }
+ }
+ }
+ Unlock(s->lock);
+
+ return ret;
+}
+
+// Clean-up the L3 switch
+void CleanupL3Sw(L3SW *s)
+{
+ UINT i;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(s->IfList);i++)
+ {
+ L3IF *f = LIST_DATA(s->IfList, i);
+ Free(f);
+ }
+ ReleaseList(s->IfList);
+
+ for (i = 0;i < LIST_NUM(s->TableList);i++)
+ {
+ L3TABLE *t = LIST_DATA(s->TableList, i);
+ Free(t);
+ }
+ ReleaseList(s->TableList);
+
+ DeleteLock(s->lock);
+ Free(s);
+}
+
+// Release the L3 switch
+void ReleaseL3Sw(L3SW *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ if (Release(s->ref) == 0)
+ {
+ CleanupL3Sw(s);
+ }
+}
+
+// Create a new L3 switch
+L3SW *NewL3Sw(CEDAR *c, char *name)
+{
+ L3SW *o;
+ // Validate arguments
+ if (c == NULL || name == NULL)
+ {
+ return NULL;
+ }
+
+ o = ZeroMalloc(sizeof(L3SW));
+
+ StrCpy(o->Name, sizeof(o->Name), name);
+
+ o->lock = NewLock();
+ o->ref = NewRef();
+ o->Cedar = c;
+ o->Active = false;
+
+ o->IfList = NewList(CmpL3If);
+ o->TableList = NewList(CmpL3Table);
+
+ return o;
+}
+
+// Stop all L3 switches in the Cedar
+void L3FreeAllSw(CEDAR *c)
+{
+ LIST *o;
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ o = NewListFast(NULL);
+
+ LockList(c->L3SwList);
+ {
+ for (i = 0;i < LIST_NUM(c->L3SwList);i++)
+ {
+ L3SW *s = LIST_DATA(c->L3SwList, i);
+ Insert(o, CopyStr(s->Name));
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ char *name = LIST_DATA(o, i);
+
+ L3DelSw(c, name);
+
+ Free(name);
+ }
+
+ ReleaseList(o);
+ }
+ UnlockList(c->L3SwList);
+}
+
+// Stop the L3 switch function of the Cedar
+void FreeCedarLayer3(CEDAR *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ ReleaseList(c->L3SwList);
+ c->L3SwList = NULL;
+}
+
+// Start the L3 switch function of the Cedar
+void InitCedarLayer3(CEDAR *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ c->L3SwList = NewList(CmpL3Sw);
+}
+
+// Interface comparison function
+int CmpL3If(void *p1, void *p2)
+{
+ L3IF *f1, *f2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ f1 = *(L3IF **)p1;
+ f2 = *(L3IF **)p2;
+ if (f1 == NULL || f2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(f1->HubName, f2->HubName);
+}
+
+// Routing table entry comparison function
+int CmpL3Table(void *p1, void *p2)
+{
+ L3TABLE *t1, *t2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ t1 = *(L3TABLE **)p1;
+ t2 = *(L3TABLE **)p2;
+ if (t1 == NULL || t2 == NULL)
+ {
+ return 0;
+ }
+
+ if (t1->NetworkAddress > t2->NetworkAddress)
+ {
+ return 1;
+ }
+ else if (t1->NetworkAddress < t2->NetworkAddress)
+ {
+ return -1;
+ }
+ else if (t1->SubnetMask > t2->SubnetMask)
+ {
+ return 1;
+ }
+ else if (t1->SubnetMask < t2->SubnetMask)
+ {
+ return -1;
+ }
+ else if (t1->GatewayAddress > t2->GatewayAddress)
+ {
+ return 1;
+ }
+ else if (t1->GatewayAddress < t2->GatewayAddress)
+ {
+ return -1;
+ }
+ else if (t1->Metric > t2->Metric)
+ {
+ return 1;
+ }
+ else if (t1->Metric < t2->Metric)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// L3SW comparison function
+int CmpL3Sw(void *p1, void *p2)
+{
+ L3SW *s1, *s2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ s1 = *(L3SW **)p1;
+ s2 = *(L3SW **)p2;
+ if (s1 == NULL || s2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(s1->Name, s2->Name);
+}
+
+// ARP waiting entry comparison function
+int CmpL3ArpWaitTable(void *p1, void *p2)
+{
+ L3ARPWAIT *w1, *w2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ w1 = *(L3ARPWAIT **)p1;
+ w2 = *(L3ARPWAIT **)p2;
+ if (w1 == NULL || w2 == NULL)
+ {
+ return 0;
+ }
+ if (w1->IpAddress > w2->IpAddress)
+ {
+ return 1;
+ }
+ else if (w1->IpAddress < w2->IpAddress)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// ARP entries comparison function
+int CmpL3ArpEntry(void *p1, void *p2)
+{
+ L3ARPENTRY *e1, *e2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ e1 = *(L3ARPENTRY **)p1;
+ e2 = *(L3ARPENTRY **)p2;
+ if (e1 == NULL || e2 == NULL)
+ {
+ return 0;
+ }
+ if (e1->IpAddress > e2->IpAddress)
+ {
+ return 1;
+ }
+ else if (e1->IpAddress < e2->IpAddress)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Layer3.h b/src/Cedar/Layer3.h
new file mode 100644
index 00000000..eca95c5e
--- /dev/null
+++ b/src/Cedar/Layer3.h
@@ -0,0 +1,229 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Layer3.h
+// Header of Layer3.c
+
+#ifndef LAYER3_H
+#define LAYER3_H
+
+// Constants
+#define L3_USERNAME "L3SW_"
+
+
+// L3 ARP table entry
+struct L3ARPENTRY
+{
+ UINT IpAddress; // IP address
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2];
+ UINT64 Expire; // Expiration date
+};
+
+// L3 ARP resolution waiting list entry
+struct L3ARPWAIT
+{
+ UINT IpAddress; // IP address
+ UINT64 LastSentTime; // Time which the data has been sent last
+ UINT64 Expire; // Expiration date
+};
+
+// L3 IP packet table
+struct L3PACKET
+{
+ PKT *Packet; // Packet data body
+ UINT64 Expire; // Expiration date
+ UINT NextHopIp; // Local delivery destination IP address
+};
+
+// L3 routing table definition
+struct L3TABLE
+{
+ UINT NetworkAddress; // Network address
+ UINT SubnetMask; // Subnet mask
+ UINT GatewayAddress; // Gateway address
+ UINT Metric; // Metric
+};
+
+// L3 interface definition
+struct L3IF
+{
+ L3SW *Switch; // Layer-3 switch
+ char HubName[MAX_HUBNAME_LEN + 1]; // Virtual HUB name
+ UINT IpAddress; // IP address
+ UINT SubnetMask; // Subnet mask
+
+ HUB *Hub; // Virtual HUB
+ SESSION *Session; // Session
+ LIST *ArpTable; // ARP table
+ LIST *ArpWaitTable; // ARP waiting table
+ QUEUE *IpPacketQueue; // IP packet queue (for reception from other interfaces)
+ LIST *IpWaitList; // IP waiting list
+ QUEUE *SendQueue; // Transmission queue
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2];
+ UINT64 LastDeleteOldArpTable; // Time that old ARP table entries are cleared
+ LIST *CancelList; // Cancellation list
+ UINT64 LastBeaconSent; // Time which the beacon has been sent last
+};
+
+// L3 switch definition
+struct L3SW
+{
+ char Name[MAX_HUBNAME_LEN + 1]; // Name
+ LOCK *lock; // Lock
+ REF *ref; // Reference counter
+ CEDAR *Cedar; // Cedar
+ bool Active; // During operation flag
+ bool Online; // Online flag
+ volatile bool Halt; // Halting flag
+ LIST *IfList; // Interface list
+ LIST *TableList; // Routing table list
+ THREAD *Thread; // Thread
+};
+
+
+
+// Function prototype
+int CmpL3Sw(void *p1, void *p2);
+int CmpL3ArpEntry(void *p1, void *p2);
+int CmpL3ArpWaitTable(void *p1, void *p2);
+int CmpL3Table(void *p1, void *p2);
+int CmpL3If(void *p1, void *p2);
+void InitCedarLayer3(CEDAR *c);
+void FreeCedarLayer3(CEDAR *c);
+L3SW *NewL3Sw(CEDAR *c, char *name);
+void ReleaseL3Sw(L3SW *s);
+void CleanupL3Sw(L3SW *s);
+bool L3AddIf(L3SW *s, char *hubname, UINT ip, UINT subnet);
+bool L3DelIf(L3SW *s, char *hubname);
+bool L3AddTable(L3SW *s, L3TABLE *tbl);
+bool L3DelTable(L3SW *s, L3TABLE *tbl);
+L3IF *L3SearchIf(L3SW *s, char *hubname);
+L3SW *L3GetSw(CEDAR *c, char *name);
+L3SW *L3AddSw(CEDAR *c, char *name);
+bool L3DelSw(CEDAR *c, char *name);
+void L3FreeAllSw(CEDAR *c);
+void L3SwStart(L3SW *s);
+void L3SwStop(L3SW *s);
+void L3SwThread(THREAD *t, void *param);
+void L3Test(SERVER *s);
+void L3InitAllInterfaces(L3SW *s);
+void L3FreeAllInterfaces(L3SW *s);
+void L3IfThread(THREAD *t, void *param);
+void L3InitInterface(L3IF *f);
+void L3FreeInterface(L3IF *f);
+L3IF *L3GetNextIf(L3SW *s, UINT ip, UINT *next_hop);
+L3TABLE *L3GetBestRoute(L3SW *s, UINT ip);
+UINT L3GetNextPacket(L3IF *f, void **data);
+void L3Polling(L3IF *f);
+void L3PollingBeacon(L3IF *f);
+void L3DeleteOldArpTable(L3IF *f);
+void L3DeleteOldIpWaitList(L3IF *f);
+void L3PollingArpWaitTable(L3IF *f);
+void L3SendL2Now(L3IF *f, UCHAR *dest_mac, UCHAR *src_mac, USHORT protocol, void *data, UINT size);
+void L3SendArpRequestNow(L3IF *f, UINT dest_ip);
+void L3SendArpResponseNow(L3IF *f, UCHAR *dest_mac, UINT dest_ip, UINT src_ip);
+void L3GenerateMacAddress(L3IF *f);
+L3ARPENTRY *L3SearchArpTable(L3IF *f, UINT ip);
+void L3SendIpNow(L3IF *f, L3ARPENTRY *a, L3PACKET *p);
+void L3SendIp(L3IF *f, L3PACKET *p);
+void L3RecvArp(L3IF *f, PKT *p);
+void L3RecvArpRequest(L3IF *f, PKT *p);
+void L3RecvArpResponse(L3IF *f, PKT *p);
+void L3KnownArp(L3IF *f, UINT ip, UCHAR *mac);
+void L3SendArp(L3IF *f, UINT ip);
+void L3InsertArpTable(L3IF *f, UINT ip, UCHAR *mac);
+void L3SendWaitingIp(L3IF *f, UCHAR *mac, UINT ip, L3ARPENTRY *a);
+void L3PutPacket(L3IF *f, void *data, UINT size);
+void L3RecvL2(L3IF *f, PKT *p);
+void L3StoreIpPacketToIf(L3IF *src_if, L3IF *dst_if, L3PACKET *p);
+void L3RecvIp(L3IF *f, PKT *p, bool self);
+void L3PollingIpQueue(L3IF *f);
+
+
+#endif // LAYER3_H
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Link.c b/src/Cedar/Link.c
new file mode 100644
index 00000000..13f001d2
--- /dev/null
+++ b/src/Cedar/Link.c
@@ -0,0 +1,655 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Link.c
+// Inter-HUB Link
+
+#include "CedarPch.h"
+
+// Link server thread
+void LinkServerSessionThread(THREAD *t, void *param)
+{
+ LINK *k = (LINK *)param;
+ CONNECTION *c;
+ SESSION *s;
+ POLICY *policy;
+ wchar_t name[MAX_SIZE];
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Create a server connection
+ c = NewServerConnection(k->Cedar, NULL, t);
+ c->Protocol = CONNECTION_HUB_LINK_SERVER;
+
+ // Create a policy
+ policy = ZeroMalloc(sizeof(POLICY));
+ Copy(policy, k->Policy, sizeof(POLICY));
+
+ // Create a server session
+ s = NewServerSession(k->Cedar, c, k->Hub, LINK_USER_NAME, policy);
+ s->LinkModeServer = true;
+ s->Link = k;
+ c->Session = s;
+ ReleaseConnection(c);
+
+ // User name
+ s->Username = CopyStr(LINK_USER_NAME_PRINT);
+
+ k->ServerSession = s;
+ AddRef(k->ServerSession->ref);
+
+ // Notify the initialization completion
+ NoticeThreadInit(t);
+
+ UniStrCpy(name, sizeof(name), k->Option->AccountName);
+ HLog(s->Hub, "LH_LINK_START", name, s->Name);
+
+ // Main function of session
+ SessionMain(s);
+
+ HLog(s->Hub, "LH_LINK_STOP", name);
+
+ ReleaseSession(s);
+}
+
+// Initialize the packet adapter
+bool LinkPaInit(SESSION *s)
+{
+ LINK *k;
+ THREAD *t;
+ // Validate arguments
+ if (s == NULL || (k = (LINK *)s->PacketAdapter->Param) == NULL)
+ {
+ return false;
+ }
+
+ // Create a transmission packet queue
+ k->SendPacketQueue = NewQueue();
+
+ // Creat a link server thread
+ t = NewThread(LinkServerSessionThread, (void *)k);
+ WaitThreadInit(t);
+
+ ReleaseThread(t);
+
+ return true;
+}
+
+// Get the cancel object
+CANCEL *LinkPaGetCancel(SESSION *s)
+{
+ LINK *k;
+ // Validate arguments
+ if (s == NULL || (k = (LINK *)s->PacketAdapter->Param) == NULL)
+ {
+ return NULL;
+ }
+
+ return NULL;
+}
+
+// Get the next packet
+UINT LinkPaGetNextPacket(SESSION *s, void **data)
+{
+ LINK *k;
+ UINT ret = 0;
+ // Validate arguments
+ if (s == NULL || data == NULL || (k = (LINK *)s->PacketAdapter->Param) == NULL)
+ {
+ return INFINITE;
+ }
+
+ // Examine whether there are packets in the queue
+ LockQueue(k->SendPacketQueue);
+ {
+ BLOCK *block = GetNext(k->SendPacketQueue);
+
+ if (block != NULL)
+ {
+ // There was a packet
+ *data = block->Buf;
+ ret = block->Size;
+ // Discard the memory for the structure
+ Free(block);
+ }
+ }
+ UnlockQueue(k->SendPacketQueue);
+
+ return ret;
+}
+
+// Write the received packet
+bool LinkPaPutPacket(SESSION *s, void *data, UINT size)
+{
+ LINK *k;
+ BLOCK *block;
+ SESSION *server_session;
+ CONNECTION *server_connection;
+ // Validate arguments
+ if (s == NULL || (k = (LINK *)s->PacketAdapter->Param) == NULL)
+ {
+ return false;
+ }
+
+ server_session = k->ServerSession;
+ server_connection = server_session->Connection;
+
+ // Since the packet arrives from the HUB of the link destination,
+ // deliver it to the ReceivedBlocks of the server session
+ if (data != NULL)
+ {
+ block = NewBlock(data, size, 0);
+
+ LockQueue(server_connection->ReceivedBlocks);
+ {
+ InsertQueue(server_connection->ReceivedBlocks, block);
+ }
+ UnlockQueue(server_connection->ReceivedBlocks);
+ }
+ else
+ {
+ // Issue the Cancel, since finished store all packets when the data == NULL
+ Cancel(server_session->Cancel1);
+
+ if (k->Hub != NULL && k->Hub->Option != NULL && k->Hub->Option->YieldAfterStorePacket)
+ {
+ YieldCpu();
+ }
+ }
+
+ return true;
+}
+
+// Release the packet adapter
+void LinkPaFree(SESSION *s)
+{
+ LINK *k;
+ // Validate arguments
+ if (s == NULL || (k = (LINK *)s->PacketAdapter->Param) == NULL)
+ {
+ return;
+ }
+
+ // Stop the server session
+ StopSession(k->ServerSession);
+ ReleaseSession(k->ServerSession);
+
+ // Release the transmission packet queue
+ LockQueue(k->SendPacketQueue);
+ {
+ BLOCK *block;
+ while (block = GetNext(k->SendPacketQueue))
+ {
+ FreeBlock(block);
+ }
+ }
+ UnlockQueue(k->SendPacketQueue);
+
+ ReleaseQueue(k->SendPacketQueue);
+}
+
+// Packet adapter
+PACKET_ADAPTER *LinkGetPacketAdapter()
+{
+ return NewPacketAdapter(LinkPaInit, LinkPaGetCancel, LinkPaGetNextPacket,
+ LinkPaPutPacket, LinkPaFree);
+}
+
+// Release all links
+void ReleaseAllLink(HUB *h)
+{
+ LINK **kk;
+ UINT num, i;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ LockList(h->LinkList);
+ {
+ num = LIST_NUM(h->LinkList);
+ kk = ToArray(h->LinkList);
+ DeleteAll(h->LinkList);
+ }
+ UnlockList(h->LinkList);
+
+ for (i = 0;i < num;i++)
+ {
+ LINK *k = kk[i];
+
+ ReleaseLink(k);
+ }
+
+ Free(kk);
+}
+
+// Release the link
+void ReleaseLink(LINK *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ if (Release(k->ref) == 0)
+ {
+ CleanupLink(k);
+ }
+}
+
+// Clean-up the link
+void CleanupLink(LINK *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ DeleteLock(k->lock);
+ if (k->ClientSession)
+ {
+ ReleaseSession(k->ClientSession);
+ }
+ Free(k->Option);
+ CiFreeClientAuth(k->Auth);
+ Free(k->Policy);
+
+ if (k->ServerCert != NULL)
+ {
+ FreeX(k->ServerCert);
+ }
+
+ Free(k);
+}
+
+// Make the link on-line
+void SetLinkOnline(LINK *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ if (k->Offline == false)
+ {
+ return;
+ }
+
+ k->Offline = false;
+ StartLink(k);
+}
+
+// Make the link off-line
+void SetLinkOffline(LINK *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ if (k->Offline)
+ {
+ return;
+ }
+
+ StopLink(k);
+ k->Offline = true;
+}
+
+// Delete the link
+void DelLink(HUB *hub, LINK *k)
+{
+ // Validate arguments
+ if (hub == NULL || k == NULL)
+ {
+ return;
+ }
+
+ LockList(hub->LinkList);
+ {
+ if (Delete(hub->LinkList, k))
+ {
+ ReleaseLink(k);
+ }
+ }
+ UnlockList(hub->LinkList);
+}
+
+// Start all links
+void StartAllLink(HUB *h)
+{
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ LockList(h->LinkList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(h->LinkList);i++)
+ {
+ LINK *k = (LINK *)LIST_DATA(h->LinkList, i);
+
+ if (k->Offline == false)
+ {
+ StartLink(k);
+ }
+ }
+ }
+ UnlockList(h->LinkList);
+}
+
+// Stop all links
+void StopAllLink(HUB *h)
+{
+ LINK **link_list;
+ UINT num_link;
+ UINT i;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return;
+ }
+
+ LockList(h->LinkList);
+ {
+ link_list = ToArray(h->LinkList);
+ num_link = LIST_NUM(h->LinkList);
+ for (i = 0;i < num_link;i++)
+ {
+ AddRef(link_list[i]->ref);
+ }
+ }
+ UnlockList(h->LinkList);
+
+ for (i = 0;i < num_link;i++)
+ {
+ StopLink(link_list[i]);
+ ReleaseLink(link_list[i]);
+ }
+
+ Free(link_list);
+}
+
+// Start the link
+void StartLink(LINK *k)
+{
+ PACKET_ADAPTER *pa;
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ LockLink(k);
+ {
+ if (k->Started || k->Halting)
+ {
+ UnlockLink(k);
+ return;
+ }
+ k->Started = true;
+ }
+ UnlockLink(k);
+
+ // Connect the client session
+ pa = LinkGetPacketAdapter();
+ pa->Param = (void *)k;
+ LockLink(k);
+ {
+ k->ClientSession = NewClientSession(k->Cedar, k->Option, k->Auth, pa);
+ }
+ UnlockLink(k);
+}
+
+// Stop the link
+void StopLink(LINK *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ LockLink(k);
+ {
+ if (k->Started == false)
+ {
+ UnlockLink(k);
+ return;
+ }
+ k->Started = false;
+ k->Halting = true;
+ }
+ UnlockLink(k);
+
+ if (k->ClientSession != NULL)
+ {
+ // Disconnect the client session
+ StopSession(k->ClientSession);
+
+ LockLink(k);
+ {
+ ReleaseSession(k->ClientSession);
+ k->ClientSession = NULL;
+ }
+ UnlockLink(k);
+ }
+
+ LockLink(k);
+ {
+ k->Halting = false;
+ }
+ UnlockLink(k);
+}
+
+// Lock the link
+void LockLink(LINK *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ Lock(k->lock);
+}
+
+// Unlock the link
+void UnlockLink(LINK *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ Unlock(k->lock);
+}
+
+// Normalize the policy for the link
+void NormalizeLinkPolicy(POLICY *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ p->Access = true;
+ p->NoBridge = p->NoRouting = p->PrivacyFilter =
+ p->MonitorPort = false;
+ p->MaxConnection = 32;
+ p->TimeOut = 20;
+ p->FixPassword = false;
+}
+
+// Create a Link
+LINK *NewLink(CEDAR *cedar, HUB *hub, CLIENT_OPTION *option, CLIENT_AUTH *auth, POLICY *policy)
+{
+ CLIENT_OPTION *o;
+ LINK *k;
+ CLIENT_AUTH *a;
+ // Validate arguments
+ if (cedar == NULL || hub == NULL || option == NULL || auth == NULL || policy == NULL)
+ {
+ return NULL;
+ }
+ if (hub->Halt)
+ {
+ return NULL;
+ }
+
+ if (LIST_NUM(hub->LinkList) >= MAX_HUB_LINKS)
+ {
+ return NULL;
+ }
+
+ if (UniIsEmptyStr(option->AccountName))
+ {
+ return NULL;
+ }
+
+ // Limitation of authentication method
+ if (auth->AuthType != CLIENT_AUTHTYPE_ANONYMOUS && auth->AuthType != CLIENT_AUTHTYPE_PASSWORD &&
+ auth->AuthType != CLIENT_AUTHTYPE_PLAIN_PASSWORD && auth->AuthType != CLIENT_AUTHTYPE_CERT)
+ {
+ // Authentication method other than anonymous authentication, password authentication, plain password, certificate authentication cannot be used
+ return NULL;
+ }
+
+ // Copy of the client options (for modification)
+ o = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(o, option, sizeof(CLIENT_OPTION));
+ StrCpy(o->DeviceName, sizeof(o->DeviceName), LINK_DEVICE_NAME);
+
+ o->RequireBridgeRoutingMode = true; // Request the bridge mode
+ o->RequireMonitorMode = false; // Not to require the monitor mode
+
+ o->NumRetry = INFINITE; // Retry the connection infinitely
+ o->RetryInterval = 10; // Retry interval is 10 seconds
+ o->NoRoutingTracking = true; // Stop the routing tracking
+
+ // Copy the authentication data
+ a = CopyClientAuth(auth);
+ a->SecureSignProc = NULL;
+ a->CheckCertProc = NULL;
+
+ // Link object
+ k = ZeroMalloc(sizeof(LINK));
+ k->lock = NewLock();
+ k->ref = NewRef();
+
+ k->Cedar = cedar;
+ k->Option = o;
+ k->Auth = a;
+ k->Hub = hub;
+
+ // Copy the policy
+ k->Policy = ZeroMalloc(sizeof(POLICY));
+ Copy(k->Policy, policy, sizeof(POLICY));
+
+ // Normalize the policy
+ NormalizeLinkPolicy(k->Policy);
+
+ // Register in the link list of the HUB
+ LockList(hub->LinkList);
+ {
+ Add(hub->LinkList, k);
+ AddRef(k->ref);
+ }
+ UnlockList(hub->LinkList);
+
+ return k;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Link.h b/src/Cedar/Link.h
new file mode 100644
index 00000000..c2e4bf95
--- /dev/null
+++ b/src/Cedar/Link.h
@@ -0,0 +1,139 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Link.h
+// Header of Link.c
+
+#ifndef LINK_H
+#define LINK_H
+
+struct LINK
+{
+ bool Started; // Running flag
+ volatile bool Halting; // Halting flag
+ bool Offline; // Offline
+ REF *ref; // Reference counter
+ LOCK *lock; // Lock
+ CEDAR *Cedar; // Cedar
+ HUB *Hub; // HUB
+ SESSION *ClientSession; // Client session
+ SESSION *ServerSession; // Server session
+ CLIENT_OPTION *Option; // Client Option
+ CLIENT_AUTH *Auth; // Authentication data
+ POLICY *Policy; // Policy
+ QUEUE *SendPacketQueue; // Transmission packet queue
+ UINT LastError; // Last error
+ bool CheckServerCert; // To check the server certificate
+ X *ServerCert; // Server certificate
+};
+
+
+PACKET_ADAPTER *LinkGetPacketAdapter();
+bool LinkPaInit(SESSION *s);
+CANCEL *LinkPaGetCancel(SESSION *s);
+UINT LinkPaGetNextPacket(SESSION *s, void **data);
+bool LinkPaPutPacket(SESSION *s, void *data, UINT size);
+void LinkPaFree(SESSION *s);
+
+void LinkServerSessionThread(THREAD *t, void *param);
+LINK *NewLink(CEDAR *cedar, HUB *hub, CLIENT_OPTION *option, CLIENT_AUTH *auth, POLICY *policy);
+void StartLink(LINK *k);
+void StopLink(LINK *k);
+void DelLink(HUB *hub, LINK *k);
+void LockLink(LINK *k);
+void UnlockLink(LINK *k);
+void StopAllLink(HUB *h);
+void StartAllLink(HUB *h);
+void SetLinkOnline(LINK *k);
+void SetLinkOffline(LINK *k);
+void ReleaseLink(LINK *k);
+void CleanupLink(LINK *k);
+void ReleaseAllLink(HUB *h);
+void NormalizeLinkPolicy(POLICY *p);
+
+#endif // LINK_H
+
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Listener.c b/src/Cedar/Listener.c
new file mode 100644
index 00000000..0babfac2
--- /dev/null
+++ b/src/Cedar/Listener.c
@@ -0,0 +1,1079 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Listener.c
+// Listener module
+
+#include "CedarPch.h"
+
+static bool disable_dos = false;
+static UINT max_connections_per_ip = DEFAULT_MAX_CONNECTIONS_PER_IP;
+static UINT max_unestablished_connections = DEFAULT_MAX_UNESTABLISHED_CONNECTIONS;
+static bool listener_proc_recv_rpc = false;
+
+// Set the flag of whether to response to the RPC of RUDP
+void ListenerSetProcRecvRpcEnable(bool b)
+{
+ listener_proc_recv_rpc = b;
+}
+
+// Get the number of allowed outstanding connections
+UINT GetMaxUnestablishedConnections()
+{
+ return max_unestablished_connections;
+}
+
+// Set the number of allowed outstanding connections
+void SetMaxUnestablishedConnections(UINT num)
+{
+ if (num == 0)
+ {
+ num = DEFAULT_MAX_UNESTABLISHED_CONNECTIONS;
+ }
+
+ max_unestablished_connections = MAX(num, max_connections_per_ip);
+}
+
+// Get the maximum number of connections per IP address
+UINT GetMaxConnectionsPerIp()
+{
+ return max_connections_per_ip;
+}
+
+// Set the maximum number of connections per IP address
+void SetMaxConnectionsPerIp(UINT num)
+{
+ if (num == 0)
+ {
+ num = DEFAULT_MAX_CONNECTIONS_PER_IP;
+ }
+ max_connections_per_ip = MAX(num, MIN_MAX_CONNECTIONS_PER_IP);
+}
+
+// Enable the DoS defense
+void EnableDosProtect()
+{
+ disable_dos = false;
+}
+
+// Disable the DoS defense
+void DisableDosProtect()
+{
+ disable_dos = true;
+}
+
+// An UDP packet has been received
+void UDPReceivedPacket(CEDAR *cedar, SOCK *s, IP *ip, UINT port, void *data, UINT size)
+{
+ SESSION *session;
+ UINT *key32;
+ UCHAR *buf;
+ CONNECTION *c;
+ // Validate arguments
+ if (s == NULL || ip == NULL || data == NULL || size == 0 || cedar == NULL)
+ {
+ return;
+ }
+
+ if (size < 16)
+ {
+ // Ignore since the packet size is not enough
+ return;
+ }
+ buf = (UCHAR *)data;
+ key32 = (UINT *)(buf + 4);
+
+
+ // Get the session from the Key32 value
+ session = GetSessionFromUDPEntry(cedar, Endian32(*key32));
+ if (session == NULL)
+ {
+ Debug("Invalid UDP Session Key 32: 0x%X\n", *key32);
+ return;
+ }
+
+ c = session->Connection;
+
+ // Write the data
+ PutUDPPacketData(c, buf, size);
+
+ // Rewrite the UDP socket associated with the connection
+ Lock(c->lock);
+ {
+ if (c->Protocol == CONNECTION_UDP)
+ {
+ if (c->Udp->s != s)
+ {
+ if (c->Udp->s != NULL)
+ {
+ ReleaseSock(c->Udp->s);
+ }
+ AddRef(s->ref);
+ c->Udp->s = s;
+ }
+ Copy(&c->Udp->ip, ip, sizeof(UINT));
+ c->Udp->port = port;
+ }
+ }
+ Unlock(c->lock);
+
+ // Invoke the Cancel
+ Cancel(session->Cancel1);
+
+ // Release the session
+ ReleaseSession(session);
+}
+
+// Thread that processes the accepted TCP connection
+void TCPAcceptedThread(THREAD *t, void *param)
+{
+ TCP_ACCEPTED_PARAM *data;
+ LISTENER *r;
+ SOCK *s;
+ CONNECTION *c;
+ bool flag1;
+ char tmp[128];
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Initialize
+ data = (TCP_ACCEPTED_PARAM *)param;
+ r = data->r;
+ s = data->s;
+ AddRef(r->ref);
+ AddRef(s->ref);
+
+ // Create a connection
+ c = NewServerConnection(r->Cedar, s, t);
+
+ // Register to Cedar as a transient connection
+ AddConnection(c->Cedar, c);
+
+ NoticeThreadInit(t);
+
+ AcceptInit(s);
+ StrCpy(c->ClientHostname, sizeof(c->ClientHostname), s->RemoteHostname);
+ IPToStr(tmp, sizeof(tmp), &s->RemoteIP);
+ if (IS_SPECIAL_PORT(s->RemotePort) == false)
+ {
+ SLog(r->Cedar, "LS_LISTENER_ACCEPT", r->Port, tmp, s->RemoteHostname, s->RemotePort);
+ }
+
+ // Reception
+ ConnectionAccept(c);
+ flag1 = c->flag1;
+
+ // Release
+ SLog(r->Cedar, "LS_CONNECTION_END_1", c->Name);
+ ReleaseConnection(c);
+
+ // Release
+ if (flag1 == false)
+ {
+ Debug("%s %u flag1 == false\n", __FILE__, __LINE__);
+ IPToStr(tmp, sizeof(tmp), &s->RemoteIP);
+
+ if (IS_SPECIAL_PORT(s->RemotePort) == false)
+ {
+ SLog(r->Cedar, "LS_LISTENER_DISCONNECT", tmp, s->RemotePort);
+ }
+ Disconnect(s);
+ }
+ ReleaseSock(s);
+ ReleaseListener(r);
+}
+
+// Jump here if there is accepted connection in the TCP
+void TCPAccepted(LISTENER *r, SOCK *s)
+{
+ TCP_ACCEPTED_PARAM *data;
+ THREAD *t;
+ char tmp[MAX_SIZE];
+ UINT num_clients_from_this_ip = 0;
+ CEDAR *cedar;
+ // Validate arguments
+ if (r == NULL || s == NULL)
+ {
+ return;
+ }
+
+ cedar = r->Cedar;
+
+ num_clients_from_this_ip = GetNumIpClient(&s->RemoteIP);
+
+
+ IPToStr(tmp, sizeof(tmp), &s->RemoteIP);
+
+ data = ZeroMalloc(sizeof(TCP_ACCEPTED_PARAM));
+ data->r = r;
+ data->s = s;
+
+ if (r->ThreadProc == TCPAcceptedThread)
+ {
+ Inc(cedar->AcceptingSockets);
+ }
+
+ t = NewThread(r->ThreadProc, data);
+ WaitThreadInit(t);
+ Free(data);
+ ReleaseThread(t);
+}
+
+
+// UDP listener main loop
+void ListenerUDPMainLoop(LISTENER *r)
+{
+ UCHAR *data;
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+ Debug("ListenerUDPMainLoop Starts.\n");
+ r->Status = LISTENER_STATUS_TRYING;
+
+ while (true)
+ {
+ // Try to listen on the UDP port
+ while (true)
+ {
+ // Stop flag inspection
+ if (r->Halt)
+ {
+ // Stop
+ return;
+ }
+
+ Debug("NewUDP()\n");
+ r->Sock = NewUDP(r->Port);
+ if (r->Sock != NULL)
+ {
+ // Wait success
+ break;
+ }
+
+ // Wait failure
+ Debug("Failed to NewUDP.\n");
+ Wait(r->Event, LISTEN_RETRY_TIME);
+
+ // Stop flag inspection
+ if (r->Halt)
+ {
+ Debug("UDP Halt.\n");
+ return;
+ }
+ }
+
+ r->Status = LISTENER_STATUS_LISTENING;
+ Debug("Start Listening at UDP Port %u.\n", r->Sock->LocalPort);
+
+ // Stop flag inspection
+ if (r->Halt)
+ {
+ // Stop
+ goto STOP;
+ }
+
+ // Allocate the buffer area
+ data = Malloc(UDP_PACKET_SIZE);
+
+ // Read the next packet
+ while (true)
+ {
+ IP src_ip;
+ UINT src_port;
+ UINT size;
+ SOCKSET set;
+
+ InitSockSet(&set);
+ AddSockSet(&set, r->Sock);
+ Select(&set, SELECT_TIME, NULL, NULL);
+
+ size = RecvFrom(r->Sock, &src_ip, &src_port, data, UDP_PACKET_SIZE);
+ if (((size == 0) && (r->Sock->IgnoreRecvErr == false)) || r->Halt)
+ {
+ // Error has occurred
+STOP:
+ Disconnect(r->Sock);
+ ReleaseSock(r->Sock);
+ r->Sock = NULL;
+ Debug("UDP Listen Stopped.\n");
+ Free(data);
+ break;
+ }
+
+ // Received an UDP packet
+ if (size != SOCK_LATER)
+ {
+ UDPReceivedPacket(r->Cedar, r->Sock, &src_ip, src_port, data, size);
+ }
+ }
+ }
+}
+
+// RPC reception procedure
+bool ListenerRUDPRpcRecvProc(RUDP_STACK *r, UDPPACKET *p)
+{
+ return false;
+}
+
+// TCP listener main loop
+void ListenerTCPMainLoop(LISTENER *r)
+{
+ SOCK *new_sock;
+ SOCK *s;
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+ Debug("ListenerTCPMainLoop Starts.\n");
+ r->Status = LISTENER_STATUS_TRYING;
+
+ while (true)
+ {
+ bool first_failed = true;
+ Debug("Status = LISTENER_STATUS_TRYING\n");
+ r->Status = LISTENER_STATUS_TRYING;
+
+ // Try to Listen
+ while (true)
+ {
+ UINT interval;
+ // Stop flag inspection
+ if (r->Halt)
+ {
+ // Stop
+ return;
+ }
+
+ s = NULL;
+
+ if (r->Protocol == LISTENER_TCP)
+ {
+ if (r->ShadowIPv6 == false)
+ {
+ s = ListenEx2(r->Port, r->LocalOnly, r->EnableConditionalAccept);
+ }
+ else
+ {
+ s = ListenEx6(r->Port, r->LocalOnly);
+ }
+ }
+ else if (r->Protocol == LISTENER_INPROC)
+ {
+ s = ListenInProc();
+ }
+ else if (r->Protocol == LISTENER_RUDP)
+ {
+ s = ListenRUDPEx(VPN_RUDP_SVC_NAME, NULL, ListenerRUDPRpcRecvProc, NULL, 0, false, false, r->NatTGlobalUdpPort, r->RandPortId);
+ }
+ else if (r->Protocol == LISTENER_ICMP)
+ {
+ s = ListenRUDP(VPN_RUDP_SVC_NAME, NULL, ListenerRUDPRpcRecvProc, NULL, MAKE_SPECIAL_PORT(IP_PROTO_ICMPV4),
+ true, false);
+ }
+ else if (r->Protocol == LISTENER_DNS)
+ {
+ s = ListenRUDP(VPN_RUDP_SVC_NAME, NULL, ListenerRUDPRpcRecvProc, NULL, 53, true, true);
+ }
+ else if (r->Protocol == LISTENER_REVERSE)
+ {
+ s = ListenReverse();
+ }
+
+ if (s != NULL)
+ {
+ // Listen success
+ AddRef(s->ref);
+
+ Lock(r->lock);
+ {
+ r->Sock = s;
+ }
+ Unlock(r->lock);
+
+ if (r->ShadowIPv6 == false && r->Protocol == LISTENER_TCP)
+ {
+ SLog(r->Cedar, "LS_LISTENER_START_2", r->Port);
+ }
+ break;
+ }
+
+ // Listen failure
+ if (first_failed)
+ {
+ first_failed = false;
+ if (r->ShadowIPv6 == false && r->Protocol == LISTENER_TCP)
+ {
+ SLog(r->Cedar, "LS_LISTENER_START_3", r->Port, LISTEN_RETRY_TIME / 1000);
+ }
+ }
+
+ interval = LISTEN_RETRY_TIME;
+
+ if (r->ShadowIPv6)
+ {
+ if (IsIPv6Supported() == false)
+ {
+ interval = LISTEN_RETRY_TIME_NOIPV6;
+
+ Debug("IPv6 is not supported.\n");
+ }
+ }
+
+ Wait(r->Event, interval);
+
+ // Stop flag inspection
+ if (r->Halt)
+ {
+ // Stop
+ Debug("Listener Halt.\n");
+ return;
+ }
+ }
+
+ r->Status = LISTENER_STATUS_LISTENING;
+ Debug("Status = LISTENER_STATUS_LISTENING\n");
+
+ // Stop flag inspection
+ if (r->Halt)
+ {
+ // Stop
+ goto STOP;
+ }
+
+ // Accpet loop
+ while (true)
+ {
+ // Accept
+ Debug("Accept()\n");
+ new_sock = Accept(s);
+ if (new_sock != NULL)
+ {
+ // Accept success
+ Debug("Accepted.\n");
+ TCPAccepted(r, new_sock);
+ ReleaseSock(new_sock);
+ }
+ else
+ {
+STOP:
+ Debug("Accept Canceled.\n");
+ // Failed to accept (socket is destroyed)
+ // Close the listening socket
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+
+ Lock(r->lock);
+ {
+ if (r->Sock != NULL)
+ {
+ s = r->Sock;
+ r->Sock = NULL;
+ }
+ }
+ Unlock(r->lock);
+
+ if (s != NULL)
+ {
+ ReleaseSock(s);
+ }
+
+ s = NULL;
+
+ break;
+ }
+ }
+
+ // Stop flag inspection
+ if (r->Halt)
+ {
+ // Stop
+ Debug("Listener Halt.\n");
+ return;
+ }
+ }
+}
+
+// Listener Thread
+void ListenerThread(THREAD *thread, void *param)
+{
+ LISTENER *r;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Initialize
+ r = (LISTENER *)param;
+ AddRef(r->ref);
+ r->Thread = thread;
+ AddRef(thread->ref);
+ NoticeThreadInit(thread);
+
+ // Main loop
+ switch (r->Protocol)
+ {
+ case LISTENER_TCP:
+ case LISTENER_INPROC:
+ case LISTENER_RUDP:
+ case LISTENER_DNS:
+ case LISTENER_ICMP:
+ case LISTENER_REVERSE:
+ // TCP or other stream-based protocol
+ ListenerTCPMainLoop(r);
+ break;
+
+ case LISTENER_UDP:
+ // UDP protocol
+ ListenerUDPMainLoop(r);
+ break;
+ }
+
+ // Release
+ ReleaseListener(r);
+}
+
+// Shutdown the Listener
+void StopListener(LISTENER *r)
+{
+ UINT port;
+ SOCK *s = NULL;
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+ Lock(r->lock);
+ if (r->Halt)
+ {
+ Unlock(r->lock);
+ return;
+ }
+
+ // Stop flag set
+ r->Halt = true;
+
+ if (r->Sock != NULL)
+ {
+ s = r->Sock;
+
+ AddRef(s->ref);
+ }
+
+ Unlock(r->lock);
+
+ port = r->Port;
+
+ if (r->ShadowIPv6 == false && r->Protocol == LISTENER_TCP)
+ {
+ SLog(r->Cedar, "LS_LISTENER_STOP_1", port);
+ }
+
+ // Close the socket
+ if (s != NULL)
+ {
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+ }
+
+ // Set the event
+ Set(r->Event);
+
+ // Wait for stopping the thread
+ WaitThread(r->Thread, INFINITE);
+
+ // Stop the shadow listener
+ if (r->ShadowIPv6 == false)
+ {
+ if (r->ShadowListener != NULL)
+ {
+ StopListener(r->ShadowListener);
+
+ ReleaseListener(r->ShadowListener);
+
+ r->ShadowListener = NULL;
+ }
+ }
+
+ if (r->ShadowIPv6 == false && r->Protocol == LISTENER_TCP)
+ {
+ SLog(r->Cedar, "LS_LISTENER_STOP_2", port);
+ }
+}
+
+// Cleanup the listener
+void CleanupListener(LISTENER *r)
+{
+ UINT i = 0;
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+
+ if (r->Sock != NULL)
+ {
+ ReleaseSock(r->Sock);
+ }
+
+ DeleteLock(r->lock);
+ ReleaseThread(r->Thread);
+ ReleaseEvent(r->Event);
+
+ ReleaseCedar(r->Cedar);
+
+ Free(r);
+}
+
+// Release the listener
+void ReleaseListener(LISTENER *r)
+{
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+ if (Release(r->ref) == 0)
+ {
+ CleanupListener(r);
+ }
+}
+
+// Comparison function of UDP entry list
+int CompareUDPEntry(void *p1, void *p2)
+{
+ UDP_ENTRY *e1, *e2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ e1 = *(UDP_ENTRY **)p1;
+ e2 = *(UDP_ENTRY **)p2;
+ if (e1 == NULL || e2 == NULL)
+ {
+ return 0;
+ }
+
+ if (e1->SessionKey32 > e2->SessionKey32)
+ {
+ return 1;
+ }
+ else if (e1->SessionKey32 == e2->SessionKey32)
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+// Comparison function of the listener
+int CompareListener(void *p1, void *p2)
+{
+ LISTENER *r1, *r2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ r1 = *(LISTENER **)p1;
+ r2 = *(LISTENER **)p2;
+ if (r1 == NULL || r2 == NULL)
+ {
+ return 0;
+ }
+
+ if (r1->Protocol > r2->Protocol)
+ {
+ return 1;
+ }
+ else if (r1->Protocol < r2->Protocol)
+ {
+ return -1;
+ }
+ else if (r1->Port > r2->Port)
+ {
+ return 1;
+ }
+ else if (r1->Port < r2->Port)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// Create a New Listener
+LISTENER *NewListener(CEDAR *cedar, UINT proto, UINT port)
+{
+ return NewListenerEx(cedar, proto, port, TCPAcceptedThread, NULL);
+}
+LISTENER *NewListenerEx(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param)
+{
+ return NewListenerEx2(cedar, proto, port, proc, thread_param, false);
+}
+LISTENER *NewListenerEx2(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only)
+{
+ return NewListenerEx3(cedar, proto, port, proc, thread_param, local_only, false);
+}
+LISTENER *NewListenerEx3(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only, bool shadow_ipv6)
+{
+ return NewListenerEx4(cedar, proto, port, proc, thread_param, local_only, shadow_ipv6, NULL, 0);
+}
+LISTENER *NewListenerEx4(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only, bool shadow_ipv6,
+ volatile UINT *natt_global_udp_port, UCHAR rand_port_id)
+{
+ return NewListenerEx5(cedar, proto, port, proc, thread_param,
+ local_only, shadow_ipv6, natt_global_udp_port, rand_port_id, false);
+}
+LISTENER *NewListenerEx5(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only, bool shadow_ipv6,
+ volatile UINT *natt_global_udp_port, UCHAR rand_port_id, bool enable_ca)
+{
+ LISTENER *r;
+ THREAD *t;
+ // Validate arguments
+ if ((proto == LISTENER_TCP && port == 0) || cedar == NULL)
+ {
+ return NULL;
+ }
+ // Check the protocol number
+ if (proto != LISTENER_TCP && proto != LISTENER_INPROC &&
+ proto != LISTENER_RUDP && proto != LISTENER_ICMP && proto != LISTENER_DNS &&
+ proto != LISTENER_REVERSE)
+ {
+ return NULL;
+ }
+
+ r = ZeroMalloc(sizeof(LISTENER));
+
+ r->ThreadProc = proc;
+ r->ThreadParam = thread_param;
+ r->Cedar = cedar;
+ AddRef(r->Cedar->ref);
+ r->lock = NewLock();
+ r->ref = NewRef();
+ r->Protocol = proto;
+ r->Port = port;
+ r->Event = NewEvent();
+
+
+ r->LocalOnly = local_only;
+ r->ShadowIPv6 = shadow_ipv6;
+ r->NatTGlobalUdpPort = natt_global_udp_port;
+ r->RandPortId = rand_port_id;
+ r->EnableConditionalAccept = enable_ca;
+
+ if (r->ShadowIPv6 == false)
+ {
+ if (proto == LISTENER_TCP)
+ {
+ SLog(cedar, "LS_LISTENER_START_1", port);
+ }
+ }
+
+ // Creating a thread
+ t = NewThread(ListenerThread, r);
+ WaitThreadInit(t);
+ ReleaseThread(t);
+
+ if (r->ShadowIPv6 == false && proto == LISTENER_TCP)
+ {
+ if (r->Cedar->DisableIPv6Listener == false)
+ {
+ // Add a shadow listener
+ r->ShadowListener = NewListenerEx3(cedar, proto, port, proc, thread_param,
+ local_only, true);
+ }
+ }
+
+ if (r->ShadowIPv6 == false)
+ {
+ // Add to the Cedar
+ AddListener(cedar, r);
+ }
+
+ return r;
+}
+
+// Get the session from the session key
+SESSION *GetSessionFromUDPEntry(CEDAR *cedar, UINT key32)
+{
+ UDP_ENTRY *e, t;
+ SESSION *s;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ t.SessionKey32 = key32;
+
+ LockList(cedar->UDPEntryList);
+ {
+ e = Search(cedar->UDPEntryList, &t);
+ if (e == NULL)
+ {
+ UnlockList(cedar->UDPEntryList);
+ return NULL;
+ }
+ s = e->Session;
+ AddRef(s->ref);
+ }
+ UnlockList(cedar->UDPEntryList);
+
+ return s;
+}
+
+// Delete the UDP session from the UDP entry
+void DelUDPEntry(CEDAR *cedar, SESSION *session)
+{
+ UINT num, i;
+ // Validate arguments
+ if (cedar == NULL || session == NULL)
+ {
+ return;
+ }
+
+ LockList(cedar->UDPEntryList);
+ {
+ num = LIST_NUM(cedar->UDPEntryList);
+ for (i = 0;i < num;i++)
+ {
+ UDP_ENTRY *e = LIST_DATA(cedar->UDPEntryList, i);
+ if (e->Session == session)
+ {
+ ReleaseSession(e->Session);
+ Delete(cedar->UDPEntryList, e);
+ Free(e);
+ UnlockList(cedar->UDPEntryList);
+ Debug("UDP_Entry Deleted.\n");
+ return;
+ }
+ }
+ }
+ UnlockList(cedar->UDPEntryList);
+}
+
+// Add an UDP session to the UDP entry
+void AddUDPEntry(CEDAR *cedar, SESSION *session)
+{
+ UDP_ENTRY *e;
+ // Validate arguments
+ if (cedar == NULL || session == NULL)
+ {
+ return;
+ }
+
+ e = ZeroMalloc(sizeof(UDP_ENTRY));
+ e->Session = session;
+ e->SessionKey32 = session->SessionKey32;
+ AddRef(session->ref);
+
+ LockList(cedar->UDPEntryList);
+ {
+ Add(cedar->UDPEntryList, e);
+ }
+ UnlockList(cedar->UDPEntryList);
+
+ Debug("UDP_Entry Added.\n");
+}
+
+// Clear the UDP entry
+void CleanupUDPEntry(CEDAR *cedar)
+{
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return;
+ }
+}
+
+// Create a new dynamic listener
+DYNAMIC_LISTENER *NewDynamicListener(CEDAR *c, bool *enable_ptr, UINT protocol, UINT port)
+{
+ DYNAMIC_LISTENER *d;
+ // Validate arguments
+ if (c == NULL || enable_ptr == NULL)
+ {
+ return NULL;
+ }
+
+ d = ZeroMalloc(sizeof(DYNAMIC_LISTENER));
+
+ d->Cedar = c;
+ AddRef(d->Cedar->ref);
+
+ d->Lock = NewLock();
+
+ d->EnablePtr = enable_ptr;
+
+ d->Listener = NULL;
+
+ d->Protocol = protocol;
+ d->Port = port;
+
+ ApplyDynamicListener(d);
+
+ return d;
+}
+
+// Release the dynamic listener
+void FreeDynamicListener(DYNAMIC_LISTENER *d)
+{
+ // Validate arguments
+ if (d == NULL)
+ {
+ return;
+ }
+
+ Lock(d->Lock);
+ {
+ if (d->Listener != NULL)
+ {
+ StopListener(d->Listener);
+ ReleaseListener(d->Listener);
+ d->Listener = NULL;
+ }
+ }
+ Unlock(d->Lock);
+
+ ReleaseCedar(d->Cedar);
+
+ DeleteLock(d->Lock);
+
+ Free(d);
+}
+
+// Set the state to dynamic listener
+void ApplyDynamicListener(DYNAMIC_LISTENER *d)
+{
+ // Validate arguments
+ if (d == NULL)
+ {
+ return;
+ }
+
+ Lock(d->Lock);
+ {
+ // Change the state
+ if (*d->EnablePtr)
+ {
+ if (d->Listener == NULL)
+ {
+ // Create a listener
+ WHERE;
+ d->Listener = NewListener(d->Cedar, d->Protocol, d->Port);
+ }
+ }
+ else
+ {
+ // Stop the listener
+ if (d->Listener != NULL)
+ {
+ WHERE;
+ StopListener(d->Listener);
+ ReleaseListener(d->Listener);
+ d->Listener = NULL;
+ }
+ }
+ }
+ Unlock(d->Lock);
+}
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Listener.h b/src/Cedar/Listener.h
new file mode 100644
index 00000000..454b5f87
--- /dev/null
+++ b/src/Cedar/Listener.h
@@ -0,0 +1,188 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Listener.h
+// Header of Listener.c
+
+#ifndef LISTENER_H
+#define LISTENER_H
+
+
+// Function to call when receiving a new connection
+typedef void (NEW_CONNECTION_PROC)(CONNECTION *c);
+
+
+
+// Listener structure
+struct LISTENER
+{
+ LOCK *lock; // Lock
+ REF *ref; // Reference counter
+ CEDAR *Cedar; // Cedar
+ UINT Protocol; // Protocol
+ UINT Port; // Port number
+ THREAD *Thread; // Operating thread
+ SOCK *Sock; // Socket
+ EVENT *Event; // Event
+ volatile bool Halt; // Halting flag
+ UINT Status; // State
+
+
+ THREAD_PROC *ThreadProc; // Thread procedure
+ void *ThreadParam; // Thread parameters
+ bool LocalOnly; // Can be connected only from localhost
+ bool ShadowIPv6; // Flag indicating that the shadow IPv6 listener
+ LISTENER *ShadowListener; // Reference to managing shadow IPv6 listener
+ bool DisableDos; // Disable the DoS attack detection
+ volatile UINT *NatTGlobalUdpPort; // NAT-T global UDP port number
+ UCHAR RandPortId; // NAT-T UDP random port ID
+ bool EnableConditionalAccept; // The flag of whether to enable the Conditional Accept
+};
+
+// Parameters of TCPAcceptedThread
+struct TCP_ACCEPTED_PARAM
+{
+ LISTENER *r;
+ SOCK *s;
+};
+
+// UDP entry
+struct UDP_ENTRY
+{
+ UINT SessionKey32; // 32bit session key
+ SESSION *Session; // Reference to the session
+};
+
+// Dynamic listener
+struct DYNAMIC_LISTENER
+{
+ UINT Protocol; // Protocol
+ UINT Port; // Port
+ LOCK *Lock; // Lock
+ CEDAR *Cedar; // Cedar
+ bool *EnablePtr; // A pointer to the flag of the valid / invalid state
+ LISTENER *Listener; // Listener
+};
+
+
+// Function prototype
+LISTENER *NewListener(CEDAR *cedar, UINT proto, UINT port);
+LISTENER *NewListenerEx(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param);
+LISTENER *NewListenerEx2(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only);
+LISTENER *NewListenerEx3(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only, bool shadow_ipv6);
+LISTENER *NewListenerEx4(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only, bool shadow_ipv6,
+ volatile UINT *natt_global_udp_port, UCHAR rand_port_id);
+LISTENER *NewListenerEx5(CEDAR *cedar, UINT proto, UINT port, THREAD_PROC *proc, void *thread_param, bool local_only, bool shadow_ipv6,
+ volatile UINT *natt_global_udp_port, UCHAR rand_port_id, bool enable_ca);
+void ReleaseListener(LISTENER *r);
+void CleanupListener(LISTENER *r);
+void ListenerThread(THREAD *thread, void *param);
+void ListenerTCPMainLoop(LISTENER *r);
+void StopListener(LISTENER *r);
+int CompareListener(void *p1, void *p2);
+void TCPAccepted(LISTENER *r, SOCK *s);
+void EnableDosProtect();
+void DisableDosProtect();
+void TCPAcceptedThread(THREAD *t, void *param);
+void ListenerUDPMainLoop(LISTENER *r);
+void UDPReceivedPacket(CEDAR *cedar, SOCK *s, IP *ip, UINT port, void *data, UINT size);
+int CompareUDPEntry(void *p1, void *p2);
+void CleanupUDPEntry(CEDAR *cedar);
+void AddUDPEntry(CEDAR *cedar, SESSION *session);
+void DelUDPEntry(CEDAR *cedar, SESSION *session);
+SESSION *GetSessionFromUDPEntry(CEDAR *cedar, UINT key32);
+UINT GetMaxConnectionsPerIp();
+void SetMaxConnectionsPerIp(UINT num);
+UINT GetMaxUnestablishedConnections();
+void SetMaxUnestablishedConnections(UINT num);
+DYNAMIC_LISTENER *NewDynamicListener(CEDAR *c, bool *enable_ptr, UINT protocol, UINT port);
+void ApplyDynamicListener(DYNAMIC_LISTENER *d);
+void FreeDynamicListener(DYNAMIC_LISTENER *d);
+bool ListenerRUDPRpcRecvProc(RUDP_STACK *r, UDPPACKET *p);
+void ListenerSetProcRecvRpcEnable(bool b);
+
+
+#endif // LISTENER_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Logging.c b/src/Cedar/Logging.c
new file mode 100644
index 00000000..a5bcf2d8
--- /dev/null
+++ b/src/Cedar/Logging.c
@@ -0,0 +1,2054 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Logging.c
+// Log storaging module
+
+#include "CedarPch.h"
+
+static char *delete_targets[] =
+{
+ "backup.vpn_bridge.config",
+ "backup.vpn_client.config",
+ "backup.vpn_server.config",
+ "backup.vpn_gate_svc.config",
+ "backup.etherlogger.config",
+ "packet_log",
+ "etherlogger_log",
+ "secure_nat_log",
+ "security_log",
+ "server_log",
+ "bridge_log",
+ "packet_log_archive",
+};
+
+// Send with syslog
+void SendSysLog(SLOG *g, wchar_t *str)
+{
+}
+
+// Release the syslog client
+void FreeSysLog(SLOG *g)
+{
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ DeleteLock(g->lock);
+ ReleaseSock(g->Udp);
+ Free(g);
+}
+
+// Configure the syslog client
+void SetSysLog(SLOG *g, char *hostname, UINT port)
+{
+ IP ip;
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+ if (port == 0)
+ {
+ port = SYSLOG_PORT;
+ }
+
+ if (hostname == NULL)
+ {
+ hostname = "";
+ }
+
+ Zero(&ip, sizeof(IP));
+ GetIP(&ip, hostname);
+
+ Lock(g->lock);
+ {
+ Copy(&g->DestIp, &ip, sizeof(IP));
+ g->DestPort = port;
+ StrCpy(g->HostName, sizeof(g->HostName), hostname);
+ g->NextPollIp = Tick64() + IsZeroIp(&ip) ? SYSLOG_POLL_IP_INTERVAL_NG : SYSLOG_POLL_IP_INTERVAL;
+ }
+ Unlock(g->lock);
+}
+
+// Create a syslog client
+SLOG *NewSysLog(char *hostname, UINT port)
+{
+ // Validate arguments
+ SLOG *g = ZeroMalloc(sizeof(SLOG));
+
+ g->lock = NewLock();
+ g->Udp = NewUDP(0);
+
+ SetSysLog(g, hostname, port);
+
+ return g;
+}
+
+// Check if there is enough free space on the disk
+bool CheckEraserDiskFreeSpace(ERASER *e)
+{
+ UINT64 s;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return true;
+ }
+
+ // Get the free disk space
+ if (GetDiskFree(e->DirName, &s, NULL, NULL) == false)
+ {
+ // Acquisition failure
+ return true;
+ }
+
+ if (e->MinFreeSpace > s)
+ {
+ // The free space is smaller than specified bytes
+ return false;
+ }
+
+ // Vacant enough
+ return true;
+}
+
+// Release the deleting file list
+void FreeEraseFileList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ ERASE_FILE *f = LIST_DATA(o, i);
+ Free(f->FullPath);
+ Free(f);
+ }
+
+ ReleaseList(o);
+}
+
+// Show the deleting file list
+void PrintEraseFileList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ ERASE_FILE *f = LIST_DATA(o, i);
+ Print("%I64u - %s\n", f->UpdateTime, f->FullPath);
+ }
+}
+
+// Generate a deleting file list of the specified directory
+void EnumEraseFile(LIST *o, char *dirname)
+{
+ DIRLIST *dir;
+ UINT i;
+ char tmp[MAX_PATH];
+ // Validate arguments
+ if (o == NULL || dirname == NULL)
+ {
+ return;
+ }
+
+ // Enumeration
+ dir = EnumDir(dirname);
+
+ for (i = 0;i < dir->NumFiles;i++)
+ {
+ DIRENT *e = dir->File[i];
+ Format(tmp, sizeof(tmp), "%s/%s", dirname, e->FileName);
+ NormalizePath(tmp, sizeof(tmp), tmp);
+
+ if (e->Folder == false)
+ {
+ // File
+ ERASE_FILE *f;
+
+ if (EndWith(tmp, ".log") || EndWith(tmp, ".config") || EndWith(tmp, ".old"))
+ {
+ // Target only .config files and .log files
+ f = ZeroMalloc(sizeof(ERASE_FILE));
+ f->FullPath = CopyStr(tmp);
+ f->UpdateTime = e->UpdateDate;
+
+ Add(o, f);
+ }
+ }
+ else
+ {
+ // Folder
+ EnumEraseFile(o, tmp);
+ }
+ }
+
+ FreeDir(dir);
+}
+
+// Generate a deleting file list
+LIST *GenerateEraseFileList(ERASER *e)
+{
+ LIST *o;
+ UINT i;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return NULL;
+ }
+
+ o = NewListFast(CompareEraseFile);
+
+ // Scan for each directory
+ for (i = 0;i < sizeof(delete_targets) / sizeof(delete_targets[0]);i++)
+ {
+ char dirname[MAX_PATH];
+ Format(dirname, sizeof(dirname), "%s/%s", e->DirName, delete_targets[i]);
+
+ EnumEraseFile(o, dirname);
+ }
+
+ // Sort
+ Sort(o);
+
+ return o;
+}
+
+// Process of erasing unnecessary files
+void EraserMain(ERASER *e)
+{
+ LIST *o;
+ UINT i;
+ bool ok = false;
+ char bs[64];
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ // Check the free space first
+ if (CheckEraserDiskFreeSpace(e))
+ {
+ // Vacant enough
+ return;
+ }
+
+ ToStrByte(bs, sizeof(bs), e->MinFreeSpace);
+
+ // Generate the file list
+ o = GenerateEraseFileList(e);
+
+ // Try to delete one by one in order from oldest file
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ ERASE_FILE *f = LIST_DATA(o, i);
+
+ // Delete the file
+ if (FileDelete(f->FullPath))
+ {
+ ELog(e, "LE_DELETE", bs, f->FullPath);
+ }
+
+ // Check the free space after the deleted
+ if (CheckEraserDiskFreeSpace(e))
+ {
+ // Free space has been restored
+ ok = true;
+ break;
+ }
+ }
+
+ // Release the file list
+ FreeEraseFileList(o);
+
+ if (e->LastFailed == false && ok == false)
+ {
+ // Free space is not enough, but can not delete the file any more
+ ELog(e, "LE_NOT_ENOUGH_FREE", bs);
+ }
+
+ e->LastFailed = ok ? false : true;
+}
+
+// Comparison of the deleting file entries
+int CompareEraseFile(void *p1, void *p2)
+{
+ ERASE_FILE *f1, *f2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ f1 = *(ERASE_FILE **)p1;
+ f2 = *(ERASE_FILE **)p2;
+ if (f1 == NULL || f2 == NULL)
+ {
+ return 0;
+ }
+ if (f1->UpdateTime > f2->UpdateTime)
+ {
+ return 1;
+ }
+ else if (f1->UpdateTime == f2->UpdateTime)
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+// Eraser thread
+void EraserThread(THREAD *t, void *p)
+{
+ ERASER *e = (ERASER *)p;
+ char bs[64];
+ // Validate arguments
+ if (t == NULL || e == NULL)
+ {
+ return;
+ }
+
+ // Start monitoring
+ ToStrByte(bs, sizeof(bs), e->MinFreeSpace);
+ ELog(e, "LE_START", e->DirName, bs);
+
+ while (e->Halt == false)
+ {
+ // Check the amount of free space on the disk periodically
+ EraserMain(e);
+
+ Wait(e->HaltEvent, DISK_FREE_CHECK_INTERVAL);
+ }
+}
+
+// Create a new eraser
+ERASER *NewEraser(LOG *log, UINT64 min_size)
+{
+ ERASER *e;
+ char dir[MAX_PATH];
+
+ if (min_size == 0)
+ {
+ if (OS_IS_WINDOWS(GetOsInfo()->OsType))
+ {
+ min_size = DISK_FREE_SPACE_DEFAULT_WINDOWS;
+ }
+ else
+ {
+ min_size = DISK_FREE_SPACE_DEFAULT;
+ }
+ }
+
+ if (min_size < DISK_FREE_SPACE_MIN)
+ {
+ min_size = DISK_FREE_SPACE_MIN;
+ }
+
+ e = ZeroMalloc(sizeof(ERASER));
+
+ GetExeDir(dir, sizeof(dir));
+
+ e->Log = log;
+ e->MinFreeSpace = min_size;
+ e->DirName = CopyStr(dir);
+ e->HaltEvent = NewEvent();
+
+ e->Thread = NewThread(EraserThread, e);
+
+ return e;
+}
+
+// Release the eraser
+void FreeEraser(ERASER *e)
+{
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ e->Halt = true;
+ Set(e->HaltEvent);
+ WaitThread(e->Thread, INFINITE);
+ ReleaseThread(e->Thread);
+ ReleaseEvent(e->HaltEvent);
+
+ Free(e->DirName);
+ Free(e);
+}
+
+// Take the debug log (variable-length argument)
+void DebugLog(CEDAR *c, char *fmt, ...)
+{
+ char buf[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (fmt == NULL)
+ {
+ return;
+ }
+ if (c->DebugLog == NULL)
+ {
+ return;
+ }
+
+ va_start(args, fmt);
+ FormatArgs(buf, sizeof(buf), fmt, args);
+
+ InsertStringRecord(c->DebugLog, buf);
+ va_end(args);
+}
+
+// Take the log of eraser
+void ELog(ERASER *e, char *name, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return;
+ }
+
+ va_start(args, name);
+ UniFormatArgs(buf, sizeof(buf), _UU(name), args);
+
+ InsertUnicodeRecord(e->Log, buf);
+
+ if (IsDebug())
+ {
+ UniPrint(L"LOG: %s\n", buf);
+ }
+ va_end(args);
+}
+
+// Take the log of the server
+void ServerLog(CEDAR *c, wchar_t *fmt, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (fmt == NULL)
+ {
+ return;
+ }
+
+ va_start(args, fmt);
+ UniFormatArgs(buf, sizeof(buf), fmt, args);
+
+ WriteServerLog(c, buf);
+ va_end(args);
+}
+void SLog(CEDAR *c, char *name, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return;
+ }
+
+ va_start(args, name);
+ UniFormatArgs(buf, sizeof(buf), _UU(name), args);
+
+ WriteServerLog(c, buf);
+ va_end(args);
+}
+
+// Client log
+void CLog(CLIENT *c, char *name, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return;
+ }
+
+ if (c == NULL || c->NoSaveLog)
+ {
+ return;
+ }
+
+ va_start(args, name);
+ UniFormatArgs(buf, sizeof(buf), _UU(name), args);
+
+ WriteClientLog(c, buf);
+ va_end(args);
+}
+
+// Take the security log of the HUB
+void HubLog(HUB *h, wchar_t *fmt, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (fmt == NULL)
+ {
+ return;
+ }
+
+ va_start(args, fmt);
+ UniFormatArgs(buf, sizeof(buf), fmt, args);
+
+ WriteHubLog(h, buf);
+ va_end(args);
+}
+void ALog(ADMIN *a, HUB *h, char *name, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ wchar_t tmp[MAX_SIZE * 2];
+ va_list args;
+ RPC *r;
+ // Validate arguments
+ if (a == NULL || name == NULL)
+ {
+ return;
+ }
+
+ r = a->Rpc;
+
+ va_start(args, name);
+ UniFormatArgs(buf, sizeof(buf), _UU(name), args);
+
+ if (h == NULL)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("LA_TAG_1"), r->Name);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("LA_TAG_2"), r->Name, h->Name);
+ }
+
+ UniStrCat(tmp, sizeof(tmp), buf);
+
+ if (h == NULL)
+ {
+ WriteServerLog(((ADMIN *)r->Param)->Server->Cedar, tmp);
+ }
+ else
+ {
+ WriteHubLog(h, tmp);
+ }
+ va_end(args);
+}
+void HLog(HUB *h, char *name, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return;
+ }
+
+ va_start(args, name);
+ UniFormatArgs(buf, sizeof(buf), _UU(name), args);
+
+ WriteHubLog(h, buf);
+ va_end(args);
+}
+void NLog(VH *v, char *name, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ static wchar_t snat_prefix[] = L"SecureNAT: ";
+ va_list args;
+ // Validate arguments
+ if (name == NULL || v == NULL || v->nat == NULL || v->nat->SecureNAT == NULL || v->SaveLog == false)
+ {
+ return;
+ }
+
+ va_start(args, name);
+ Copy(buf, snat_prefix, sizeof(snat_prefix));
+ UniFormatArgs(&buf[11], sizeof(buf) - 12 * sizeof(wchar_t), _UU(name), args);
+
+ WriteHubLog(v->nat->SecureNAT->Hub, buf);
+ va_end(args);
+}
+
+// Writing EtherIP log
+void EtherIPLog(ETHERIP_SERVER *s, char *name, ...)
+{
+ wchar_t prefix[MAX_SIZE * 2];
+ wchar_t buf2[MAX_SIZE * 2];
+ char server_ip[64];
+ char client_ip[64];
+ va_list args;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ IPToStr(server_ip, sizeof(server_ip), &s->ServerIP);
+ IPToStr(client_ip, sizeof(client_ip), &s->ClientIP);
+
+ UniFormat(prefix, sizeof(prefix), _UU("LE_PREFIX"), s->Id,
+ server_ip, s->ServerPort, client_ip, s->ClientPort);
+
+ va_start(args, name);
+ UniFormatArgs(buf2, sizeof(buf2), _UU(name), args);
+ va_end(args);
+
+ UniStrCat(prefix, sizeof(prefix), buf2);
+
+ WriteServerLog(s->Cedar, prefix);
+}
+
+// Write an IPsec log
+void IPsecLog(IKE_SERVER *ike, IKE_CLIENT *c, IKE_SA *ike_sa, IPSECSA *ipsec_sa, char *name, ...)
+{
+ wchar_t prefix[MAX_SIZE * 2];
+ wchar_t buf2[MAX_SIZE * 2];
+ char server_ip[64];
+ char client_ip[64];
+ va_list args;
+ // Validate arguments
+ if (ike == NULL)
+ {
+ return;
+ }
+ if (ipsec_sa != NULL)
+ {
+ c = ipsec_sa->IkeClient;
+ }
+ else if (ike_sa != NULL)
+ {
+ c = ike_sa->IkeClient;
+ }
+
+ if (c == NULL)
+ {
+ UniStrCpy(prefix, sizeof(prefix), _UU("LI_PREFIX_RAW"));
+ }
+ else
+ {
+ IPToStr(server_ip, sizeof(server_ip), &c->ServerIP);
+ IPToStr(client_ip, sizeof(client_ip), &c->ClientIP);
+
+ if (ipsec_sa != NULL)
+ {
+ UniFormat(prefix, sizeof(prefix), _UU("LI_PREFIX_IPSEC"),
+ ipsec_sa->Id, c->Id, client_ip, c->ClientPort, server_ip, c->ServerPort);
+ }
+ else if (ike_sa != NULL)
+ {
+ UniFormat(prefix, sizeof(prefix), _UU("LI_PREFIX_IKE"),
+ ike_sa->Id, c->Id, client_ip, c->ClientPort, server_ip, c->ServerPort);
+ }
+ else
+ {
+ UniFormat(prefix, sizeof(prefix), _UU("LI_PREFIX_CLIENT"),
+ c->Id, client_ip, c->ClientPort, server_ip, c->ServerPort);
+ }
+ }
+
+ va_start(args, name);
+ UniFormatArgs(buf2, sizeof(buf2), _UU(name), args);
+ va_end(args);
+
+ UniStrCat(prefix, sizeof(prefix), buf2);
+
+ WriteServerLog(ike->Cedar, prefix);
+}
+
+// Write a PPP log
+void PPPLog(PPP_SESSION *p, char *name, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ wchar_t buf2[MAX_SIZE * 2];
+ char ipstr[128];
+ char *s1 = "", *s2 = "";
+ va_list args;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ if (StrCmpi(p->Postfix, "PPP") != 0)
+ {
+ s1 = p->Postfix;
+ s2 = " ";
+ }
+
+ va_start(args, name);
+ UniFormatArgs(buf2, sizeof(buf2), _UU(name), args);
+ va_end(args);
+
+ IPToStr(ipstr, sizeof(ipstr), &p->ClientIP);
+
+ UniFormat(buf, sizeof(buf), _UU("LP_PREFIX"), s1, s2, ipstr, p->ClientPort);
+
+ UniStrCat(buf, sizeof(buf), buf2);
+
+ WriteServerLog(p->Cedar, buf);
+}
+
+// Write an IPC log
+void IPCLog(IPC *ipc, char *name, ...)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ va_list args;
+ HUB *h;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return;
+ }
+
+ h = GetHub(ipc->Cedar, ipc->HubName);
+
+ if (h == NULL)
+ {
+ return;
+ }
+
+ va_start(args, name);
+ UniFormatArgs(buf, sizeof(buf), _UU(name), args);
+
+ WriteHubLog(h, buf);
+ va_end(args);
+
+ ReleaseHub(h);
+}
+
+// Save the security log of the HUB
+void WriteHubLog(HUB *h, wchar_t *str)
+{
+ wchar_t buf[MAX_SIZE * 2];
+ UINT syslog_status;
+ SERVER *s;
+ // Validate arguments
+ if (h == NULL || str == NULL)
+ {
+ return;
+ }
+
+ s = h->Cedar->Server;
+ syslog_status = SiGetSysLogSaveStatus(s);
+
+ UniFormat(buf, sizeof(buf), L"[HUB \"%S\"] %s", h->Name, str);
+
+ if (syslog_status == SYSLOG_NONE)
+ {
+ WriteServerLog(h->Cedar, buf);
+ }
+
+ if (h->LogSetting.SaveSecurityLog == false)
+ {
+ return;
+ }
+
+ if (syslog_status == SYSLOG_SERVER_AND_HUB_SECURITY_LOG
+ || syslog_status == SYSLOG_SERVER_AND_HUB_ALL_LOG)
+ {
+ SiWriteSysLog(s, "SECURITY_LOG", h->Name, str);
+ }
+ else
+ {
+ InsertUnicodeRecord(h->SecurityLogger, str);
+ }
+}
+
+// Save the client log
+void WriteClientLog(CLIENT *c, wchar_t *str)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ InsertUnicodeRecord(c->Logger, str);
+}
+
+// Save the security log of the server
+void WriteServerLog(CEDAR *c, wchar_t *str)
+{
+ SERVER *s;
+ // Validate arguments
+ if (c == NULL || str == NULL)
+ {
+ return;
+ }
+
+ s = c->Server;
+ if (s == NULL)
+ {
+ return;
+ }
+
+ if (IsDebug())
+ {
+ UniPrint(L"LOG: %s\n", str);
+ }
+
+ if (SiGetSysLogSaveStatus(s) != SYSLOG_NONE)
+ {
+ SiWriteSysLog(s, "SERVER_LOG", NULL, str);
+ }
+ else
+ {
+ InsertUnicodeRecord(s->Logger, str);
+ }
+}
+
+// Write a multi-line log
+void WriteMultiLineLog(LOG *g, BUF *b)
+{
+ // Validate arguments
+ if (g == NULL || b == NULL)
+ {
+ return;
+ }
+
+ SeekBuf(b, 0, 0);
+
+ while (true)
+ {
+ char *s = CfgReadNextLine(b);
+ if (s == NULL)
+ {
+ break;
+ }
+
+ if (IsEmptyStr(s) == false)
+ {
+ InsertStringRecord(g, s);
+ }
+
+ Free(s);
+ }
+}
+
+// Take the security log (variable-length argument) *abolished
+void SecLog(HUB *h, char *fmt, ...)
+{
+ char buf[MAX_SIZE * 2];
+ va_list args;
+ // Validate arguments
+ if (fmt == NULL)
+ {
+ return;
+ }
+
+ if (h->LogSetting.SaveSecurityLog == false)
+ {
+ return;
+ }
+
+ va_start(args, fmt);
+ FormatArgs(buf, sizeof(buf), fmt, args);
+
+ WriteSecurityLog(h, buf);
+ va_end(args);
+}
+
+// Take a security log
+void WriteSecurityLog(HUB *h, char *str)
+{
+ // Validate arguments
+ if (h == NULL || str == NULL)
+ {
+ return;
+ }
+
+ InsertStringRecord(h->SecurityLogger, str);
+}
+
+// Take a packet log
+bool PacketLog(HUB *hub, SESSION *src_session, SESSION *dest_session, PKT *packet, UINT64 now)
+{
+ return true;
+}
+
+// Calculate the logging level of the specified packet
+UINT CalcPacketLoggingLevelEx(HUB_LOG *g, PKT *packet)
+{
+ UINT ret = 0;
+ // Validate arguments
+ if (g == NULL || packet == NULL)
+ {
+ return PACKET_LOG_NONE;
+ }
+
+ // Ethernet log
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ETHERNET]);
+
+ switch (packet->TypeL3)
+ {
+ case L3_ARPV4:
+ // ARP
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ARP]);
+ break;
+
+ case L3_IPV4:
+ // IPv4
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_IP]);
+
+ switch (packet->TypeL4)
+ {
+ case L4_ICMPV4:
+ // ICMPv4
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ICMP]);
+ break;
+
+ case L4_TCP:
+ // TCPv4
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP]);
+
+ if (packet->L4.TCPHeader->Flag & TCP_SYN ||
+ packet->L4.TCPHeader->Flag & TCP_RST ||
+ packet->L4.TCPHeader->Flag & TCP_FIN)
+ {
+ // TCP SYN LOG
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
+ }
+
+ break;
+
+ case L4_UDP:
+ // UDPv4
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_UDP]);
+
+ switch (packet->TypeL7)
+ {
+ case L7_DHCPV4:
+ // DHCPv4
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_DHCP]);
+ break;
+
+ case L7_IKECONN:
+ // IKE connection request
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
+ break;
+
+ case L7_OPENVPNCONN:
+ // OpenVPN connection request
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
+ break;
+ }
+
+ break;
+ }
+
+ break;
+
+ case L3_IPV6:
+ // IPv6
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_IP]);
+
+ switch (packet->TypeL4)
+ {
+ case L4_ICMPV6:
+ // ICMPv6
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_ICMP]);
+ break;
+
+ case L4_TCP:
+ // TCPv6
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP]);
+
+ if (packet->L4.TCPHeader->Flag & TCP_SYN ||
+ packet->L4.TCPHeader->Flag & TCP_RST ||
+ packet->L4.TCPHeader->Flag & TCP_FIN)
+ {
+ // TCP SYN LOG
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
+ }
+
+ break;
+
+ case L4_UDP:
+ // UDPv6
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_UDP]);
+
+ switch (packet->TypeL7)
+ {
+ case L7_IKECONN:
+ // IKE connection request
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
+ break;
+
+ case L7_OPENVPNCONN:
+ // OpenVPN connection request
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
+ break;
+ }
+
+ break;
+ }
+
+ break;
+ }
+
+ if (packet->HttpLog != NULL)
+ {
+ // HTTP Connect Log
+ ret = MAX(ret, g->PacketLogConfig[PACKET_LOG_TCP_CONN]);
+ }
+
+ return ret;
+}
+UINT CalcPacketLoggingLevel(HUB *hub, PKT *packet)
+{
+ // Validate arguments
+ if (hub == NULL || packet == NULL)
+ {
+ return PACKET_LOG_NONE;
+ }
+
+ return CalcPacketLoggingLevelEx(&hub->LogSetting, packet);
+}
+
+// Generate a string to be stored as an HTTP log
+char *BuildHttpLogStr(HTTPLOG *h)
+{
+ BUF *b;
+ char url[MAX_SIZE];
+ char nullchar = 0;
+ char *ret;
+ // Validate arguments
+ if (h == NULL)
+ {
+ return CopyStr("");
+ }
+
+ b = NewBuf();
+
+ // URL generation
+ if (h->Port == 80)
+ {
+ Format(url, sizeof(url), "http://%s%s",
+ h->Hostname, h->Path);
+ }
+ else
+ {
+ Format(url, sizeof(url), "http://%s:%u%s",
+ h->Hostname, h->Port, h->Path);
+ }
+
+ AddLogBufToStr(b, "HttpMethod", h->Method);
+ AddLogBufToStr(b, "HttpUrl", url);
+ AddLogBufToStr(b, "HttpProtocol", h->Protocol);
+ AddLogBufToStr(b, "HttpReferer", h->Referer);
+ AddLogBufToStr(b, "HttpUserAgent", h->UserAgent);
+
+ WriteBuf(b, &nullchar, 1);
+
+ ret = CopyStr(b->Buf);
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Append an item to the log buffer
+void AddLogBufToStr(BUF *b, char *name, char *value)
+{
+ char tmp[MAX_SIZE * 2];
+ char *p = NULL;
+ // Validate arguments
+ if (b == NULL || value == NULL)
+ {
+ return;
+ }
+
+ if (IsEmptyStr(value))
+ {
+ return;
+ }
+
+ tmp[0] = 0;
+
+ if (IsEmptyStr(name) == false)
+ {
+ p = &tmp[StrLen(tmp)];
+ StrCat(tmp, sizeof(tmp), name);
+ MakeSafeLogStr(p);
+ StrCat(tmp, sizeof(tmp), "=");
+ }
+
+ p = &tmp[StrLen(tmp)];
+ StrCat(tmp, sizeof(tmp), value);
+ MakeSafeLogStr(p);
+ StrCat(tmp, sizeof(tmp), " ");
+
+ WriteBuf(b, tmp, StrLen(tmp));
+}
+
+// Secure the log string
+void MakeSafeLogStr(char *str)
+{
+ UINT i, len;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return;
+ }
+
+ EnPrintableAsciiStr(str, '?');
+
+ len = StrLen(str);
+ for (i = 0;i < len;i++)
+ {
+ if (str[i] == ',')
+ {
+ str[i] = '.';
+ }
+ else if (str[i] == ' ')
+ {
+ str[i] = '_';
+ }
+ }
+}
+
+// Procedure for converting a packet log entry to a string
+char *PacketLogParseProc(RECORD *rec)
+{
+ return NULL;
+}
+
+// Convert TCP flags to a string
+char *TcpFlagStr(UCHAR flag)
+{
+ char tmp[MAX_SIZE];
+ StrCpy(tmp, sizeof(tmp), "");
+
+ if (flag & TCP_FIN)
+ {
+ StrCat(tmp, sizeof(tmp), "FIN+");
+ }
+
+ if (flag & TCP_SYN)
+ {
+ StrCat(tmp, sizeof(tmp), "SYN+");
+ }
+
+ if (flag & TCP_RST)
+ {
+ StrCat(tmp, sizeof(tmp), "RST+");
+ }
+
+ if (flag & TCP_PSH)
+ {
+ StrCat(tmp, sizeof(tmp), "PSH+");
+ }
+
+ if (flag & TCP_ACK)
+ {
+ StrCat(tmp, sizeof(tmp), "ACK+");
+ }
+
+ if (flag & TCP_URG)
+ {
+ StrCat(tmp, sizeof(tmp), "URG+");
+ }
+
+ if (StrLen(tmp) >= 1)
+ {
+ if (tmp[StrLen(tmp) - 1] == '+')
+ {
+ tmp[StrLen(tmp) - 1] = 0;
+ }
+ }
+
+ return CopyStr(tmp);
+}
+
+// Generate a port string
+char *PortStr(CEDAR *cedar, UINT port, bool udp)
+{
+ char tmp[MAX_SIZE];
+ char *name;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ name = GetSvcName(cedar, udp, port);
+
+ if (name == NULL)
+ {
+ snprintf(tmp, sizeof(tmp), "%u", port);
+ }
+ else
+ {
+ snprintf(tmp, sizeof(tmp), "%s(%u)", name, port);
+ }
+
+ return CopyStr(tmp);
+}
+
+// Generate a comma-separated string
+char *GenCsvLine(TOKEN_LIST *t)
+{
+ UINT i;
+ BUF *b;
+ char *ret;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ if (t->Token[i] != NULL)
+ {
+ ReplaceForCsv(t->Token[i]);
+ if (StrLen(t->Token[i]) == 0)
+ {
+ WriteBuf(b, "-", 1);
+ }
+ else
+ {
+ WriteBuf(b, t->Token[i], StrLen(t->Token[i]));
+ }
+ }
+ else
+ {
+ WriteBuf(b, "-", 1);
+ }
+ if (i != (t->NumTokens - 1))
+ {
+ WriteBuf(b, ",", 1);
+ }
+ }
+ WriteBuf(b, "\0", 1);
+
+ ret = (char *)b->Buf;
+
+ Free(b);
+
+ return ret;
+}
+
+// Replace the strings in the CSV correctly
+void ReplaceForCsv(char *str)
+{
+ UINT i, len;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return;
+ }
+
+ // If there are blanks, trim it
+ Trim(str);
+ len = StrLen(str);
+
+ for (i = 0;i < len;i++)
+ {
+ // Convert the comma to underscore
+ if (str[i] == ',')
+ {
+ str[i] = '_';
+ }
+ }
+}
+
+// Set the directory name of the log
+void SetLogDirName(LOG *g, char *dir)
+{
+ // Validate arguments
+ if (g == NULL || dir == NULL)
+ {
+ return;
+ }
+
+ LockLog(g);
+ {
+ if (g->DirName != NULL)
+ {
+ Free(g->DirName);
+ }
+ g->DirName = CopyStr(dir);
+ }
+ UnlockLog(g);
+}
+
+// Set the name of the log
+void SetLogPrefix(LOG *g, char *prefix)
+{
+ // Validate arguments
+ if (g == NULL || prefix == NULL)
+ {
+ return;
+ }
+
+ LockLog(g);
+ {
+ if (g->DirName != NULL)
+ {
+ Free(g->Prefix);
+ }
+ g->DirName = CopyStr(prefix);
+ }
+ UnlockLog(g);
+}
+
+// Set the switch type of log
+void SetLogSwitchType(LOG *g, UINT switch_type)
+{
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ LockLog(g);
+ {
+ g->SwitchType = switch_type;
+ }
+ UnlockLog(g);
+}
+
+// Parse the string record
+char *StringRecordParseProc(RECORD *rec)
+{
+ // Validate arguments
+ if (rec == NULL)
+ {
+ return NULL;
+ }
+
+ return (char *)rec->Data;
+}
+
+// Add an Unicode string record in the log
+void InsertUnicodeRecord(LOG *g, wchar_t *unistr)
+{
+ char *str;
+ UINT size;
+ // Validate arguments
+ if (g == NULL || unistr == NULL)
+ {
+ return;
+ }
+
+ size = CalcUniToUtf8(unistr) + 32;
+ str = ZeroMalloc(size);
+
+ UniToUtf8((BYTE *)str, size, unistr);
+ InsertStringRecord(g, str);
+ Free(str);
+}
+
+// Add a string record to the log
+void InsertStringRecord(LOG *g, char *str)
+{
+ char *str_copy;
+ // Validate arguments
+ if (g == NULL || str == NULL)
+ {
+ return;
+ }
+
+ str_copy = CopyStr(str);
+
+ InsertRecord(g, str_copy, StringRecordParseProc);
+}
+
+// Add a record to the log
+void InsertRecord(LOG *g, void *data, RECORD_PARSE_PROC *proc)
+{
+ RECORD *rec;
+ // Validate arguments
+ if (g == NULL || data == NULL || proc == NULL)
+ {
+ return;
+ }
+
+ rec = ZeroMalloc(sizeof(RECORD));
+ rec->Tick = Tick64();
+ rec->ParseProc = proc;
+ rec->Data = data;
+
+ LockQueue(g->RecordQueue);
+ {
+ InsertQueue(g->RecordQueue, rec);
+ }
+ UnlockQueue(g->RecordQueue);
+
+ Set(g->Event);
+}
+
+// Lock the log
+void LockLog(LOG *g)
+{
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ Lock(g->lock);
+}
+
+// Unlock the log
+void UnlockLog(LOG *g)
+{
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ Unlock(g->lock);
+}
+
+// Generate the string portion of the log file name from the time and the switching rule
+void MakeLogFileNameStringFromTick(LOG *g, char *str, UINT size, UINT64 tick, UINT switch_type)
+{
+ UINT64 time;
+ SYSTEMTIME st;
+
+ // Validate arguments
+ if (str == NULL || g == NULL)
+ {
+ return;
+ }
+
+ if (g->CacheFlag)
+ {
+ if (g->LastTick == tick &&
+ g->LastSwitchType == switch_type)
+ {
+ StrCpy(str, size, g->LastStr);
+ return;
+ }
+ }
+
+ time = TickToTime(tick);
+ UINT64ToSystem(&st, SystemToLocal64(time));
+
+ switch (switch_type)
+ {
+ case LOG_SWITCH_SECOND: // Secondly basis
+ snprintf(str, size, "_%04u%02u%02u_%02u%02u%02u",
+ st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
+ break;
+
+ case LOG_SWITCH_MINUTE: // Minutely basis
+ snprintf(str, size, "_%04u%02u%02u_%02u%02u",
+ st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute);
+ break;
+
+ case LOG_SWITCH_HOUR: // Hourly basis
+ snprintf(str, size, "_%04u%02u%02u_%02u", st.wYear, st.wMonth, st.wDay, st.wHour);
+ break;
+
+ case LOG_SWITCH_DAY: // Daily basis
+ snprintf(str, size, "_%04u%02u%02u", st.wYear, st.wMonth, st.wDay);
+ break;
+
+ case LOG_SWITCH_MONTH: // Monthly basis
+ snprintf(str, size, "_%04u%02u", st.wYear, st.wMonth);
+ break;
+
+ default: // Without switching
+ snprintf(str, size, "");
+ break;
+ }
+
+ g->CacheFlag = true;
+ g->LastTick = tick;
+ g->LastSwitchType = switch_type;
+ StrCpy(g->LastStr, sizeof(g->LastStr), str);
+}
+
+// Create a log file name
+bool MakeLogFileName(LOG *g, char *name, UINT size, char *dir, char *prefix, UINT64 tick, UINT switch_type, UINT num, char *old_datestr)
+{
+ char tmp[MAX_SIZE];
+ char tmp2[64];
+ bool ret = false;
+ // Validate arguments
+ if (g == NULL || name == NULL || prefix == NULL || old_datestr == NULL)
+ {
+ return false;
+ }
+
+ MakeLogFileNameStringFromTick(g, tmp, sizeof(tmp), tick, switch_type);
+
+ if (num == 0)
+ {
+ tmp2[0] = 0;
+ }
+ else
+ {
+ snprintf(tmp2, sizeof(tmp2), "~%02u", num);
+ }
+
+ if (strcmp(old_datestr, tmp) != 0)
+ {
+ ret = true;
+ strcpy(old_datestr, tmp);
+ }
+
+ snprintf(name, size, "%s%s%s%s%s.log", dir,
+ StrLen(dir) == 0 ? "" : "/",
+ prefix, tmp, tmp2
+ );
+
+ return ret;
+}
+
+// Wait until the log have been flushed
+void WaitLogFlush(LOG *g)
+{
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ UINT num;
+ LockQueue(g->RecordQueue);
+ {
+ num = g->RecordQueue->num_item;
+ }
+ UnlockQueue(g->RecordQueue);
+
+ if (num == 0)
+ {
+ break;
+ }
+
+ Wait(g->FlushEvent, 100);
+ }
+}
+
+// Logging thread
+void LogThread(THREAD *thread, void *param)
+{
+ LOG *g;
+ IO *io;
+ BUF *b;
+ bool flag = false;
+ char current_file_name[MAX_SIZE];
+ char current_logfile_datename[MAX_SIZE];
+ bool last_priority_flag = false;
+ bool log_date_changed = false;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ Zero(current_file_name, sizeof(current_file_name));
+ Zero(current_logfile_datename, sizeof(current_logfile_datename));
+
+ g = (LOG *)param;
+
+ io = NULL;
+ b = NewBuf();
+
+#ifdef OS_WIN32
+
+ // Lower priority to bottom
+ MsSetThreadPriorityIdle();
+
+#endif // OS_WIN32
+
+ NoticeThreadInit(thread);
+
+ while (true)
+ {
+ RECORD *rec;
+ UINT64 s = Tick64();
+
+ while (true)
+ {
+ char file_name[MAX_SIZE];
+ UINT num;
+
+ // Retrieve a record from the head of the queue
+ LockQueue(g->RecordQueue);
+ {
+ rec = GetNext(g->RecordQueue);
+ num = g->RecordQueue->num_item;
+ }
+ UnlockQueue(g->RecordQueue);
+
+#ifdef OS_WIN32
+ if (num >= LOG_ENGINE_SAVE_START_CACHE_COUNT)
+ {
+ // Raise the priority
+ if (last_priority_flag == false)
+ {
+ Debug("LOG_THREAD: MsSetThreadPriorityRealtime\n");
+ MsSetThreadPriorityRealtime();
+ last_priority_flag = true;
+ }
+ }
+
+ if (num < (LOG_ENGINE_SAVE_START_CACHE_COUNT / 2))
+ {
+ // Restore the priority
+ if (last_priority_flag)
+ {
+ Debug("LOG_THREAD: MsSetThreadPriorityIdle\n");
+ MsSetThreadPriorityIdle();
+ last_priority_flag = false;
+ }
+ }
+#endif // OS_WIN32
+
+ if (b->Size > g->MaxLogFileSize)
+ {
+ // Erase if the size of the buffer is larger than the maximum log file size
+ ClearBuf(b);
+ }
+
+ if (b->Size >= LOG_ENGINE_BUFFER_CACHE_SIZE_MAX)
+ {
+ // Write the contents of the buffer to the file
+ if (io != NULL)
+ {
+ if ((g->CurrentFilePointer + (UINT64)b->Size) > g->MaxLogFileSize)
+ {
+ if (g->log_number_incremented == false)
+ {
+ g->CurrentLogNumber++;
+ g->log_number_incremented = true;
+ }
+ }
+ else
+ {
+ if (FileWrite(io, b->Buf, b->Size) == false)
+ {
+ FileCloseEx(io, true);
+ // If it fails to write to the file,
+ // erase the buffer and give up
+ ClearBuf(b);
+ io = NULL;
+ }
+ else
+ {
+ g->CurrentFilePointer += (UINT64)b->Size;
+ ClearBuf(b);
+ }
+ }
+ }
+ }
+
+ if (rec == NULL)
+ {
+ if (b->Size != 0)
+ {
+ // Write the contents of the buffer to the file
+ if (io != NULL)
+ {
+ if ((g->CurrentFilePointer + (UINT64)b->Size) > g->MaxLogFileSize)
+ {
+ if (g->log_number_incremented == false)
+ {
+ g->CurrentLogNumber++;
+ g->log_number_incremented = true;
+ }
+ }
+ else
+ {
+ if (FileWrite(io, b->Buf, b->Size) == false)
+ {
+ FileCloseEx(io, true);
+ // If it fails to write to the file,
+ // erase the buffer and give up
+ ClearBuf(b);
+ io = NULL;
+ }
+ else
+ {
+ g->CurrentFilePointer += (UINT64)b->Size;
+ ClearBuf(b);
+ }
+ }
+ }
+ }
+
+ Set(g->FlushEvent);
+ break;
+ }
+
+ // Generate a log file name
+ LockLog(g);
+ {
+ log_date_changed = MakeLogFileName(g, file_name, sizeof(file_name),
+ g->DirName, g->Prefix, rec->Tick, g->SwitchType, g->CurrentLogNumber, current_logfile_datename);
+
+ if (log_date_changed)
+ {
+ UINT i;
+
+ g->CurrentLogNumber = 0;
+ MakeLogFileName(g, file_name, sizeof(file_name),
+ g->DirName, g->Prefix, rec->Tick, g->SwitchType, 0, current_logfile_datename);
+ for (i = 0;;i++)
+ {
+ char tmp[MAX_SIZE];
+ MakeLogFileName(g, tmp, sizeof(tmp),
+ g->DirName, g->Prefix, rec->Tick, g->SwitchType, i, current_logfile_datename);
+
+ if (IsFileExists(tmp) == false)
+ {
+ break;
+ }
+ StrCpy(file_name, sizeof(file_name), tmp);
+ g->CurrentLogNumber = i;
+ }
+ }
+ }
+ UnlockLog(g);
+
+ if (io != NULL)
+ {
+ if (StrCmp(current_file_name, file_name) != 0)
+ {
+ // If a log file is currently opened and writing to another log
+ // file is needed for this time, write the contents of the
+ //buffer and close the log file. Write the contents of the buffer
+ if (io != NULL)
+ {
+ if (log_date_changed)
+ {
+ if ((g->CurrentFilePointer + (UINT64)b->Size) <= g->MaxLogFileSize)
+ {
+ if (FileWrite(io, b->Buf, b->Size) == false)
+ {
+ FileCloseEx(io, true);
+ ClearBuf(b);
+ io = NULL;
+ }
+ else
+ {
+ g->CurrentFilePointer += (UINT64)b->Size;
+ ClearBuf(b);
+ }
+ }
+ }
+ // Close the file
+ FileCloseEx(io, true);
+ }
+
+ g->log_number_incremented = false;
+
+ // Open or create a new log file
+ StrCpy(current_file_name, sizeof(current_file_name), file_name);
+ io = FileOpen(file_name, true);
+ if (io == NULL)
+ {
+ // Create a log file
+ LockLog(g);
+ {
+ MakeDir(g->DirName);
+
+#ifdef OS_WIN32
+ Win32SetFolderCompress(g->DirName, true);
+#endif // OS_WIN32
+ }
+ UnlockLog(g);
+ io = FileCreate(file_name);
+ g->CurrentFilePointer = 0;
+ }
+ else
+ {
+ // Seek to the end of the log file
+ g->CurrentFilePointer = FileSize64(io);
+ FileSeek(io, SEEK_END, 0);
+ }
+ }
+ }
+ else
+ {
+ // Open or create a new log file
+ StrCpy(current_file_name, sizeof(current_file_name), file_name);
+ io = FileOpen(file_name, true);
+ if (io == NULL)
+ {
+ // Create a log file
+ LockLog(g);
+ {
+ MakeDir(g->DirName);
+#ifdef OS_WIN32
+ Win32SetFolderCompress(g->DirName, true);
+#endif // OS_WIN32
+ }
+ UnlockLog(g);
+ io = FileCreate(file_name);
+ g->CurrentFilePointer = 0;
+ if (io == NULL)
+ {
+ //Debug("Logging.c: SleepThread(30);\n");
+ SleepThread(30);
+ }
+ }
+ else
+ {
+ // Seek to the end of the log file
+ g->CurrentFilePointer = FileSize64(io);
+ FileSeek(io, SEEK_END, 0);
+ }
+
+ g->log_number_incremented = false;
+ }
+
+ // Write the contents of the log to the buffer
+ WriteRecordToBuffer(b, rec);
+
+ // Release the memory of record
+ Free(rec);
+
+ if (io == NULL)
+ {
+ break;
+ }
+ }
+
+ if (g->Halt)
+ {
+ // Break after finishing to save all records
+ // when the stop flag stood
+ UINT num;
+
+ if (flag == false)
+ {
+#ifdef OS_WIN32
+ MsSetThreadPriorityRealtime();
+#endif // OS_WIN32
+ flag = true;
+ }
+
+ LockQueue(g->RecordQueue);
+ {
+ num = g->RecordQueue->num_item;
+ }
+ UnlockQueue(g->RecordQueue);
+
+ if (num == 0 || io == NULL)
+ {
+ break;
+ }
+ }
+ else
+ {
+ Wait(g->Event, 9821);
+ }
+ }
+
+ if (io != NULL)
+ {
+ FileCloseEx(io, true);
+ }
+
+ FreeBuf(b);
+}
+
+// Write the contents of the log to the buffer
+void WriteRecordToBuffer(BUF *b, RECORD *r)
+{
+ UINT64 time;
+ char time_str[MAX_SIZE];
+ char date_str[MAX_SIZE];
+ char *s;
+ // Validate arguments
+ if (b == NULL || r == NULL)
+ {
+ return;
+ }
+
+ // Get the time
+ time = SystemToLocal64(TickToTime(r->Tick));
+
+ // Convert a time to a string
+ GetDateStr64(date_str, sizeof(date_str), time);
+ GetTimeStrMilli64(time_str, sizeof(time_str), time);
+
+ if (r->ParseProc != PacketLogParseProc)
+ {
+ // Other than packet log
+ WriteBuf(b, date_str, StrLen(date_str));
+ WriteBuf(b, " ", 1);
+ WriteBuf(b, time_str, StrLen(time_str));
+ WriteBuf(b, " ", 1);
+ }
+ else
+ {
+ // Packet log
+ WriteBuf(b, date_str, StrLen(date_str));
+ WriteBuf(b, ",", 1);
+ WriteBuf(b, time_str, StrLen(time_str));
+ WriteBuf(b, ",", 1);
+ }
+
+ // Output text
+ s = r->ParseProc(r);
+ WriteBuf(b, s, StrLen(s));
+ Free(s);
+
+ WriteBuf(b, "\r\n", 2);
+}
+
+// End of logging
+void FreeLog(LOG *g)
+{
+ RECORD *rec;
+ // Validate arguments
+ if (g == NULL)
+ {
+ return;
+ }
+
+ // Halting flag
+ g->Halt = true;
+ Set(g->Event);
+
+ WaitThread(g->Thread, INFINITE);
+ ReleaseThread(g->Thread);
+
+ DeleteLock(g->lock);
+ Free(g->DirName);
+ Free(g->Prefix);
+
+ // Release the unprocessed record if it remains
+ // (It should not remain here)
+ while (rec = GetNext(g->RecordQueue))
+ {
+ char *s = rec->ParseProc(rec);
+ Free(s);
+ Free(rec);
+ }
+ ReleaseQueue(g->RecordQueue);
+
+ ReleaseEvent(g->Event);
+ ReleaseEvent(g->FlushEvent);
+
+ Free(g);
+}
+
+// Start a new logging
+LOG *NewLog(char *dir, char *prefix, UINT switch_type)
+{
+ LOG *g;
+
+ g = ZeroMalloc(sizeof(LOG));
+ g->lock = NewLock();
+ g->DirName = CopyStr(dir == NULL ? "" : dir);
+ g->Prefix = CopyStr(prefix == NULL ? "log" : prefix);
+ g->SwitchType = switch_type;
+ g->RecordQueue = NewQueue();
+ g->Event = NewEvent();
+ g->MaxLogFileSize = MAX_LOG_SIZE;
+ g->FlushEvent = NewEvent();
+
+ g->Thread = NewThread(LogThread, g);
+
+ WaitThreadInit(g->Thread);
+
+ return g;
+}
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Logging.h b/src/Cedar/Logging.h
new file mode 100644
index 00000000..cffec6fe
--- /dev/null
+++ b/src/Cedar/Logging.h
@@ -0,0 +1,248 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Logging.h
+// Header of Logging.c
+
+#ifndef LOGGING_H
+#define LOGGING_H
+
+
+// Port number for HTTP monitoring
+#define LOG_HTTP_PORT 80
+
+
+#define MAX_LOG_SIZE 1073741823ULL
+
+typedef char *(RECORD_PARSE_PROC)(RECORD *rec);
+
+// Packet log structure
+struct PACKET_LOG
+{
+ CEDAR *Cedar;
+ struct PKT *Packet;
+ char *SrcSessionName;
+ char *DestSessionName;
+ bool PurePacket; // Packet not cloned
+ bool PurePacketNoPayload; // Packet not cloned (without payload)
+ SESSION *SrcSession;
+ bool NoLog; // Not to write a log
+};
+
+// Log save options of the HUB
+struct HUB_LOG
+{
+ bool SaveSecurityLog; // To save the security log
+ UINT SecurityLogSwitchType; // Switching type of security log
+ bool SavePacketLog; // To save the packet log
+ UINT PacketLogSwitchType; // Switching type of packet log
+ UINT PacketLogConfig[NUM_PACKET_LOG]; // Packet log settings
+};
+
+// Record
+struct RECORD
+{
+ UINT64 Tick; // Time
+ RECORD_PARSE_PROC *ParseProc; // Parsing procedure
+ void *Data; // Data
+};
+
+// LOG object
+struct LOG
+{
+ LOCK *lock; // Lock
+ THREAD *Thread; // Thread
+ char *DirName; // Destination directory name
+ char *Prefix; // File name
+ UINT SwitchType; // Switching type of log file
+ QUEUE *RecordQueue; // Record queue
+ volatile bool Halt; // Halting flag
+ EVENT *Event; // Event for Log
+ EVENT *FlushEvent; // Flash completion event
+ bool CacheFlag;
+ UINT64 LastTick;
+ UINT LastSwitchType;
+ char LastStr[MAX_SIZE];
+ UINT64 CurrentFilePointer; // The current file pointer
+ UINT64 MaxLogFileSize; // Maximum log file size
+ UINT CurrentLogNumber; // Log file number of the current
+ bool log_number_incremented;
+};
+
+
+// ERASER object
+struct ERASER
+{
+ LOG *Log; // Logger
+ UINT64 MinFreeSpace; // Disk space to start deleting files
+ char *DirName; // Directory name
+ volatile bool Halt; // Halting flag
+ THREAD *Thread; // Thread
+ bool LastFailed; // Whether deletion of the file failed at the end
+ EVENT *HaltEvent; // Halting event
+};
+
+// List of files that can be deleted
+typedef struct ERASE_FILE
+{
+ char *FullPath; // Full path
+ UINT64 UpdateTime; // Updating date
+} ERASE_FILE;
+
+// SYSLOG object
+struct SLOG
+{
+ LOCK *lock; // Lock
+ SOCK *Udp; // UDP socket
+ IP DestIp; // Destination IP address
+ UINT DestPort; // Destination port number
+ char HostName[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT64 NextPollIp; // Time of examination of the IP address at the end
+};
+
+// Function prototype
+LOG *NewLog(char *dir, char *prefix, UINT switch_type);
+void FreeLog(LOG *g);
+void LogThread(THREAD *thread, void *param);
+void WaitLogFlush(LOG *g);
+void LockLog(LOG *g);
+void UnlockLog(LOG *g);
+void InsertRecord(LOG *g, void *data, RECORD_PARSE_PROC *proc);
+void InsertStringRecord(LOG *g, char *str);
+void InsertUnicodeRecord(LOG *g, wchar_t *unistr);
+char *StringRecordParseProc(RECORD *rec);
+bool MakeLogFileName(LOG *g, char *name, UINT size, char *dir, char *prefix, UINT64 tick, UINT switch_type, UINT num, char *old_datestr);
+void MakeLogFileNameStringFromTick(LOG *g, char *str, UINT size, UINT64 tick, UINT switch_type);
+void WriteRecordToBuffer(BUF *b, RECORD *r);
+void SetLogDirName(LOG *g, char *dir);
+void SetLogPrefix(LOG *g, char *prefix);
+void SetLogSwitchType(LOG *g, UINT switch_type);
+bool PacketLog(HUB *hub, SESSION *src_session, SESSION *dest_session, PKT *packet, UINT64 now);
+char *PacketLogParseProc(RECORD *rec);
+UINT CalcPacketLoggingLevel(HUB *hub, PKT *packet);
+UINT CalcPacketLoggingLevelEx(HUB_LOG *g, PKT *packet);
+char *GenCsvLine(TOKEN_LIST *t);
+void ReplaceForCsv(char *str);
+char *PortStr(CEDAR *cedar, UINT port, bool udp);
+char *TcpFlagStr(UCHAR flag);
+void WriteSecurityLog(HUB *h, char *str);
+void SecLog(HUB *h, char *fmt, ...);
+void SiSetDefaultLogSetting(HUB_LOG *g);
+void DebugLog(CEDAR *c, char *fmt, ...);
+void HubLog(HUB *h, wchar_t *fmt, ...);
+void ServerLog(CEDAR *c, wchar_t *fmt, ...);
+void SLog(CEDAR *c, char *name, ...);
+void WriteHubLog(HUB *h, wchar_t *str);
+void HLog(HUB *h, char *name, ...);
+void NLog(VH *v, char *name, ...);
+void IPCLog(IPC *ipc, char *name, ...);
+void PPPLog(PPP_SESSION *p, char *name, ...);
+void IPsecLog(IKE_SERVER *ike, IKE_CLIENT *c, IKE_SA *ike_sa, IPSECSA *ipsec_sa, char *name, ...);
+void EtherIPLog(ETHERIP_SERVER *s, char *name, ...);
+void WriteServerLog(CEDAR *c, wchar_t *str);
+void ALog(ADMIN *a, HUB *h, char *name, ...);
+void CLog(CLIENT *c, char *name, ...);
+void WriteClientLog(CLIENT *c, wchar_t *str);
+ERASER *NewEraser(LOG *log, UINT64 min_size);
+void FreeEraser(ERASER *e);
+void ELog(ERASER *e, char *name, ...);
+void EraserThread(THREAD *t, void *p);
+void EraserMain(ERASER *e);
+bool CheckEraserDiskFreeSpace(ERASER *e);
+int CompareEraseFile(void *p1, void *p2);
+LIST *GenerateEraseFileList(ERASER *e);
+void FreeEraseFileList(LIST *o);
+void PrintEraseFileList(LIST *o);
+void EnumEraseFile(LIST *o, char *dirname);
+SLOG *NewSysLog(char *hostname, UINT port);
+void SetSysLog(SLOG *g, char *hostname, UINT port);
+void FreeSysLog(SLOG *g);
+void SendSysLog(SLOG *g, wchar_t *str);
+void WriteMultiLineLog(LOG *g, BUF *b);
+char *BuildHttpLogStr(HTTPLOG *h);
+void MakeSafeLogStr(char *str);
+void AddLogBufToStr(BUF *b, char *name, char *value);
+
+#endif // LOGGING_G
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/NM.c b/src/Cedar/NM.c
new file mode 100644
index 00000000..74bb88fd
--- /dev/null
+++ b/src/Cedar/NM.c
@@ -0,0 +1,1516 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// NM.c
+// VPN User-mode Router Manager for Win32
+
+#include <GlobalConst.h>
+
+#ifdef WIN32
+
+#define SM_C
+#define CM_C
+#define NM_C
+
+#define _WIN32_WINNT 0x0502
+#define WINVER 0x0502
+#include <winsock2.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <wininet.h>
+#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+#include "CMInner.h"
+#include "SMInner.h"
+#include "NMInner.h"
+#include "EMInner.h"
+#include "../PenCore/resource.h"
+
+// Global variable
+static NM *nm = NULL;
+
+
+// Change Password dialog
+UINT NmChangePasswordProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ RPC *r = (RPC *)param;
+ char tmp1[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ RPC_SET_PASSWORD t;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ FormatText(hWnd, 0, r->Sock->RemoteHostname);
+ FormatText(hWnd, S_TITLE, r->Sock->RemoteHostname);
+ break;
+
+ case WM_COMMAND:
+ GetTxtA(hWnd, E_PASSWORD1, tmp1, sizeof(tmp1));
+ GetTxtA(hWnd, E_PASSWORD2, tmp2, sizeof(tmp2));
+ switch (LOWORD(wParam))
+ {
+ case E_PASSWORD1:
+ case E_PASSWORD2:
+ SetEnable(hWnd, IDOK, StrCmp(tmp1, tmp2) == 0);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ Zero(&t, sizeof(t));
+ Hash(t.HashedPassword, tmp1, StrLen(tmp1), true);
+
+ if (CALL(hWnd, NcSetPassword(r, &t)))
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("NM_PASSWORD_MSG"));
+ EndDialog(hWnd, true);
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Change the password
+void NmChangePassword(HWND hWnd, RPC *r)
+{
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_NM_CHANGE_PASSWORD, NmChangePasswordProc, r);
+}
+
+// DHCP enumeration initialization
+void NmDhcpInit(HWND hWnd, SM_HUB *r)
+{
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_INTERNET);
+
+ LvInit(hWnd, L_TABLE);
+ LvInsertColumn(hWnd, L_TABLE, 0, _UU("DHCP_DHCP_ID"), 50);
+ LvInsertColumn(hWnd, L_TABLE, 1, _UU("DHCP_LEASED_TIME"), 200);
+ LvInsertColumn(hWnd, L_TABLE, 2, _UU("DHCP_EXPIRE_TIME"), 200);
+ LvInsertColumn(hWnd, L_TABLE, 3, _UU("DHCP_MAC_ADDRESS"), 130);
+ LvInsertColumn(hWnd, L_TABLE, 4, _UU("DHCP_IP_ADDRESS"), 100);
+ LvInsertColumn(hWnd, L_TABLE, 5, _UU("DHCP_HOSTNAME"), 150);
+
+ NmDhcpRefresh(hWnd, r);
+}
+
+// DHCP enumeration
+void NmDhcpRefresh(HWND hWnd, SM_HUB *r)
+{
+ LVB *b;
+ RPC_ENUM_DHCP t;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), r->HubName);
+
+ if (CALL(hWnd, ScEnumDHCP(r->Rpc, &t)) == false)
+ {
+ return;
+ }
+
+ b = LvInsertStart();
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_DHCP_ITEM *e = &t.Items[i];
+ wchar_t tmp0[MAX_SIZE];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t tmp5[MAX_SIZE];
+ char str[MAX_SIZE];
+
+ // ID
+ UniToStru(tmp0, e->Id);
+
+ // Time
+ GetDateTimeStrEx64(tmp1, sizeof(tmp1), SystemToLocal64(e->LeasedTime), NULL);
+ GetDateTimeStrEx64(tmp2, sizeof(tmp2), SystemToLocal64(e->ExpireTime), NULL);
+
+ MacToStr(str, sizeof(str), e->MacAddress);
+ StrToUni(tmp3, sizeof(tmp3), str);
+
+ IPToStr32(str, sizeof(str), e->IpAddress);
+ StrToUni(tmp4, sizeof(tmp4), str);
+
+ StrToUni(tmp5, sizeof(tmp5), e->Hostname);
+
+ LvInsertAdd(b, ICO_INTERNET, NULL, 6,
+ tmp0, tmp1, tmp2, tmp3, tmp4, tmp5);
+ }
+
+ LvInsertEnd(b, hWnd, L_TABLE);
+
+ FreeRpcEnumDhcp(&t);
+}
+
+// DHCP enumeration procedure
+UINT NmDhcpProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_HUB *r = (SM_HUB *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ NmDhcpInit(hWnd, r);
+ SetTimer(hWnd, 1, NM_DHCP_REFRESH_TIME, NULL);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case B_REFRESH:
+ NmDhcpRefresh(hWnd, r);
+ break;
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+ NmDhcpRefresh(hWnd, r);
+ SetTimer(hWnd, 1, NM_DHCP_REFRESH_TIME, NULL);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_TABLE);
+
+ return 0;
+}
+
+// DHCP enumeration
+void NmDhcp(HWND hWnd, SM_HUB *r)
+{
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_NM_DHCP, NmDhcpProc, r);
+}
+
+
+// NAT enumeration initialization
+void NmNatInit(HWND hWnd, SM_HUB *r)
+{
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_PROTOCOL);
+
+ LvInit(hWnd, L_TABLE);
+ LvInsertColumn(hWnd, L_TABLE, 0, _UU("NM_NAT_ID"), 50);
+ LvInsertColumn(hWnd, L_TABLE, 1, _UU("NM_NAT_PROTOCOL"), 80);
+ LvInsertColumn(hWnd, L_TABLE, 2, _UU("NM_NAT_SRC_HOST"), 100);
+ LvInsertColumn(hWnd, L_TABLE, 3, _UU("NM_NAT_SRC_PORT"), 80);
+ LvInsertColumn(hWnd, L_TABLE, 4, _UU("NM_NAT_DST_HOST"), 150);
+ LvInsertColumn(hWnd, L_TABLE, 5, _UU("NM_NAT_DST_PORT"), 80);
+ LvInsertColumn(hWnd, L_TABLE, 6, _UU("NM_NAT_CREATED"), 200);
+ LvInsertColumn(hWnd, L_TABLE, 7, _UU("NM_NAT_LAST_COMM"), 200);
+ LvInsertColumn(hWnd, L_TABLE, 8, _UU("NM_NAT_SIZE"), 120);
+ LvInsertColumn(hWnd, L_TABLE, 9, _UU("NM_NAT_TCP_STATUS"), 120);
+
+ NmNatRefresh(hWnd, r);
+}
+
+// NAT enumeration
+void NmNatRefresh(HWND hWnd, SM_HUB *r)
+{
+ LVB *b;
+ RPC_ENUM_NAT t;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), r->HubName);
+
+ if (CALL(hWnd, ScEnumNAT(r->Rpc, &t)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ b = LvInsertStart();
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_NAT_ITEM *e = &t.Items[i];
+ wchar_t tmp0[MAX_SIZE];
+ wchar_t *tmp1 = L"";
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t tmp5[MAX_SIZE];
+ wchar_t tmp6[MAX_SIZE];
+ wchar_t tmp7[MAX_SIZE];
+ wchar_t tmp8[MAX_SIZE];
+ wchar_t *tmp9 = L"";
+ char v1[128], v2[128];
+
+ // ID
+ UniToStru(tmp0, e->Id);
+
+ // Protocol
+ switch (e->Protocol)
+ {
+ case NAT_TCP:
+ tmp1 = _UU("NM_NAT_PROTO_TCP");
+ break;
+ case NAT_UDP:
+ tmp1 = _UU("NM_NAT_PROTO_UDP");
+ break;
+ case NAT_DNS:
+ tmp1 = _UU("NM_NAT_PROTO_DNS");
+ break;
+ case NAT_ICMP:
+ tmp1 = _UU("NM_NAT_PROTO_ICMP");
+ break;
+ }
+
+ // Source host
+ StrToUni(tmp2, sizeof(tmp2), e->SrcHost);
+
+ // Source port
+ UniToStru(tmp3, e->SrcPort);
+
+ // Destination host
+ StrToUni(tmp4, sizeof(tmp4), e->DestHost);
+
+ // Destination port
+ UniToStru(tmp5, e->DestPort);
+
+ // Creation date and time of the session
+ GetDateTimeStrEx64(tmp6, sizeof(tmp6), SystemToLocal64(e->CreatedTime), NULL);
+
+ // Last communication date and time
+ GetDateTimeStrEx64(tmp7, sizeof(tmp7), SystemToLocal64(e->LastCommTime), NULL);
+
+ // Communication amount
+ ToStr3(v1, sizeof(v1), e->RecvSize);
+ ToStr3(v2, sizeof(v2), e->SendSize);
+ UniFormat(tmp8, sizeof(tmp8), L"%S / %S", v1, v2);
+
+ // TCP state
+ if (e->Protocol == NAT_TCP)
+ {
+ switch (e->TcpStatus)
+ {
+ case NAT_TCP_CONNECTING:
+ tmp9 = _UU("NAT_TCP_CONNECTING");
+ break;
+ case NAT_TCP_SEND_RESET:
+ tmp9 = _UU("NAT_TCP_SEND_RESET");
+ break;
+ case NAT_TCP_CONNECTED:
+ tmp9 = _UU("NAT_TCP_CONNECTED");
+ break;
+ case NAT_TCP_ESTABLISHED:
+ tmp9 = _UU("NAT_TCP_ESTABLISHED");
+ break;
+ case NAT_TCP_WAIT_DISCONNECT:
+ tmp9 = _UU("NAT_TCP_WAIT_DISCONNECT");
+ break;
+ }
+ }
+
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 10,
+ tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9);
+ }
+
+ LvInsertEnd(b, hWnd, L_TABLE);
+
+ FreeRpcEnumNat(&t);
+}
+
+// NAT enumeration procedure
+UINT NmNatProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_HUB *r = (SM_HUB *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ NmNatInit(hWnd, r);
+ SetTimer(hWnd, 1, NM_NAT_REFRESH_TIME, NULL);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case B_REFRESH:
+ NmNatRefresh(hWnd, r);
+ break;
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+ NmNatRefresh(hWnd, r);
+ SetTimer(hWnd, 1, NM_NAT_REFRESH_TIME, NULL);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_TABLE);
+
+ return 0;
+}
+
+// NAT enumeration
+void NmNat(HWND hWnd, SM_HUB *r)
+{
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_NM_NAT, NmNatProc, r);
+}
+
+// Show the information of the router
+bool NmInfo(HWND hWnd, SM_SERVER *s, void *param)
+{
+ LVB *b;
+ RPC_NAT_INFO t;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+
+ if (CALL(hWnd, NcGetInfo(s->Rpc, &t)) == false)
+ {
+ return false;
+ }
+
+ b = LvInsertStart();
+
+ StrToUni(tmp, sizeof(tmp), t.NatProductName);
+ LvInsertAdd(b, ICO_ROUTER, NULL, 2, _UU("NM_INFO_PRODUCT_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.NatVersionString);
+ LvInsertAdd(b, ICO_INFORMATION, NULL, 2, _UU("NM_INFO_VERSION_STR"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.NatBuildInfoString);
+ LvInsertAdd(b, ICO_INFORMATION, NULL, 2, _UU("NM_INFO_BUILD_INFO"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.NatHostName);
+ LvInsertAdd(b, ICO_TOWER, NULL, 2, _UU("NM_INFO_HOSTNAME"), tmp);
+
+ // OS
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsSystemName);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_SYSTEM_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsProductName);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_PRODUCT_NAME"), tmp);
+
+ if (t.OsInfo.OsServicePack != 0)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SM_OS_SP_TAG"), t.OsInfo.OsServicePack);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_SERVICE_PACK"), tmp);
+ }
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsVendorName);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_VENDER_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsVersion);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_VERSION"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.KernelName);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_KERNEL_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.KernelVersion);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_KERNEL_VERSION"), tmp);
+
+ // Memory information
+ if (t.MemInfo.TotalMemory != 0)
+ {
+ char vv[128];
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.TotalMemory);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_TOTAL_MEMORY"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.UsedMemory);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_USED_MEMORY"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.FreeMemory);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_FREE_MEMORY"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.TotalPhys);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_TOTAL_PHYS"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.UsedPhys);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_USED_PHYS"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.FreePhys);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_FREE_PHYS"), tmp);
+ }
+
+ LvInsertEnd(b, hWnd, L_STATUS);
+
+ FreeRpcNatInfo(&t);
+
+ return true;
+}
+
+// Show the status of the router
+bool NmStatus(HWND hWnd, SM_SERVER *s, void *param)
+{
+ LVB *b;
+ RPC_NAT_STATUS t;
+ wchar_t tmp[MAX_SIZE];
+ SM_HUB *h = (SM_HUB *)param;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), h->HubName);
+
+ if (CALL(hWnd, ScGetSecureNATStatus(s->Rpc, &t)) == false)
+ {
+ return false;
+ }
+
+ b = LvInsertStart();
+
+ StrToUni(tmp, sizeof(tmp), h->HubName);
+ LvInsertAdd(b, ICO_HUB, NULL, 2, _UU("SM_HUB_COLUMN_1"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumTcpSessions);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("NM_STATUS_TCP"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumUdpSessions);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("NM_STATUS_UDP"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumIcmpSessions);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("NM_STATUS_ICMP"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_SESSION"), t.NumDnsSessions);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("NM_STATUS_DNS"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SNAT_NUM_CLIENT"), t.NumDhcpClients);
+ LvInsertAdd(b, ICO_PROTOCOL_DHCP, NULL, 2, _UU("NM_STATUS_DHCP"), tmp);
+
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_SNAT_IS_KERNEL"), t.IsKernelMode ? _UU("SEC_YES") : _UU("SEC_NO"));
+
+ LvInsertEnd(b, hWnd, L_STATUS);
+
+ FreeRpcNatStatus(&t);
+
+ return true;
+}
+
+// Convert the contents of the form to the VH_OPTION
+void NmEditVhOptionFormToVH(HWND hWnd, VH_OPTION *t)
+{
+ char tmp[MAX_SIZE];
+ BUF *b;
+ // Validate arguments
+ if (hWnd == NULL || t == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(VH_OPTION));
+
+ GetTxtA(hWnd, E_MAC, tmp, sizeof(tmp));
+ b = StrToBin(tmp);
+ if (b != NULL)
+ {
+ if (b->Size == 6)
+ {
+ Copy(t->MacAddress, b->Buf, 6);
+ }
+ FreeBuf(b);
+ }
+
+ UINTToIP(&t->Ip, IpGet(hWnd, E_IP));
+ UINTToIP(&t->Mask, IpGet(hWnd, E_MASK));
+
+ t->UseNat = IsChecked(hWnd, R_USE_NAT);
+ t->Mtu = GetInt(hWnd, E_MTU);
+ t->NatTcpTimeout = GetInt(hWnd, E_TCP);
+ t->NatUdpTimeout = GetInt(hWnd, E_UDP);
+
+ t->UseDhcp = IsChecked(hWnd, R_USE_DHCP);
+ UINTToIP(&t->DhcpLeaseIPStart, IpGet(hWnd, E_DHCP_START));
+ UINTToIP(&t->DhcpLeaseIPEnd, IpGet(hWnd, E_DHCP_END));
+ UINTToIP(&t->DhcpSubnetMask, IpGet(hWnd, E_DHCP_MASK));
+ t->DhcpExpireTimeSpan = GetInt(hWnd, E_EXPIRES);
+ UINTToIP(&t->DhcpGatewayAddress, IpGet(hWnd, E_GATEWAY));
+ UINTToIP(&t->DhcpDnsServerAddress, IpGet(hWnd, E_DNS));
+ UINTToIP(&t->DhcpDnsServerAddress2, IpGet(hWnd, E_DNS2));
+ GetTxtA(hWnd, E_DOMAIN, t->DhcpDomainName, sizeof(t->DhcpDomainName));
+ t->SaveLog = IsChecked(hWnd, R_SAVE_LOG);
+}
+
+// Initialize
+void NmEditVhOptionInit(HWND hWnd, SM_HUB *r)
+{
+ char tmp[MAX_SIZE];
+ VH_OPTION t;
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ FormatText(hWnd, S_TITLE, r->HubName);
+
+ Zero(&t, sizeof(VH_OPTION));
+ StrCpy(t.HubName, sizeof(t.HubName), r->HubName);
+ if (CALL(hWnd, ScGetSecureNATOption(r->Rpc, &t)) == false)
+ {
+ EndDialog(hWnd, false);
+ return;
+ }
+
+ if (GetCapsBool(r->p->CapsList, "b_virtual_nat_disabled"))
+ {
+ SetEnable(hWnd, R_USE_NAT, false);
+ Check(hWnd, R_USE_NAT, false);
+ }
+
+ MacToStr(tmp, sizeof(tmp), t.MacAddress);
+ SetTextA(hWnd, E_MAC, tmp);
+ IpSet(hWnd, E_IP, IPToUINT(&t.Ip));
+ IpSet(hWnd, E_MASK, IPToUINT(&t.Mask));
+
+ Check(hWnd, R_USE_NAT, t.UseNat);
+ SetIntEx(hWnd, E_MTU, t.Mtu);
+ SetIntEx(hWnd, E_TCP, t.NatTcpTimeout);
+ SetIntEx(hWnd, E_UDP, t.NatUdpTimeout);
+
+ Check(hWnd, R_USE_DHCP, t.UseDhcp);
+ IpSet(hWnd, E_DHCP_START, IPToUINT(&t.DhcpLeaseIPStart));
+ IpSet(hWnd, E_DHCP_END, IPToUINT(&t.DhcpLeaseIPEnd));
+ IpSet(hWnd, E_DHCP_MASK, IPToUINT(&t.DhcpSubnetMask));
+ SetIntEx(hWnd, E_EXPIRES, t.DhcpExpireTimeSpan);
+
+ if (IPToUINT(&t.DhcpGatewayAddress) != 0)
+ {
+ IpSet(hWnd, E_GATEWAY, IPToUINT(&t.DhcpGatewayAddress));
+ }
+
+ if (IPToUINT(&t.DhcpDnsServerAddress) != 0)
+ {
+ IpSet(hWnd, E_DNS, IPToUINT(&t.DhcpDnsServerAddress));
+ }
+
+ if (IPToUINT(&t.DhcpDnsServerAddress2) != 0)
+ {
+ IpSet(hWnd, E_DNS2, IPToUINT(&t.DhcpDnsServerAddress2));
+ }
+
+ SetTextA(hWnd, E_DOMAIN, t.DhcpDomainName);
+ Check(hWnd, R_SAVE_LOG, t.SaveLog);
+
+ NmEditVhOptionUpdate(hWnd, r);
+
+}
+
+void NmEditVhOptionUpdate(HWND hWnd, SM_HUB *r)
+{
+ VH_OPTION t;
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ NmEditVhOptionFormToVH(hWnd, &t);
+
+ if (IsZero(t.MacAddress, 6))
+ {
+ ok = false;
+ }
+
+ if (IPToUINT(&t.Ip) == 0 || IPToUINT(&t.Mask) == 0)
+ {
+ ok = false;
+ }
+
+ if (IpIsFilled(hWnd, E_IP) == false || IpIsFilled(hWnd, E_MASK) == false)
+ {
+ ok = false;
+ }
+
+ if (IsHostIPAddress4(&t.Ip) == false || IsSubnetMask4(&t.Mask) == false)
+ {
+ ok = false;
+ }
+
+ if (t.UseNat)
+ {
+ if (t.Mtu < 64 || t.Mtu > 1500)
+ {
+ ok = false;
+ }
+
+ if (t.NatTcpTimeout < (NAT_TCP_MIN_TIMEOUT / 1000) || t.NatTcpTimeout > (NAT_TCP_MAX_TIMEOUT / 1000))
+ {
+ ok = false;
+ }
+
+ if (t.NatUdpTimeout < (NAT_UDP_MIN_TIMEOUT / 1000) || t.NatUdpTimeout > (NAT_UDP_MAX_TIMEOUT / 1000))
+ {
+ ok = false;
+ }
+ }
+
+ if (t.UseDhcp)
+ {
+ if (IpIsFilled(hWnd, E_DHCP_START) == false || IpIsFilled(hWnd, E_DHCP_END) == false ||
+ IpIsFilled(hWnd, E_DHCP_MASK) == false)
+ {
+ ok = false;
+ }
+
+ if (IpGetFilledNum(hWnd, E_GATEWAY) != 0 && IpGetFilledNum(hWnd, E_GATEWAY) != 4)
+ {
+ ok = false;
+ }
+
+ if (IpGetFilledNum(hWnd, E_DNS) != 0 && IpGetFilledNum(hWnd, E_DNS) != 4)
+ {
+ ok = false;
+ }
+
+ if (IpGetFilledNum(hWnd, E_DNS2) != 0 && IpGetFilledNum(hWnd, E_DNS2) != 4)
+ {
+ ok = false;
+ }
+
+ if (IPToUINT(&t.DhcpLeaseIPStart) == 0 || IPToUINT(&t.DhcpLeaseIPEnd) == 0 ||
+ IPToUINT(&t.DhcpSubnetMask) == 0)
+ {
+ ok = false;
+ }
+
+ if (t.DhcpExpireTimeSpan < 15)
+ {
+ ok = false;
+ }
+
+ if (Endian32(IPToUINT(&t.DhcpLeaseIPStart)) > Endian32(IPToUINT(&t.DhcpLeaseIPEnd)))
+ {
+ ok = false;
+ }
+
+ if (IsHostIPAddress4(&t.DhcpLeaseIPStart) == false ||
+ IsHostIPAddress4(&t.DhcpLeaseIPEnd) == false)
+ {
+ ok = false;
+ }
+
+ if (IsSubnetMask4(&t.DhcpSubnetMask) == false)
+ {
+ ok = false;
+ }
+ }
+
+ SetEnable(hWnd, E_MTU, t.UseNat);
+ SetEnable(hWnd, E_TCP, t.UseNat);
+ SetEnable(hWnd, E_UDP, t.UseNat);
+
+ SetEnable(hWnd, E_DHCP_START, t.UseDhcp);
+ SetEnable(hWnd, E_DHCP_END, t.UseDhcp);
+ SetEnable(hWnd, E_DHCP_MASK, t.UseDhcp);
+ SetEnable(hWnd, E_EXPIRES, t.UseDhcp);
+ SetEnable(hWnd, E_GATEWAY, t.UseDhcp);
+ SetEnable(hWnd, E_DNS, t.UseDhcp);
+ SetEnable(hWnd, E_DNS2, t.UseDhcp);
+ SetEnable(hWnd, E_DOMAIN, t.UseDhcp);
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// [OK] button
+void NmEditVhOptionOnOk(HWND hWnd, SM_HUB *r)
+{
+ VH_OPTION t;
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ NmEditVhOptionFormToVH(hWnd, &t);
+ StrCpy(t.HubName, sizeof(t.HubName), r->HubName);
+
+ if (CALL(hWnd, ScSetSecureNATOption(r->Rpc, &t)))
+ {
+ EndDialog(hWnd, true);
+ }
+}
+
+// Virtual host options editing dialog
+UINT NmEditVhOptionProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_HUB *r = (SM_HUB *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ NmEditVhOptionInit(hWnd, r);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_MAC:
+ case E_IP:
+ case E_MASK:
+ case R_USE_NAT:
+ case E_MTU:
+ case E_TCP:
+ case E_UDP:
+ case R_SAVE_LOG:
+ case R_USE_DHCP:
+ case E_DHCP_START:
+ case E_DHCP_END:
+ case E_DHCP_MASK:
+ case E_EXPIRES:
+ case E_GATEWAY:
+ case E_DNS:
+ case E_DNS2:
+ case E_DOMAIN:
+ NmEditVhOptionUpdate(hWnd, r);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ NmEditVhOptionOnOk(hWnd, r);
+ break;
+
+ case IDCANCEL:
+ EndDialog(hWnd, false);
+ break;
+
+ case R_USE_NAT:
+ if (IsChecked(hWnd, R_USE_NAT))
+ {
+ FocusEx(hWnd, E_MTU);
+ }
+
+ if (IsChecked(hWnd, R_USE_DHCP))
+ {
+ Focus(hWnd, E_DHCP_START);
+ }
+ break;
+ }
+
+ break;
+ }
+
+ return 0;
+}
+
+// Edit the virtual host option
+void NmEditVhOption(HWND hWnd, SM_HUB *r)
+{
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_NM_OPTION, NmEditVhOptionProc, r);
+}
+
+// Edit the client configuration
+void NmEditClientConfig(HWND hWnd, RPC *r)
+{
+ CM_ACCOUNT a;
+ RPC_CREATE_LINK t;
+ bool ret = false;
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ Zero(&a, sizeof(a));
+ Zero(&t, sizeof(t));
+
+ a.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ a.NatMode = true;
+ a.Rpc = r;
+
+ if (CALLEX(hWnd, NcGetClientConfig(r, &t)) != ERR_NO_ERROR)
+ {
+ // Create New
+ a.ClientOption->Port = 443;
+ a.ClientOption->RetryInterval = 15;
+ a.ClientOption->NumRetry = INFINITE;
+ a.ClientOption->AdditionalConnectionInterval = 1;
+ a.ClientOption->UseEncrypt = true;
+ a.ClientOption->NoRoutingTracking = true;
+ a.ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+ a.ClientAuth->AuthType = CLIENT_AUTHTYPE_PASSWORD;
+ }
+ else
+ {
+ // Edit
+ a.EditMode = true;
+ Copy(a.ClientOption, t.ClientOption, sizeof(CLIENT_OPTION));
+ a.ClientAuth = CopyClientAuth(t.ClientAuth);
+
+ FreeRpcCreateLink(&t);
+ }
+
+ ret = CmEditAccountDlg(hWnd, &a);
+
+ Free(a.ServerCert);
+ Free(a.ClientOption);
+ CiFreeClientAuth(a.ClientAuth);
+}
+
+// Initialize
+void NmMainDlgInit(HWND hWnd, RPC *r)
+{
+ // Validate arguments
+ if (r == NULL || hWnd == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_ROUTER);
+ FormatText(hWnd, 0, r->Sock->RemoteHostname);
+ DlgFont(hWnd, S_STATUS, 11, true);
+
+ NmMainDlgRefresh(hWnd, r);
+}
+
+// Update
+void NmMainDlgRefresh(HWND hWnd, RPC *r)
+{
+#if 0
+ RPC_NAT_STATUS t;
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ // Validate arguments
+ if (r == NULL || hWnd == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(RPC_NAT_STATUS));
+
+ CALL(hWnd, NcGetStatus(r, &t));
+
+ if (t.Online == false)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("NM_OFFLINE"));
+
+ Enable(hWnd, B_CONNECT);
+ Disable(hWnd, B_DISCONNECT);
+ }
+ else
+ {
+ if (t.Connected)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("NM_CONNECTED"), t.Status.ServerName);
+ }
+ else
+ {
+ if (t.LastError == ERR_NO_ERROR)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("NM_CONNECTING"));
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("NM_CONNECT_ERROR"), t.LastError, _E(t.LastError));
+ }
+ }
+ Disable(hWnd, B_CONNECT);
+ Enable(hWnd, B_DISCONNECT);
+ }
+
+ UniFormat(tmp2, sizeof(tmp2), _UU("NM_STATUS_TAG"), tmp);
+
+ SetText(hWnd, S_STATUS, tmp2);
+
+ FreeRpcNatStatus(&t);
+#endif
+}
+
+// Main dialog procedure
+UINT NmMainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+#if 0
+ SM_HUB *r = (SM_HUB *)param;
+ RPC_DUMMY dummy;
+ SM_SERVER sm;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ NmMainDlgInit(hWnd, r);
+
+ SetTimer(hWnd, 1, NM_REFRESH_TIME, NULL);
+
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_SETTING:
+ // Connection setting
+ NmEditClientConfig(hWnd, r);
+ break;
+
+ case B_CONNECT:
+ // Connection
+ Zero(&dummy, sizeof(dummy));
+ CALL(hWnd, NcOnline(r, &dummy));
+ NmMainDlgRefresh(hWnd, r);
+ break;
+
+ case B_DISCONNECT:
+ // Disconnect
+ Zero(&dummy, sizeof(dummy));
+ CALL(hWnd, NcOffline(r, &dummy));
+ NmMainDlgRefresh(hWnd, r);
+ break;
+
+ case B_OPTION:
+ // Operation setting
+ NmEditVhOption(hWnd, r->Rpc);
+ break;
+
+ case B_NAT:
+ // NAT
+ NmNat(hWnd, r);
+ break;
+
+ case B_DHCP:
+ // DHCP
+ NmDhcp(hWnd, r);
+ break;
+
+ case B_STATUS:
+ // Status
+ Zero(&sm, sizeof(sm));
+ sm.Rpc = r;
+ SmStatusDlg(hWnd, &sm, NULL, true, true, _UU("NM_STATUS"), ICO_ROUTER,
+ NULL, NmStatus);
+ break;
+
+ case B_INFO:
+ // Information
+ Zero(&sm, sizeof(sm));
+ sm.Rpc = r;
+ SmStatusDlg(hWnd, &sm, NULL, false, true, _UU("NM_INFO"), ICO_ROUTER,
+ NULL, NmInfo);
+ break;
+
+ case B_REFRESH:
+ // Refresh
+ NmMainDlgRefresh(hWnd, r);
+ break;
+
+ case B_PASSWORD:
+ // Change the password
+ NmChangePassword(hWnd, r);
+ break;
+
+ case B_ABOUT:
+ // Version information
+ About(hWnd, nm->Cedar, CEDAR_ROUTER_STR);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+
+ if (IsEnable(hWnd, 0))
+ {
+ NmMainDlgRefresh(hWnd, r);
+ }
+
+ SetTimer(hWnd, 1, NM_REFRESH_TIME, NULL);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+#endif
+
+ return 0;
+}
+
+// Main dialog
+void NmMainDlg(RPC *r)
+{
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+ Dialog(NULL, D_NM_MAIN, NmMainDlgProc, r);
+}
+
+// Login dialog
+UINT NmLogin(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ NM_LOGIN *login = (NM_LOGIN *)param;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ FormatText(hWnd, S_TITLE, login->Hostname);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ GetTxtA(hWnd, E_PASSWORD, tmp, sizeof(tmp));
+ Hash(login->hashed_password, tmp, StrLen(tmp), true);
+ EndDialog(hWnd, true);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Connecting dialog
+UINT NmConnectDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ NM_CONNECT *t = (NM_CONNECT *)param;
+ RPC *rpc;
+ NM_LOGIN login;
+ UINT err;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ FormatText(hWnd, S_TITLE, t->Hostname);
+ SetTimer(hWnd, 1, 50, NULL);
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+
+ while (true)
+ {
+ bool flag = false;
+RETRY_PASSWORD:
+ // Password input dialog
+ Zero(&login, sizeof(login));
+ login.Hostname = t->Hostname;
+ login.Port = t->Port;
+ Hash(login.hashed_password, "", 0, true);
+
+ if (flag)
+ {
+ if (Dialog(hWnd, D_NM_LOGIN, NmLogin, &login) == false)
+ {
+ EndDialog(hWnd, false);
+ break;
+ }
+ }
+
+RETRY_CONNECT:
+ Refresh(DlgItem(hWnd, S_TITLE));
+ Refresh(hWnd);
+ // Connection
+ rpc = NatAdminConnect(nm->Cedar, t->Hostname, t->Port, login.hashed_password, &err);
+ if (rpc != NULL)
+ {
+ t->Rpc = rpc;
+ EndDialog(hWnd, true);
+ break;
+ }
+
+ // Error
+ if (err == ERR_ACCESS_DENIED || err == ERR_AUTH_FAILED)
+ {
+ if (flag)
+ {
+ if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_RETRYCANCEL,
+ _E(err)) == IDCANCEL)
+ {
+ EndDialog(hWnd, false);
+ break;
+ }
+ }
+ flag = true;
+ goto RETRY_PASSWORD;
+ }
+ else
+ {
+ if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_RETRYCANCEL,
+ _E(err)) == IDCANCEL)
+ {
+ EndDialog(hWnd, false);
+ break;
+ }
+ goto RETRY_CONNECT;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Connect to the User-mode NAT program
+RPC *NmConnect(char *hostname, UINT port)
+{
+ NM_CONNECT t;
+ // Validate arguments
+ if (hostname == NULL || port == 0)
+ {
+ return NULL;
+ }
+
+ Zero(&t, sizeof(t));
+ t.Hostname = hostname;
+ t.Port = port;
+
+ Dialog(NULL, D_NM_CONNECT, NmConnectDlgProc, &t);
+
+ return t.Rpc;
+}
+
+// Main process
+void MainNM()
+{
+ UINT port;
+ char hostname[MAX_HOST_NAME_LEN + 1];
+ char *tmp =
+ RemoteDlg(NULL, NM_SETTING_REG_KEY, ICO_ROUTER,
+ _UU("NM_TITLE"), _UU("NM_CONNECT_TITLE"), NULL);
+ TOKEN_LIST *t;
+
+ Zero(hostname, sizeof(hostname));
+
+ if (tmp == NULL)
+ {
+ return;
+ }
+
+ t = ParseToken(tmp, ":");
+ port = DEFAULT_NAT_ADMIN_PORT;
+
+ if (t->NumTokens >= 2)
+ {
+ UINT i = ToInt(t->Token[1]);
+ if (i != 0)
+ {
+ port = i;
+ }
+ }
+ if (t->NumTokens >= 1)
+ {
+ RPC *rpc;
+ StrCpy(hostname, sizeof(hostname), t->Token[0]);
+
+ // Connection
+ Trim(hostname);
+
+ if (StrLen(hostname) != 0)
+ {
+ rpc = NmConnect(hostname, port);
+ if (rpc != NULL)
+ {
+ // Connected
+ NmMainDlg(rpc);
+ NatAdminDisconnect(rpc);
+ }
+ }
+ }
+
+ FreeToken(t);
+
+ Free(tmp);
+}
+
+// Initialize
+void InitNM()
+{
+ if (nm != NULL)
+ {
+ // Already initialized
+ return;
+ }
+
+ nm = ZeroMalloc(sizeof(NM));
+
+ InitWinUi(_UU("NM_TITLE"), _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+
+ nm->Cedar = NewCedar(NULL, NULL);
+
+ InitCM(false);
+ InitSM();
+}
+
+// Release
+void FreeNM()
+{
+ if (nm == NULL)
+ {
+ // Uninitialized
+ return;
+ }
+
+ FreeSM();
+ FreeCM();
+
+ ReleaseCedar(nm->Cedar);
+
+ FreeWinUi();
+
+ Free(nm);
+ nm = NULL;
+}
+
+// Execution of NM
+void NMExec()
+{
+ InitNM();
+ MainNM();
+ FreeNM();
+}
+
+#endif
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/NM.h b/src/Cedar/NM.h
new file mode 100644
index 00000000..27039ea6
--- /dev/null
+++ b/src/Cedar/NM.h
@@ -0,0 +1,96 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// NM.h
+// Header of NM.c
+
+#ifndef NM_H
+#define NM_H
+
+// External function
+void NMExec();
+
+#endif // NM_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/NMInner.h b/src/Cedar/NMInner.h
new file mode 100644
index 00000000..802172dc
--- /dev/null
+++ b/src/Cedar/NMInner.h
@@ -0,0 +1,148 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// NMInner.h
+// The internal header of NM.c
+
+
+// Constants
+#define NM_REG_KEY "Software\\" GC_REG_COMPANY_NAME "\\PacketiX VPN\\User-mode Router Manager"
+#define NM_SETTING_REG_KEY "Software\\" GC_REG_COMPANY_NAME "\\PacketiX VPN\\User-mode Router Manager\\Settings"
+
+#define NM_REFRESH_TIME 1000
+#define NM_NAT_REFRESH_TIME 1000
+#define NM_DHCP_REFRESH_TIME 1000
+
+// Nat Admin structure
+typedef struct NM
+{
+ CEDAR *Cedar; // Cedar
+} NM;
+
+// Connection structure
+typedef struct NM_CONNECT
+{
+ RPC *Rpc; // RPC
+ char *Hostname;
+ UINT Port;
+} NM_CONNECT;
+
+// Login
+typedef struct NM_LOGIN
+{
+ char *Hostname;
+ UINT Port;
+ UCHAR hashed_password[SHA1_SIZE];
+} NM_LOGIN;
+
+// Internal function
+void InitNM();
+void FreeNM();
+void MainNM();
+RPC *NmConnect(char *hostname, UINT port);
+UINT NmConnectDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+UINT NmLogin(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void NmMainDlg(RPC *r);
+UINT NmMainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void NmMainDlgInit(HWND hWnd, RPC *r);
+void NmMainDlgRefresh(HWND hWnd, RPC *r);
+void NmEditClientConfig(HWND hWnd, RPC *r);
+void NmEditVhOption(HWND hWnd, SM_HUB *r);
+UINT NmEditVhOptionProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void NmEditVhOptionInit(HWND hWnd, SM_HUB *r);
+void NmEditVhOptionUpdate(HWND hWnd, SM_HUB *r);
+void NmEditVhOptionOnOk(HWND hWnd, SM_HUB *r);
+void NmEditVhOptionFormToVH(HWND hWnd, VH_OPTION *t);
+bool NmStatus(HWND hWnd, SM_SERVER *s, void *param);
+bool NmInfo(HWND hWnd, SM_SERVER *s, void *param);
+void NmNat(HWND hWnd, SM_HUB *r);
+UINT NmNatProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void NmNatInit(HWND hWnd, SM_HUB *r);
+void NmNatRefresh(HWND hWnd, SM_HUB *r);
+void NmDhcp(HWND hWnd, SM_HUB *r);
+UINT NmDhcpProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void NmDhcpRefresh(HWND hWnd, SM_HUB *r);
+void NmDhcpInit(HWND hWnd, SM_HUB *r);
+void NmChangePassword(HWND hWnd, RPC *r);
+UINT NmChangePasswordProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Nat.c b/src/Cedar/Nat.c
new file mode 100644
index 00000000..33e6243e
--- /dev/null
+++ b/src/Cedar/Nat.c
@@ -0,0 +1,1876 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Nat.c
+// User-mode Router
+
+#include "CedarPch.h"
+
+static LOCK *nat_lock = NULL;
+static NAT *nat = NULL;
+
+
+// Disconnect the connection for the NAT administrator
+void NatAdminDisconnect(RPC *r)
+{
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+ EndRpc(r);
+}
+
+// Connection for NAT administrator
+RPC *NatAdminConnect(CEDAR *cedar, char *hostname, UINT port, void *hashed_password, UINT *err)
+{
+ UCHAR secure_password[SHA1_SIZE];
+ UCHAR random[SHA1_SIZE];
+ SOCK *sock;
+ RPC *rpc;
+ PACK *p;
+ UINT error;
+ // Validate arguments
+ if (cedar == NULL || hostname == NULL || port == 0 || hashed_password == NULL || err == NULL)
+ {
+ if (err != NULL)
+ {
+ *err = ERR_INTERNAL_ERROR;
+ }
+ return NULL;
+ }
+
+ // Connection
+ sock = Connect(hostname, port);
+ if (sock == NULL)
+ {
+ *err = ERR_CONNECT_FAILED;
+ return NULL;
+ }
+
+ if (StartSSL(sock, NULL, NULL) == false)
+ {
+ *err = ERR_PROTOCOL_ERROR;
+ ReleaseSock(sock);
+ return NULL;
+ }
+
+ SetTimeout(sock, 5000);
+
+ p = HttpClientRecv(sock);
+ if (p == NULL)
+ {
+ *err = ERR_DISCONNECTED;
+ ReleaseSock(sock);
+ return NULL;
+ }
+
+ if (PackGetData2(p, "auth_random", random, SHA1_SIZE) == false)
+ {
+ FreePack(p);
+ *err = ERR_PROTOCOL_ERROR;
+ ReleaseSock(sock);
+ return NULL;
+ }
+
+ FreePack(p);
+
+ SecurePassword(secure_password, hashed_password, random);
+
+ p = NewPack();
+ PackAddData(p, "secure_password", secure_password, SHA1_SIZE);
+
+ if (HttpClientSend(sock, p) == false)
+ {
+ FreePack(p);
+ *err = ERR_DISCONNECTED;
+ ReleaseSock(sock);
+ return NULL;
+ }
+
+ FreePack(p);
+
+ p = HttpClientRecv(sock);
+ if (p == NULL)
+ {
+ *err = ERR_DISCONNECTED;
+ ReleaseSock(sock);
+ return NULL;
+ }
+
+ error = GetErrorFromPack(p);
+
+ FreePack(p);
+
+ if (error != ERR_NO_ERROR)
+ {
+ *err = error;
+ ReleaseSock(sock);
+ return NULL;
+ }
+
+ SetTimeout(sock, TIMEOUT_INFINITE);
+
+ rpc = StartRpcClient(sock, NULL);
+ ReleaseSock(sock);
+
+ return rpc;
+}
+
+// RPC functional related macro
+#define DECLARE_RPC_EX(rpc_name, data_type, function, in_rpc, out_rpc, free_rpc) \
+ else if (StrCmpi(name, rpc_name) == 0) \
+ { \
+ data_type t; \
+ Zero(&t, sizeof(t)); \
+ in_rpc(&t, p); \
+ err = function(n, &t); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ out_rpc(ret, &t); \
+ } \
+ free_rpc(&t); \
+ ok = true; \
+ }
+#define DECLARE_RPC(rpc_name, data_type, function, in_rpc, out_rpc) \
+ else if (StrCmpi(name, rpc_name) == 0) \
+ { \
+ data_type t; \
+ Zero(&t, sizeof(t)); \
+ in_rpc(&t, p); \
+ err = function(n, &t); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ out_rpc(ret, &t); \
+ } \
+ ok = true; \
+ }
+#define DECLARE_SC_EX(rpc_name, data_type, function, in_rpc, out_rpc, free_rpc) \
+ UINT function(RPC *r, data_type *t) \
+ { \
+ PACK *p, *ret; \
+ UINT err; \
+ if (r == NULL || t == NULL) \
+ { \
+ return ERR_INTERNAL_ERROR; \
+ } \
+ p = NewPack(); \
+ out_rpc(p, t); \
+ free_rpc(t); \
+ Zero(t, sizeof(data_type)); \
+ ret = AdminCall(r, rpc_name, p); \
+ err = GetErrorFromPack(ret); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ in_rpc(t, ret); \
+ } \
+ FreePack(ret); \
+ return err; \
+ }
+#define DECLARE_SC(rpc_name, data_type, function, in_rpc, out_rpc) \
+ UINT function(RPC *r, data_type *t) \
+ { \
+ PACK *p, *ret; \
+ UINT err; \
+ if (r == NULL || t == NULL) \
+ { \
+ return ERR_INTERNAL_ERROR; \
+ } \
+ p = NewPack(); \
+ out_rpc(p, t); \
+ ret = AdminCall(r, rpc_name, p); \
+ err = GetErrorFromPack(ret); \
+ if (err == ERR_NO_ERROR) \
+ { \
+ in_rpc(t, ret); \
+ } \
+ FreePack(ret); \
+ return err; \
+ }
+
+// RPC server function
+PACK *NiRpcServer(RPC *r, char *name, PACK *p)
+{
+ NAT *n = (NAT *)r->Param;
+ PACK *ret;
+ UINT err;
+ bool ok;
+ // Validate arguments
+ if (r == NULL || name == NULL || p == NULL)
+ {
+ return NULL;
+ }
+
+ ret = NewPack();
+ err = ERR_NO_ERROR;
+ ok = false;
+
+ if (0) {}
+
+ // RPC function definition: From here
+
+// DECLARE_RPC("Online", RPC_DUMMY, NtOnline, InRpcDummy, OutRpcDummy)
+// DECLARE_RPC("Offline", RPC_DUMMY, NtOffline, InRpcDummy, OutRpcDummy)
+ DECLARE_RPC("SetHostOption", VH_OPTION, NtSetHostOption, InVhOption, OutVhOption)
+ DECLARE_RPC("GetHostOption", VH_OPTION, NtGetHostOption, InVhOption, OutVhOption)
+// DECLARE_RPC_EX("SetClientConfig", RPC_CREATE_LINK, NtSetClientConfig, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+// DECLARE_RPC_EX("GetClientConfig", RPC_CREATE_LINK, NtGetClientConfig, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+ DECLARE_RPC_EX("GetStatus", RPC_NAT_STATUS, NtGetStatus, InRpcNatStatus, OutRpcNatStatus, FreeRpcNatStatus)
+// DECLARE_RPC_EX("GetInfo", RPC_NAT_INFO, NtGetInfo, InRpcNatInfo, OutRpcNatInfo, FreeRpcNatInfo)
+ DECLARE_RPC_EX("EnumNatList", RPC_ENUM_NAT, NtEnumNatList, InRpcEnumNat, OutRpcEnumNat, FreeRpcEnumNat)
+ DECLARE_RPC_EX("EnumDhcpList", RPC_ENUM_DHCP, NtEnumDhcpList, InRpcEnumDhcp, OutRpcEnumDhcp, FreeRpcEnumDhcp)
+// DECLARE_RPC("SetPassword", RPC_SET_PASSWORD, NtSetPassword, InRpcSetPassword, OutRpcSetPassword)
+
+ // RPC function definition: To here
+
+ if (ok == false)
+ {
+ err = ERR_NOT_SUPPORTED;
+ }
+
+ PackAddInt(ret, "error", err);
+
+ return ret;
+}
+
+
+
+
+// RPC call definition: From here
+
+DECLARE_SC("Online", RPC_DUMMY, NcOnline, InRpcDummy, OutRpcDummy)
+DECLARE_SC("Offline", RPC_DUMMY, NcOffline, InRpcDummy, OutRpcDummy)
+DECLARE_SC("SetHostOption", VH_OPTION, NcSetHostOption, InVhOption, OutVhOption)
+DECLARE_SC("GetHostOption", VH_OPTION, NcGetHostOption, InVhOption, OutVhOption)
+DECLARE_SC_EX("SetClientConfig", RPC_CREATE_LINK, NcSetClientConfig, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+DECLARE_SC_EX("GetClientConfig", RPC_CREATE_LINK, NcGetClientConfig, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)
+DECLARE_SC_EX("GetStatus", RPC_NAT_STATUS, NcGetStatus, InRpcNatStatus, OutRpcNatStatus, FreeRpcNatStatus)
+DECLARE_SC_EX("GetInfo", RPC_NAT_INFO, NcGetInfo, InRpcNatInfo, OutRpcNatInfo, FreeRpcNatInfo)
+DECLARE_SC_EX("EnumNatList", RPC_ENUM_NAT, NcEnumNatList, InRpcEnumNat, OutRpcEnumNat, FreeRpcEnumNat)
+DECLARE_SC_EX("EnumDhcpList", RPC_ENUM_DHCP, NcEnumDhcpList, InRpcEnumDhcp, OutRpcEnumDhcp, FreeRpcEnumDhcp)
+DECLARE_SC("SetPassword", RPC_SET_PASSWORD, NcSetPassword, InRpcSetPassword, OutRpcSetPassword)
+
+// RPC call definition: To here
+
+
+
+// Set a password
+UINT NtSetPassword(NAT *n, RPC_SET_PASSWORD *t)
+{
+ Copy(n->HashedPassword, t->HashedPassword, SHA1_SIZE);
+
+ NiWriteConfig(n);
+
+ return ERR_NO_ERROR;
+}
+
+// Online
+UINT NtOnline(NAT *n, RPC_DUMMY *t)
+{
+ UINT ret = ERR_NO_ERROR;
+
+ Lock(n->lock);
+ {
+ if (n->Online)
+ {
+ // It is already online
+ ret = ERR_ALREADY_ONLINE;
+ }
+ else
+ {
+ if (n->ClientOption == NULL || n->ClientAuth == NULL)
+ {
+ // Setting is not yet done
+ ret = ERR_ACCOUNT_NOT_PRESENT;
+ }
+ else
+ {
+ // OK
+ n->Online = true;
+
+ // Start connection
+ n->Virtual = NewVirtualHostEx(n->Cedar, n->ClientOption, n->ClientAuth,
+ &n->Option, n);
+ }
+ }
+ }
+ Unlock(n->lock);
+
+ NiWriteConfig(n);
+
+ return ret;
+}
+
+// Offline
+UINT NtOffline(NAT *n, RPC_DUMMY *t)
+{
+ UINT ret = ERR_NO_ERROR;
+
+ Lock(n->lock);
+ {
+ if (n->Online == false)
+ {
+ // It is offline
+ ret = ERR_OFFLINE;
+ }
+ else
+ {
+ // Offline
+ StopVirtualHost(n->Virtual);
+ ReleaseVirtual(n->Virtual);
+ n->Virtual = NULL;
+
+ n->Online = false;
+ }
+ }
+ Unlock(n->lock);
+
+ NiWriteConfig(n);
+
+ return ret;
+}
+
+// Set host options
+UINT NtSetHostOption(NAT *n, VH_OPTION *t)
+{
+ UINT ret = ERR_NO_ERROR;
+
+ Lock(n->lock);
+ {
+ Copy(&n->Option, t, sizeof(VH_OPTION));
+ }
+ Unlock(n->lock);
+
+ SetVirtualHostOption(n->Virtual, t);
+
+ NiWriteConfig(n);
+
+ return ret;
+}
+
+// Get host options
+UINT NtGetHostOption(NAT *n, VH_OPTION *t)
+{
+ UINT ret = ERR_NO_ERROR;
+
+ Lock(n->lock);
+ {
+ Copy(t, &n->Option, sizeof(VH_OPTION));
+ }
+ Unlock(n->lock);
+
+ return ret;
+}
+
+// Set the connection settings
+UINT NtSetClientConfig(NAT *n, RPC_CREATE_LINK *t)
+{
+ Lock(n->lock);
+ {
+ if (n->ClientOption != NULL || n->ClientAuth != NULL)
+ {
+ Free(n->ClientOption);
+ CiFreeClientAuth(n->ClientAuth);
+ }
+
+ n->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(n->ClientOption, t->ClientOption, sizeof(CLIENT_OPTION));
+ n->ClientAuth = CopyClientAuth(t->ClientAuth);
+ }
+ Unlock(n->lock);
+
+ NiWriteConfig(n);
+
+ if (n->Online)
+ {
+ NtOffline(n, NULL);
+ NtOnline(n, NULL);
+ }
+
+ return ERR_NO_ERROR;
+}
+
+// Get the connection settings
+UINT NtGetClientConfig(NAT *n, RPC_CREATE_LINK *t)
+{
+ UINT err = ERR_NO_ERROR;
+
+ Lock(n->lock);
+ {
+ if (n->ClientOption == NULL || n->ClientAuth == NULL)
+ {
+ err = ERR_ACCOUNT_NOT_PRESENT;
+ }
+ else
+ {
+ FreeRpcCreateLink(t);
+
+ Zero(t, sizeof(RPC_CREATE_LINK));
+ t->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ Copy(t->ClientOption, n->ClientOption, sizeof(CLIENT_OPTION));
+ t->ClientAuth = CopyClientAuth(n->ClientAuth);
+ }
+ }
+ Unlock(n->lock);
+
+ return err;
+}
+
+// Get the state
+UINT NtGetStatus(NAT *n, RPC_NAT_STATUS *t)
+{
+ Lock(n->lock);
+ {
+ VH *v = n->Virtual;
+ FreeRpcNatStatus(t);
+ Zero(t, sizeof(RPC_NAT_STATUS));
+
+ LockVirtual(v);
+ {
+ UINT i;
+
+ LockList(v->NatTable);
+ {
+ for (i = 0;i < LIST_NUM(v->NatTable);i++)
+ {
+ NAT_ENTRY *e = LIST_DATA(v->NatTable, i);
+
+ switch (e->Protocol)
+ {
+ case NAT_TCP:
+ t->NumTcpSessions++;
+ break;
+
+ case NAT_UDP:
+ t->NumUdpSessions++;
+ break;
+
+ case NAT_ICMP:
+ t->NumIcmpSessions++;
+ break;
+
+ case NAT_DNS:
+ t->NumDnsSessions++;
+ break;
+ }
+ }
+
+ if (NnIsActive(v) && v->NativeNat != NULL)
+ {
+ NATIVE_NAT *nn = v->NativeNat;
+
+ for (i = 0;i < LIST_NUM(nn->NatTableForSend->AllList);i++)
+ {
+ NATIVE_NAT_ENTRY *e = LIST_DATA(nn->NatTableForSend->AllList, i);
+
+ switch (e->Protocol)
+ {
+ case NAT_TCP:
+ t->NumTcpSessions++;
+ break;
+
+ case NAT_UDP:
+ t->NumUdpSessions++;
+ break;
+
+ case NAT_ICMP:
+ t->NumIcmpSessions++;
+ break;
+
+ case NAT_DNS:
+ t->NumDnsSessions++;
+ break;
+ }
+ }
+ }
+ }
+ UnlockList(v->NatTable);
+
+ t->NumDhcpClients = LIST_NUM(v->DhcpLeaseList);
+
+ t->IsKernelMode = NnIsActive(v);
+ }
+ UnlockVirtual(v);
+ }
+ Unlock(n->lock);
+
+ return ERR_NO_ERROR;
+}
+
+// Get the information
+UINT NtGetInfo(NAT *n, RPC_NAT_INFO *t)
+{
+ OS_INFO *info;
+ FreeRpcNatInfo(t);
+ Zero(t, sizeof(RPC_NAT_INFO));
+
+ StrCpy(t->NatProductName, sizeof(t->NatProductName), CEDAR_ROUTER_STR);
+ StrCpy(t->NatVersionString, sizeof(t->NatVersionString), n->Cedar->VerString);
+ StrCpy(t->NatBuildInfoString, sizeof(t->NatBuildInfoString), n->Cedar->BuildInfo);
+ t->NatVerInt = n->Cedar->Build;
+ t->NatBuildInt = n->Cedar->Build;
+
+ GetMachineName(t->NatHostName, sizeof(t->NatHostName));
+
+ info = GetOsInfo();
+
+ CopyOsInfo(&t->OsInfo, info);
+
+ GetMemInfo(&t->MemInfo);
+
+ return ERR_NO_ERROR;
+}
+
+// Get the NAT list
+UINT NtEnumNatList(NAT *n, RPC_ENUM_NAT *t)
+{
+ UINT ret = ERR_NO_ERROR;
+ VH *v = NULL;
+
+ Lock(n->lock);
+ {
+ v = n->Virtual;
+
+ if (n->Online == false || v == NULL)
+ {
+ ret = ERR_OFFLINE;
+ }
+ else
+ {
+ LockVirtual(v);
+ {
+ if (v->Active == false)
+ {
+ ret = ERR_OFFLINE;
+ }
+ else
+ {
+ FreeRpcEnumNat(t);
+ Zero(t, sizeof(RPC_ENUM_NAT));
+
+ LockList(v->NatTable);
+ {
+ UINT i;
+ UINT num_usermode_nat = LIST_NUM(v->NatTable);
+ UINT num_kernel_mode_nat = 0;
+ NATIVE_NAT *native = NULL;
+
+ if (NnIsActive(v) && (v->NativeNat != NULL))
+ {
+ native = v->NativeNat;
+
+ num_kernel_mode_nat = LIST_NUM(native->NatTableForSend->AllList);
+ }
+
+ t->NumItem = num_usermode_nat + num_kernel_mode_nat;
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_NAT_ITEM) * t->NumItem);
+
+ // Enumerate entries of the user mode NAT
+ for (i = 0;i < num_usermode_nat;i++)
+ {
+ NAT_ENTRY *nat = LIST_DATA(v->NatTable, i);
+ RPC_ENUM_NAT_ITEM *e = &t->Items[i];
+
+ e->Id = nat->Id;
+ e->Protocol = nat->Protocol;
+ e->SrcIp = nat->SrcIp;
+ e->DestIp = nat->DestIp;
+ e->SrcPort = nat->SrcPort;
+ e->DestPort = nat->DestPort;
+
+ e->CreatedTime = TickToTime(nat->CreatedTime);
+ e->LastCommTime = TickToTime(nat->LastCommTime);
+
+ IPToStr32(e->SrcHost, sizeof(e->SrcHost), e->SrcIp);
+ IPToStr32(e->DestHost, sizeof(e->DestHost), e->DestIp);
+
+ if (nat->Sock != NULL)
+ {
+ e->SendSize = nat->Sock->SendSize;
+ e->RecvSize = nat->Sock->RecvSize;
+
+ if (nat->Sock->Type == SOCK_TCP)
+ {
+ StrCpy(e->DestHost, sizeof(e->DestHost), nat->Sock->RemoteHostname);
+ }
+ }
+
+ e->TcpStatus = nat->TcpStatus;
+ }
+
+ // Enumerate the entries in the kernel-mode NAT
+ if (native != NULL)
+ {
+ for (i = 0;i < num_kernel_mode_nat;i++)
+ {
+ NATIVE_NAT_ENTRY *nat = LIST_DATA(native->NatTableForSend->AllList, i);
+ RPC_ENUM_NAT_ITEM *e = &t->Items[num_usermode_nat + i];
+
+ e->Id = nat->Id;
+ e->Protocol = nat->Protocol;
+ e->SrcIp = nat->SrcIp;
+ e->DestIp = nat->DestIp;
+ e->SrcPort = nat->SrcPort;
+ e->DestPort = nat->DestPort;
+ e->CreatedTime = TickToTime(nat->CreatedTime);
+ e->LastCommTime = TickToTime(nat->LastCommTime);
+
+ IPToStr32(e->SrcHost, sizeof(e->SrcHost), e->SrcIp);
+ IPToStr32(e->DestHost, sizeof(e->DestHost), e->DestIp);
+
+ e->SendSize = nat->TotalSent;
+ e->RecvSize = nat->TotalRecv;
+
+ e->TcpStatus = nat->Status;
+ }
+ }
+ }
+ UnlockList(v->NatTable);
+ }
+ }
+ UnlockVirtual(v);
+ }
+ }
+ Unlock(n->lock);
+
+ return ret;
+}
+
+UINT NtEnumDhcpList(NAT *n, RPC_ENUM_DHCP *t)
+{
+ UINT ret = ERR_NO_ERROR;
+ VH *v = NULL;
+
+ Lock(n->lock);
+ {
+ v = n->Virtual;
+
+ if (n->Online == false || v == NULL)
+ {
+ ret = ERR_OFFLINE;
+ }
+ else
+ {
+ LockVirtual(v);
+ {
+ if (v->Active == false)
+ {
+ ret = ERR_OFFLINE;
+ }
+ else
+ {
+ FreeRpcEnumDhcp(t);
+ Zero(t, sizeof(RPC_ENUM_DHCP));
+
+ LockList(v->DhcpLeaseList);
+ {
+ UINT i;
+ t->NumItem = LIST_NUM(v->DhcpLeaseList);
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_DHCP_ITEM) * t->NumItem);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ DHCP_LEASE *dhcp = LIST_DATA(v->DhcpLeaseList, i);
+ RPC_ENUM_DHCP_ITEM *e = &t->Items[i];
+
+ e->Id = dhcp->Id;
+ e->LeasedTime = TickToTime(dhcp->LeasedTime);
+ e->ExpireTime = TickToTime(dhcp->ExpireTime);
+ Copy(e->MacAddress, dhcp->MacAddress, 6);
+ e->IpAddress = dhcp->IpAddress;
+ e->Mask = dhcp->Mask;
+ StrCpy(e->Hostname, sizeof(e->Hostname), dhcp->Hostname);
+ }
+ }
+ UnlockList(v->DhcpLeaseList);
+ }
+ }
+ UnlockVirtual(v);
+ }
+ }
+ Unlock(n->lock);
+
+ return ret;
+}
+
+// VH_OPTION
+void InVhOption(VH_OPTION *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(VH_OPTION));
+ PackGetData2(p, "MacAddress", t->MacAddress, 6);
+ PackGetIp(p, "Ip", &t->Ip);
+ PackGetIp(p, "Mask", &t->Mask);
+ t->UseNat = PackGetBool(p, "UseNat");
+ t->Mtu = PackGetInt(p, "Mtu");
+ t->NatTcpTimeout = PackGetInt(p, "NatTcpTimeout");
+ t->NatUdpTimeout = PackGetInt(p, "NatUdpTimeout");
+ t->UseDhcp = PackGetBool(p, "UseDhcp");
+ PackGetIp(p, "DhcpLeaseIPStart", &t->DhcpLeaseIPStart);
+ PackGetIp(p, "DhcpLeaseIPEnd", &t->DhcpLeaseIPEnd);
+ PackGetIp(p, "DhcpSubnetMask", &t->DhcpSubnetMask);
+ t->DhcpExpireTimeSpan = PackGetInt(p, "DhcpExpireTimeSpan");
+ PackGetIp(p, "DhcpGatewayAddress", &t->DhcpGatewayAddress);
+ PackGetIp(p, "DhcpDnsServerAddress", &t->DhcpDnsServerAddress);
+ PackGetIp(p, "DhcpDnsServerAddress2", &t->DhcpDnsServerAddress2);
+ PackGetStr(p, "DhcpDomainName", t->DhcpDomainName, sizeof(t->DhcpDomainName));
+ t->SaveLog = PackGetBool(p, "SaveLog");
+ PackGetStr(p, "RpcHubName", t->HubName, sizeof(t->HubName));
+}
+void OutVhOption(PACK *p, VH_OPTION *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddData(p, "MacAddress", t->MacAddress, 6);
+ PackAddIp(p, "Ip", &t->Ip);
+ PackAddIp(p, "Mask", &t->Mask);
+ PackAddBool(p, "UseNat", t->UseNat);
+ PackAddInt(p, "Mtu", t->Mtu);
+ PackAddInt(p, "NatTcpTimeout", t->NatTcpTimeout);
+ PackAddInt(p, "NatUdpTimeout", t->NatUdpTimeout);
+ PackAddBool(p, "UseDhcp", t->UseDhcp);
+ PackAddIp(p, "DhcpLeaseIPStart", &t->DhcpLeaseIPStart);
+ PackAddIp(p, "DhcpLeaseIPEnd", &t->DhcpLeaseIPEnd);
+ PackAddIp(p, "DhcpSubnetMask", &t->DhcpSubnetMask);
+ PackAddInt(p, "DhcpExpireTimeSpan", t->DhcpExpireTimeSpan);
+ PackAddIp(p, "DhcpGatewayAddress", &t->DhcpGatewayAddress);
+ PackAddIp(p, "DhcpDnsServerAddress", &t->DhcpDnsServerAddress);
+ PackAddIp(p, "DhcpDnsServerAddress2", &t->DhcpDnsServerAddress2);
+ PackAddStr(p, "DhcpDomainName", t->DhcpDomainName);
+ PackAddBool(p, "SaveLog", t->SaveLog);
+ PackAddStr(p, "RpcHubName", t->HubName);
+}
+
+// RPC_ENUM_DHCP
+void InRpcEnumDhcp(RPC_ENUM_DHCP *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_DHCP));
+ t->NumItem = PackGetInt(p, "NumItem");
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_DHCP_ITEM) * t->NumItem);
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_DHCP_ITEM *e = &t->Items[i];
+
+ e->Id = PackGetIntEx(p, "Id", i);
+ e->LeasedTime = PackGetInt64Ex(p, "LeasedTime", i);
+ e->ExpireTime = PackGetInt64Ex(p, "ExpireTime", i);
+ PackGetDataEx2(p, "MacAddress", e->MacAddress, 6, i);
+ e->IpAddress = PackGetIp32Ex(p, "IpAddress", i);
+ e->Mask = PackGetIntEx(p, "Mask", i);
+ PackGetStrEx(p, "Hostname", e->Hostname, sizeof(e->Hostname), i);
+ }
+}
+void OutRpcEnumDhcp(PACK *p, RPC_ENUM_DHCP *t)
+{
+ UINT i;
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+ PackAddStr(p, "HubName", t->HubName);
+
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_DHCP_ITEM *e = &t->Items[i];
+
+ PackAddIntEx(p, "Id", e->Id, i, t->NumItem);
+ PackAddInt64Ex(p, "LeasedTime", e->LeasedTime, i, t->NumItem);
+ PackAddInt64Ex(p, "ExpireTime", e->ExpireTime, i, t->NumItem);
+ PackAddDataEx(p, "MacAddress", e->MacAddress, 6, i, t->NumItem);
+ PackAddIp32Ex(p, "IpAddress", e->IpAddress, i, t->NumItem);
+ PackAddIntEx(p, "Mask", e->Mask, i, t->NumItem);
+ PackAddStrEx(p, "Hostname", e->Hostname, i, t->NumItem);
+ }
+}
+void FreeRpcEnumDhcp(RPC_ENUM_DHCP *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_ENUM_NAT
+void InRpcEnumNat(RPC_ENUM_NAT *t, PACK *p)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_ENUM_NAT));
+ t->NumItem = PackGetInt(p, "NumItem");
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+ t->Items = ZeroMalloc(sizeof(RPC_ENUM_NAT_ITEM) * t->NumItem);
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_NAT_ITEM *e = &t->Items[i];
+
+ e->Id = PackGetIntEx(p, "Id", i);
+ e->Protocol = PackGetIntEx(p, "Protocol", i);
+ e->SrcIp = PackGetIntEx(p, "SrcIp", i);
+ PackGetStrEx(p, "SrcHost", e->SrcHost, sizeof(e->SrcHost), i);
+ e->SrcPort = PackGetIntEx(p, "SrcPort", i);
+ e->DestIp = PackGetIntEx(p, "DestIp", i);
+ PackGetStrEx(p, "DestHost", e->DestHost, sizeof(e->DestHost), i);
+ e->DestPort = PackGetIntEx(p, "DestPort", i);
+ e->CreatedTime = PackGetInt64Ex(p, "CreatedTime", i);
+ e->LastCommTime = PackGetInt64Ex(p, "LastCommTime", i);
+ e->SendSize = PackGetInt64Ex(p, "SendSize", i);
+ e->RecvSize = PackGetInt64Ex(p, "RecvSize", i);
+ e->TcpStatus = PackGetIntEx(p, "TcpStatus", i);
+ }
+}
+void OutRpcEnumNat(PACK *p, RPC_ENUM_NAT *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "NumItem", t->NumItem);
+ PackAddStr(p, "HubName", t->HubName);
+ for (i = 0;i < t->NumItem;i++)
+ {
+ RPC_ENUM_NAT_ITEM *e = &t->Items[i];
+
+ PackAddIntEx(p, "Id", e->Id, i, t->NumItem);
+ PackAddIntEx(p, "Protocol", e->Protocol, i, t->NumItem);
+ PackAddIp32Ex(p, "SrcIp", e->SrcIp, i, t->NumItem);
+ PackAddStrEx(p, "SrcHost", e->SrcHost, i, t->NumItem);
+ PackAddIntEx(p, "SrcPort", e->SrcPort, i, t->NumItem);
+ PackAddIp32Ex(p, "DestIp", e->DestIp, i, t->NumItem);
+ PackAddStrEx(p, "DestHost", e->DestHost, i, t->NumItem);
+ PackAddIntEx(p, "DestPort", e->DestPort, i, t->NumItem);
+ PackAddInt64Ex(p, "CreatedTime", e->CreatedTime, i, t->NumItem);
+ PackAddInt64Ex(p, "LastCommTime", e->LastCommTime, i, t->NumItem);
+ PackAddInt64Ex(p, "SendSize", e->SendSize, i, t->NumItem);
+ PackAddInt64Ex(p, "RecvSize", e->RecvSize, i, t->NumItem);
+ PackAddIntEx(p, "TcpStatus", e->TcpStatus, i, t->NumItem);
+ }
+}
+void FreeRpcEnumNat(RPC_ENUM_NAT *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Free(t->Items);
+}
+
+// RPC_NAT_INFO
+void InRpcNatInfo(RPC_NAT_INFO *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_NAT_INFO));
+ PackGetStr(p, "NatProductName", t->NatProductName, sizeof(t->NatProductName));
+ PackGetStr(p, "NatVersionString", t->NatVersionString, sizeof(t->NatVersionString));
+ PackGetStr(p, "NatBuildInfoString", t->NatBuildInfoString, sizeof(t->NatBuildInfoString));
+ t->NatVerInt = PackGetInt(p, "NatVerInt");
+ t->NatBuildInt = PackGetInt(p, "NatBuildInt");
+ PackGetStr(p, "NatHostName", t->NatHostName, sizeof(t->NatHostName));
+ InRpcOsInfo(&t->OsInfo, p);
+ InRpcMemInfo(&t->MemInfo, p);
+}
+void OutRpcNatInfo(PACK *p, RPC_NAT_INFO *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "NatProductName", t->NatProductName);
+ PackAddStr(p, "NatVersionString", t->NatVersionString);
+ PackAddStr(p, "NatBuildInfoString", t->NatBuildInfoString);
+ PackAddInt(p, "NatVerInt", t->NatVerInt);
+ PackAddInt(p, "NatBuildInt", t->NatBuildInt);
+ PackAddStr(p, "NatHostName", t->NatHostName);
+ OutRpcOsInfo(p, &t->OsInfo);
+ OutRpcMemInfo(p, &t->MemInfo);
+}
+void FreeRpcNatInfo(RPC_NAT_INFO *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ FreeRpcOsInfo(&t->OsInfo);
+}
+
+// RPC_NAT_STATUS
+void InRpcNatStatus(RPC_NAT_STATUS *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_NAT_STATUS));
+ t->NumTcpSessions = PackGetInt(p, "NumTcpSessions");
+ t->NumUdpSessions = PackGetInt(p, "NumUdpSessions");
+ t->NumIcmpSessions = PackGetInt(p, "NumIcmpSessions");
+ t->NumDnsSessions = PackGetInt(p, "NumDnsSessions");
+ t->NumDhcpClients = PackGetInt(p, "NumDhcpClients");
+ t->IsKernelMode = PackGetBool(p, "IsKernelMode");
+ PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));
+}
+void OutRpcNatStatus(PACK *p, RPC_NAT_STATUS *t)
+{
+ // Validate arguments
+ if (p == NULL || t == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "HubName", t->HubName);
+ PackAddInt(p, "NumTcpSessions", t->NumTcpSessions);
+ PackAddInt(p, "NumUdpSessions", t->NumUdpSessions);
+ PackAddInt(p, "NumIcmpSessions", t->NumIcmpSessions);
+ PackAddInt(p, "NumDnsSessions", t->NumDnsSessions);
+ PackAddInt(p, "NumDhcpClients", t->NumDhcpClients);
+ PackAddBool(p, "IsKernelMode", t->IsKernelMode);
+}
+void FreeRpcNatStatus(RPC_NAT_STATUS *t)
+{
+}
+
+// RPC_DUMMY
+void InRpcDummy(RPC_DUMMY *t, PACK *p)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(t, sizeof(RPC_DUMMY));
+ t->DummyValue = PackGetInt(p, "DummyValue");
+}
+void OutRpcDummy(PACK *p, RPC_DUMMY *t)
+{
+ // Validate arguments
+ if (t == NULL || p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "DummyValue", t->DummyValue);
+}
+
+// Main procedure for management
+void NiAdminMain(NAT *n, SOCK *s)
+{
+ RPC *r;
+ PACK *p;
+ // Validate arguments
+ if (n == NULL || s == NULL)
+ {
+ return;
+ }
+
+ p = NewPack();
+ HttpServerSend(s, p);
+ FreePack(p);
+
+ r = StartRpcServer(s, NiRpcServer, n);
+
+ RpcServer(r);
+
+ RpcFree(r);
+}
+
+// Management thread
+void NiAdminThread(THREAD *thread, void *param)
+{
+ NAT_ADMIN *a = (NAT_ADMIN *)param;
+ NAT *n;
+ SOCK *s;
+ UCHAR random[SHA1_SIZE];
+ UINT err;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Random number generation
+ Rand(random, sizeof(random));
+
+ a->Thread = thread;
+ AddRef(a->Thread->ref);
+ s = a->Sock;
+ AddRef(s->ref);
+
+ n = a->Nat;
+
+ LockList(n->AdminList);
+ {
+ Add(n->AdminList, a);
+ }
+ UnlockList(n->AdminList);
+
+ NoticeThreadInit(thread);
+
+ err = ERR_AUTH_FAILED;
+
+ if (StartSSL(s, n->AdminX, n->AdminK))
+ {
+ PACK *p;
+
+ // Send the random number
+ p = NewPack();
+ PackAddData(p, "auth_random", random, sizeof(random));
+
+ if (HttpServerSend(s, p))
+ {
+ PACK *p;
+ // Receive a password
+ p = HttpServerRecv(s);
+ if (p != NULL)
+ {
+ UCHAR secure_password[SHA1_SIZE];
+ UCHAR secure_check[SHA1_SIZE];
+
+ if (PackGetData2(p, "secure_password", secure_password, sizeof(secure_password)))
+ {
+ SecurePassword(secure_check, n->HashedPassword, random);
+
+ if (Cmp(secure_check, secure_password, SHA1_SIZE) == 0)
+ {
+ UCHAR test[SHA1_SIZE];
+ // Password match
+ Hash(test, "", 0, true);
+ SecurePassword(test, test, random);
+
+#if 0
+ if (Cmp(test, secure_check, SHA1_SIZE) == 0 && s->RemoteIP.addr[0] != 127)
+ {
+ // A client can not connect from the outside with blank password
+ err = ERR_NULL_PASSWORD_LOCAL_ONLY;
+ }
+ else
+#endif
+
+ {
+ // Successful connection
+ err = ERR_NO_ERROR;
+ NiAdminMain(n, s);
+ }
+ }
+ }
+
+ FreePack(p);
+ }
+ }
+
+ FreePack(p);
+
+ if (err != ERR_NO_ERROR)
+ {
+ p = PackError(err);
+ HttpServerSend(s, p);
+ FreePack(p);
+ }
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+}
+
+// Management port Listen thread
+void NiListenThread(THREAD *thread, void *param)
+{
+ NAT *n = (NAT *)param;
+ SOCK *a;
+ UINT i;
+ bool b = false;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Initialize the management list
+ n->AdminList = NewList(NULL);
+
+ while (true)
+ {
+ a = Listen(DEFAULT_NAT_ADMIN_PORT);
+ if (b == false)
+ {
+ b = true;
+ NoticeThreadInit(thread);
+ }
+ if (a != NULL)
+ {
+ break;
+ }
+
+ Wait(n->HaltEvent, NAT_ADMIN_PORT_LISTEN_INTERVAL);
+ if (n->Halt)
+ {
+ return;
+ }
+ }
+
+ n->AdminListenSock = a;
+ AddRef(a->ref);
+
+ // Waiting
+ while (true)
+ {
+ SOCK *s = Accept(a);
+ THREAD *t;
+ NAT_ADMIN *admin;
+ if (s == NULL)
+ {
+ break;
+ }
+ if (n->Halt)
+ {
+ ReleaseSock(s);
+ break;
+ }
+
+ admin = ZeroMalloc(sizeof(NAT_ADMIN));
+ admin->Nat = n;
+ admin->Sock = s;
+ t = NewThread(NiAdminThread, admin);
+ WaitThreadInit(t);
+ ReleaseThread(t);
+ }
+
+ // Disconnect all management connections
+ LockList(n->AdminList);
+ {
+ for (i = 0;i < LIST_NUM(n->AdminList);i++)
+ {
+ NAT_ADMIN *a = LIST_DATA(n->AdminList, i);
+ Disconnect(a->Sock);
+ WaitThread(a->Thread, INFINITE);
+ ReleaseThread(a->Thread);
+ ReleaseSock(a->Sock);
+ Free(a);
+ }
+ }
+ UnlockList(n->AdminList);
+
+ ReleaseList(n->AdminList);
+
+ ReleaseSock(a);
+}
+
+// Initialize receiving management command
+void NiInitAdminAccept(NAT *n)
+{
+ THREAD *t;
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ t = NewThread(NiListenThread, n);
+ WaitThreadInit(t);
+ n->AdminAcceptThread = t;
+}
+
+// Complete receiving management command
+void NiFreeAdminAccept(NAT *n)
+{
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ n->Halt = true;
+ Disconnect(n->AdminListenSock);
+ Set(n->HaltEvent);
+
+ while (true)
+ {
+ if (WaitThread(n->AdminAcceptThread, 1000) == false)
+ {
+ Disconnect(n->AdminListenSock);
+ }
+ else
+ {
+ break;
+ }
+ }
+ ReleaseThread(n->AdminAcceptThread);
+
+ ReleaseSock(n->AdminListenSock);
+}
+
+// Clear the DHCP options that are not supported by the dynamic Virtual HUB
+void NiClearUnsupportedVhOptionForDynamicHub(VH_OPTION *o, bool initial)
+{
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ o->UseNat = false;
+
+ if (initial)
+ {
+ Zero(&o->DhcpGatewayAddress, sizeof(IP));
+ Zero(&o->DhcpDnsServerAddress, sizeof(IP));
+ Zero(&o->DhcpDnsServerAddress2, sizeof(IP));
+ StrCpy(o->DhcpDomainName, sizeof(o->DhcpDomainName), "");
+ }
+}
+
+// Initialize the options for the virtual host
+void NiSetDefaultVhOption(NAT *n, VH_OPTION *o)
+{
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ Zero(o, sizeof(VH_OPTION));
+ GenMacAddress(o->MacAddress);
+
+ // Set the virtual IP to 192.168.30.1/24
+ SetIP(&o->Ip, 192, 168, 30, 1);
+ SetIP(&o->Mask, 255, 255, 255, 0);
+ o->UseNat = true;
+ o->Mtu = 1500;
+ o->NatTcpTimeout = 1800;
+ o->NatUdpTimeout = 60;
+ o->UseDhcp = true;
+ SetIP(&o->DhcpLeaseIPStart, 192, 168, 30, 10);
+ SetIP(&o->DhcpLeaseIPEnd, 192, 168, 30, 200);
+ SetIP(&o->DhcpSubnetMask, 255, 255, 255, 0);
+ o->DhcpExpireTimeSpan = 7200;
+ o->SaveLog = true;
+
+ SetIP(&o->DhcpGatewayAddress, 192, 168, 30, 1);
+ SetIP(&o->DhcpDnsServerAddress, 192, 168, 30, 1);
+
+ GetDomainName(o->DhcpDomainName, sizeof(o->DhcpDomainName));
+}
+
+// Reset the setting of NAT to the default
+void NiInitDefaultConfig(NAT *n)
+{
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ // Initialize the virtual host option
+ NiSetDefaultVhOption(n, &n->Option);
+
+ // Initialize management port
+ n->AdminPort = DEFAULT_NAT_ADMIN_PORT;
+
+ // Offline
+ n->Online = false;
+
+ // Save the log
+ n->Option.SaveLog = true;
+}
+
+// Initialize the NAT configuration
+void NiInitConfig(NAT *n)
+{
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ // Initial state
+ NiInitDefaultConfig(n);
+}
+
+// Read the virtual host option (extended)
+void NiLoadVhOptionEx(VH_OPTION *o, FOLDER *root)
+{
+ FOLDER *host, *nat, *dhcp;
+ char mac_address[MAX_SIZE];
+ // Validate arguments
+ if (o == NULL || root == NULL)
+ {
+ return;
+ }
+
+ host = CfgGetFolder(root, "VirtualHost");
+ nat = CfgGetFolder(root, "VirtualRouter");
+ dhcp = CfgGetFolder(root, "VirtualDhcpServer");
+
+ Zero(o, sizeof(VH_OPTION));
+
+ GenMacAddress(o->MacAddress);
+ if (CfgGetStr(host, "VirtualHostMacAddress", mac_address, sizeof(mac_address)))
+ {
+ BUF *b = StrToBin(mac_address);
+ if (b != NULL)
+ {
+ if (b->Size == 6)
+ {
+ Copy(o->MacAddress, b->Buf, 6);
+ }
+ }
+ FreeBuf(b);
+ }
+ CfgGetIp(host, "VirtualHostIp", &o->Ip);
+ CfgGetIp(host, "VirtualHostIpSubnetMask", &o->Mask);
+
+ o->UseNat = CfgGetBool(nat, "NatEnabled");
+ o->Mtu = CfgGetInt(nat, "NatMtu");
+ o->NatTcpTimeout = CfgGetInt(nat, "NatTcpTimeout");
+ o->NatUdpTimeout = CfgGetInt(nat, "NatUdpTimeout");
+
+ o->UseDhcp = CfgGetBool(dhcp, "DhcpEnabled");
+ CfgGetIp(dhcp, "DhcpLeaseIPStart", &o->DhcpLeaseIPStart);
+ CfgGetIp(dhcp, "DhcpLeaseIPEnd", &o->DhcpLeaseIPEnd);
+ CfgGetIp(dhcp, "DhcpSubnetMask", &o->DhcpSubnetMask);
+ o->DhcpExpireTimeSpan = CfgGetInt(dhcp, "DhcpExpireTimeSpan");
+ CfgGetIp(dhcp, "DhcpGatewayAddress", &o->DhcpGatewayAddress);
+ CfgGetIp(dhcp, "DhcpDnsServerAddress", &o->DhcpDnsServerAddress);
+ CfgGetIp(dhcp, "DhcpDnsServerAddress2", &o->DhcpDnsServerAddress2);
+ CfgGetStr(dhcp, "DhcpDomainName", o->DhcpDomainName, sizeof(o->DhcpDomainName));
+
+ Trim(o->DhcpDomainName);
+ if (StrLen(o->DhcpDomainName) == 0)
+ {
+ //GetDomainName(o->DhcpDomainName, sizeof(o->DhcpDomainName));
+ }
+
+ o->SaveLog = CfgGetBool(root, "SaveLog");
+}
+
+// Read the virtual host option
+void NiLoadVhOption(NAT *n, FOLDER *root)
+{
+ VH_OPTION *o;
+ FOLDER *host, *nat, *dhcp;
+ char mac_address[MAX_SIZE];
+ // Validate arguments
+ if (n == NULL || root == NULL)
+ {
+ return;
+ }
+
+ host = CfgGetFolder(root, "VirtualHost");
+ nat = CfgGetFolder(root, "VirtualRouter");
+ dhcp = CfgGetFolder(root, "VirtualDhcpServer");
+
+ o = &n->Option;
+ Zero(o, sizeof(VH_OPTION));
+
+ GenMacAddress(o->MacAddress);
+ if (CfgGetStr(host, "VirtualHostMacAddress", mac_address, sizeof(mac_address)))
+ {
+ BUF *b = StrToBin(mac_address);
+ if (b != NULL)
+ {
+ if (b->Size == 6)
+ {
+ Copy(o->MacAddress, b->Buf, 6);
+ }
+ }
+ FreeBuf(b);
+ }
+ CfgGetIp(host, "VirtualHostIp", &o->Ip);
+ CfgGetIp(host, "VirtualHostIpSubnetMask", &o->Mask);
+
+ o->UseNat = CfgGetBool(nat, "NatEnabled");
+ o->Mtu = CfgGetInt(nat, "NatMtu");
+ o->NatTcpTimeout = CfgGetInt(nat, "NatTcpTimeout");
+ o->NatUdpTimeout = CfgGetInt(nat, "NatUdpTimeout");
+
+ o->UseDhcp = CfgGetBool(dhcp, "DhcpEnabled");
+ CfgGetIp(dhcp, "DhcpLeaseIPStart", &o->DhcpLeaseIPStart);
+ CfgGetIp(dhcp, "DhcpLeaseIPEnd", &o->DhcpLeaseIPEnd);
+ CfgGetIp(dhcp, "DhcpSubnetMask", &o->DhcpSubnetMask);
+ o->DhcpExpireTimeSpan = CfgGetInt(dhcp, "DhcpExpireTimeSpan");
+ CfgGetIp(dhcp, "DhcpGatewayAddress", &o->DhcpGatewayAddress);
+ CfgGetIp(dhcp, "DhcpDnsServerAddress", &o->DhcpDnsServerAddress);
+ CfgGetIp(dhcp, "DhcpDnsServerAddress2", &o->DhcpDnsServerAddress2);
+ CfgGetStr(dhcp, "DhcpDomainName", o->DhcpDomainName, sizeof(o->DhcpDomainName));
+
+ o->SaveLog = CfgGetBool(root, "SaveLog");
+}
+
+// Read connection options from the VPN server
+void NiLoadClientData(NAT *n, FOLDER *root)
+{
+ FOLDER *co, *ca;
+ // Validate arguments
+ if (n == NULL || root == NULL)
+ {
+ return;
+ }
+
+ co = CfgGetFolder(root, "VpnClientOption");
+ ca = CfgGetFolder(root, "VpnClientAuth");
+ if (co == NULL || ca == NULL)
+ {
+ return;
+ }
+
+ n->ClientOption = CiLoadClientOption(co);
+ n->ClientAuth = CiLoadClientAuth(ca);
+}
+
+// Write connection options to the VPN server
+void NiWriteClientData(NAT *n, FOLDER *root)
+{
+ // Validate arguments
+ if (n == NULL || root == NULL || n->ClientOption == NULL || n->ClientAuth == NULL)
+ {
+ return;
+ }
+
+ CiWriteClientOption(CfgCreateFolder(root, "VpnClientOption"), n->ClientOption);
+ CiWriteClientAuth(CfgCreateFolder(root, "VpnClientAuth"), n->ClientAuth);
+}
+
+// Write the virtual host option (extended)
+void NiWriteVhOptionEx(VH_OPTION *o, FOLDER *root)
+{
+ FOLDER *host, *nat, *dhcp;
+ char mac_address[MAX_SIZE];
+ // Validate arguments
+ if (o == NULL || root == NULL)
+ {
+ return;
+ }
+
+ host = CfgCreateFolder(root, "VirtualHost");
+ nat = CfgCreateFolder(root, "VirtualRouter");
+ dhcp = CfgCreateFolder(root, "VirtualDhcpServer");
+
+ MacToStr(mac_address, sizeof(mac_address), o->MacAddress);
+ CfgAddStr(host, "VirtualHostMacAddress", mac_address);
+ CfgAddIp(host, "VirtualHostIp", &o->Ip);
+ CfgAddIp(host, "VirtualHostIpSubnetMask", &o->Mask);
+
+ CfgAddBool(nat, "NatEnabled", o->UseNat);
+ CfgAddInt(nat, "NatMtu", o->Mtu);
+ CfgAddInt(nat, "NatTcpTimeout", o->NatTcpTimeout);
+ CfgAddInt(nat, "NatUdpTimeout", o->NatUdpTimeout);
+
+ CfgAddBool(dhcp, "DhcpEnabled", o->UseDhcp);
+ CfgAddIp(dhcp, "DhcpLeaseIPStart", &o->DhcpLeaseIPStart);
+ CfgAddIp(dhcp, "DhcpLeaseIPEnd", &o->DhcpLeaseIPEnd);
+ CfgAddIp(dhcp, "DhcpSubnetMask", &o->DhcpSubnetMask);
+ CfgAddInt(dhcp, "DhcpExpireTimeSpan", o->DhcpExpireTimeSpan);
+ CfgAddIp(dhcp, "DhcpGatewayAddress", &o->DhcpGatewayAddress);
+ CfgAddIp(dhcp, "DhcpDnsServerAddress", &o->DhcpDnsServerAddress);
+ CfgAddIp(dhcp, "DhcpDnsServerAddress2", &o->DhcpDnsServerAddress2);
+ CfgAddStr(dhcp, "DhcpDomainName", o->DhcpDomainName);
+
+ CfgAddBool(root, "SaveLog", o->SaveLog);
+}
+
+// Write the virtual host option
+void NiWriteVhOption(NAT *n, FOLDER *root)
+{
+ VH_OPTION *o;
+ FOLDER *host, *nat, *dhcp;
+ char mac_address[MAX_SIZE];
+ // Validate arguments
+ if (n == NULL || root == NULL)
+ {
+ return;
+ }
+
+ host = CfgCreateFolder(root, "VirtualHost");
+ nat = CfgCreateFolder(root, "VirtualRouter");
+ dhcp = CfgCreateFolder(root, "VirtualDhcpServer");
+
+ o = &n->Option;
+
+ MacToStr(mac_address, sizeof(mac_address), o->MacAddress);
+ CfgAddStr(host, "VirtualHostMacAddress", mac_address);
+ CfgAddIp(host, "VirtualHostIp", &o->Ip);
+ CfgAddIp(host, "VirtualHostIpSubnetMask", &o->Mask);
+
+ CfgAddBool(nat, "NatEnabled", o->UseNat);
+ CfgAddInt(nat, "NatMtu", o->Mtu);
+ CfgAddInt(nat, "NatTcpTimeout", o->NatTcpTimeout);
+ CfgAddInt(nat, "NatUdpTimeout", o->NatUdpTimeout);
+
+ CfgAddBool(dhcp, "DhcpEnabled", o->UseDhcp);
+ CfgAddIp(dhcp, "DhcpLeaseIPStart", &o->DhcpLeaseIPStart);
+ CfgAddIp(dhcp, "DhcpLeaseIPEnd", &o->DhcpLeaseIPEnd);
+ CfgAddIp(dhcp, "DhcpSubnetMask", &o->DhcpSubnetMask);
+ CfgAddInt(dhcp, "DhcpExpireTimeSpan", o->DhcpExpireTimeSpan);
+ CfgAddIp(dhcp, "DhcpGatewayAddress", &o->DhcpGatewayAddress);
+ CfgAddIp(dhcp, "DhcpDnsServerAddress", &o->DhcpDnsServerAddress);
+ CfgAddIp(dhcp, "DhcpDnsServerAddress2", &o->DhcpDnsServerAddress2);
+ CfgAddStr(dhcp, "DhcpDomainName", o->DhcpDomainName);
+
+ CfgAddBool(root, "SaveLog", o->SaveLog);
+}
+
+// Read the configuration file
+bool NiLoadConfig(NAT *n, FOLDER *root)
+{
+ FOLDER *host;
+ BUF *b;
+ // Validate arguments
+ if (n == NULL || root == NULL)
+ {
+ return false;
+ }
+
+ host = CfgGetFolder(root, "VirtualHost");
+ if (host == NULL)
+ {
+ return false;
+ }
+
+ CfgGetByte(root, "HashedPassword", n->HashedPassword, sizeof(n->HashedPassword));
+ n->AdminPort = CfgGetInt(root, "AdminPort");
+ n->Online = CfgGetBool(root, "Online");
+
+ b = CfgGetBuf(root, "AdminCert");
+ if (b != NULL)
+ {
+ n->AdminX = BufToX(b, false);
+ FreeBuf(b);
+ }
+
+ b = CfgGetBuf(root, "AdminKey");
+ if (b != NULL)
+ {
+ n->AdminK = BufToK(b, true, false, NULL);
+ FreeBuf(b);
+ }
+
+ NiLoadVhOption(n, root);
+
+ NiLoadClientData(n, root);
+
+ return true;
+}
+
+// Write the configuration to a file
+void NiWriteConfig(NAT *n)
+{
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ Lock(n->lock);
+ {
+ FOLDER *root = CfgCreateFolder(NULL, TAG_ROOT);
+ BUF *b;
+
+ // Certificate
+ b = XToBuf(n->AdminX, false);
+ CfgAddBuf(root, "AdminCert", b);
+ FreeBuf(b);
+
+ // Secret key
+ b = KToBuf(n->AdminK, false, NULL);
+ CfgAddBuf(root, "AdminKey", b);
+ FreeBuf(b);
+
+ // Password
+ CfgAddByte(root, "HashedPassword", n->HashedPassword, sizeof(n->HashedPassword));
+ CfgAddInt(root, "AdminPort", n->AdminPort);
+ CfgAddBool(root, "Online", n->Online);
+
+ // Virtual host option
+ NiWriteVhOption(n, root);
+
+ // Connection options
+ if (n->ClientOption != NULL && n->ClientAuth != NULL)
+ {
+ NiWriteClientData(n, root);
+ }
+
+ SaveCfgRw(n->CfgRw, root);
+ CfgDeleteFolder(root);
+ }
+ Unlock(n->lock);
+}
+
+// Release the NAT configuration
+void NiFreeConfig(NAT *n)
+{
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ // Write the latest configuration
+ NiWriteConfig(n);
+
+ // Release the configuration R/W
+ FreeCfgRw(n->CfgRw);
+ n->CfgRw = NULL;
+
+ Free(n->ClientOption);
+ CiFreeClientAuth(n->ClientAuth);
+
+ FreeX(n->AdminX);
+ FreeK(n->AdminK);
+}
+
+// Create a NAT
+NAT *NiNewNatEx(SNAT *snat, VH_OPTION *o)
+{
+ NAT *n = ZeroMalloc(sizeof(NAT));
+
+ n->lock = NewLock();
+ Hash(n->HashedPassword, "", 0, true);
+ n->HaltEvent = NewEvent();
+
+ //n->Cedar = NewCedar(NULL, NULL);
+
+ n->SecureNAT = snat;
+
+ // Raise the priority
+ //OSSetHighPriority();
+
+ // Initialize the settings
+ NiInitConfig(n);
+
+#if 0
+ // Start the operation of the virtual host
+ if (n->Online && n->ClientOption != NULL)
+ {
+ n->Virtual = NewVirtualHostEx(n->Cedar, n->ClientOption, n->ClientAuth, &n->Option, n);
+ }
+ else
+ {
+ n->Online = false;
+ n->Virtual = NULL;
+ }
+#else
+ n->Virtual = NewVirtualHostEx(n->Cedar, NULL, NULL, o, n);
+ n->Online = true;
+#endif
+
+ // Start management command
+ //NiInitAdminAccept(n);
+
+ return n;
+}
+NAT *NiNewNat()
+{
+ return NiNewNatEx(NULL, NULL);
+}
+
+// Release the NAT
+void NiFreeNat(NAT *n)
+{
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ // Complete management command
+ //NiFreeAdminAccept(n);
+
+ // Stop if the virtual host is running
+ Lock(n->lock);
+ {
+ if (n->Virtual != NULL)
+ {
+ StopVirtualHost(n->Virtual);
+ ReleaseVirtual(n->Virtual);
+ n->Virtual = NULL;
+ }
+ }
+ Unlock(n->lock);
+
+ // Release the settings
+ NiFreeConfig(n);
+
+ // Delete the object
+ ReleaseCedar(n->Cedar);
+ ReleaseEvent(n->HaltEvent);
+ DeleteLock(n->lock);
+
+ Free(n);
+}
+
+// Stop the NAT
+void NtStopNat()
+{
+ Lock(nat_lock);
+ {
+ if (nat != NULL)
+ {
+ NiFreeNat(nat);
+ nat = NULL;
+ }
+ }
+ Unlock(nat_lock);
+}
+
+// Start the NAT
+void NtStartNat()
+{
+ Lock(nat_lock);
+ {
+ if (nat == NULL)
+ {
+ nat = NiNewNat();
+ }
+ }
+ Unlock(nat_lock);
+}
+
+// Initialize the NtXxx function
+void NtInit()
+{
+ if (nat_lock != NULL)
+ {
+ return;
+ }
+
+ nat_lock = NewLock();
+}
+
+// Release the NtXxx function
+void NtFree()
+{
+ if (nat_lock == NULL)
+ {
+ return;
+ }
+
+ DeleteLock(nat_lock);
+ nat_lock = NULL;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Nat.h b/src/Cedar/Nat.h
new file mode 100644
index 00000000..60a865ea
--- /dev/null
+++ b/src/Cedar/Nat.h
@@ -0,0 +1,291 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Nat.h
+// Header of Nat.c
+
+#ifndef NAT_H
+#define NAT_H
+
+// Constants
+#define NAT_CONFIG_FILE_NAME "@vpn_router.config" // NAT configuration file
+#define DEFAULT_NAT_ADMIN_PORT 2828 // Default port number for management
+#define NAT_ADMIN_PORT_LISTEN_INTERVAL 1000 // Interval for trying to open a port for management
+#define NAT_FILE_SAVE_INTERVAL (30 * 1000) // Interval to save
+
+
+// NAT object
+struct NAT
+{
+ LOCK *lock; // Lock
+ UCHAR HashedPassword[SHA1_SIZE]; // Administrative password
+ VH_OPTION Option; // Option
+ CEDAR *Cedar; // Cedar
+ UINT AdminPort; // Management port number
+ bool Online; // Online flag
+ VH *Virtual; // Virtual host object
+ CLIENT_OPTION *ClientOption; // Client Option
+ CLIENT_AUTH *ClientAuth; // Client authentication data
+ CFG_RW *CfgRw; // Config file R/W
+ THREAD *AdminAcceptThread; // Management connection reception thread
+ SOCK *AdminListenSock; // Management port socket
+ EVENT *HaltEvent; // Halting event
+ volatile bool Halt; // Halting flag
+ LIST *AdminList; // Management thread list
+ X *AdminX; // Server certificate for management
+ K *AdminK; // Server private key for management
+ SNAT *SecureNAT; // SecureNAT object
+};
+
+// NAT management connection
+struct NAT_ADMIN
+{
+ NAT *Nat; // NAT
+ SOCK *Sock; // Socket
+ THREAD *Thread; // Thread
+};
+
+// RPC_DUMMY
+struct RPC_DUMMY
+{
+ UINT DummyValue;
+};
+
+// RPC_NAT_STATUS
+struct RPC_NAT_STATUS
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB name
+ UINT NumTcpSessions; // Number of TCP sessions
+ UINT NumUdpSessions; // Ntmber of UDP sessions
+ UINT NumIcmpSessions; // Nymber of ICMP sessions
+ UINT NumDnsSessions; // Number of DNS sessions
+ UINT NumDhcpClients; // Number of DHCP clients
+ bool IsKernelMode; // Whether kernel mode
+};
+
+// RPC_NAT_INFO *
+struct RPC_NAT_INFO
+{
+ char NatProductName[128]; // Server product name
+ char NatVersionString[128]; // Server version string
+ char NatBuildInfoString[128]; // Server build information string
+ UINT NatVerInt; // Server version integer value
+ UINT NatBuildInt; // Server build number integer value
+ char NatHostName[MAX_HOST_NAME_LEN + 1]; // Server host name
+ OS_INFO OsInfo; // OS information
+ MEMINFO MemInfo; // Memory information
+};
+
+// RPC_ENUM_NAT_ITEM
+struct RPC_ENUM_NAT_ITEM
+{
+ UINT Id; // ID
+ UINT Protocol; // Protocol
+ UINT SrcIp; // Source IP address
+ char SrcHost[MAX_HOST_NAME_LEN + 1]; // Source host name
+ UINT SrcPort; // Source port number
+ UINT DestIp; // Destination IP address
+ char DestHost[MAX_HOST_NAME_LEN + 1]; // Destination host name
+ UINT DestPort; // Destination port number
+ UINT64 CreatedTime; // Connection time
+ UINT64 LastCommTime; // Last communication time
+ UINT64 SendSize; // Transmission size
+ UINT64 RecvSize; // Receive size
+ UINT TcpStatus; // TCP state
+};
+
+// RPC_ENUM_NAT *
+struct RPC_ENUM_NAT
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB name
+ UINT NumItem; // Number of items
+ RPC_ENUM_NAT_ITEM *Items; // Item
+};
+
+// RPC_ENUM_DHCP_ITEM
+struct RPC_ENUM_DHCP_ITEM
+{
+ UINT Id; // ID
+ UINT64 LeasedTime; // Lease time
+ UINT64 ExpireTime; // Expiration date
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2]; // Padding
+ UINT IpAddress; // IP address
+ UINT Mask; // Subnet mask
+ char Hostname[MAX_HOST_NAME_LEN + 1]; // Host name
+};
+
+// RPC_ENUM_DHCP *
+struct RPC_ENUM_DHCP
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB name
+ UINT NumItem; // Number of items
+ RPC_ENUM_DHCP_ITEM *Items; // Item
+};
+
+
+// Function prototype
+NAT *NiNewNat();
+NAT *NiNewNatEx(SNAT *snat, VH_OPTION *o);
+void NiFreeNat(NAT *n);
+void NiInitConfig(NAT *n);
+void NiFreeConfig(NAT *n);
+void NiInitDefaultConfig(NAT *n);
+void NiSetDefaultVhOption(NAT *n, VH_OPTION *o);
+void NiClearUnsupportedVhOptionForDynamicHub(VH_OPTION *o, bool initial);
+void NiWriteConfig(NAT *n);
+void NiWriteVhOption(NAT *n, FOLDER *root);
+void NiWriteVhOptionEx(VH_OPTION *o, FOLDER *root);
+void NiWriteClientData(NAT *n, FOLDER *root);
+void NiLoadVhOption(NAT *n, FOLDER *root);
+void NiLoadVhOptionEx(VH_OPTION *o, FOLDER *root);
+bool NiLoadConfig(NAT *n, FOLDER *root);
+void NiLoadClientData(NAT *n, FOLDER *root);
+void NiInitAdminAccept(NAT *n);
+void NiFreeAdminAccept(NAT *n);
+void NiListenThread(THREAD *thread, void *param);
+void NiAdminThread(THREAD *thread, void *param);
+void NiAdminMain(NAT *n, SOCK *s);
+PACK *NiRpcServer(RPC *r, char *name, PACK *p);
+
+RPC *NatAdminConnect(CEDAR *cedar, char *hostname, UINT port, void *hashed_password, UINT *err);
+void NatAdminDisconnect(RPC *r);
+
+void NtStartNat();
+void NtStopNat();
+void NtInit();
+void NtFree();
+
+
+UINT NtOnline(NAT *n, RPC_DUMMY *t);
+UINT NtOffline(NAT *n, RPC_DUMMY *t);
+UINT NtSetHostOption(NAT *n, VH_OPTION *t);
+UINT NtGetHostOption(NAT *n, VH_OPTION *t);
+UINT NtSetClientConfig(NAT *n, RPC_CREATE_LINK *t);
+UINT NtGetClientConfig(NAT *n, RPC_CREATE_LINK *t);
+UINT NtGetStatus(NAT *n, RPC_NAT_STATUS *t);
+UINT NtGetInfo(NAT *n, RPC_NAT_INFO *t);
+UINT NtEnumNatList(NAT *n, RPC_ENUM_NAT *t);
+UINT NtEnumDhcpList(NAT *n, RPC_ENUM_DHCP *t);
+UINT NtSetPassword(NAT *n, RPC_SET_PASSWORD *t);
+
+
+UINT NcOnline(RPC *r, RPC_DUMMY *t);
+UINT NcOffline(RPC *r, RPC_DUMMY *t);
+UINT NcSetHostOption(RPC *r, VH_OPTION *t);
+UINT NcGetHostOption(RPC *r, VH_OPTION *t);
+UINT NcSetClientConfig(RPC *r, RPC_CREATE_LINK *t);
+UINT NcGetClientConfig(RPC *r, RPC_CREATE_LINK *t);
+UINT NcGetStatus(RPC *r, RPC_NAT_STATUS *t);
+UINT NcGetInfo(RPC *r, RPC_NAT_INFO *t);
+UINT NcEnumNatList(RPC *r, RPC_ENUM_NAT *t);
+UINT NcEnumDhcpList(RPC *r, RPC_ENUM_DHCP *t);
+UINT NcSetPassword(RPC *r, RPC_SET_PASSWORD *t);
+
+
+
+
+void InRpcEnumDhcp(RPC_ENUM_DHCP *t, PACK *p);
+void OutRpcEnumDhcp(PACK *p, RPC_ENUM_DHCP *t);
+void FreeRpcEnumDhcp(RPC_ENUM_DHCP *t);
+void InRpcEnumNat(RPC_ENUM_NAT *t, PACK *p);
+void OutRpcEnumNat(PACK *p, RPC_ENUM_NAT *t);
+void FreeRpcEnumNat(RPC_ENUM_NAT *t);
+void InRpcNatInfo(RPC_NAT_INFO *t, PACK *p);
+void OutRpcNatInfo(PACK *p, RPC_NAT_INFO *t);
+void FreeRpcNatInfo(RPC_NAT_INFO *t);
+void InRpcNatStatus(RPC_NAT_STATUS *t, PACK *p);
+void OutRpcNatStatus(PACK *p, RPC_NAT_STATUS *t);
+void FreeRpcNatStatus(RPC_NAT_STATUS *t);
+void InVhOption(VH_OPTION *t, PACK *p);
+void OutVhOption(PACK *p, VH_OPTION *t);
+void InRpcDummy(RPC_DUMMY *t, PACK *p);
+void OutRpcDummy(PACK *p, RPC_DUMMY *t);
+
+
+
+
+#endif // NAT_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/NativeStack.c b/src/Cedar/NativeStack.c
new file mode 100644
index 00000000..9689964e
--- /dev/null
+++ b/src/Cedar/NativeStack.c
@@ -0,0 +1,417 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// NativeStack.c
+// Native IP stack
+
+#include "CedarPch.h"
+
+// Stack main thread
+void NsMainThread(THREAD *thread, void *param)
+{
+ NATIVE_STACK *a = (NATIVE_STACK *)param;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ SOCKSET set;
+ bool err = false;
+ bool flush_tube;
+ LIST *recv_packets;
+ bool state_changed = false;
+
+ InitSockSet(&set);
+ AddSockSet(&set, a->Sock1);
+
+ if (a->Halt)
+ {
+ break;
+ }
+
+ // Pass to the IPC by receiving from the bridge
+LABEL_RESTART:
+ state_changed = false;
+ flush_tube = false;
+ while (true)
+ {
+ void *data;
+ UINT size;
+
+ size = EthGetPacket(a->Eth, &data);
+
+ if (size == INFINITE)
+ {
+ // Device error
+ err = true;
+ break;
+ }
+ else if (size == 0)
+ {
+ // Can not get any more
+ break;
+ }
+ else
+ {
+ // Pass the IPC socket
+ TubeSendEx(a->Sock1->SendTube, data, size, NULL, true);
+ Free(data);
+ flush_tube = true;
+ state_changed = true;
+ }
+ }
+
+ if (flush_tube)
+ {
+ TubeFlush(a->Sock1->SendTube);
+ }
+
+ // Pass to the bridge by receiving from IPC
+ recv_packets = NULL;
+ while (true)
+ {
+ TUBEDATA *d = TubeRecvAsync(a->Sock1->RecvTube);
+
+ if (d == NULL)
+ {
+ break;
+ }
+
+ if (recv_packets == NULL)
+ {
+ recv_packets = NewListFast(NULL);
+ }
+
+ Add(recv_packets, d);
+
+ state_changed = true;
+ }
+ if (recv_packets != NULL)
+ {
+ UINT i;
+ UINT num = LIST_NUM(recv_packets);
+ void **data_array;
+ UINT *size_array;
+
+ data_array = Malloc(sizeof(void *) * num);
+ size_array = Malloc(sizeof(UINT) * num);
+
+ for (i = 0;i < num;i++)
+ {
+ TUBEDATA *d = LIST_DATA(recv_packets, i);
+
+ data_array[i] = d->Data;
+ size_array[i] = d->DataSize;
+ }
+
+ EthPutPackets(a->Eth, num, data_array, size_array);
+
+ for (i = 0;i < num;i++)
+ {
+ TUBEDATA *d = LIST_DATA(recv_packets, i);
+
+ // Because the data buffer has been already released, not to release twice
+ d->Data = NULL;
+
+ FreeTubeData(d);
+ }
+
+ Free(data_array);
+ Free(size_array);
+
+ ReleaseList(recv_packets);
+ }
+
+ if (IsTubeConnected(a->Sock1->SendTube) == false || IsTubeConnected(a->Sock1->RecvTube) == false)
+ {
+ err = true;
+ }
+
+ if (err)
+ {
+ // An error has occured
+ Debug("Native Stack: Error !\n");
+ a->Halt = true;
+ continue;
+ }
+
+ if (state_changed)
+ {
+ goto LABEL_RESTART;
+ }
+
+ Select(&set, 1234, a->Cancel, NULL);
+ }
+
+ Disconnect(a->Sock1);
+ Disconnect(a->Sock2);
+}
+
+// Release the stack
+void FreeNativeStack(NATIVE_STACK *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ if (a->Ipc != NULL && IsZero(&a->CurrentDhcpOptionList, sizeof(a->CurrentDhcpOptionList)) == false)
+ {
+ IP dhcp_server;
+
+ UINTToIP(&dhcp_server, a->CurrentDhcpOptionList.ServerAddress);
+
+ IPCDhcpFreeIP(a->Ipc, &dhcp_server);
+ SleepThread(200);
+ }
+
+ a->Halt = true;
+ Cancel(a->Cancel);
+ Disconnect(a->Sock1);
+ Disconnect(a->Sock2);
+
+ WaitThread(a->MainThread, INFINITE);
+
+ ReleaseThread(a->MainThread);
+
+ CloseEth(a->Eth);
+ FreeIPC(a->Ipc);
+
+ ReleaseCancel(a->Cancel);
+
+ ReleaseSock(a->Sock1);
+ ReleaseSock(a->Sock2);
+
+ ReleaseCedar(a->Cedar);
+
+ Free(a);
+}
+
+// Create a new stack
+NATIVE_STACK *NewNativeStack(CEDAR *cedar, char *device_name, char *mac_address_seed)
+{
+ ETH *eth;
+ NATIVE_STACK *a;
+ IP localhost;
+ char tmp[64];
+ bool release_cedar = false;
+ // Validate arguments
+ if (device_name == NULL || mac_address_seed == NULL)
+ {
+ return NULL;
+ }
+
+ if (cedar == NULL)
+ {
+ cedar = NewCedar(NULL, NULL);
+ release_cedar = true;
+ }
+
+ GetLocalHostIP4(&localhost);
+
+ // Open the Eth device
+ eth = OpenEth(device_name, false, false, NULL);
+ if (eth == NULL)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(NATIVE_STACK));
+
+ NewSocketPair(&a->Sock1, &a->Sock2, &localhost, 1, &localhost, 1);
+
+ a->Cedar = cedar;
+ AddRef(a->Cedar->ref);
+
+ NsGenMacAddress(a->MacAddress, mac_address_seed, device_name);
+
+ BinToStr(tmp, sizeof(tmp), a->MacAddress, sizeof(a->MacAddress));
+ Debug("NewNativeStack: MAC Address = %s\n", tmp);
+
+ a->Ipc = NewIPCBySock(cedar, a->Sock2, a->MacAddress);
+
+ StrCpy(a->DeviceName, sizeof(a->DeviceName), device_name);
+
+ a->Eth = eth;
+ a->Cancel = EthGetCancel(eth);
+
+ a->MainThread = NewThread(NsMainThread, a);
+
+ if (release_cedar)
+ {
+ ReleaseCedar(cedar);
+ }
+
+ return a;
+}
+
+// Identify whether the specified MAC address is for the Native Stack which operate on the same host
+bool NsIsMacAddressOnLocalhost(UCHAR *mac)
+{
+ UCHAR tmp[2];
+ // Validate arguments
+ if (mac == NULL)
+ {
+ return false;
+ }
+
+ if (mac[0] != NS_MAC_ADDRESS_BYTE_1)
+ {
+ return false;
+ }
+
+ NsGenMacAddressSignatureForMachine(tmp, mac);
+
+ if (Cmp(mac + 4, tmp, 2) == 0)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Determine the last two bytes of the MAC address
+void NsGenMacAddressSignatureForMachine(UCHAR *dst_last_2, UCHAR *src_mac_addr_4)
+{
+ char machine_name[MAX_SIZE];
+ BUF *b;
+ UCHAR hash[SHA1_SIZE];
+ // Validate arguments
+ if (dst_last_2 == NULL || src_mac_addr_4 == NULL)
+ {
+ return;
+ }
+
+ GetMachineHostName(machine_name, sizeof(machine_name));
+
+ Trim(machine_name);
+ StrUpper(machine_name);
+
+ b = NewBuf();
+ WriteBuf(b, src_mac_addr_4, 4);
+ WriteBufStr(b, machine_name);
+
+ HashSha1(hash, b->Buf, b->Size);
+
+ FreeBuf(b);
+
+ Copy(dst_last_2, hash, 2);
+}
+
+// Generate the MAC address
+void NsGenMacAddress(void *dest, char *mac_address_seed, char *device_name)
+{
+ char tmp[MAX_SIZE];
+ UCHAR mac[6];
+ UCHAR hash[SHA1_SIZE];
+
+ Zero(tmp, sizeof(tmp));
+
+ StrCat(tmp, sizeof(tmp), mac_address_seed);
+ StrCat(tmp, sizeof(tmp), "@");
+ StrCat(tmp, sizeof(tmp), device_name);
+
+ Trim(tmp);
+
+ StrLower(tmp);
+
+ HashSha1(hash, tmp, StrLen(tmp));
+
+ mac[0] = NS_MAC_ADDRESS_BYTE_1;
+ mac[1] = hash[1];
+ mac[2] = hash[2];
+ mac[3] = hash[3];
+ mac[4] = hash[4];
+ mac[5] = hash[5];
+
+ NsGenMacAddressSignatureForMachine(mac + 4, mac);
+
+ Copy(dest, mac, 6);
+}
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/NativeStack.h b/src/Cedar/NativeStack.h
new file mode 100644
index 00000000..f115e671
--- /dev/null
+++ b/src/Cedar/NativeStack.h
@@ -0,0 +1,123 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// NativeStack.h
+// Header of NativeStack.c
+
+#ifndef NATIVESTACK_H
+#define NATIVESTACK_H
+
+//// Constants
+#define NS_MAC_ADDRESS_BYTE_1 0xDA // First byte of the MAC address
+
+//// Type
+struct NATIVE_STACK
+{
+ CEDAR *Cedar;
+ IPC *Ipc; // IPC object
+ char DeviceName[MAX_SIZE]; // Ethernet device name
+ THREAD *MainThread; // Main thread
+ bool Halt; // Halting flag
+ CANCEL *Cancel; // Cancel
+ UCHAR MacAddress[6]; // MAC address of the virtual host
+ ETH *Eth; // Eth device
+ SOCK *Sock1; // Sock1 (To be used in the bridge side)
+ SOCK *Sock2; // Sock2 (Used in the IPC side)
+ DHCP_OPTION_LIST CurrentDhcpOptionList; // Current DHCP options list
+ IP DnsServerIP; // IP address of the DNS server
+};
+
+
+//// Function prototype
+NATIVE_STACK *NewNativeStack(CEDAR *cedar, char *device_name, char *mac_address_seed);
+void FreeNativeStack(NATIVE_STACK *a);
+
+void NsGenMacAddress(void *dest, char *mac_address_seed, char *device_name);
+void NsMainThread(THREAD *thread, void *param);
+void NsGenMacAddressSignatureForMachine(UCHAR *dst_last_2, UCHAR *src_mac_addr_4);
+bool NsIsMacAddressOnLocalhost(UCHAR *mac);
+
+#endif // NATIVESTACK_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/NullLan.c b/src/Cedar/NullLan.c
new file mode 100644
index 00000000..8f3fad40
--- /dev/null
+++ b/src/Cedar/NullLan.c
@@ -0,0 +1,256 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// NullLan.c
+// Virtual LAN card device driver for testing
+
+#include "CedarPch.h"
+
+static UCHAR null_lan_broadcast_address[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+// Get the packet adapter
+PACKET_ADAPTER *NullGetPacketAdapter()
+{
+ PACKET_ADAPTER *pa = NewPacketAdapter(NullPaInit, NullPaGetCancel, NullPaGetNextPacket,
+ NullPaPutPacket, NullPaFree);
+
+ return pa;
+}
+
+// Packet generation thread
+void NullPacketGenerateThread(THREAD *t, void *param)
+{
+ NULL_LAN *n = (NULL_LAN *)param;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ Wait(n->Event, Rand32() % NULL_PACKET_GENERATE_INTERVAL);
+ if (n->Halt)
+ {
+ break;
+ }
+
+ LockQueue(n->PacketQueue);
+ {
+ UCHAR *data;
+ BLOCK *b;
+ UINT size = Rand32() % 1500 + 14;
+ data = Malloc(size);
+ Copy(data, null_lan_broadcast_address, 6);
+ Copy(data + 6, n->MacAddr, 6);
+ b = NewBlock(data, size, 0);
+ InsertQueue(n->PacketQueue, b);
+ }
+ UnlockQueue(n->PacketQueue);
+ Cancel(n->Cancel);
+ }
+}
+
+// Initialize the packet adapter
+bool NullPaInit(SESSION *s)
+{
+ NULL_LAN *n;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ n = ZeroMalloc(sizeof(NULL_LAN));
+ s->PacketAdapter->Param = (void *)n;
+
+ n->Cancel = NewCancel();
+ n->PacketQueue = NewQueue();
+ n->Event = NewEvent();
+
+ GenMacAddress(n->MacAddr);
+
+ n->PacketGeneratorThread = NewThread(NullPacketGenerateThread, n);
+
+ return true;
+}
+
+// Get the cancel object
+CANCEL *NullPaGetCancel(SESSION *s)
+{
+ // Validate arguments
+ NULL_LAN *n;
+ if (s == NULL || (n = s->PacketAdapter->Param) == NULL)
+ {
+ return NULL;
+ }
+
+ AddRef(n->Cancel->ref);
+
+ return n->Cancel;
+}
+
+// Get the next packet
+UINT NullPaGetNextPacket(SESSION *s, void **data)
+{
+ UINT size = 0;
+ // Validate arguments
+ NULL_LAN *n;
+ if (s == NULL || (n = s->PacketAdapter->Param) == NULL)
+ {
+ return INFINITE;
+ }
+
+ LockQueue(n->PacketQueue);
+ {
+ BLOCK *b = GetNext(n->PacketQueue);
+
+ if (b != NULL)
+ {
+ *data = b->Buf;
+ size = b->Size;
+ Free(b);
+ }
+ }
+ UnlockQueue(n->PacketQueue);
+
+ return size;
+}
+
+// Write the packet
+bool NullPaPutPacket(SESSION *s, void *data, UINT size)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+ if (data == NULL)
+ {
+ return true;
+ }
+
+ // Packet ignored
+ Free(data);
+
+ return true;
+}
+
+// Release
+void NullPaFree(SESSION *s)
+{
+ // Validate arguments
+ NULL_LAN *n;
+ BLOCK *b;
+ if (s == NULL || (n = s->PacketAdapter->Param) == NULL)
+ {
+ return;
+ }
+
+ n->Halt = true;
+ Set(n->Event);
+
+ WaitThread(n->PacketGeneratorThread, INFINITE);
+ ReleaseThread(n->PacketGeneratorThread);
+
+ LockQueue(n->PacketQueue);
+ {
+ while (b = GetNext(n->PacketQueue))
+ {
+ FreeBlock(b);
+ }
+ }
+ UnlockQueue(n->PacketQueue);
+
+ ReleaseQueue(n->PacketQueue);
+
+ ReleaseCancel(n->Cancel);
+
+ ReleaseEvent(n->Event);
+
+ s->PacketAdapter->Param = NULL;
+ Free(n);
+}
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/NullLan.h b/src/Cedar/NullLan.h
new file mode 100644
index 00000000..3ccc068e
--- /dev/null
+++ b/src/Cedar/NullLan.h
@@ -0,0 +1,117 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// NullLan.h
+// Header of NullLan.c
+
+#ifndef NULLLAN_H
+#define NULLLAN_H
+
+
+#define NULL_PACKET_GENERATE_INTERVAL 100000000 // Packet generation interval
+
+// NULL device structure
+struct NULL_LAN
+{
+ THREAD *PacketGeneratorThread;
+ CANCEL *Cancel;
+ QUEUE *PacketQueue;
+ volatile bool Halt;
+ EVENT *Event;
+ UCHAR MacAddr[6];
+ UCHAR Padding[2];
+};
+
+PACKET_ADAPTER *NullGetPacketAdapter();
+bool NullPaInit(SESSION *s);
+CANCEL *NullPaGetCancel(SESSION *s);
+UINT NullPaGetNextPacket(SESSION *s, void **data);
+bool NullPaPutPacket(SESSION *s, void *data, UINT size);
+void NullPaFree(SESSION *s);
+void NullPacketGenerateThread(THREAD *t, void *param);
+
+#endif // NULLAN_H
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Protocol.c b/src/Cedar/Protocol.c
new file mode 100644
index 00000000..beb2f3b4
--- /dev/null
+++ b/src/Cedar/Protocol.c
@@ -0,0 +1,6535 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Protocol.c
+// SoftEther protocol related routines
+
+#include "CedarPch.h"
+
+static UCHAR ssl_packet_start[3] = {0x17, 0x03, 0x00};
+
+
+// Convert the date of YYYYMMDD format to a number
+UINT64 ShortStrToDate64(char *str)
+{
+ UINT v;
+ SYSTEMTIME st;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return 0;
+ }
+
+ v = ToInt(str);
+
+ Zero(&st, sizeof(st));
+
+ st.wYear = (v % 100000000) / 10000;
+ st.wMonth = (v % 10000) / 100;
+ st.wDay = v % 100;
+
+ return SystemToUINT64(&st);
+}
+
+// Handle the response that is returned from the server in the update client
+void UpdateClientThreadProcessResults(UPDATE_CLIENT *c, BUF *b)
+{
+ bool exit = false;
+ // Validate arguments
+ if (c == NULL || b == NULL)
+ {
+ return;
+ }
+
+ SeekBufToBegin(b);
+
+ while (true)
+ {
+ char *line = CfgReadNextLine(b);
+ if (line == NULL)
+ {
+ break;
+ }
+
+ Trim(line);
+
+ if (StartWith(line, "#") == false && IsEmptyStr(line) == false)
+ {
+ TOKEN_LIST *t = ParseTokenWithNullStr(line, " \t");
+
+ if (t != NULL)
+ {
+ if (t->NumTokens >= 5)
+ {
+ if (StrCmpi(t->Token[0], c->FamilyName) == 0)
+ {
+ // Match
+ UINT64 date = ShortStrToDate64(t->Token[1]);
+ if (date != 0)
+ {
+ UINT build = ToInt(t->Token[2]);
+ if (build != 0)
+ {
+ if (build > c->MyBuild && build > c->LatestBuild && build > c->Setting.LatestIgnoreBuild)
+ {
+ c->Callback(c, build, date, t->Token[3], t->Token[4], &c->HaltFlag, c->Param);
+
+ c->LatestBuild = build;
+
+ exit = true;
+ }
+ }
+ }
+ }
+ }
+
+ FreeToken(t);
+ }
+ }
+
+ Free(line);
+
+ if (exit)
+ {
+ break;
+ }
+ }
+}
+
+// Update client main process
+void UpdateClientThreadMain(UPDATE_CLIENT *c)
+{
+ char url[MAX_SIZE];
+ char id[MAX_SIZE];
+ URL_DATA data;
+ BUF *cert_hash;
+ UINT ret = 0;
+ BUF *recv;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Generate the URL
+ Format(url, sizeof(url), IsUseAlternativeHostname() ? UPDATE_SERVER_URL_CHINA : UPDATE_SERVER_URL_GLOBAL, c->FamilyName, c->SoftwareName, c->MyBuild, c->MyLanguage);
+
+ if (IsEmptyStr(c->ClientId) == false)
+ {
+ Format(id, sizeof(id), "&id=%s", c->ClientId);
+ StrCat(url, sizeof(url), id);
+ }
+
+ // Get a text file at this URL
+ if (ParseUrl(&data, url, false, NULL) == false)
+ {
+ return;
+ }
+
+ cert_hash = StrToBin(UPDATE_SERVER_CERT_HASH);
+
+ recv = HttpRequest(&data, NULL, UPDATE_CONNECT_TIMEOUT, UPDATE_COMM_TIMEOUT, &ret, false, NULL, NULL,
+ NULL, ((cert_hash != NULL && cert_hash->Size == SHA1_SIZE) ? cert_hash->Buf : NULL));
+
+ FreeBuf(cert_hash);
+
+ if (recv != NULL)
+ {
+ UpdateClientThreadProcessResults(c, recv);
+
+ FreeBuf(recv);
+ }
+}
+
+// Update client main thread
+void UpdateClientThreadProc(THREAD *thread, void *param)
+{
+ UPDATE_CLIENT *c = (UPDATE_CLIENT *)param;
+ bool first_loop = true;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ // Termination check
+ if (c->HaltFlag)
+ {
+ break;
+ }
+
+ if (first_loop == false)
+ {
+ // Wait for the foreground
+ if (c->IsForegroundCb != NULL)
+ {
+ while (true)
+ {
+ if (c->HaltFlag)
+ {
+ break;
+ }
+
+ if (c->IsForegroundCb(c, c->Param))
+ {
+ break;
+ }
+
+ Wait(c->HaltEvent, 1000);
+ }
+ }
+ }
+
+ first_loop = false;
+
+ if (c->HaltFlag)
+ {
+ break;
+ }
+
+ if (c->Setting.DisableCheck == false)
+ {
+ UpdateClientThreadMain(c);
+ }
+
+ // Wait until the next attempt
+ Wait(c->HaltEvent, GenRandInterval(UPDATE_CHECK_INTERVAL_MIN, UPDATE_CHECK_INTERVAL_MAX));
+ }
+}
+
+// Update the configuration of the update client
+void SetUpdateClientSetting(UPDATE_CLIENT *c, UPDATE_CLIENT_SETTING *s)
+{
+ bool old_disable;
+ // Validate arguments
+ if (c == NULL || s == NULL)
+ {
+ return;
+ }
+
+ old_disable = c->Setting.DisableCheck;
+
+ Copy(&c->Setting, s, sizeof(UPDATE_CLIENT_SETTING));
+
+ Set(c->HaltEvent);
+}
+
+// Start the update client
+UPDATE_CLIENT *NewUpdateClient(UPDATE_NOTIFY_PROC *cb, UPDATE_ISFOREGROUND_PROC *isforeground_cb, void *param, char *family_name, char *software_name, wchar_t *software_title, UINT my_build, UINT64 my_date, char *my_lang, UPDATE_CLIENT_SETTING *current_setting, char *client_id)
+{
+ UPDATE_CLIENT *c;
+ // Validate arguments
+ if (family_name == NULL || software_title == NULL || software_name == NULL || my_build == 0 ||
+ my_lang == NULL || current_setting == NULL || cb == NULL)
+ {
+ return NULL;
+ }
+
+ c = ZeroMalloc(sizeof(UPDATE_CLIENT));
+
+ c->Callback = cb;
+ c->IsForegroundCb = isforeground_cb;
+
+ StrCpy(c->ClientId, sizeof(c->ClientId), client_id);
+ StrCpy(c->FamilyName, sizeof(c->FamilyName), family_name);
+ StrCpy(c->SoftwareName, sizeof(c->SoftwareName), software_name);
+ UniStrCpy(c->SoftwareTitle, sizeof(c->SoftwareTitle), software_title);
+ c->MyBuild = my_build;
+ c->MyDate = my_date;
+ StrCpy(c->MyLanguage, sizeof(c->MyLanguage), my_lang);
+
+ Copy(&c->Setting, current_setting, sizeof(c->Setting));
+
+ c->Param = param;
+
+ c->HaltEvent = NewEvent();
+
+ // Create a thread
+ c->Thread = NewThread(UpdateClientThreadProc, c);
+
+ return c;
+}
+
+// Terminate the update client
+void FreeUpdateClient(UPDATE_CLIENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Thread stop
+ c->HaltFlag = true;
+ Set(c->HaltEvent);
+
+ // Wait for thread termination
+ WaitThread(c->Thread, INFINITE);
+
+ ReleaseThread(c->Thread);
+ ReleaseEvent(c->HaltEvent);
+
+ Free(c);
+}
+
+// Generate unique IDs for each machine
+void GenerateMachineUniqueHash(void *data)
+{
+ BUF *b;
+ char name[64];
+ char ip_str[64];
+ IP ip;
+ OS_INFO *osinfo;
+ // Validate arguments
+ if (data == NULL)
+ {
+ return;
+ }
+
+ b = NewBuf();
+ GetMachineName(name, sizeof(name));
+ GetMachineIp(&ip);
+ IPToStr(ip_str, sizeof(ip_str), &ip);
+
+ osinfo = GetOsInfo();
+
+ WriteBuf(b, name, StrLen(name));
+ WriteBuf(b, ip_str, StrLen(ip_str));
+
+ WriteBuf(b, &osinfo->OsType, sizeof(osinfo->OsType));
+ WriteBuf(b, osinfo->KernelName, StrLen(osinfo->KernelName));
+ WriteBuf(b, osinfo->KernelVersion, StrLen(osinfo->KernelVersion));
+ WriteBuf(b, osinfo->OsProductName, StrLen(osinfo->OsProductName));
+ WriteBuf(b, &osinfo->OsServicePack, sizeof(osinfo->OsServicePack));
+ WriteBuf(b, osinfo->OsSystemName, StrLen(osinfo->OsSystemName));
+ WriteBuf(b, osinfo->OsVendorName, StrLen(osinfo->OsVendorName));
+ WriteBuf(b, osinfo->OsVersion, StrLen(osinfo->OsVersion));
+
+ Hash(data, b->Buf, b->Size, true);
+
+ FreeBuf(b);
+}
+
+// Convert a node information to a string
+void NodeInfoToStr(wchar_t *str, UINT size, NODE_INFO *info)
+{
+ char client_ip[128], server_ip[128], proxy_ip[128], unique_id[128];
+ // Validate arguments
+ if (str == NULL || info == NULL)
+ {
+ return;
+ }
+
+ IPToStr4or6(client_ip, sizeof(client_ip), info->ClientIpAddress, info->ClientIpAddress6);
+ IPToStr4or6(server_ip, sizeof(server_ip), info->ServerIpAddress, info->ServerIpAddress6);
+ IPToStr4or6(proxy_ip, sizeof(proxy_ip), info->ProxyIpAddress, info->ProxyIpAddress6);
+ BinToStr(unique_id, sizeof(unique_id), info->UniqueId, sizeof(info->UniqueId));
+
+ UniFormat(str, size, _UU("LS_NODE_INFO_TAG"), info->ClientProductName,
+ Endian32(info->ClientProductVer), Endian32(info->ClientProductBuild),
+ info->ServerProductName, Endian32(info->ServerProductVer), Endian32(info->ServerProductBuild),
+ info->ClientOsName, info->ClientOsVer, info->ClientOsProductId,
+ info->ClientHostname, client_ip, Endian32(info->ClientPort),
+ info->ServerHostname, server_ip, Endian32(info->ServerPort),
+ info->ProxyHostname, proxy_ip, Endian32(info->ProxyPort),
+ info->HubName, unique_id);
+}
+
+// Comparison of node information
+bool CompareNodeInfo(NODE_INFO *a, NODE_INFO *b)
+{
+ // Validate arguments
+ if (a == NULL || b == NULL)
+ {
+ return false;
+ }
+
+ if (StrCmp(a->ClientProductName, b->ClientProductName) != 0)
+ {
+ return false;
+ }
+ if (a->ClientProductVer != b->ClientProductVer)
+ {
+ return false;
+ }
+ if (a->ClientProductBuild != b->ClientProductBuild)
+ {
+ return false;
+ }
+ if (StrCmp(a->ServerProductName, b->ServerProductName) != 0)
+ {
+ return false;
+ }
+ if (a->ServerProductVer != b->ServerProductVer)
+ {
+ return false;
+ }
+ if (a->ServerProductBuild != b->ServerProductBuild)
+ {
+ return false;
+ }
+ if (StrCmp(a->ClientOsName, b->ClientOsName) != 0)
+ {
+ return false;
+ }
+ if (StrCmp(a->ClientOsVer, b->ClientOsVer) != 0)
+ {
+ return false;
+ }
+ if (StrCmp(a->ClientOsProductId, b->ClientOsProductId) != 0)
+ {
+ return false;
+ }
+ if (StrCmp(a->ClientHostname, b->ClientHostname) != 0)
+ {
+ return false;
+ }
+ if (a->ClientIpAddress != b->ClientIpAddress)
+ {
+ return false;
+ }
+ if (StrCmp(a->ServerHostname, b->ServerHostname) != 0)
+ {
+ return false;
+ }
+ if (a->ServerIpAddress != b->ServerIpAddress)
+ {
+ return false;
+ }
+ if (a->ServerPort != b->ServerPort)
+ {
+ return false;
+ }
+ if (StrCmp(a->ProxyHostname, b->ProxyHostname) != 0)
+ {
+ return false;
+ }
+ if (a->ProxyIpAddress != b->ProxyIpAddress)
+ {
+ return false;
+ }
+ if (a->ProxyPort != b->ProxyPort)
+ {
+ return false;
+ }
+ if (StrCmp(a->HubName, b->HubName) != 0)
+ {
+ return false;
+ }
+ if (Cmp(a->UniqueId, b->UniqueId, 16) != 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Accept the password change
+UINT ChangePasswordAccept(CONNECTION *c, PACK *p)
+{
+ CEDAR *cedar;
+ UCHAR random[SHA1_SIZE];
+ char hubname[MAX_HUBNAME_LEN + 1];
+ char username[MAX_USERNAME_LEN + 1];
+ UCHAR secure_old_password[SHA1_SIZE];
+ UCHAR new_password[SHA1_SIZE];
+ UCHAR new_password_ntlm[SHA1_SIZE];
+ UCHAR check_secure_old_password[SHA1_SIZE];
+ UINT ret = ERR_NO_ERROR;
+ HUB *hub;
+ bool save = false;
+ // Validate arguments
+ if (c == NULL || p == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ Copy(random, c->Random, SHA1_SIZE);
+ if (PackGetStr(p, "hubname", hubname, sizeof(hubname)) == false ||
+ PackGetStr(p, "username", username, sizeof(username)) == false ||
+ PackGetData2(p, "secure_old_password", secure_old_password, sizeof(secure_old_password)) == false ||
+ PackGetData2(p, "new_password", new_password, sizeof(new_password)) == false)
+ {
+ return ERR_PROTOCOL_ERROR;
+ }
+
+ if (PackGetData2(p, "new_password_ntlm", new_password_ntlm, MD5_SIZE) == false)
+ {
+ Zero(new_password_ntlm, sizeof(new_password_ntlm));
+ }
+
+ cedar = c->Cedar;
+
+ LockHubList(cedar);
+ {
+ hub = GetHub(cedar, hubname);
+ }
+ UnlockHubList(cedar);
+
+ if (hub == NULL)
+ {
+ ret = ERR_HUB_NOT_FOUND;
+ }
+ else
+ {
+ char tmp[MAX_SIZE];
+
+ if (GetHubAdminOption(hub, "deny_change_user_password") != 0)
+ {
+ ReleaseHub(hub);
+ return ERR_NOT_ENOUGH_RIGHT;
+ }
+
+ IPToStr(tmp, sizeof(tmp), &c->FirstSock->RemoteIP);
+ HLog(hub, "LH_CHANGE_PASSWORD_1", c->Name, tmp);
+
+ AcLock(hub);
+ {
+ USER *u = AcGetUser(hub, username);
+ if (u == NULL)
+ {
+ HLog(hub, "LH_CHANGE_PASSWORD_2", c->Name, username);
+ ret = ERR_OLD_PASSWORD_WRONG;
+ }
+ else
+ {
+ Lock(u->lock);
+ {
+ if (u->AuthType != AUTHTYPE_PASSWORD)
+ {
+ // Not a password authentication
+ HLog(hub, "LH_CHANGE_PASSWORD_3", c->Name, username);
+ ret = ERR_USER_AUTHTYPE_NOT_PASSWORD;
+ }
+ else
+ {
+ bool fix_password = false;
+ if (u->Policy != NULL)
+ {
+ fix_password = u->Policy->FixPassword;
+ }
+ else
+ {
+ if (u->Group != NULL)
+ {
+ if (u->Group->Policy != NULL)
+ {
+ fix_password = u->Group->Policy->FixPassword;
+ }
+ }
+ }
+ if (fix_password == false)
+ {
+ // Confirmation of the old password
+ AUTHPASSWORD *pw = (AUTHPASSWORD *)u->AuthData;
+
+ SecurePassword(check_secure_old_password, pw->HashedKey, random);
+ if (Cmp(check_secure_old_password, secure_old_password, SHA1_SIZE) != 0)
+ {
+ // Old password is incorrect
+ ret = ERR_OLD_PASSWORD_WRONG;
+ HLog(hub, "LH_CHANGE_PASSWORD_4", c->Name, username);
+ }
+ else
+ {
+ // Write a new password
+ if (Cmp(pw->HashedKey, new_password, SHA1_SIZE) != 0 || IsZero(pw->NtLmSecureHash, MD5_SIZE))
+ {
+ Copy(pw->HashedKey, new_password, SHA1_SIZE);
+ Copy(pw->NtLmSecureHash, new_password_ntlm, MD5_SIZE);
+ }
+ HLog(hub, "LH_CHANGE_PASSWORD_5", c->Name, username);
+ save = true;
+ }
+ }
+ else
+ {
+ // Password change is prohibited
+ ret = ERR_NOT_ENOUGH_RIGHT;
+ }
+ }
+ }
+ Unlock(u->lock);
+
+ ReleaseUser(u);
+ }
+ }
+ AcUnlock(hub);
+ ReleaseHub(hub);
+ }
+
+ return ret;
+}
+
+// Change the password
+UINT ChangePassword(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, char *username, char *old_pass, char *new_pass)
+{
+ UINT ret = ERR_NO_ERROR;
+ UCHAR old_password[SHA1_SIZE];
+ UCHAR secure_old_password[SHA1_SIZE];
+ UCHAR new_password[SHA1_SIZE];
+ UCHAR new_password_ntlm[MD5_SIZE];
+ SOCK *sock;
+ SESSION *s;
+ // Validate arguments
+ if (cedar == NULL || o == NULL || hubname == NULL || username == NULL || old_pass == NULL || new_pass == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+
+ // Create a session
+ s = NewRpcSessionEx(cedar, o, &ret, NULL);
+
+ if (s != NULL)
+ {
+ PACK *p = NewPack();
+
+ sock = s->Connection->FirstSock;
+
+ HashPassword(old_password, username, old_pass);
+ SecurePassword(secure_old_password, old_password, s->Connection->Random);
+ HashPassword(new_password, username, new_pass);
+ GenerateNtPasswordHash(new_password_ntlm, new_pass);
+
+ PackAddClientVersion(p, s->Connection);
+
+ PackAddStr(p, "method", "password");
+ PackAddStr(p, "hubname", hubname);
+ PackAddStr(p, "username", username);
+ PackAddData(p, "secure_old_password", secure_old_password, SHA1_SIZE);
+ PackAddData(p, "new_password", new_password, SHA1_SIZE);
+ PackAddData(p, "new_password_ntlm", new_password_ntlm, MD5_SIZE);
+
+ if (HttpClientSend(sock, p))
+ {
+ PACK *p = HttpClientRecv(sock);
+ if (p == NULL)
+ {
+ ret = ERR_DISCONNECTED;
+ }
+ else
+ {
+ ret = GetErrorFromPack(p);
+ }
+ FreePack(p);
+ }
+ else
+ {
+ ret = ERR_DISCONNECTED;
+ }
+ FreePack(p);
+
+ ReleaseSession(s);
+ }
+
+ return ret;
+}
+
+// Enumerate HUBs
+TOKEN_LIST *EnumHub(SESSION *s)
+{
+ SOCK *sock;
+ TOKEN_LIST *ret;
+ PACK *p;
+ UINT num;
+ UINT i;
+ // Validate arguments
+ if (s == NULL || s->Connection == NULL)
+ {
+ return NULL;
+ }
+
+ sock = s->Connection->FirstSock;
+ if (sock == NULL)
+ {
+ return NULL;
+ }
+
+ // Set the Timeout
+ SetTimeout(sock, 10000);
+
+ p = NewPack();
+ PackAddStr(p, "method", "enum_hub");
+
+ PackAddClientVersion(p, s->Connection);
+
+ if (HttpClientSend(sock, p) == false)
+ {
+ FreePack(p);
+ return NULL;
+ }
+ FreePack(p);
+
+ p = HttpClientRecv(sock);
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ num = PackGetInt(p, "NumHub");
+ ret = ZeroMalloc(sizeof(TOKEN_LIST));
+ ret->NumTokens = num;
+ ret->Token = ZeroMalloc(sizeof(char *) * num);
+ for (i = 0;i < num;i++)
+ {
+ char tmp[MAX_SIZE];
+ if (PackGetStrEx(p, "HubName", tmp, sizeof(tmp), i))
+ {
+ ret->Token[i] = CopyStr(tmp);
+ }
+ }
+ FreePack(p);
+
+ return ret;
+}
+
+// Server accepts a connection from client
+bool ServerAccept(CONNECTION *c)
+{
+ bool ret = false;
+ UINT err;
+ PACK *p;
+ char username_real[MAX_SIZE];
+ char method[MAX_SIZE];
+ char hubname[MAX_SIZE];
+ char username[MAX_SIZE];
+ char groupname[MAX_SIZE];
+ UCHAR session_key[SHA1_SIZE];
+ UCHAR ticket[SHA1_SIZE];
+ RC4_KEY_PAIR key_pair;
+ UINT authtype;
+ POLICY *policy;
+ HUB *hub;
+ SESSION *s = NULL;
+ UINT64 user_expires = 0;
+ bool use_encrypt;
+ bool use_compress;
+ bool half_connection;
+ UINT adjust_mss;
+ bool use_udp_acceleration_client;
+ bool support_hmac_on_udp_acceleration_client = false;
+ bool support_udp_accel_fast_disconnect_detect;
+ bool use_hmac_on_udp_acceleration = false;
+ IP udp_acceleration_client_ip;
+ UCHAR udp_acceleration_client_key[UDP_ACCELERATION_COMMON_KEY_SIZE];
+ UINT udp_acceleration_client_port;
+ bool use_fast_rc4;
+ bool admin_mode = false;
+ UINT direction;
+ UINT max_connection;
+ UINT timeout;
+ bool no_reconnect_to_session = false;
+ bool farm_controller = false;
+ bool farm_member = false;
+ bool farm_mode = false;
+ bool require_bridge_routing_mode;
+ bool require_monitor_mode;
+ bool support_bulk_on_rudp = false;
+ bool support_hmac_on_bulk_of_rudp = false;
+ bool support_udp_recovery = false;
+ bool enable_bulk_on_rudp = false;
+ bool enable_udp_recovery = false;
+ bool enable_hmac_on_bulk_of_rudp = false;
+ bool use_client_license = false, use_bridge_license = false;
+ bool local_host_session = false;
+ char sessionname[MAX_SESSION_NAME_LEN + 1];
+ bool is_server_or_bridge = false;
+ bool qos = false;
+ bool cluster_dynamic_secure_nat = false;
+ bool no_save_password = false;
+ NODE_INFO node;
+ wchar_t *msg = NULL;
+ USER *loggedin_user_object = NULL;
+ FARM_MEMBER *f = NULL;
+ SERVER *server = NULL;
+ POLICY ticketed_policy;
+ UINT64 timestamp;
+ UCHAR unique[SHA1_SIZE], unique2[SHA1_SIZE];
+ CEDAR *cedar;
+ RPC_WINVER winver;
+ UINT client_id;
+ bool no_more_users_in_server = false;
+ UCHAR mschap_v2_server_response_20[20];
+ UINT ms_chap_error = 0;
+ bool is_empty_password = false;
+ char *error_detail = NULL;
+ char *error_detail_2 = NULL;
+ char ctoken_hash_str[64];
+
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ Zero(ctoken_hash_str, sizeof(ctoken_hash_str));
+
+ Zero(mschap_v2_server_response_20, sizeof(mschap_v2_server_response_20));
+
+ Zero(&udp_acceleration_client_ip, sizeof(udp_acceleration_client_ip));
+ udp_acceleration_client_port = 0;
+ Zero(udp_acceleration_client_key, sizeof(udp_acceleration_client_key));
+
+ Zero(&winver, sizeof(winver));
+
+ StrCpy(groupname, sizeof(groupname), "");
+ StrCpy(sessionname, sizeof(sessionname), "");
+
+ if (IsZero(c->CToken_Hash, SHA1_SIZE) == false)
+ {
+ BinToStr(ctoken_hash_str, sizeof(ctoken_hash_str), c->CToken_Hash, SHA1_SIZE);
+ }
+
+ cedar = c->Cedar;
+
+ // Get the license status
+
+ no_more_users_in_server = SiTooManyUserObjectsInServer(cedar->Server, true);
+
+ c->Status = CONNECTION_STATUS_NEGOTIATION;
+
+ if (c->Cedar->Server != NULL)
+ {
+ SERVER *s = c->Cedar->Server;
+ server = s;
+
+ if (s->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ farm_member = true;
+ farm_mode = true;
+ }
+
+ if (s->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ farm_controller = true;
+ farm_mode = true;
+ }
+ }
+
+ // Receive the signature
+ Debug("Downloading Signature...\n");
+ error_detail_2 = NULL;
+ if (ServerDownloadSignature(c, &error_detail_2) == false)
+ {
+ if (error_detail_2 == NULL)
+ {
+ error_detail = "ServerDownloadSignature";
+ }
+ else
+ {
+ error_detail = error_detail_2;
+ }
+ goto CLEANUP;
+ }
+
+ // Send a Hello packet
+ Debug("Uploading Hello...\n");
+ if (ServerUploadHello(c) == false)
+ {
+ error_detail = "ServerUploadHello";
+ goto CLEANUP;
+ }
+
+ // Receive the authentication data
+ Debug("Auth...\n");
+
+ p = HttpServerRecv(c->FirstSock);
+ if (p == NULL)
+ {
+ // The connection disconnected
+ c->Err = ERR_DISCONNECTED;
+ error_detail = "RecvAuth1";
+ goto CLEANUP;
+ }
+
+ if (err = GetErrorFromPack(p))
+ {
+ // An error has occured
+ FreePack(p);
+ c->Err = err;
+ error_detail = "RecvAuth2";
+ goto CLEANUP;
+ }
+
+ // Get the method
+ if (GetMethodFromPack(p, method, sizeof(method)) == false)
+ {
+ // Protocol error
+ FreePack(p);
+ c->Err = ERR_PROTOCOL_ERROR;
+ error_detail = "GetMethodFromPack";
+ goto CLEANUP;
+ }
+
+ // Brand string for the connection limit
+ {
+ char tmp[20];
+ char *branded_ctos = _SS("BRANDED_C_TO_S");
+ PackGetStr(p, "branded_ctos", tmp, sizeof(tmp));
+
+ if(StrCmpi(method, "login") == 0 && StrLen(branded_ctos) > 0 && StrCmpi(branded_ctos, tmp) != 0)
+ {
+ FreePack(p);
+ c->Err = ERR_BRANDED_C_TO_S;
+ goto CLEANUP;
+ }
+ }
+
+ // Time inspection
+ timestamp = PackGetInt64(p, "timestamp");
+ if (timestamp != 0)
+ {
+ UINT64 now = SystemTime64();
+ UINT64 abs;
+ if (now >= timestamp)
+ {
+ abs = now - timestamp;
+ }
+ else
+ {
+ abs = timestamp - now;
+ }
+
+ if (abs > ALLOW_TIMESTAMP_DIFF)
+ {
+ // Time difference is too large
+ FreePack(p);
+ c->Err = ERR_BAD_CLOCK;
+ error_detail = "ERR_BAD_CLOCK";
+ goto CLEANUP;
+ }
+ }
+
+ // Get the client version
+ PackGetStr(p, "client_str", c->ClientStr, sizeof(c->ClientStr));
+ c->ClientVer = PackGetInt(p, "client_ver");
+ c->ClientBuild = PackGetInt(p, "client_build");
+
+ if (SearchStrEx(c->ClientStr, "server", 0, false) != INFINITE ||
+ SearchStrEx(c->ClientStr, "bridge", 0, false) != INFINITE)
+ {
+ is_server_or_bridge = true;
+ }
+
+ // Get the client Windows version
+ InRpcWinVer(&winver, p);
+
+ DecrementNoSsl(c->Cedar, &c->FirstSock->RemoteIP, 2);
+
+ if (StrCmpi(method, "login") == 0)
+ {
+ bool auth_ret = false;
+
+ Debug("Login...\n");
+ c->Status = CONNECTION_STATUS_USERAUTH;
+
+ c->Type = CONNECTION_TYPE_LOGIN;
+
+ if (no_more_users_in_server)
+ {
+ // There are many users than are allowed in the VPN Server
+ FreePack(p);
+ c->Err = ERR_TOO_MANY_USER;
+ error_detail = "ERR_TOO_MANY_USER";
+ goto CLEANUP;
+ }
+
+ // Such as the client name
+ if (PackGetStr(p, "hello", c->ClientStr, sizeof(c->ClientStr)) == false)
+ {
+ StrCpy(c->ClientStr, sizeof(c->ClientStr), "Unknown");
+ }
+ c->ServerVer = CEDAR_VER;
+ c->ServerBuild = CEDAR_BUILD;
+
+ // Get the NODE_INFO
+ Zero(&node, sizeof(node));
+ InRpcNodeInfo(&node, p);
+
+ // Protocol
+ c->Protocol = GetProtocolFromPack(p);
+ if (c->Protocol == CONNECTION_UDP)
+ {
+ // Release the structure of the TCP connection
+ if (c->Tcp)
+ {
+ ReleaseList(c->Tcp->TcpSockList);
+ Free(c->Tcp);
+ }
+ }
+
+ if (GetServerCapsBool(c->Cedar->Server, "b_vpn_client_connect") == false)
+ {
+ // VPN client is unable to connect
+ FreePack(p);
+ c->Err = ERR_NOT_SUPPORTED;
+ goto CLEANUP;
+ }
+
+
+
+ // Login
+ if (GetHubnameAndUsernameFromPack(p, username, sizeof(username), hubname, sizeof(hubname)) == false)
+ {
+ // Protocol error
+ FreePack(p);
+ c->Err = ERR_PROTOCOL_ERROR;
+ error_detail = "GetHubnameAndUsernameFromPack";
+ goto CLEANUP;
+ }
+
+ if (farm_member)
+ {
+ bool ok = false;
+ UINT authtype;
+
+ authtype = GetAuthTypeFromPack(p);
+ if (StrCmpi(username, ADMINISTRATOR_USERNAME) == 0 &&
+ authtype == AUTHTYPE_PASSWORD)
+ {
+ ok = true;
+ }
+
+ if (authtype == AUTHTYPE_TICKET)
+ {
+ ok = true;
+ }
+
+ if (ok == false)
+ {
+ // Logging on directly to server farm members by
+ // non-Administrators are prohibited
+ FreePack(p);
+ SLog(c->Cedar, "LS_FARMMEMBER_NOT_ADMIN", c->Name, hubname, ADMINISTRATOR_USERNAME, username);
+ c->Err = ERR_ACCESS_DENIED;
+ goto CLEANUP;
+ }
+ }
+
+ Debug("Username = %s, HubName = %s\n", username, hubname);
+ LockHubList(c->Cedar);
+ {
+ hub = GetHub(c->Cedar, hubname);
+ }
+ UnlockHubList(c->Cedar);
+ if (hub == NULL)
+ {
+ // The HUB does not exist
+ FreePack(p);
+ c->Err = ERR_HUB_NOT_FOUND;
+ SLog(c->Cedar, "LS_HUB_NOT_FOUND", c->Name, hubname);
+ error_detail = "ERR_HUB_NOT_FOUND";
+ goto CLEANUP;
+ }
+
+
+ Lock(hub->lock);
+ {
+ UINT cert_size = 0;
+ void *cert_buf = NULL;
+ USER *user;
+ USERGROUP *group;
+ char plain_password[MAX_PASSWORD_LEN + 1];
+ if (hub->Halt || hub->Offline)
+ {
+ // HUB is off-line
+ FreePack(p);
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ c->Err = ERR_HUB_STOPPING;
+ goto CLEANUP;
+ }
+
+ // Get the various flags
+ use_encrypt = PackGetInt(p, "use_encrypt") == 0 ? false : true;
+ use_compress = PackGetInt(p, "use_compress") == 0 ? false : true;
+ max_connection = PackGetInt(p, "max_connection");
+ half_connection = PackGetInt(p, "half_connection") == 0 ? false : true;
+ use_fast_rc4 = PackGetInt(p, "use_fast_rc4") == 0 ? false : true;
+ qos = PackGetInt(p, "qos") ? true : false;
+ client_id = PackGetInt(p, "client_id");
+ adjust_mss = PackGetInt(p, "adjust_mss");
+ use_udp_acceleration_client = PackGetBool(p, "use_udp_acceleration");
+ support_hmac_on_udp_acceleration_client = PackGetBool(p, "support_hmac_on_udp_acceleration");
+ support_udp_accel_fast_disconnect_detect = PackGetBool(p, "support_udp_accel_fast_disconnect_detect");
+ support_bulk_on_rudp = PackGetBool(p, "support_bulk_on_rudp");
+ support_hmac_on_bulk_of_rudp = PackGetBool(p, "support_hmac_on_bulk_of_rudp");
+ support_udp_recovery = PackGetBool(p, "support_udp_recovery");
+
+ if (c->IsInProc)
+ {
+ char tmp[MAX_SIZE];
+ PackGetStr(p, "inproc_postfix", c->InProcPrefix, sizeof(c->InProcPrefix));
+ Zero(tmp, sizeof(tmp));
+ PackGetStr(p, "inproc_cryptname", tmp, sizeof(tmp));
+
+ if (c->FirstSock != NULL)
+ {
+ if (IsEmptyStr(c->InProcPrefix) == false)
+ {
+ Format(c->FirstSock->UnderlayProtocol, sizeof(c->FirstSock->UnderlayProtocol),
+ SOCK_UNDERLAY_INPROC_EX, c->InProcPrefix);
+ }
+ }
+
+ if (c->CipherName != NULL)
+ {
+ Free(c->CipherName);
+ }
+
+ c->CipherName = NULL;
+
+ if (IsEmptyStr(tmp) == false)
+ {
+ c->CipherName = CopyStr(tmp);
+ use_encrypt = true;
+ }
+
+ use_udp_acceleration_client = false;
+ }
+ else
+ {
+ if (c->CipherName != NULL)
+ {
+ Free(c->CipherName);
+ }
+ c->CipherName = NULL;
+
+ if (c->FirstSock != NULL && IsEmptyStr(c->FirstSock->CipherName) == false)
+ {
+ c->CipherName = CopyStr(c->FirstSock->CipherName);
+ }
+ }
+
+ if (support_bulk_on_rudp && c->FirstSock != NULL && c->FirstSock->IsRUDPSocket &&
+ c->FirstSock->BulkRecvKey != NULL && c->FirstSock->BulkSendKey != NULL)
+ {
+ // RAllow UDP bulk transfer if the client side supports
+ // in the case of using R-UDP Socket
+ enable_bulk_on_rudp = true;
+
+ enable_hmac_on_bulk_of_rudp = support_hmac_on_bulk_of_rudp;
+ }
+
+ if (support_udp_recovery && c->FirstSock != NULL && c->FirstSock->IsRUDPSocket)
+ {
+ // Allow UDP recovery
+ enable_udp_recovery = true;
+ }
+
+ if (use_udp_acceleration_client)
+ {
+ // Get the parameters for the UDP acceleration function
+ if (PackGetIp(p, "udp_acceleration_client_ip", &udp_acceleration_client_ip) == false ||
+ PackGetData2(p, "udp_acceleration_client_key", udp_acceleration_client_key, UDP_ACCELERATION_COMMON_KEY_SIZE) == false)
+ {
+ use_udp_acceleration_client = false;
+ }
+ else
+ {
+ if (IsZeroIp(&udp_acceleration_client_ip))
+ {
+ Copy(&udp_acceleration_client_ip, &c->FirstSock->RemoteIP, sizeof(IP));
+ }
+ udp_acceleration_client_port = PackGetInt(p, "udp_acceleration_client_port");
+ if (udp_acceleration_client_port == 0)
+ {
+ use_udp_acceleration_client = false;
+ }
+ }
+
+ use_hmac_on_udp_acceleration = support_hmac_on_udp_acceleration_client;
+ }
+
+ Debug("use_udp_acceleration_client = %u\n", use_udp_acceleration_client);
+ Debug("use_hmac_on_udp_acceleration = %u\n", use_hmac_on_udp_acceleration);
+
+ // Request mode
+ require_bridge_routing_mode = PackGetBool(p, "require_bridge_routing_mode");
+ require_monitor_mode = PackGetBool(p, "require_monitor_mode");
+ if (require_monitor_mode)
+ {
+ qos = false;
+ }
+
+ if (is_server_or_bridge)
+ {
+ require_bridge_routing_mode = true;
+ }
+
+ // Client unique ID
+ Zero(unique, sizeof(unique));
+ if (PackGetDataSize(p, "unique_id") == SHA1_SIZE)
+ {
+ PackGetData(p, "unique_id", unique);
+ }
+
+ // Get the authentication method
+ authtype = GetAuthTypeFromPack(p);
+
+ if (1)
+ {
+ // Log
+ char ip1[64], ip2[64], verstr[64];
+ wchar_t *authtype_str = _UU("LH_AUTH_UNKNOWN");
+ switch (authtype)
+ {
+ case CLIENT_AUTHTYPE_ANONYMOUS:
+ authtype_str = _UU("LH_AUTH_ANONYMOUS");
+ break;
+ case CLIENT_AUTHTYPE_PASSWORD:
+ authtype_str = _UU("LH_AUTH_PASSWORD");
+ break;
+ case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+ authtype_str = _UU("LH_AUTH_PLAIN_PASSWORD");
+ break;
+ case CLIENT_AUTHTYPE_CERT:
+ authtype_str = _UU("LH_AUTH_CERT");
+ break;
+ case AUTHTYPE_TICKET:
+ authtype_str = _UU("LH_AUTH_TICKET");
+ break;
+ }
+ IPToStr(ip1, sizeof(ip1), &c->FirstSock->RemoteIP);
+ IPToStr(ip2, sizeof(ip2), &c->FirstSock->LocalIP);
+
+ Format(verstr, sizeof(verstr), "%u.%02u", c->ClientVer / 100, c->ClientVer % 100);
+
+ HLog(hub, "LH_CONNECT_CLIENT", c->Name, ip1, c->FirstSock->RemoteHostname, c->FirstSock->RemotePort,
+ c->ClientStr, verstr, c->ClientBuild, authtype_str, username);
+ }
+
+ // Attempt an anonymous authentication first
+ auth_ret = SamAuthUserByAnonymous(hub, username);
+
+ if (auth_ret)
+ {
+ if (c->IsInProc)
+ {
+ IPC_MSCHAP_V2_AUTHINFO mschap;
+ char password_tmp[MAX_SIZE];
+
+ Zero(&mschap, sizeof(mschap));
+
+ Zero(password_tmp, sizeof(password_tmp));
+ PackGetStr(p, "plain_password", password_tmp, sizeof(password_tmp));
+
+ if (ParseAndExtractMsChapV2InfoFromPassword(&mschap, password_tmp))
+ {
+ // Because the server don't know the NTLM hashed password, the bet to the possibility of
+ // the same character to the user name and empty, search a password of different
+ // versions of the upper and lower case characters in the case of anonymous authentication.
+ // Returns the MS-CHAPv2 response by using the password if there is a match.
+ // Fail the authentication if no match is found.
+ // (Because, if return a false MS-CHAPv2 Response, PPP client cause an error)
+ LIST *o = NewListFast(NULL);
+ char tmp1[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ char tmp3[MAX_SIZE];
+ char tmp4[MAX_SIZE];
+ char *response_pw;
+ char psk[MAX_SIZE];
+
+ ParseNtUsername(mschap.MsChapV2_PPPUsername, tmp1, sizeof(tmp1), tmp2, sizeof(tmp2), false);
+ ParseNtUsername(mschap.MsChapV2_PPPUsername, tmp3, sizeof(tmp3), tmp4, sizeof(tmp4), true);
+
+ Add(o, "");
+ Add(o, "-");
+ Add(o, ".");
+ Add(o, "*");
+ Add(o, "?");
+ Add(o, " ");
+ Add(o, "p");
+ Add(o, "guest");
+ Add(o, "anony");
+ Add(o, "anonymouse");
+ Add(o, "password");
+ Add(o, "passwd");
+ Add(o, "pass");
+ Add(o, "pw");
+ Add(o, mschap.MsChapV2_PPPUsername);
+ Add(o, tmp1);
+ Add(o, tmp2);
+ Add(o, tmp3);
+ Add(o, tmp4);
+
+ Zero(psk, sizeof(psk));
+
+ if (c->Cedar->Server != NULL)
+ {
+ SERVER *s = c->Cedar->Server;
+
+ if (s->IPsecServer != NULL)
+ {
+ StrCpy(psk, sizeof(psk), s->IPsecServer->Services.IPsec_Secret);
+
+ Add(o, psk);
+ }
+ }
+
+ response_pw = MsChapV2DoBruteForce(&mschap, o);
+
+ ReleaseList(o);
+
+ if (response_pw != NULL)
+ {
+ UCHAR challenge8[8];
+ UCHAR nt_hash[16];
+ UCHAR nt_hash_hash[16];
+
+ GenerateNtPasswordHash(nt_hash, response_pw);
+ GenerateNtPasswordHashHash(nt_hash_hash, nt_hash);
+ MsChapV2_GenerateChallenge8(challenge8, mschap.MsChapV2_ClientChallenge, mschap.MsChapV2_ServerChallenge,
+ mschap.MsChapV2_PPPUsername);
+ MsChapV2Server_GenerateResponse(mschap_v2_server_response_20, nt_hash_hash,
+ mschap.MsChapV2_ClientResponse, challenge8);
+
+ Free(response_pw);
+ }
+ else
+ {
+ auth_ret = false;
+ }
+ }
+ }
+
+ if (auth_ret)
+ {
+ // User authentication success by anonymous authentication
+ HLog(hub, "LH_AUTH_OK", c->Name, username);
+ is_empty_password = true;
+ }
+ }
+
+ if (auth_ret == false)
+ {
+ // Attempt other authentication methods if anonymous authentication fails
+ switch (authtype)
+ {
+ case CLIENT_AUTHTYPE_ANONYMOUS:
+ // Anonymous authentication (this have been already attempted)
+ break;
+
+ case AUTHTYPE_TICKET:
+ // Ticket authentication
+ if (PackGetDataSize(p, "ticket") == SHA1_SIZE)
+ {
+ PackGetData(p, "ticket", ticket);
+
+ auth_ret = SiCheckTicket(hub, ticket, username, sizeof(username), username_real, sizeof(username_real),
+ &ticketed_policy, sessionname, sizeof(sessionname), groupname, sizeof(groupname));
+ }
+ break;
+
+ case CLIENT_AUTHTYPE_PASSWORD:
+ // Password authentication
+ if (PackGetDataSize(p, "secure_password") == SHA1_SIZE)
+ {
+ POLICY *pol = NULL;
+ UCHAR secure_password[SHA1_SIZE];
+ Zero(secure_password, sizeof(secure_password));
+ if (PackGetDataSize(p, "secure_password") == SHA1_SIZE)
+ {
+ PackGetData(p, "secure_password", secure_password);
+ }
+ auth_ret = SamAuthUserByPassword(hub, username, c->Random, secure_password, NULL, NULL, NULL);
+
+ pol = SamGetUserPolicy(hub, username);
+ if (pol != NULL)
+ {
+ no_save_password = pol->NoSavePassword;
+ Free(pol);
+ }
+
+ if(auth_ret){
+ // Check whether the password was empty
+ UCHAR hashed_empty_password[SHA1_SIZE];
+ UCHAR secure_empty_password[SHA1_SIZE];
+ HashPassword(hashed_empty_password, username, "");
+ SecurePassword(secure_empty_password, hashed_empty_password, c->Random);
+ if(Cmp(secure_password, secure_empty_password, SHA1_SIZE)==0){
+ is_empty_password = true;
+ }
+ }
+ }
+ break;
+
+ case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+ {
+ POLICY *pol = NULL;
+
+ // Plaintext password authentication
+ Zero(plain_password, sizeof(plain_password));
+ PackGetStr(p, "plain_password", plain_password, sizeof(plain_password));
+ if (c->IsInProc == false && StartWith(plain_password, IPC_PASSWORD_MSCHAPV2_TAG))
+ {
+ // Do not allow the MS-CHAPv2 authentication other than IPC sessions
+ Zero(plain_password, sizeof(plain_password));
+ }
+
+ if (auth_ret == false)
+ {
+ // Attempt a password authentication of normal user
+ UCHAR secure_password[SHA1_SIZE];
+ UCHAR hash_password[SHA1_SIZE];
+ bool is_mschap = StartWith(plain_password, IPC_PASSWORD_MSCHAPV2_TAG);
+
+ HashPassword(hash_password, username, plain_password);
+ SecurePassword(secure_password, hash_password, c->Random);
+
+ if (is_mschap == false)
+ {
+ auth_ret = SamAuthUserByPassword(hub, username, c->Random, secure_password, NULL, NULL, NULL);
+ }
+ else
+ {
+ auth_ret = SamAuthUserByPassword(hub, username, c->Random, secure_password,
+ plain_password, mschap_v2_server_response_20, &ms_chap_error);
+ }
+
+ if (auth_ret && pol == NULL)
+ {
+ pol = SamGetUserPolicy(hub, username);
+ }
+ }
+
+ if (auth_ret == false)
+ {
+ // Attempt external authentication registered users
+ bool fail_ext_user_auth = false;
+ if (true)
+ {
+ fail_ext_user_auth = true;
+ }
+
+ if (fail_ext_user_auth == false)
+ {
+ auth_ret = SamAuthUserByPlainPassword(c, hub, username, plain_password, false, mschap_v2_server_response_20);
+ }
+
+ if (auth_ret && pol == NULL)
+ {
+ pol = SamGetUserPolicy(hub, username);
+ }
+ }
+
+
+ if (pol != NULL)
+ {
+ no_save_password = pol->NoSavePassword;
+ Free(pol);
+ }
+
+ if(auth_ret){
+ // Check whether the password was empty
+ if(IsEmptyStr(plain_password)){
+ is_empty_password = true;
+ }
+ }
+ }
+ break;
+
+ case CLIENT_AUTHTYPE_CERT:
+ // Certificate authentication is not supported in the open source version
+ HLog(hub, "LH_AUTH_CERT_NOT_SUPPORT_ON_OPEN_SOURCE", c->Name, username);
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ FreePack(p);
+ c->Err = ERR_AUTHTYPE_NOT_SUPPORTED;
+ goto CLEANUP;
+ break;
+
+ default:
+ // Unknown authentication method
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ FreePack(p);
+ c->Err = ERR_AUTHTYPE_NOT_SUPPORTED;
+ error_detail = "ERR_AUTHTYPE_NOT_SUPPORTED";
+ goto CLEANUP;
+ }
+
+ if (auth_ret == false)
+ {
+ // Authentication failure
+ HLog(hub, "LH_AUTH_NG", c->Name, username);
+ }
+ else
+ {
+ // Authentication success
+ HLog(hub, "LH_AUTH_OK", c->Name, username);
+ }
+ }
+
+ if (auth_ret == false)
+ {
+ // Authentication failure
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ FreePack(p);
+ c->Err = ERR_AUTH_FAILED;
+ if (ms_chap_error != 0)
+ {
+ c->Err = ms_chap_error;
+ }
+ error_detail = "ERR_AUTH_FAILED";
+ goto CLEANUP;
+ }
+ else
+ {
+ if(is_empty_password)
+ {
+ SOCK *s = c->FirstSock;
+ if (s != NULL && s->RemoteIP.addr[0] != 127)
+ {
+ if(StrCmpi(username, ADMINISTRATOR_USERNAME) == 0 ||
+ GetHubAdminOption(hub, "deny_empty_password") != 0)
+ {
+ // When the password is empty, remote connection is not acceptable
+ HLog(hub, "LH_LOCAL_ONLY", c->Name, username);
+
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ FreePack(p);
+ c->Err = ERR_NULL_PASSWORD_LOCAL_ONLY;
+ error_detail = "ERR_NULL_PASSWORD_LOCAL_ONLY";
+ goto CLEANUP;
+ }
+ }
+ }
+ }
+
+ policy = NULL;
+
+ // Authentication success
+ FreePack(p);
+
+ if (StrCmpi(username, ADMINISTRATOR_USERNAME) != 0)
+ {
+ // Get the policy
+ if (farm_member == false)
+ {
+ // In the case of not a farm member
+ user = AcGetUser(hub, username);
+ if (user == NULL)
+ {
+ user = AcGetUser(hub, "*");
+ if (user == NULL)
+ {
+ // User acquisition failure
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ c->Err = ERR_ACCESS_DENIED;
+ error_detail = "AcGetUser";
+ goto CLEANUP;
+ }
+ }
+
+ policy = NULL;
+
+ Lock(user->lock);
+ {
+ // Get the expiration date
+ user_expires = user->ExpireTime;
+
+ StrCpy(username_real, sizeof(username_real), user->Name);
+ group = user->Group;
+ if (group != NULL)
+ {
+ AddRef(group->ref);
+
+ Lock(group->lock);
+ {
+ // Get the group name
+ StrCpy(groupname, sizeof(groupname), group->Name);
+ }
+ Unlock(group->lock);
+ }
+
+ if (user->Policy != NULL)
+ {
+ policy = ClonePolicy(user->Policy);
+ }
+ else
+ {
+ if (group)
+ {
+ Lock(group->lock);
+ {
+ if (group->Policy != NULL)
+ {
+ policy = ClonePolicy(group->Policy);
+ }
+ }
+ Unlock(group->lock);
+ }
+ }
+
+ if (group != NULL)
+ {
+ ReleaseGroup(group);
+ }
+ }
+ Unlock(user->lock);
+ loggedin_user_object = user;
+ }
+ else
+ {
+ // In the case of farm member
+ policy = ClonePolicy(&ticketed_policy);
+ }
+ }
+ else
+ {
+ // Administrator mode
+ admin_mode = true;
+ StrCpy(username_real, sizeof(username_real), ADMINISTRATOR_USERNAME);
+
+ policy = ClonePolicy(GetDefaultPolicy());
+ policy->NoBroadcastLimiter = true;
+ policy->MonitorPort = true;
+ }
+
+ if (policy == NULL)
+ {
+ // Use the default policy
+ policy = ClonePolicy(GetDefaultPolicy());
+ }
+
+ if (policy->MaxConnection == 0)
+ {
+ policy->MaxConnection = MAX_TCP_CONNECTION;
+ }
+
+ if (policy->TimeOut == 0)
+ {
+ policy->TimeOut = 20;
+ }
+
+ if (qos)
+ {
+ // VoIP / QoS
+ if (policy->NoQoS)
+ {
+ // Policy does not allow QoS
+ qos = false;
+ }
+ if (GetServerCapsBool(c->Cedar->Server, "b_support_qos") == false)
+ {
+ // Server does not support QoS
+ qos = false;
+ policy->NoQoS = true;
+ }
+ if (GetHubAdminOption(hub, "deny_qos") != 0)
+ {
+ // It is prohibited in the management options
+ qos = false;
+ policy->NoQoS = true;
+ }
+ }
+
+ if (GetHubAdminOption(hub, "max_bitrates_download") != 0)
+ {
+ if (policy->MaxDownload == 0)
+ {
+ policy->MaxDownload = GetHubAdminOption(hub, "max_bitrates_download");
+ }
+ else
+ {
+ UINT r = GetHubAdminOption(hub, "max_bitrates_download");
+ policy->MaxDownload = MIN(policy->MaxDownload, r);
+ }
+ }
+
+ if (GetHubAdminOption(hub, "max_bitrates_upload") != 0)
+ {
+ if (policy->MaxUpload == 0)
+ {
+ policy->MaxUpload = GetHubAdminOption(hub, "max_bitrates_upload");
+ }
+ else
+ {
+ UINT r = GetHubAdminOption(hub, "max_bitrates_upload");
+ policy->MaxUpload = MIN(policy->MaxUpload, r);
+ }
+ }
+
+ if (GetHubAdminOption(hub, "deny_bridge") != 0)
+ {
+ policy->NoBridge = true;
+ }
+
+ if (GetHubAdminOption(hub, "deny_routing") != 0)
+ {
+ policy->NoRouting = true;
+ }
+
+ if (c->IsInProc)
+ {
+ policy->NoBridge = false;
+ policy->NoRouting = false;
+ }
+
+ if (hub->Option->ClientMinimumRequiredBuild > c->ClientBuild &&
+ InStrEx(c->ClientStr, "client", false))
+ {
+ // Build number of the client is too small
+ HLog(hub, "LH_CLIENT_VERSION_OLD", c->Name, c->ClientBuild, hub->Option->ClientMinimumRequiredBuild);
+
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ c->Err = ERR_VERSION_INVALID;
+ Free(policy);
+ error_detail = "ERR_VERSION_INVALID";
+ goto CLEANUP;
+ }
+
+ if (hub->Option->RequiredClientId != 0 &&
+ hub->Option->RequiredClientId != client_id &&
+ InStrEx(c->ClientStr, "client", false))
+ {
+ // Build number of the client is too small
+ HLog(hub, "LH_CLIENT_ID_REQUIRED", c->Name, client_id, hub->Option->RequiredClientId);
+
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ c->Err = ERR_CLIENT_ID_REQUIRED;
+ error_detail = "ERR_CLIENT_ID_REQUIRED";
+ Free(policy);
+ goto CLEANUP;
+ }
+
+ if ((policy->NoSavePassword) || (policy->AutoDisconnect != 0))
+ {
+ if (c->ClientBuild < 6560 && InStrEx(c->ClientStr, "client", false))
+ {
+ // If NoSavePassword policy is specified,
+ // only supported client can connect
+ HLog(hub, "LH_CLIENT_VERSION_OLD", c->Name, c->ClientBuild, 6560);
+
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ c->Err = ERR_VERSION_INVALID;
+ error_detail = "ERR_VERSION_INVALID";
+ Free(policy);
+ goto CLEANUP;
+ }
+ }
+
+ if (user_expires != 0 && user_expires <= SystemTime64())
+ {
+ // User expired
+ HLog(hub, "LH_USER_EXPIRES", c->Name, username);
+
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ c->Err = ERR_ACCESS_DENIED;
+ error_detail = "LH_USER_EXPIRES";
+ Free(policy);
+ goto CLEANUP;
+ }
+
+ if (policy->Access == false)
+ {
+ // Access is denied
+ HLog(hub, "LH_POLICY_ACCESS_NG", c->Name, username);
+
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ error_detail = "LH_POLICY_ACCESS_NG";
+ c->Err = ERR_ACCESS_DENIED;
+ Free(policy);
+ goto CLEANUP;
+ }
+
+ // Determine the contents of the policy by comparing to
+ // option presented by client or deny the connection.
+ // Confirm the connectivity in the monitor-mode first
+ if (require_monitor_mode && policy->MonitorPort == false)
+ {
+ // Can not connect in the monitor port mode
+ HLog(hub, "LH_POLICY_MONITOR_MODE", c->Name);
+
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ c->Err = ERR_MONITOR_MODE_DENIED;
+ Free(policy);
+ error_detail = "ERR_MONITOR_MODE_DENIED";
+ goto CLEANUP;
+ }
+
+ if (policy->MonitorPort)
+ {
+ if (require_monitor_mode == false)
+ {
+ policy->MonitorPort = false;
+ }
+ }
+
+ if (policy->MonitorPort)
+ {
+ qos = false;
+ }
+
+ // Determine whether it can be connected by a bridge / routing mode next
+ if (require_bridge_routing_mode &&
+ (policy->NoBridge && policy->NoRouting))
+ {
+ // Can not be connected by a bridge / routing mode
+ HLog(hub, "LH_POLICY_BRIDGE_MODE", c->Name);
+
+ Unlock(hub->lock);
+ ReleaseHub(hub);
+ c->Err = ERR_BRIDGE_MODE_DENIED;
+ error_detail = "ERR_BRIDGE_MODE_DENIED";
+ Free(policy);
+ goto CLEANUP;
+ }
+
+ if (require_bridge_routing_mode == false)
+ {
+ policy->NoBridge = true;
+ policy->NoRouting = true;
+ }
+
+ GenerateMachineUniqueHash(unique2);
+
+ if (Cmp(unique, unique2, SHA1_SIZE) == 0)
+ {
+ // It's a localhost session
+ local_host_session = true;
+ }
+
+ if (local_host_session == false)
+ {
+ // Make further judgment whether localhost session
+ SOCK *s = c->FirstSock;
+
+ if (s != NULL)
+ {
+ if (IsIPMyHost(&s->RemoteIP))
+ {
+ // It's a localhost session
+ local_host_session = true;
+ }
+ }
+ }
+
+ if (local_host_session)
+ {
+ // Permit routing or bridging in the case of localhost session
+ policy->NoBridge = false;
+ policy->NoRouting = false;
+ }
+
+ if (local_host_session == false)
+ {
+
+ if (policy->NoBridge == false || policy->NoRouting == false)
+ {
+ use_bridge_license = true;
+ }
+ else
+ {
+ use_client_license = true;
+ }
+ }
+
+
+ if (server != NULL && server->ServerType != SERVER_TYPE_FARM_MEMBER &&
+ policy != NULL)
+ {
+ if (GetServerCapsBool(hub->Cedar->Server, "b_support_limit_multilogin"))
+ {
+ // Check if the number of concurrent multiple logins limit is specified in the policy
+ RPC_ENUM_SESSION t;
+ UINT i, num;
+ UINT max_logins = policy->MultiLogins;
+ UINT ao = GetHubAdminOption(hub, "max_multilogins_per_user");
+
+ if (ao != 0)
+ {
+ if (max_logins != 0)
+ {
+ max_logins = MIN(max_logins, ao);
+ }
+ else
+ {
+ max_logins = ao;
+ }
+ }
+
+ if (max_logins != 0)
+ {
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hub->Name);
+
+ Unlock(hub->lock);
+
+ SiEnumSessionMain(server, &t);
+
+ Lock(hub->lock);
+
+ num = 0;
+
+ for (i = 0;i < t.NumSession;i++)
+ {
+ RPC_ENUM_SESSION_ITEM *e = &t.Sessions[i];
+
+ if (e->BridgeMode == false && e->Layer3Mode == false && e->LinkMode == false && e->CurrentNumTcp != 0)
+ {
+ if (StrCmpi(e->Username, username) == 0 &&
+ (IsZero(e->UniqueId, 16) || Cmp(e->UniqueId, node.UniqueId, 16) != 0))
+ {
+ num++;
+ }
+ }
+ }
+
+ FreeRpcEnumSession(&t);
+
+ if (num >= max_logins)
+ {
+ // Can not connect any more
+ Unlock(hub->lock);
+
+ // Dump a detailed error log
+ HLog(hub, "LH_TOO_MANY_MULTILOGINS",
+ c->Name,
+ username, max_logins, num);
+
+ ReleaseHub(hub);
+ c->Err = ERR_TOO_MANY_USER_SESSION;
+ Free(policy);
+ goto CLEANUP;
+ }
+ }
+ }
+ }
+
+ if (loggedin_user_object != NULL)
+ {
+ // Update the user information
+ Lock(loggedin_user_object->lock);
+ {
+ loggedin_user_object->LastLoginTime = SystemTime64();
+ }
+ Unlock(loggedin_user_object->lock);
+ }
+
+ // Update the number of log-ins
+ hub->LastCommTime = hub->LastLoginTime = SystemTime64();
+
+ if (farm_controller)
+ {
+ wchar_t *msg = GetHubMsg(hub);
+
+ Unlock(hub->lock);
+
+ Lock(cedar->CedarSuperLock);
+
+ // In the case of farm controller, choose a farm members to host this HUB
+ LockList(server->FarmMemberList);
+ {
+ HLog(hub, "LH_FARM_SELECT_1", c->Name);
+ f = SiGetHubHostingMember(server, hub, admin_mode, c);
+
+ if (f == NULL)
+ {
+ // Failed in the selection
+ HLog(hub, "LH_FARM_SELECT_2", c->Name);
+ UnlockList(server->FarmMemberList);
+ Unlock(cedar->CedarSuperLock);
+ ReleaseHub(hub);
+ c->Err = ERR_COULD_NOT_HOST_HUB_ON_FARM;
+ Free(policy);
+ Free(msg);
+ goto CLEANUP;
+ }
+ else
+ {
+ if (f->Me == false)
+ {
+ UCHAR ticket[SHA1_SIZE];
+ PACK *p;
+ BUF *b;
+ UINT i;
+
+ SLog(c->Cedar, "LH_FARM_SELECT_4", c->Name, f->hostname);
+
+ // Create a session on the selected server farm member
+ Rand(ticket, sizeof(ticket));
+ SiCallCreateTicket(server, f, hub->Name,
+ username, username_real, policy, ticket, Inc(hub->SessionCounter), groupname);
+
+ p = NewPack();
+ PackAddInt(p, "Redirect", 1);
+ PackAddIp32(p, "Ip", f->Ip);
+ for (i = 0;i < f->NumPort;i++)
+ {
+ PackAddIntEx(p, "Port", f->Ports[i], i, f->NumPort);
+ }
+ PackAddData(p, "Ticket", ticket, sizeof(ticket));
+
+ if (true)
+ {
+ char *utf = CopyUniToUtf(msg);
+
+ PackAddData(p, "Msg", utf, StrLen(utf));
+
+ Free(utf);
+ }
+
+ b = XToBuf(f->ServerCert, false);
+ PackAddBuf(p, "Cert", b);
+ FreeBuf(b);
+
+ UnlockList(server->FarmMemberList);
+ Unlock(cedar->CedarSuperLock);
+ ReleaseHub(hub);
+
+ HttpServerSend(c->FirstSock, p);
+ FreePack(p);
+
+ c->Err = 0;
+ Free(policy);
+
+ FreePack(HttpServerRecv(c->FirstSock));
+ Free(msg);
+ goto CLEANUP;
+ }
+ else
+ {
+ HLog(hub, "LH_FARM_SELECT_3", c->Name);
+ // Continue the process because myself was selected
+ UnlockList(server->FarmMemberList);
+ Unlock(cedar->CedarSuperLock);
+ f->Point = SiGetPoint(server);
+ Lock(hub->lock);
+ Free(msg);
+ }
+ }
+ }
+ }
+
+ if (admin_mode == false)
+ {
+ // Check the maximum number of connections of the HUB
+ if (hub->Option->MaxSession != 0 &&
+ hub->Option->MaxSession <= Count(hub->NumSessions))
+ {
+ // Can not connect any more
+ Unlock(hub->lock);
+
+ HLog(hub, "LH_MAX_SESSION", c->Name, hub->Option->MaxSession);
+
+ ReleaseHub(hub);
+ c->Err = ERR_HUB_IS_BUSY;
+ Free(policy);
+ error_detail = "ERR_HUB_IS_BUSY";
+ goto CLEANUP;
+ }
+ }
+
+ if (use_client_license || use_bridge_license)
+ {
+ // Examine whether not to conflict with the limit of simultaneous connections
+ // number of sessions defined by the Virtual HUB management options
+ if (
+ (GetHubAdminOption(hub, "max_sessions") != 0 &&
+ (Count(hub->NumSessionsClient) + Count(hub->NumSessionsBridge)) >= GetHubAdminOption(hub, "max_sessions"))
+ ||
+ (hub->Option->MaxSession != 0 &&
+ (Count(hub->NumSessionsClient) + Count(hub->NumSessionsBridge)) >= hub->Option->MaxSession))
+ {
+ // Can not connect any more
+ Unlock(hub->lock);
+
+ HLog(hub, "LH_MAX_SESSION", c->Name, GetHubAdminOption(hub, "max_sessions"));
+
+ ReleaseHub(hub);
+ c->Err = ERR_HUB_IS_BUSY;
+ Free(policy);
+ goto CLEANUP;
+ }
+ }
+
+ if (use_client_license)
+ {
+ // Examine whether not to conflict with the limit of simultaneous connections
+ // number of sessions(client) defined by the Virtual HUB management options
+ if (((GetHubAdminOption(hub, "max_sessions_client_bridge_apply") != 0
+ ) &&
+ Count(hub->NumSessionsClient) >= GetHubAdminOption(hub, "max_sessions_client") && hub->Cedar->Server != NULL && hub->Cedar->Server->ServerType != SERVER_TYPE_FARM_MEMBER)
+ ||
+ (hub->FarmMember_MaxSessionClientBridgeApply &&
+ Count(hub->NumSessionsClient) >= hub->FarmMember_MaxSessionClient))
+ {
+ // Can not connect any more
+ Unlock(hub->lock);
+
+ HLog(hub, "LH_MAX_SESSION_CLIENT", c->Name, GetHubAdminOption(hub, "max_sessions_client"));
+
+ ReleaseHub(hub);
+ c->Err = ERR_HUB_IS_BUSY;
+ Free(policy);
+ goto CLEANUP;
+ }
+ }
+
+ if (use_bridge_license)
+ {
+ // Examine whether not to conflict with the limit of simultaneous connections
+ // number of sessions(bridge) defined by the Virtual HUB management options
+ if (((GetHubAdminOption(hub, "max_sessions_client_bridge_apply") != 0
+ ) &&
+ Count(hub->NumSessionsBridge) >= GetHubAdminOption(hub, "max_sessions_bridge") && hub->Cedar->Server != NULL && hub->Cedar->Server->ServerType != SERVER_TYPE_FARM_MEMBER)
+ ||
+ (hub->FarmMember_MaxSessionClientBridgeApply &&
+ Count(hub->NumSessionsBridge) >= hub->FarmMember_MaxSessionBridge))
+ {
+ // Can not connect any more
+ Unlock(hub->lock);
+
+ HLog(hub, "LH_MAX_SESSION_BRIDGE", c->Name, GetHubAdminOption(hub, "max_sessions_bridge"));
+
+ ReleaseHub(hub);
+ c->Err = ERR_HUB_IS_BUSY;
+ Free(policy);
+ goto CLEANUP;
+ }
+ }
+
+ if (Count(hub->Cedar->CurrentSessions) >= GetServerCapsInt(hub->Cedar->Server, "i_max_sessions"))
+ {
+ // Can not connect any more
+ Unlock(hub->lock);
+
+ HLog(hub, "LH_MAX_SESSION_2", c->Name, GetServerCapsInt(hub->Cedar->Server, "i_max_sessions"));
+
+ ReleaseHub(hub);
+ c->Err = ERR_HUB_IS_BUSY;
+ Free(policy);
+ goto CLEANUP;
+ }
+
+ // Increment the current number of connections
+ Inc(hub->NumSessions);
+ if (use_bridge_license)
+ {
+ Inc(hub->NumSessionsBridge);
+ }
+
+ if (use_client_license)
+ {
+ Inc(hub->NumSessionsClient);
+ }
+ Inc(hub->Cedar->CurrentSessions);
+
+ // Calculate the time-out period
+ timeout = policy->TimeOut * 1000; // Convert milliseconds to seconds
+ if (timeout == 0)
+ {
+ timeout = TIMEOUT_DEFAULT;
+ }
+ timeout = MIN(timeout, TIMEOUT_MAX);
+ timeout = MAX(timeout, TIMEOUT_MIN);
+
+ // Update the max_connection according to the policy
+ max_connection = MIN(max_connection, policy->MaxConnection);
+ max_connection = MIN(max_connection, MAX_TCP_CONNECTION);
+ max_connection = MAX(max_connection, 1);
+
+ if (c->FirstSock->IsRUDPSocket)
+ {
+ // In the case of TCP-over-UDP
+ half_connection = false;
+
+ // Disable the QoS
+ qos = false;
+
+ if (enable_udp_recovery == false)
+ {
+ // Disable the session reconnection feature
+ no_reconnect_to_session = true;
+ max_connection = 1;
+ }
+ else
+ {
+ // If the UDP recovery is enabled, permit the session re-connection feature (for 2)
+ no_reconnect_to_session = false;
+ max_connection = NUM_TCP_CONNECTION_FOR_UDP_RECOVERY;
+ }
+ }
+
+ if (half_connection)
+ {
+ // Number of connections should be more than 2 in the case of Half Connection
+ max_connection = MAX(max_connection, 2);
+ }
+
+ if (qos)
+ {
+ // Number of connections is set to 2 or more when using the VoIP / QoS
+ max_connection = MAX(max_connection, 2);
+ if (half_connection)
+ {
+ max_connection = MAX(max_connection, 4);
+ }
+ }
+
+ c->Status = CONNECTION_STATUS_ESTABLISHED;
+
+ // Remove the connection from Cedar
+ DelConnection(c->Cedar, c);
+
+ // Create a Session
+ StrLower(username);
+ s = NewServerSessionEx(c->Cedar, c, hub, username, policy, c->IsInProc);
+
+ s->EnableUdpRecovery = enable_udp_recovery;
+ s->LocalHostSession = local_host_session;
+ s->NormalClient = true;
+
+ if (c->FirstSock->IsRUDPSocket)
+ {
+ // R-UDP session
+ s->IsRUDPSession = true;
+ s->RUdpMss = c->FirstSock->RUDP_OptimizedMss;
+ Debug("Optimized MSS Value for R-UDP: %u\n", s->RUdpMss);
+ }
+
+ if (enable_bulk_on_rudp)
+ {
+ // Allow bulk transfer on R-UDP
+ s->EnableBulkOnRUDP = true;
+ s->EnableHMacOnBulkOfRUDP = enable_hmac_on_bulk_of_rudp;
+ }
+
+ s->IsAzureSession = c->FirstSock->IsReverseAcceptedSocket;
+
+ StrCpy(s->UnderlayProtocol, sizeof(s->UnderlayProtocol), c->FirstSock->UnderlayProtocol);
+
+ if (server != NULL)
+ {
+ s->NoSendSignature = server->NoSendSignature;
+ }
+
+ if (c->IsInProc)
+ {
+ s->NoSendSignature = true;
+ }
+
+ if (c->IsInProc && StrCmpi(c->InProcPrefix, OPENVPN_IPC_POSTFIX_L3) == 0)
+ {
+ // OpenVPN L3 session
+ s->IsOpenVPNL3Session = true;
+ }
+
+ if (c->IsInProc && StrCmpi(c->InProcPrefix, OPENVPN_IPC_POSTFIX_L2) == 0)
+ {
+ // OpenVPN L2 session
+ s->IsOpenVPNL2Session = true;
+ }
+
+ // Determine whether the use of UDP acceleration mode
+ if (use_udp_acceleration_client)
+ {
+ s->UseUdpAcceleration = true;
+
+ s->UdpAccelFastDisconnectDetect = support_udp_accel_fast_disconnect_detect;
+ }
+
+ if (hub->Option != NULL && hub->Option->DisableUdpAcceleration)
+ {
+ s->UseUdpAcceleration = false;
+ }
+
+ if (IsZeroIP(&c->FirstSock->Reverse_MyServerGlobalIp) == false &&
+ CmpIpAddr(&c->FirstSock->Reverse_MyServerGlobalIp, &c->FirstSock->RemoteIP) == 0)
+ {
+ // Disable forcibly the UDP acceleration mode if VPN Server and VPN Client
+ // are in same LAN in the case of using VPN Azure.
+ // (Or this may cause infinite loop of packet)
+ s->UseUdpAcceleration = false;
+ }
+
+ if (s->UseUdpAcceleration)
+ {
+ s->UseHMacOnUdpAcceleration = use_hmac_on_udp_acceleration;
+ }
+
+ Debug("UseUdpAcceleration = %u\n", s->UseUdpAcceleration);
+ Debug("UseHMacOnUdpAcceleration = %u\n", s->UseHMacOnUdpAcceleration);
+
+ if (s->UseUdpAcceleration)
+ {
+ // Initialize the UDP acceleration function
+ s->UdpAccel = NewUdpAccel(c->Cedar, (c->FirstSock->IsRUDPSocket ? NULL : &c->FirstSock->LocalIP), false, c->FirstSock->IsRUDPSocket, false);
+ if (s->UdpAccel == NULL)
+ {
+ s->UseUdpAcceleration = false;
+ Debug("NewUdpAccel Failed.\n");
+ }
+ else
+ {
+ if (UdpAccelInitServer(s->UdpAccel, udp_acceleration_client_key, &udp_acceleration_client_ip, udp_acceleration_client_port,
+ &c->FirstSock->RemoteIP) == false)
+ {
+ Debug("UdpAccelInitServer Failed.\n");
+ s->UseUdpAcceleration = false;
+ }
+
+ s->UdpAccel->FastDetect = s->UdpAccelFastDisconnectDetect;
+
+ if (use_encrypt == false)
+ {
+ s->UdpAccel->PlainTextMode = true;
+ }
+
+ s->UdpAccel->UseHMac = s->UseHMacOnUdpAcceleration;
+ }
+ }
+
+ s->UseClientLicense = use_client_license;
+ s->UseBridgeLicense = use_bridge_license;
+
+ s->AdjustMss = adjust_mss;
+ if (s->AdjustMss != 0)
+ {
+ Debug("AdjustMSS: %u\n", s->AdjustMss);
+ }
+
+ s->IsBridgeMode = (policy->NoBridge == false) || (policy->NoRouting == false);
+ s->IsMonitorMode = policy->MonitorPort;
+
+ // Decide whether IPv6 session
+ s->IPv6Session = false;
+
+ if (node.ClientIpAddress == 0)
+ {
+ s->IPv6Session = true;
+ }
+
+ if (use_bridge_license)
+ {
+ Inc(s->Cedar->AssignedBridgeLicense);
+ }
+
+ if (use_client_license)
+ {
+ Inc(s->Cedar->AssignedClientLicense);
+ }
+
+ if (server != NULL)
+ {
+ // Update the total allocation of the number of licenses for Server structure
+ if (server->ServerType == SERVER_TYPE_STANDALONE)
+ {
+ // Update only stand-alone mode
+ // (Periodically poll in the cluster controller mode)
+ server->CurrentAssignedClientLicense = Count(s->Cedar->AssignedClientLicense);
+ server->CurrentAssignedBridgeLicense = Count(s->Cedar->AssignedBridgeLicense);
+ }
+ }
+
+ if (StrLen(sessionname) != 0)
+ {
+ // Specify the session name
+ Free(s->Name);
+ s->Name = CopyStr(sessionname);
+ }
+
+ {
+ char ip[128];
+ IPToStr(ip, sizeof(ip), &c->FirstSock->RemoteIP);
+ HLog(hub, "LH_NEW_SESSION", c->Name, s->Name, ip, c->FirstSock->RemotePort,
+ c->FirstSock->UnderlayProtocol);
+ }
+
+ c->Session = s;
+ s->AdministratorMode = admin_mode;
+ StrCpy(s->UserNameReal, sizeof(s->UserNameReal), username_real);
+ StrCpy(s->GroupName, sizeof(s->GroupName), groupname);
+
+ // Get the session key
+ Copy(session_key, s->SessionKey, SHA1_SIZE);
+
+ // Set the parameters
+ s->MaxConnection = max_connection;
+ s->UseEncrypt = use_encrypt;
+ if (s->UseEncrypt && use_fast_rc4)
+ {
+ s->UseFastRC4 = use_fast_rc4;
+ }
+ s->UseCompress = use_compress;
+ s->HalfConnection = half_connection;
+ s->Timeout = timeout;
+ s->QoS = qos;
+ s->NoReconnectToSession = no_reconnect_to_session;
+
+ if (policy != NULL)
+ {
+ s->VLanId = policy->VLanId;
+ }
+
+ // User name
+ s->Username = CopyStr(username);
+
+ HLog(hub, "LH_SET_SESSION", s->Name, s->MaxConnection,
+ s->UseEncrypt ? _UU("L_YES") : _UU("L_NO"),
+ s->UseCompress ? _UU("L_YES") : _UU("L_NO"),
+ s->HalfConnection ? _UU("L_YES") : _UU("L_NO"),
+ s->Timeout / 1000);
+
+ msg = GetHubMsg(hub);
+ }
+ Unlock(hub->lock);
+
+ // Send a Welcome packet to the client
+ p = PackWelcome(s);
+
+ if (s->InProcMode)
+ {
+ if (IsZero(mschap_v2_server_response_20, sizeof(mschap_v2_server_response_20)) == false)
+ {
+ // MS-CHAPv2 Response
+ PackAddData(p, "IpcMsChapV2ServerResponse", mschap_v2_server_response_20, sizeof(mschap_v2_server_response_20));
+ }
+ }
+
+ if (true)
+ {
+ // A message to be displayed in the VPN Client (Will not be displayed if the VPN Gate Virtual HUB)
+ char *utf;
+ wchar_t winver_msg_client[3800];
+ wchar_t winver_msg_server[3800];
+ UINT tmpsize;
+ wchar_t *tmp;
+ RPC_WINVER server_winver;
+
+ GetWinVer(&server_winver);
+
+ Zero(winver_msg_client, sizeof(winver_msg_client));
+ Zero(winver_msg_server, sizeof(winver_msg_server));
+
+ if (IsSupportedWinVer(&winver) == false)
+ {
+ SYSTEMTIME st;
+
+ LocalTime(&st);
+
+ UniFormat(winver_msg_client, sizeof(winver_msg_client), _UU("WINVER_ERROR_FORMAT"),
+ _UU("WINVER_ERROR_PC_LOCAL"),
+ winver.Title,
+ _UU("WINVER_ERROR_VPNSERVER"),
+ SUPPORTED_WINDOWS_LIST,
+ _UU("WINVER_ERROR_PC_LOCAL"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ st.wYear, st.wMonth);
+ }
+
+ if (IsSupportedWinVer(&server_winver) == false)
+ {
+ SYSTEMTIME st;
+
+ LocalTime(&st);
+
+ UniFormat(winver_msg_server, sizeof(winver_msg_server), _UU("WINVER_ERROR_FORMAT"),
+ _UU("WINVER_ERROR_PC_REMOTE"),
+ server_winver.Title,
+ _UU("WINVER_ERROR_VPNSERVER"),
+ SUPPORTED_WINDOWS_LIST,
+ _UU("WINVER_ERROR_PC_REMOTE"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ _UU("WINVER_ERROR_VPNSERVER"),
+ st.wYear, st.wMonth);
+ }
+
+ tmpsize = UniStrSize(winver_msg_client) + UniStrSize(winver_msg_server) + UniStrSize(msg) + 16000;
+
+ tmp = ZeroMalloc(tmpsize);
+
+ if (IsURLMsg(msg, NULL, 0) == false)
+ {
+
+ {
+ if (GetCurrentLangId() != SE_LANG_ENGLISH)
+ {
+ UniStrCat(tmp, tmpsize, _UU("OSS_MSG"));
+ }
+ }
+
+ {
+ UniStrCat(tmp, tmpsize, winver_msg_client);
+ UniStrCat(tmp, tmpsize, winver_msg_server);
+ }
+ }
+ UniStrCat(tmp, tmpsize, msg);
+
+ utf = CopyUniToUtf(tmp);
+
+ PackAddData(p, "Msg", utf, StrLen(utf));
+
+ Free(tmp);
+ Free(utf);
+ }
+
+ Free(msg);
+
+
+ if (s->UseFastRC4)
+ {
+ // Generate a RC4 key pair
+ GenerateRC4KeyPair(&key_pair);
+
+ // Add to Welcome packet
+ PackAddData(p, "rc4_key_client_to_server", key_pair.ClientToServerKey, sizeof(key_pair.ClientToServerKey));
+ PackAddData(p, "rc4_key_server_to_client", key_pair.ServerToClientKey, sizeof(key_pair.ServerToClientKey));
+ {
+ char key1[64], key2[64];
+ BinToStr(key1, sizeof(key1), key_pair.ClientToServerKey, 16);
+ BinToStr(key2, sizeof(key2), key_pair.ServerToClientKey, 16);
+ Debug(
+ "Client to Server Key: %s\n"
+ "Server to Client Key: %s\n",
+ key1, key2);
+ }
+ }
+
+ // Brand string for the connection limit
+ {
+ char *branded_cfroms = _SS("BRANDED_C_FROM_S");
+ if(StrLen(branded_cfroms) > 0)
+ {
+ PackAddStr(p, "branded_cfroms", branded_cfroms);
+ }
+ }
+
+ HttpServerSend(c->FirstSock, p);
+ FreePack(p);
+
+ // Receive a signature
+ Copy(&c->Session->NodeInfo, &node, sizeof(NODE_INFO));
+
+
+ {
+ wchar_t tmp[MAX_SIZE * 2];
+ NodeInfoToStr(tmp, sizeof(tmp), &s->NodeInfo);
+
+ HLog(hub, "LH_NODE_INFO", s->Name, tmp);
+ }
+
+ // Shift the connection to the tunneling mode
+ StartTunnelingMode(c);
+
+ // Processing of half-connection mode
+ if (s->HalfConnection)
+ {
+ // The direction of the first socket is client to server
+ TCPSOCK *ts = (TCPSOCK *)LIST_DATA(c->Tcp->TcpSockList, 0);
+ ts->Direction = TCP_CLIENT_TO_SERVER;
+ }
+
+ if (s->UseFastRC4)
+ {
+ // Set the RC4 key information to the first TCP connection
+ TCPSOCK *ts = (TCPSOCK *)LIST_DATA(c->Tcp->TcpSockList, 0);
+ Copy(&ts->Rc4KeyPair, &key_pair, sizeof(RC4_KEY_PAIR));
+
+ InitTcpSockRc4Key(ts, true);
+ }
+
+ if (s->UseEncrypt && s->UseFastRC4 == false)
+ {
+ s->UseSSLDataEncryption = true;
+ }
+ else
+ {
+ s->UseSSLDataEncryption = false;
+ }
+
+ if (s->Hub->Type == HUB_TYPE_FARM_DYNAMIC && s->Cedar->Server != NULL && s->Cedar->Server->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ if (s->Hub->BeingOffline == false)
+ {
+ // Start the SecureNAT on the dynamic Virtual HUB
+ EnableSecureNATEx(s->Hub, false, true);
+
+ cluster_dynamic_secure_nat = true;
+ }
+ }
+
+ if (s->LocalHostSession)
+ {
+ // Update the local MAC address list
+ RefreshLocalMacAddressList();
+ }
+
+ // Discard the user list cache
+ DeleteAllUserListCache(hub->UserList);
+
+
+ // Main routine of the session
+ Debug("SessionMain()\n");
+ s->NumLoginIncrementUserObject = loggedin_user_object;
+ s->NumLoginIncrementHubObject = s->Hub;
+ s->NumLoginIncrementTick = Tick64() + (UINT64)NUM_LOGIN_INCREMENT_INTERVAL;
+ SessionMain(s);
+
+
+ // Discard the user list cache
+ DeleteAllUserListCache(hub->UserList);
+
+ // Decrement the current number of connections
+ Lock(s->Hub->lock);
+ {
+ if (use_bridge_license)
+ {
+ Dec(hub->NumSessionsBridge);
+ }
+
+ if (use_client_license)
+ {
+ Dec(hub->NumSessionsClient);
+ }
+
+ Dec(s->Hub->NumSessions);
+ Dec(s->Hub->Cedar->CurrentSessions);
+
+ // Decrement the number of licenses
+ if (use_bridge_license)
+ {
+ Dec(s->Cedar->AssignedBridgeLicense);
+ }
+
+ if (use_client_license)
+ {
+ Dec(s->Cedar->AssignedClientLicense);
+ }
+
+ if (server != NULL)
+ {
+ // Update the total allocation of the number of licenses for Server structure
+ if (server->ServerType == SERVER_TYPE_STANDALONE)
+ {
+ // Update only stand-alone mode
+ // (Periodically polled in the cluster controller mode)
+ server->CurrentAssignedClientLicense = Count(s->Cedar->AssignedClientLicense);
+ server->CurrentAssignedBridgeLicense = Count(s->Cedar->AssignedBridgeLicense);
+ }
+ }
+ }
+ Unlock(s->Hub->lock);
+
+ PrintSessionTotalDataSize(s);
+
+ HLog(s->Hub, "LH_END_SESSION", s->Name, s->TotalSendSizeReal, s->TotalRecvSizeReal);
+
+ if (cluster_dynamic_secure_nat && s->Hub->BeingOffline == false)
+ {
+ // Stop the SecureNAT on the dynamic Virtual HUB
+ EnableSecureNATEx(s->Hub, false, true);
+ }
+
+ if (s->UdpAccel != NULL)
+ {
+ // Release the UDP acceleration
+ FreeUdpAccel(s->UdpAccel);
+ s->UdpAccel = NULL;
+ }
+
+ ReleaseSession(s);
+
+ ret = true;
+ c->Err = ERR_SESSION_REMOVED;
+
+ ReleaseHub(hub);
+
+ goto CLEANUP;
+ }
+ else if (StrCmpi(method, "additional_connect") == 0)
+ {
+ SOCK *sock;
+ TCPSOCK *ts;
+ UINT dummy;
+
+ c->Type = CONNECTION_TYPE_ADDITIONAL;
+
+ // Additional connection
+ // Read the session key
+ if (GetSessionKeyFromPack(p, session_key, &dummy) == false)
+ {
+ FreePack(p);
+ c->Err = ERR_PROTOCOL_ERROR;
+ goto CLEANUP;
+ }
+
+ FreePack(p);
+
+ // Get the session from the session key
+ s = GetSessionFromKey(c->Cedar, session_key);
+ if (s == NULL || s->Halt || s->NoReconnectToSession)
+ {
+ // Session can not be found, or re-connection is prohibited
+ Debug("Session Not Found.\n");
+ c->Err = ERR_SESSION_TIMEOUT;
+ goto CLEANUP;
+ }
+
+ // Session is found
+ Debug("Session Found: %s\n", s->Name);
+ // Check the protocol of session
+ c->Err = 0;
+ Lock(s->lock);
+ {
+ if (s->Connection->Protocol != CONNECTION_TCP)
+ {
+ c->Err = ERR_INVALID_PROTOCOL;
+ }
+ }
+ Unlock(s->lock);
+ // Check the current number of connections of the session
+ Lock(s->Connection->lock);
+ if (c->Err == 0)
+ {
+ if (Count(s->Connection->CurrentNumConnection) > s->MaxConnection)
+ {
+ c->Err = ERR_TOO_MANY_CONNECTION;
+ }
+ }
+ if (c->Err != 0)
+ {
+ Unlock(s->Connection->lock);
+ if (c->Err == ERR_TOO_MANY_CONNECTION)
+ {
+ Debug("Session TOO MANY CONNECTIONS !!: %u\n",
+ Count(s->Connection->CurrentNumConnection));
+ }
+ else
+ {
+ Debug("Session Invalid Protocol.\n");
+ }
+ ReleaseSession(s);
+ goto CLEANUP;
+ }
+
+ // Generate a high-speed RC4 encryption key
+ if (s->UseFastRC4)
+ {
+ GenerateRC4KeyPair(&key_pair);
+ }
+
+ // Add the socket of this connection to the connection list of the session (TCP)
+ sock = c->FirstSock;
+ ts = NewTcpSock(sock);
+ SetTimeout(sock, CONNECTING_TIMEOUT);
+ direction = TCP_BOTH;
+ LockList(s->Connection->Tcp->TcpSockList);
+ {
+ if (s->HalfConnection)
+ {
+ // In half-connection, directions of the TCP connections are automatically
+ // adjusted by examining all current direction of the TCP connections
+ UINT i, c2s, s2c;
+ c2s = s2c = 0;
+ for (i = 0;i < LIST_NUM(s->Connection->Tcp->TcpSockList);i++)
+ {
+ TCPSOCK *ts = (TCPSOCK *)LIST_DATA(s->Connection->Tcp->TcpSockList, i);
+ if (ts->Direction == TCP_SERVER_TO_CLIENT)
+ {
+ s2c++;
+ }
+ else
+ {
+ c2s++;
+ }
+ }
+ if (s2c > c2s)
+ {
+ direction = TCP_CLIENT_TO_SERVER;
+ }
+ else
+ {
+ direction = TCP_SERVER_TO_CLIENT;
+ }
+ Debug("%u/%u\n", s2c, c2s);
+ ts->Direction = direction;
+ }
+ }
+ UnlockList(s->Connection->Tcp->TcpSockList);
+
+ if (s->UseFastRC4)
+ {
+ // Set the RC4 key information
+ Copy(&ts->Rc4KeyPair, &key_pair, sizeof(RC4_KEY_PAIR));
+
+ InitTcpSockRc4Key(ts, true);
+ }
+
+ // Return a success result
+ p = PackError(ERR_NO_ERROR);
+ PackAddInt(p, "direction", direction);
+
+ if (s->UseFastRC4)
+ {
+ // Add a RC4 key information
+ PackAddData(p, "rc4_key_client_to_server", key_pair.ClientToServerKey, sizeof(key_pair.ClientToServerKey));
+ PackAddData(p, "rc4_key_server_to_client", key_pair.ServerToClientKey, sizeof(key_pair.ServerToClientKey));
+ {
+ char key1[64], key2[64];
+ BinToStr(key1, sizeof(key1), key_pair.ClientToServerKey, 16);
+ BinToStr(key2, sizeof(key2), key_pair.ServerToClientKey, 16);
+ Debug(
+ "Client to Server Key: %s\n"
+ "Server to Client Key: %s\n",
+ key1, key2);
+ }
+ }
+
+ HttpServerSend(c->FirstSock, p);
+ FreePack(p);
+
+ SetTimeout(sock, INFINITE);
+
+ LockList(s->Connection->Tcp->TcpSockList);
+ {
+ Add(s->Connection->Tcp->TcpSockList, ts);
+ }
+ UnlockList(s->Connection->Tcp->TcpSockList);
+
+ // Increment the number of connections
+ Inc(s->Connection->CurrentNumConnection);
+ Debug("TCP Connection Incremented: %u\n", Count(s->Connection->CurrentNumConnection));
+
+ // Issue the Cancel of session
+ Cancel(s->Cancel1);
+
+ Unlock(s->Connection->lock);
+
+ c->flag1 = true;
+
+ ReleaseSession(s);
+
+ return true;
+ }
+ else if (StrCmpi(method, "enum_hub") == 0)
+ {
+ // Enumerate the Virtual HUB
+ UINT i, num;
+ LIST *o;
+ o = NewListFast(NULL);
+
+ c->Type = CONNECTION_TYPE_ENUM_HUB;
+
+ FreePack(p);
+ p = NewPack();
+ LockList(c->Cedar->HubList);
+ {
+ num = LIST_NUM(c->Cedar->HubList);
+ for (i = 0;i < num;i++)
+ {
+ HUB *h = LIST_DATA(c->Cedar->HubList, i);
+ if (h->Option != NULL && h->Option->NoEnum == false)
+ {
+ Insert(o, CopyStr(h->Name));
+ }
+ }
+ }
+ UnlockList(c->Cedar->HubList);
+
+ num = LIST_NUM(o);
+ for (i = 0;i < num;i++)
+ {
+ char *name = LIST_DATA(o, i);
+ PackAddStrEx(p, "HubName", name, i, num);
+ Free(name);
+ }
+ ReleaseList(o);
+ PackAddInt(p, "NumHub", num);
+
+ HttpServerSend(c->FirstSock, p);
+ FreePack(p);
+ FreePack(HttpServerRecv(c->FirstSock));
+ c->Err = 0;
+
+ SLog(c->Cedar, "LS_ENUM_HUB", c->Name, num);
+
+ error_detail = "enum_hub";
+
+ goto CLEANUP;
+ }
+ else if (StrCmpi(method, "farm_connect") == 0)
+ {
+ // Server farm connection request
+ CEDAR *cedar = c->Cedar;
+ c->Type = CONNECTION_TYPE_FARM_RPC;
+ c->Err = 0;
+ if (c->Cedar->Server == NULL)
+ {
+ // Unsupported
+ c->Err = ERR_NOT_FARM_CONTROLLER;
+ }
+ else
+ {
+ SERVER *s = c->Cedar->Server;
+ if (s->ServerType != SERVER_TYPE_FARM_CONTROLLER || s->FarmControllerInited == false)
+ {
+ // Not a farm controller
+ SLog(c->Cedar, "LS_FARM_ACCEPT_1", c->Name);
+ c->Err = ERR_NOT_FARM_CONTROLLER;
+ }
+ else
+ {
+ UCHAR check_secure_password[SHA1_SIZE];
+ UCHAR secure_password[SHA1_SIZE];
+ // User authentication
+ SecurePassword(check_secure_password, s->HashedPassword, c->Random);
+ if (PackGetDataSize(p, "SecurePassword") == sizeof(secure_password))
+ {
+ PackGetData(p, "SecurePassword", secure_password);
+ }
+ else
+ {
+ Zero(secure_password, sizeof(secure_password));
+ }
+
+ if (Cmp(secure_password, check_secure_password, SHA1_SIZE) != 0)
+ {
+ // Password is different
+ SLog(c->Cedar, "LS_FARM_ACCEPT_2", c->Name);
+ c->Err = ERR_ACCESS_DENIED;
+ }
+ else
+ {
+ // Get the certificate
+ BUF *b;
+ X *server_x;
+
+ SLog(c->Cedar, "LS_FARM_ACCEPT_3", c->Name);
+ b = PackGetBuf(p, "ServerCert");
+ if (b == NULL)
+ {
+ c->Err = ERR_PROTOCOL_ERROR;
+ }
+ else
+ {
+ server_x = BufToX(b, false);
+ FreeBuf(b);
+ if (server_x == NULL)
+ {
+ c->Err = ERR_PROTOCOL_ERROR;
+ }
+ else
+ {
+ UINT ip;
+ UINT point;
+ char hostname[MAX_SIZE];
+
+#ifdef OS_WIN32
+ MsSetThreadPriorityRealtime();
+#endif // OS_WIN32
+
+ SetTimeout(c->FirstSock, SERVER_CONTROL_TCP_TIMEOUT);
+
+ ip = PackGetIp32(p, "PublicIp");
+ point = PackGetInt(p, "Point");
+ if (PackGetStr(p, "HostName", hostname, sizeof(hostname)))
+ {
+ UINT num_port = PackGetIndexCount(p, "PublicPort");
+ if (num_port >= 1 && num_port <= MAX_PUBLIC_PORT_NUM)
+ {
+ UINT *ports = ZeroMalloc(sizeof(UINT) * num_port);
+ UINT i;
+
+ for (i = 0;i < num_port;i++)
+ {
+ ports[i] = PackGetIntEx(p, "PublicPort", i);
+ }
+
+ SiFarmServ(s, c->FirstSock, server_x, ip, num_port, ports, hostname, point,
+ PackGetInt(p, "Weight"), PackGetInt(p, "MaxSessions"));
+
+ Free(ports);
+ }
+ }
+
+ FreeX(server_x);
+ }
+ }
+ }
+ }
+ }
+ FreePack(p);
+ goto CLEANUP;
+ }
+ else if (StrCmpi(method, "admin") == 0 && c->Cedar->Server != NULL)
+ {
+ UINT err;
+ // Administrative RPC connection request
+ c->Type = CONNECTION_TYPE_ADMIN_RPC;
+ err = AdminAccept(c, p);
+ FreePack(p);
+ if (err != ERR_NO_ERROR)
+ {
+ PACK *p = PackError(err);
+ HttpServerSend(c->FirstSock, p);
+ FreePack(p);
+ }
+
+ error_detail = "admin_rpc";
+
+ goto CLEANUP;
+ }
+ else if (StrCmpi(method, "password") == 0)
+ {
+ UINT err;
+ // Password change request
+ c->Type = CONNECTION_TYPE_PASSWORD;
+ err = ChangePasswordAccept(c, p);
+ FreePack(p);
+
+ p = PackError(err);
+ HttpServerSend(c->FirstSock, p);
+ FreePack(p);
+
+ error_detail = "change_password";
+
+ goto CLEANUP;
+ }
+ else
+ {
+ // Unknown method
+ FreePack(p);
+ c->Err = ERR_PROTOCOL_ERROR;
+
+ error_detail = "unknown_method";
+
+ goto CLEANUP;
+ }
+
+CLEANUP:
+ // Release the user object
+ if (loggedin_user_object != NULL)
+ {
+ ReleaseUser(loggedin_user_object);
+ }
+
+
+ // Error packet transmission
+ p = PackError(c->Err);
+ PackAddBool(p, "no_save_password", no_save_password);
+ HttpServerSend(c->FirstSock, p);
+ FreePack(p);
+ FreePack(HttpServerRecv(c->FirstSock));
+ SleepThread(25);
+
+ SLog(c->Cedar, "LS_CONNECTION_ERROR", c->Name, GetUniErrorStr(c->Err), c->Err);
+
+ return ret;
+}
+
+
+// Create a Node information
+void CreateNodeInfo(NODE_INFO *info, CONNECTION *c)
+{
+ SESSION *s;
+ OS_INFO *os;
+ char *product_id;
+ IP ip;
+ bool is_vgc = false;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ s = c->Session;
+ os = GetOsInfo();
+
+
+
+ Zero(info, sizeof(NODE_INFO));
+
+ // Client product name
+ StrCpy(info->ClientProductName, sizeof(info->ClientProductName), c->ClientStr);
+ // Client version
+ info->ClientProductVer = Endian32(c->ClientVer);
+ // Client build number
+ info->ClientProductBuild = Endian32(c->ClientBuild);
+
+ // Server product name
+ StrCpy(info->ServerProductName, sizeof(info->ServerProductName), c->ServerStr);
+ // Server version
+ info->ServerProductVer = Endian32(c->ServerVer);
+ // Server build number
+ info->ServerProductBuild = Endian32(c->ServerBuild);
+
+ // Client OS name
+ StrCpy(info->ClientOsName, sizeof(info->ClientOsName), os->OsProductName);
+ // Client OS version
+ StrCpy(info->ClientOsVer, sizeof(info->ClientOsVer), os->OsVersion);
+ // Client OS Product ID
+ product_id = OSGetProductId();
+ StrCpy(info->ClientOsProductId, sizeof(info->ClientOsProductId), product_id);
+ Free(product_id);
+
+ // Client host name
+#ifndef OS_WIN32
+ GetMachineName(info->ClientHostname, sizeof(info->ClientHostname));
+#else // OS_WIN32
+ if (true)
+ {
+ wchar_t namew[256];
+ char namea[256];
+
+ Zero(namew, sizeof(namew));
+ MsGetComputerNameFullEx(namew, sizeof(namew), true);
+
+ Zero(namea, sizeof(namea));
+ UniToStr(namea, sizeof(namea), namew);
+
+ if (IsEmptyStr(namea))
+ {
+ GetMachineName(namea, sizeof(namea));
+ }
+
+ StrCpy(info->ClientHostname, sizeof(info->ClientHostname), namea);
+
+ }
+#endif // OS_WIN32
+ // Client IP address
+ if (IsIP6(&c->FirstSock->LocalIP) == false)
+ {
+ info->ClientIpAddress = IPToUINT(&c->FirstSock->LocalIP);
+ }
+ else
+ {
+ Copy(info->ClientIpAddress6, c->FirstSock->LocalIP.ipv6_addr, sizeof(info->ClientIpAddress6));
+ }
+ // Client port number
+ info->ClientPort = Endian32(c->FirstSock->LocalPort);
+
+ // Server host name
+ StrCpy(info->ServerHostname, sizeof(info->ServerHostname), c->ServerName);
+ // Server IP address
+ if (GetIP(&ip, info->ServerHostname))
+ {
+ if (IsIP6(&ip) == false)
+ {
+ info->ServerIpAddress = IPToUINT(&ip);
+ }
+ else
+ {
+ Copy(info->ServerIpAddress6, ip.ipv6_addr, sizeof(info->ServerIpAddress6));
+ }
+ }
+ // Server port number
+ info->ServerPort = Endian32(c->ServerPort);
+
+ if (s->ClientOption->ProxyType == PROXY_SOCKS || s->ClientOption->ProxyType == PROXY_HTTP)
+ {
+ // Proxy host name
+ StrCpy(info->ProxyHostname, sizeof(info->ProxyHostname), s->ClientOption->ProxyName);
+
+ // Proxy Server IP Address
+ if (IsIP6(&c->FirstSock->RemoteIP) == false)
+ {
+ info->ProxyIpAddress = IPToUINT(&c->FirstSock->RemoteIP);
+ }
+ else
+ {
+ Copy(&info->ProxyIpAddress6, c->FirstSock->RemoteIP.ipv6_addr, sizeof(info->ProxyIpAddress6));
+ }
+
+ info->ProxyPort = Endian32(c->FirstSock->RemotePort);
+ }
+
+ // HUB name
+ StrCpy(info->HubName, sizeof(info->HubName), s->ClientOption->HubName);
+
+ // Unique ID
+ Copy(info->UniqueId, c->Cedar->UniqueId, sizeof(info->UniqueId));
+}
+
+// Connect a socket additionally
+SOCK *ClientAdditionalConnectToServer(CONNECTION *c)
+{
+ SOCK *s;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ // Socket connection
+ s = ClientConnectGetSocket(c, true, (c->DontUseTls1 ? false : true));
+ if (s == NULL)
+ {
+ // Connection failure
+ return NULL;
+ }
+
+ // Add the socket to the list
+ LockList(c->ConnectingSocks);
+ {
+ Add(c->ConnectingSocks, s);
+ AddRef(s->ref);
+ }
+ UnlockList(c->ConnectingSocks);
+
+ if (c->Session->Halt)
+ {
+ // Stop
+ Disconnect(s);
+ LockList(c->ConnectingSocks);
+ {
+ if (Delete(c->ConnectingSocks, s))
+ {
+ ReleaseSock(s);
+ }
+ }
+ UnlockList(c->ConnectingSocks);
+ ReleaseSock(s);
+ return NULL;
+ }
+
+ // Time-out
+ SetTimeout(s, CONNECTING_TIMEOUT);
+
+ // Start the SSL communication
+ if (StartSSLEx(s, NULL, NULL, (c->DontUseTls1 ? false : true), 0, c->ServerName) == false)
+ {
+ // SSL communication failure
+ Disconnect(s);
+ LockList(c->ConnectingSocks);
+ {
+ if (Delete(c->ConnectingSocks, s))
+ {
+ ReleaseSock(s);
+ }
+ }
+ UnlockList(c->ConnectingSocks);
+ ReleaseSock(s);
+ return NULL;
+ }
+
+ // Check the certificate
+ if (CompareX(s->RemoteX, c->ServerX) == false)
+ {
+ // The certificate is invalid
+ Disconnect(s);
+ c->Session->SessionTimeOuted = true;
+ }
+
+ return s;
+}
+
+// Remove the key and certificate in the secure device
+UINT SecureDelete(UINT device_id, char *pin, char *cert_name, char *key_name)
+{
+ SECURE *sec;
+ // Validate arguments
+ if (pin == NULL || device_id == 0)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ // Open the device
+ sec = OpenSec(device_id);
+ if (sec == NULL)
+ {
+ return ERR_SECURE_DEVICE_OPEN_FAILED;
+ }
+
+ // Open the session
+ if (OpenSecSession(sec, 0) == false)
+ {
+ CloseSec(sec);
+ return ERR_SECURE_DEVICE_OPEN_FAILED;
+ }
+
+ // Login
+ if (LoginSec(sec, pin) == false)
+ {
+ CloseSecSession(sec);
+ CloseSec(sec);
+ return ERR_SECURE_PIN_LOGIN_FAILED;
+ }
+
+ // Delete the certificate
+ if (cert_name != NULL)
+ {
+ DeleteSecCert(sec, cert_name);
+ }
+
+ // Delete the Private key
+ if (key_name != NULL)
+ {
+ DeleteSecKey(sec, key_name);
+ }
+
+ // Log out
+ LogoutSec(sec);
+
+ // Close the session
+ CloseSecSession(sec);
+
+ // Close the device
+ CloseSec(sec);
+
+ return ERR_NO_ERROR;
+}
+
+// Enumerate certificates and keys in the secure device
+UINT SecureEnum(UINT device_id, char *pin, TOKEN_LIST **cert_list, TOKEN_LIST **key_list)
+{
+ SECURE *sec;
+ LIST *o;
+ LIST *cert_name_list, *key_name_list;
+ // Validate arguments
+ if (pin == NULL || device_id == 0 || cert_list == NULL || key_list == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ // Open the device
+ sec = OpenSec(device_id);
+ if (sec == NULL)
+ {
+ return ERR_SECURE_DEVICE_OPEN_FAILED;
+ }
+
+ // Open the session
+ if (OpenSecSession(sec, 0) == false)
+ {
+ CloseSec(sec);
+ return ERR_SECURE_DEVICE_OPEN_FAILED;
+ }
+
+ // Login
+ if (LoginSec(sec, pin) == false)
+ {
+ CloseSecSession(sec);
+ CloseSec(sec);
+ return ERR_SECURE_PIN_LOGIN_FAILED;
+ }
+
+ // Enumerate objects
+ if ((o = EnumSecObject(sec)) != NULL)
+ {
+ UINT i;
+
+ cert_name_list = NewList(CompareStr);
+ key_name_list = NewList(CompareStr);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ SEC_OBJ *obj = LIST_DATA(o, i);
+
+ if (obj->Type == SEC_X)
+ {
+ Add(cert_name_list, CopyStr(obj->Name));
+ }
+ else if (obj->Type == SEC_K)
+ {
+ Add(key_name_list, CopyStr(obj->Name));
+ }
+ }
+
+ Sort(cert_name_list);
+ Sort(key_name_list);
+
+ *cert_list = ListToTokenList(cert_name_list);
+ *key_list = ListToTokenList(key_name_list);
+
+ // Release the memory
+ FreeStrList(cert_name_list);
+ FreeStrList(key_name_list);
+ FreeEnumSecObject(o);
+ }
+ else
+ {
+ *cert_list = NullToken();
+ *key_list = NullToken();
+ }
+
+ // Log out
+ LogoutSec(sec);
+
+ // Close the session
+ CloseSecSession(sec);
+
+ // Close the device
+ CloseSec(sec);
+
+ return ERR_NO_ERROR;
+}
+
+// Record the certificate and key to secure device
+UINT SecureWrite(UINT device_id, char *cert_name, X *x, char *key_name, K *k, char *pin)
+{
+ SECURE *sec;
+ bool failed;
+ // Validate arguments
+ if (pin == NULL || device_id == 0 || cert_name == NULL || x == NULL || key_name == NULL || k == NULL)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ // Open the device
+ sec = OpenSec(device_id);
+ if (sec == NULL)
+ {
+ return ERR_SECURE_DEVICE_OPEN_FAILED;
+ }
+
+ // Open the session
+ if (OpenSecSession(sec, 0) == false)
+ {
+ CloseSec(sec);
+ return ERR_SECURE_DEVICE_OPEN_FAILED;
+ }
+
+ // Login
+ if (LoginSec(sec, pin) == false)
+ {
+ CloseSecSession(sec);
+ CloseSec(sec);
+ return ERR_SECURE_PIN_LOGIN_FAILED;
+ }
+
+ // Registration
+ failed = false;
+
+ // Register the certificate
+ if (WriteSecCert(sec, true, cert_name, x) == false)
+ {
+ failed = true;
+ }
+
+ // Register the private key
+ if (WriteSecKey(sec, true, key_name, k) == false)
+ {
+ failed = true;
+ }
+
+ // Log out
+ LogoutSec(sec);
+
+ // Close the session
+ CloseSecSession(sec);
+
+ // Close the device
+ CloseSec(sec);
+
+ if (failed == false)
+ {
+ // Success
+ return ERR_NO_ERROR;
+ }
+ else
+ {
+ // Failure
+ return ERR_SECURE_CANT_WRITE;
+ }
+}
+
+// Attempt to sign by the secure device
+UINT SecureSign(SECURE_SIGN *sign, UINT device_id, char *pin)
+{
+ SECURE *sec;
+ X *x;
+ // Validate arguments
+ if (sign == false || pin == NULL || device_id == 0)
+ {
+ return ERR_INTERNAL_ERROR;
+ }
+
+ // Open the device
+ sec = OpenSec(device_id);
+ if (sec == NULL)
+ {
+ return ERR_SECURE_DEVICE_OPEN_FAILED;
+ }
+
+ // Open the session
+ if (OpenSecSession(sec, 0) == false)
+ {
+ CloseSec(sec);
+ return ERR_SECURE_DEVICE_OPEN_FAILED;
+ }
+
+ // Login
+ if (LoginSec(sec, pin) == false)
+ {
+ CloseSecSession(sec);
+ CloseSec(sec);
+ return ERR_SECURE_PIN_LOGIN_FAILED;
+ }
+
+ // Read the certificate
+ x = ReadSecCert(sec, sign->SecurePublicCertName);
+ if (x == NULL)
+ {
+ LogoutSec(sec);
+ CloseSecSession(sec);
+ CloseSec(sec);
+ return ERR_SECURE_NO_CERT;
+ }
+
+ // Sign by the private key
+ if (SignSec(sec, sign->SecurePrivateKeyName, sign->Signature, sign->Random, SHA1_SIZE) == false)
+ {
+ // Signing failure
+ FreeX(x);
+ LogoutSec(sec);
+ CloseSecSession(sec);
+ CloseSec(sec);
+ return ERR_SECURE_NO_PRIVATE_KEY;
+ }
+
+ // Convert the certificate to buffer
+ sign->ClientCert = x;
+
+ // Log out
+ LogoutSec(sec);
+
+ // Close the session
+ CloseSecSession(sec);
+
+ // Close the device
+ CloseSec(sec);
+
+ // Success
+ return ERR_NO_ERROR;
+}
+
+// Client connects to the server additionally
+bool ClientAdditionalConnect(CONNECTION *c, THREAD *t)
+{
+ SOCK *s;
+ PACK *p;
+ TCPSOCK *ts;
+ UINT err;
+ UINT direction;
+ RC4_KEY_PAIR key_pair;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ // Socket connection to the server
+ s = ClientAdditionalConnectToServer(c);
+ if (s == NULL)
+ {
+ // Failed to connect socket
+ return false;
+ }
+
+ if (c->Halt)
+ {
+ goto CLEANUP;
+ }
+
+ // Send a signature
+ Debug("Uploading Signature...\n");
+ if (ClientUploadSignature(s) == false)
+ {
+ goto CLEANUP;
+ }
+
+ if (c->Halt)
+ {
+ // Stop
+ goto CLEANUP;
+ }
+
+ // Receive a Hello packet
+ Debug("Downloading Hello...\n");
+ if (ClientDownloadHello(c, s) == false)
+ {
+ goto CLEANUP;
+ }
+
+ if (c->Halt)
+ {
+ // Stop
+ goto CLEANUP;
+ }
+
+ // Send a authentication data for the additional connection
+ if (ClientUploadAuth2(c, s) == false)
+ {
+ // Disconnected
+ goto CLEANUP;
+ }
+
+ // Receive a response
+ p = HttpClientRecv(s);
+ if (p == NULL)
+ {
+ // Disconnected
+ goto CLEANUP;
+ }
+
+ err = GetErrorFromPack(p);
+ direction = PackGetInt(p, "direction");
+
+ if (c->Session->UseFastRC4)
+ {
+ // Get the RC4 key information
+ if (PackGetDataSize(p, "rc4_key_client_to_server") == 16)
+ {
+ PackGetData(p, "rc4_key_client_to_server", key_pair.ClientToServerKey);
+ }
+ if (PackGetDataSize(p, "rc4_key_server_to_client") == 16)
+ {
+ PackGetData(p, "rc4_key_server_to_client", key_pair.ServerToClientKey);
+ }
+ {
+ char key1[64], key2[64];
+ BinToStr(key1, sizeof(key1), key_pair.ClientToServerKey, 16);
+ BinToStr(key2, sizeof(key2), key_pair.ServerToClientKey, 16);
+ Debug(
+ "Client to Server Key: %s\n"
+ "Server to Client Key: %s\n",
+ key1, key2);
+ }
+ }
+
+ FreePack(p);
+ p = NULL;
+
+ if (err != 0)
+ {
+ // Error has occurred
+ Debug("Additional Connect Error: %u\n", err);
+ if (err == ERR_SESSION_TIMEOUT || err == ERR_INVALID_PROTOCOL)
+ {
+ // We shall re-connection because it is a fatal error
+ c->Session->SessionTimeOuted = true;
+ }
+ goto CLEANUP;
+ }
+
+ Debug("Additional Connect Succeed!\n");
+
+ // Success the additional connection
+ // Add to the TcpSockList of the connection
+ ts = NewTcpSock(s);
+
+ if (c->ServerMode == false)
+ {
+ if (c->Session->ClientOption->ConnectionDisconnectSpan != 0)
+ {
+ ts->DisconnectTick = Tick64() + c->Session->ClientOption->ConnectionDisconnectSpan * (UINT64)1000;
+ }
+ }
+
+ LockList(c->Tcp->TcpSockList);
+ {
+ ts->Direction = direction;
+ Add(c->Tcp->TcpSockList, ts);
+ }
+ UnlockList(c->Tcp->TcpSockList);
+ Debug("TCP Connection Incremented: %u\n", Count(c->CurrentNumConnection));
+
+ if (c->Session->HalfConnection)
+ {
+ Debug("New Half Connection: %s\n",
+ direction == TCP_SERVER_TO_CLIENT ? "TCP_SERVER_TO_CLIENT" : "TCP_CLIENT_TO_SERVER"
+ );
+ }
+
+ if (c->Session->UseFastRC4)
+ {
+ // Set the RC4 encryption key
+ Copy(&ts->Rc4KeyPair, &key_pair, sizeof(RC4_KEY_PAIR));
+
+ InitTcpSockRc4Key(ts, false);
+ }
+
+ // Issue the Cancel to the session
+ Cancel(c->Session->Cancel1);
+
+ // Remove the socket from the socket list of connected
+ LockList(c->ConnectingSocks);
+ {
+ if (Delete(c->ConnectingSocks, s))
+ {
+ ReleaseSock(s);
+ }
+ }
+ UnlockList(c->ConnectingSocks);
+ ReleaseSock(s);
+ return true;
+
+CLEANUP:
+ // Disconnection process
+ Disconnect(s);
+ LockList(c->ConnectingSocks);
+ {
+ if (Delete(c->ConnectingSocks, s))
+ {
+ ReleaseSock(s);
+
+ }
+ }
+ UnlockList(c->ConnectingSocks);
+ ReleaseSock(s);
+ return false;
+}
+
+// Secure device signing thread
+void ClientSecureSignThread(THREAD *thread, void *param)
+{
+ SECURE_SIGN_THREAD_PROC *p = (SECURE_SIGN_THREAD_PROC *)param;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ NoticeThreadInit(thread);
+
+ p->Ok = p->SecureSignProc(p->Connection->Session, p->Connection, p->SecureSign);
+ p->UserFinished = true;
+}
+
+// Signing with the secure device
+bool ClientSecureSign(CONNECTION *c, UCHAR *sign, UCHAR *random, X **x)
+{
+ SECURE_SIGN_THREAD_PROC *p;
+ SECURE_SIGN *ss;
+ SESSION *s;
+ CLIENT_OPTION *o;
+ CLIENT_AUTH *a;
+ THREAD *thread;
+ UINT64 start;
+ bool ret;
+ // Validate arguments
+ if (c == NULL || sign == NULL || random == NULL || x == NULL)
+ {
+ return false;
+ }
+
+ s = c->Session;
+ o = s->ClientOption;
+ a = s->ClientAuth;
+
+ p = ZeroMalloc(sizeof(SECURE_SIGN_THREAD_PROC));
+ p->Connection = c;
+ ss = p->SecureSign = ZeroMallocEx(sizeof(SECURE_SIGN), true);
+ StrCpy(ss->SecurePrivateKeyName, sizeof(ss->SecurePrivateKeyName),
+ a->SecurePrivateKeyName);
+ StrCpy(ss->SecurePublicCertName, sizeof(ss->SecurePublicCertName),
+ a->SecurePublicCertName);
+ ss->UseSecureDeviceId = c->Cedar->Client->UseSecureDeviceId;
+ Copy(ss->Random, random, SHA1_SIZE);
+
+#ifdef OS_WIN32
+ ss->BitmapId = CmGetSecureBitmapId(c->ServerName);
+#endif // OS_WIN32
+
+ p->SecureSignProc = a->SecureSignProc;
+
+ // Create a thread
+ thread = NewThread(ClientSecureSignThread, p);
+ WaitThreadInit(thread);
+
+ // Poll every 0.5 seconds until signing is completed or canceled
+ start = Tick64();
+ while (true)
+ {
+ if ((Tick64() - start) > CONNECTING_POOLING_SPAN)
+ {
+ // Send a NOOP periodically for disconnection prevention
+ start = Tick64();
+ ClientUploadNoop(c);
+ }
+ if (p->UserFinished)
+ {
+ // User selected
+ break;
+ }
+ WaitThread(thread, 500);
+ }
+ ReleaseThread(thread);
+
+ ret = p->Ok;
+
+ if (ret)
+ {
+ Copy(sign, ss->Signature, 128);
+ *x = ss->ClientCert;
+ }
+
+ Free(p->SecureSign);
+ Free(p);
+
+ return ret;
+}
+
+// Server certificate confirmation thread
+void ClientCheckServerCertThread(THREAD *thread, void *param)
+{
+ CHECK_CERT_THREAD_PROC *p = (CHECK_CERT_THREAD_PROC *)param;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Notify the completion of initialization
+ NoticeThreadInit(thread);
+
+ // Query for the selection to the user
+ p->Ok = p->CheckCertProc(p->Connection->Session, p->Connection, p->ServerX, &p->Exipred);
+ p->UserSelected = true;
+}
+
+// Client verify the certificate of the server
+bool ClientCheckServerCert(CONNECTION *c, bool *expired)
+{
+ CLIENT_AUTH *auth;
+ X *x;
+ CHECK_CERT_THREAD_PROC *p;
+ THREAD *thread;
+ CEDAR *cedar;
+ bool ret;
+ UINT64 start;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ if (expired != NULL)
+ {
+ *expired = false;
+ }
+
+ auth = c->Session->ClientAuth;
+ cedar = c->Cedar;
+
+ if (auth->CheckCertProc == NULL && c->Session->LinkModeClient == false)
+ {
+ // No checking function
+ return true;
+ }
+
+ if (c->Session->LinkModeClient && c->Session->Link->CheckServerCert == false)
+ {
+ // It's in cascade connection mode, but do not check the server certificate
+ return true;
+ }
+
+ if (c->UseTicket)
+ {
+ // Check the certificate of the redirected VPN server
+ if (CompareX(c->FirstSock->RemoteX, c->ServerX) == false)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ x = CloneX(c->FirstSock->RemoteX);
+ if (x == NULL)
+ {
+ // Strange error occurs
+ return false;
+ }
+
+ if (CheckXDateNow(x))
+ {
+ // Check whether it is signed by the root certificate to trust
+ if (c->Session->LinkModeClient == false)
+ {
+ // Normal VPN Client mode
+ if (CheckSignatureByCa(cedar, x))
+ {
+ // This certificate can be trusted because it is signed
+ FreeX(x);
+ return true;
+ }
+ }
+ else
+ {
+ // Cascade connection mode
+ if (CheckSignatureByCaLinkMode(c->Session, x))
+ {
+ // This certificate can be trusted because it is signed
+ FreeX(x);
+ return true;
+ }
+ }
+ }
+
+ if (c->Session->LinkModeClient)
+ {
+ if (CheckXDateNow(x))
+ {
+ Lock(c->Session->Link->lock);
+ {
+ if (c->Session->Link->ServerCert != NULL)
+ {
+ if (CompareX(c->Session->Link->ServerCert, x))
+ {
+ Unlock(c->Session->Link->lock);
+ // Exactly match the certificate that is registered in the cascade configuration
+ FreeX(x);
+ return true;
+ }
+ }
+ }
+ Unlock(c->Session->Link->lock);
+ }
+ else
+ {
+ if (expired != NULL)
+ {
+ *expired = true;
+ }
+ }
+
+ // Verification failure at this point in the case of cascade connection mode
+ FreeX(x);
+ return false;
+ }
+
+ p = ZeroMalloc(sizeof(CHECK_CERT_THREAD_PROC));
+ p->ServerX = x;
+ p->CheckCertProc = auth->CheckCertProc;
+ p->Connection = c;
+
+ // Create a thread
+ thread = NewThread(ClientCheckServerCertThread, p);
+ WaitThreadInit(thread);
+
+ // Poll at 0.5-second intervals until the user selects whether the connection
+ start = Tick64();
+ while (true)
+ {
+ if ((Tick64() - start) > CONNECTING_POOLING_SPAN)
+ {
+ // Send a NOOP periodically for disconnection prevention
+ start = Tick64();
+ ClientUploadNoop(c);
+ }
+ if (p->UserSelected)
+ {
+ // User-selected
+ break;
+ }
+ WaitThread(thread, 500);
+ }
+
+ if (expired != NULL)
+ {
+ *expired = p->Exipred;
+ }
+
+ ret = p->Ok;
+ FreeX(p->ServerX);
+ Free(p);
+ ReleaseThread(thread);
+
+ return ret;
+}
+
+// Client connects to the server
+bool ClientConnect(CONNECTION *c)
+{
+ bool ret = false;
+ bool ok = false;
+ UINT err;
+ SOCK *s;
+ PACK *p = NULL;
+ UINT session_key_32;
+ SESSION *sess;
+ char session_name[MAX_SESSION_NAME_LEN + 1];
+ char connection_name[MAX_CONNECTION_NAME_LEN + 1];
+ UCHAR session_key[SHA1_SIZE];
+ RC4_KEY_PAIR key_pair;
+ POLICY *policy;
+ bool expired = false;
+ IP server_ip;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ sess = c->Session;
+
+ PrintStatus(sess, L"init");
+ PrintStatus(sess, _UU("STATUS_1"));
+
+REDIRECTED:
+
+ // [Connecting]
+ c->Status = CONNECTION_STATUS_CONNECTING;
+ c->Session->ClientStatus = CLIENT_STATUS_CONNECTING;
+
+ s = ClientConnectToServer(c);
+ if (s == NULL)
+ {
+ PrintStatus(sess, L"free");
+ return false;
+ }
+
+ Copy(&server_ip, &s->RemoteIP, sizeof(IP));
+
+ if (c->Halt)
+ {
+ // Stop
+ c->Err = ERR_USER_CANCEL;
+ goto CLEANUP;
+ }
+
+ // [Negotiating]
+ c->Session->ClientStatus = CLIENT_STATUS_NEGOTIATION;
+
+ // Initialize the UDP acceleration function
+ if (sess->ClientOption != NULL && sess->ClientOption->NoUdpAcceleration == false)
+ {
+ if (sess->ClientOption->ProxyType == PROXY_DIRECT)
+ {
+ if (s->Type == SOCK_TCP)
+ {
+ if (sess->UdpAccel == NULL)
+ {
+ bool no_nat_t = false;
+
+ if (sess->ClientOption->PortUDP != 0)
+ {
+ // There is no need for NAT-T treatment on my part if the UDP port on the other end is known beforehand
+ no_nat_t = true;
+ }
+
+
+ sess->UdpAccel = NewUdpAccel(c->Cedar, &s->LocalIP, true, true, no_nat_t);
+ }
+ }
+ }
+ }
+
+ // Send a signature
+ Debug("Uploading Signature...\n");
+ if (ClientUploadSignature(s) == false)
+ {
+ c->Err = ERR_DISCONNECTED;
+ goto CLEANUP;
+ }
+
+ if (c->Halt)
+ {
+ // Stop
+ c->Err = ERR_USER_CANCEL;
+ goto CLEANUP;
+ }
+
+ PrintStatus(sess, _UU("STATUS_5"));
+
+ // Receive a Hello packet
+ Debug("Downloading Hello...\n");
+ if (ClientDownloadHello(c, s) == false)
+ {
+ goto CLEANUP;
+ }
+
+ if (c->Session->ClientOption != NULL && c->Session->ClientOption->FromAdminPack)
+ {
+ if (IsAdminPackSupportedServerProduct(c->ServerStr) == false)
+ {
+ c->Err = ERR_NOT_ADMINPACK_SERVER;
+ goto CLEANUP;
+ }
+ }
+
+ if (c->Halt)
+ {
+ // Stop
+ c->Err = ERR_USER_CANCEL;
+ goto CLEANUP;
+ }
+
+ Debug("Server Version : %u\n"
+ "Server String : %s\n"
+ "Server Build : %u\n"
+ "Client Version : %u\n"
+ "Client String : %s\n"
+ "Client Build : %u\n",
+ c->ServerVer, c->ServerStr, c->ServerBuild,
+ c->ClientVer, c->ClientStr, c->ClientBuild);
+
+ // During user authentication
+ c->Session->ClientStatus = CLIENT_STATUS_AUTH;
+
+ // Verify the server certificate by the client
+ if (ClientCheckServerCert(c, &expired) == false)
+ {
+ if (expired == false)
+ {
+ c->Err = ERR_CERT_NOT_TRUSTED;
+ }
+ else
+ {
+ c->Err = ERR_SERVER_CERT_EXPIRES;
+ }
+
+ if (c->Session->LinkModeClient == false && c->Err == ERR_CERT_NOT_TRUSTED)
+ {
+ c->Session->ForceStopFlag = true;
+ }
+
+ goto CLEANUP;
+ }
+
+ PrintStatus(sess, _UU("STATUS_6"));
+
+ // Send the authentication data
+ if (ClientUploadAuth(c) == false)
+ {
+ goto CLEANUP;
+ }
+
+ if (c->Halt)
+ {
+ // Stop
+ c->Err = ERR_USER_CANCEL;
+ goto CLEANUP;
+ }
+
+ // Receive a Welcome packet
+ p = HttpClientRecv(s);
+ if (p == NULL)
+ {
+ c->Err = ERR_DISCONNECTED;
+ goto CLEANUP;
+ }
+
+ // Error checking
+ err = GetErrorFromPack(p);
+ if (err != 0)
+ {
+ // An error has occured
+ c->Err = err;
+ c->ClientConnectError_NoSavePassword = PackGetBool(p, "no_save_password");
+ goto CLEANUP;
+ }
+
+ // Branding string check for the connection limit
+ {
+ char tmp[20];
+ char *branded_cfroms = _SS("BRANDED_C_FROM_S");
+ PackGetStr(p, "branded_cfroms", tmp, sizeof(tmp));
+
+ if(StrLen(branded_cfroms) > 0 && StrCmpi(branded_cfroms, tmp) != 0)
+ {
+ c->Err = ERR_BRANDED_C_FROM_S;
+ goto CLEANUP;
+ }
+ }
+
+ if (true)
+ {
+ // Message retrieval
+ UINT utf_size;
+ char *utf;
+ wchar_t *msg;
+
+ utf_size = PackGetDataSize(p, "Msg");
+ utf = ZeroMalloc(utf_size + 8);
+ PackGetData(p, "Msg", utf);
+
+ msg = CopyUtfToUni(utf);
+
+ if (IsEmptyUniStr(msg) == false)
+ {
+ if (c->Session->Client_Message != NULL)
+ {
+ Free(c->Session->Client_Message);
+ }
+
+ c->Session->Client_Message = msg;
+ }
+ else
+ {
+ Free(msg);
+ }
+
+ Free(utf);
+ }
+
+ if (PackGetInt(p, "Redirect") != 0)
+ {
+ UINT i;
+ UINT ip;
+ UINT num_port;
+ UINT *ports;
+ UINT use_port = 0;
+ UINT current_port = c->ServerPort;
+ UCHAR ticket[SHA1_SIZE];
+ X *server_cert;
+ BUF *b;
+
+ // Redirect mode
+ PrintStatus(sess, _UU("STATUS_8"));
+
+ ip = PackGetIp32(p, "Ip");
+ num_port = MAX(MIN(PackGetIndexCount(p, "Port"), MAX_PUBLIC_PORT_NUM), 1);
+ ports = ZeroMalloc(sizeof(UINT) * num_port);
+ for (i = 0;i < num_port;i++)
+ {
+ ports[i] = PackGetIntEx(p, "Port", i);
+ }
+
+ // Select a port number
+ for (i = 0;i < num_port;i++)
+ {
+ if (ports[i] == current_port)
+ {
+ use_port = current_port;
+ }
+ }
+ if (use_port == 0)
+ {
+ use_port = ports[0];
+ }
+
+ Free(ports);
+
+ if (PackGetDataSize(p, "Ticket") == SHA1_SIZE)
+ {
+ PackGetData(p, "Ticket", ticket);
+ }
+
+ b = PackGetBuf(p, "Cert");
+ if (b != NULL)
+ {
+ server_cert = BufToX(b, false);
+ FreeBuf(b);
+ }
+
+ if (c->ServerX != NULL)
+ {
+ FreeX(c->ServerX);
+ }
+ c->ServerX = server_cert;
+
+ IPToStr32(c->ServerName, sizeof(c->ServerName), ip);
+ c->ServerPort = use_port;
+
+ c->UseTicket = true;
+ Copy(c->Ticket, ticket, SHA1_SIZE);
+
+ FreePack(p);
+
+ p = NewPack();
+ HttpClientSend(s, p);
+ FreePack(p);
+
+ p = NULL;
+
+ c->FirstSock = NULL;
+ Disconnect(s);
+ ReleaseSock(s);
+ s = NULL;
+
+ goto REDIRECTED;
+ }
+
+ PrintStatus(sess, _UU("STATUS_7"));
+
+ // Parse the Welcome packet
+ if (ParseWelcomeFromPack(p, session_name, sizeof(session_name),
+ connection_name, sizeof(connection_name), &policy) == false)
+ {
+ // Parsing failure
+ c->Err = ERR_PROTOCOL_ERROR;
+ goto CLEANUP;
+ }
+
+ // Get the session key
+ if (GetSessionKeyFromPack(p, session_key, &session_key_32) == false)
+ {
+ // Acquisition failure
+ Free(policy);
+ policy = NULL;
+ c->Err = ERR_PROTOCOL_ERROR;
+ goto CLEANUP;
+ }
+
+ Copy(c->Session->SessionKey, session_key, SHA1_SIZE);
+ c->Session->SessionKey32 = session_key_32;
+
+ // Save the contents of the Welcome packet
+ Debug("session_name: %s, connection_name: %s\n",
+ session_name, connection_name);
+
+ Lock(c->Session->lock);
+ {
+ // Deploy and update connection parameters
+ sess->EnableUdpRecovery = PackGetBool(p, "enable_udp_recovery");
+ c->Session->MaxConnection = PackGetInt(p, "max_connection");
+
+ if (sess->EnableUdpRecovery == false)
+ {
+ c->Session->MaxConnection = MIN(c->Session->MaxConnection, c->Session->ClientOption->MaxConnection);
+ }
+
+ c->Session->MaxConnection = MIN(c->Session->MaxConnection, MAX_TCP_CONNECTION);
+ c->Session->MaxConnection = MAX(c->Session->MaxConnection, 1);
+ c->Session->UseCompress = PackGetInt(p, "use_compress") == 0 ? false : true;
+ c->Session->UseEncrypt = PackGetInt(p, "use_encrypt") == 0 ? false : true;
+ c->Session->NoSendSignature = PackGetBool(p, "no_send_signature");
+ if (c->Session->UseEncrypt)
+ {
+ c->Session->UseFastRC4 = PackGetInt(p, "use_fast_rc4") == 0 ? false : true;
+ }
+ c->Session->HalfConnection = PackGetInt(p, "half_connection") == 0 ? false : true;
+ c->Session->IsAzureSession = PackGetInt(p, "is_azure_session") == 0 ? false : true;
+ c->Session->Timeout = PackGetInt(p, "timeout");
+ c->Session->QoS = PackGetInt(p, "qos") == 0 ? false : true;
+ if (c->Session->QoS)
+ {
+ c->Session->MaxConnection = MAX(c->Session->MaxConnection, (UINT)(c->Session->HalfConnection ? 4 : 2));
+ }
+ c->Session->VLanId = PackGetInt(p, "vlan_id");
+
+ // R-UDP Session ?
+ c->Session->IsRUDPSession = s->IsRUDPSocket;
+
+ ZeroIP4(&c->Session->AzureRealServerGlobalIp);
+
+ if (c->Session->IsAzureSession)
+ {
+ // Disable the life parameter of the connection in the case of VPN Azure relayed session
+ c->Session->ClientOption->ConnectionDisconnectSpan = 0;
+
+ // Get the AzureRealServerGlobalIp the case of VPN Azure relayed
+ PackGetIp(p, "azure_real_server_global_ip", &c->Session->AzureRealServerGlobalIp);
+ }
+
+ if (c->Session->IsRUDPSession)
+ {
+ // Disable the life parameter of the connection in the case of R-UDP session
+ c->Session->ClientOption->ConnectionDisconnectSpan = 0;
+
+ // Disable QoS, etc. in the case of R-UDP session
+ c->Session->QoS = false;
+ c->Session->HalfConnection = false;
+
+ if (c->Session->EnableUdpRecovery == false)
+ {
+ // Set the number of connection to 1 if UDP recovery is not supported
+ c->Session->MaxConnection = 1;
+ }
+ }
+
+ // Physical communication protocol
+ StrCpy(c->Session->UnderlayProtocol, sizeof(c->Session->UnderlayProtocol), s->UnderlayProtocol);
+
+ if (c->Session->IsAzureSession)
+ {
+ StrCpy(c->Session->UnderlayProtocol, sizeof(c->Session->UnderlayProtocol), SOCK_UNDERLAY_AZURE);
+ }
+
+ if (c->Protocol == CONNECTION_UDP)
+ {
+ // In the case of UDP protocol, receive the key from the server
+ if (PackGetDataSize(p, "udp_send_key") == sizeof(c->Session->UdpSendKey))
+ {
+ PackGetData(p, "udp_send_key", c->Session->UdpSendKey);
+ }
+
+ if (PackGetDataSize(p, "udp_recv_key") == sizeof(c->Session->UdpRecvKey))
+ {
+ PackGetData(p, "udp_recv_key", c->Session->UdpRecvKey);
+ }
+ }
+
+ if (c->Session->UseFastRC4)
+ {
+ // Get the RC4 key information
+ if (PackGetDataSize(p, "rc4_key_client_to_server") == 16)
+ {
+ PackGetData(p, "rc4_key_client_to_server", key_pair.ClientToServerKey);
+ }
+ if (PackGetDataSize(p, "rc4_key_server_to_client") == 16)
+ {
+ PackGetData(p, "rc4_key_server_to_client", key_pair.ServerToClientKey);
+ }
+ {
+ char key1[64], key2[64];
+ BinToStr(key1, sizeof(key1), key_pair.ClientToServerKey, 16);
+ BinToStr(key2, sizeof(key2), key_pair.ServerToClientKey, 16);
+ Debug(
+ "Client to Server Key: %s\n"
+ "Server to Client Key: %s\n",
+ key1, key2);
+ }
+ }
+
+ sess->EnableBulkOnRUDP = false;
+ sess->EnableHMacOnBulkOfRUDP = false;
+ if (s != NULL && s->IsRUDPSocket && s->BulkRecvKey != NULL && s->BulkSendKey != NULL)
+ {
+ // Bulk transfer on R-UDP
+ if (PackGetBool(p, "enable_bulk_on_rudp"))
+ {
+ // Receive the key
+ UCHAR key_send[SHA1_SIZE];
+ UCHAR key_recv[SHA1_SIZE];
+
+ if (PackGetData2(p, "bulk_on_rudp_send_key", key_send, SHA1_SIZE) &&
+ PackGetData2(p, "bulk_on_rudp_recv_key", key_recv, SHA1_SIZE))
+ {
+ sess->EnableBulkOnRUDP = true;
+
+ Copy(s->BulkSendKey->Data, key_send, SHA1_SIZE);
+ Copy(s->BulkRecvKey->Data, key_recv, SHA1_SIZE);
+ }
+ }
+
+ sess->EnableHMacOnBulkOfRUDP = PackGetBool(p, "enable_hmac_on_bulk_of_rudp");
+ }
+
+ Debug("EnableBulkOnRUDP = %u\n", sess->EnableBulkOnRUDP);
+ Debug("EnableHMacOnBulkOfRUDP = %u\n", sess->EnableHMacOnBulkOfRUDP);
+ Debug("EnableUdpRecovery = %u\n", sess->EnableUdpRecovery);
+
+ sess->UseUdpAcceleration = false;
+ sess->IsUsingUdpAcceleration = false;
+ sess->UseHMacOnUdpAcceleration = false;
+
+ if (sess->UdpAccel != NULL)
+ {
+ sess->UdpAccel->UseHMac = false;
+
+ sess->UdpAccelFastDisconnectDetect = false;
+
+ if (PackGetBool(p, "use_udp_acceleration"))
+ {
+ IP udp_acceleration_server_ip;
+
+ sess->UdpAccelFastDisconnectDetect = PackGetBool(p, "udp_accel_fast_disconnect_detect");
+
+ if (PackGetIp(p, "udp_acceleration_server_ip", &udp_acceleration_server_ip))
+ {
+ UINT udp_acceleration_server_port = PackGetInt(p, "udp_acceleration_server_port");
+
+ if (IsZeroIp(&udp_acceleration_server_ip))
+ {
+ Copy(&udp_acceleration_server_ip, &s->RemoteIP, sizeof(IP));
+ }
+
+ if (udp_acceleration_server_port != 0)
+ {
+ UCHAR udp_acceleration_server_key[UDP_ACCELERATION_COMMON_KEY_SIZE];
+
+ if (PackGetData2(p, "udp_acceleration_server_key", udp_acceleration_server_key, UDP_ACCELERATION_COMMON_KEY_SIZE))
+ {
+ UINT server_cookie = PackGetInt(p, "udp_acceleration_server_cookie");
+ UINT client_cookie = PackGetInt(p, "udp_acceleration_client_cookie");
+ bool encryption = PackGetBool(p, "udp_acceleration_use_encryption");
+
+ if (server_cookie != 0 && client_cookie != 0)
+ {
+ IP remote_ip;
+
+ Copy(&remote_ip, &s->RemoteIP, sizeof(IP));
+
+ if (IsZeroIp(&c->Session->AzureRealServerGlobalIp) == false)
+ {
+ Copy(&remote_ip, &c->Session->AzureRealServerGlobalIp, sizeof(IP));
+ }
+
+ if (UdpAccelInitClient(sess->UdpAccel, udp_acceleration_server_key,
+ &udp_acceleration_server_ip, udp_acceleration_server_port,
+ server_cookie, client_cookie, &remote_ip) == false)
+ {
+ Debug("UdpAccelInitClient failed.\n");
+ }
+ else
+ {
+ sess->UseUdpAcceleration = true;
+
+ sess->UdpAccel->FastDetect = sess->UdpAccelFastDisconnectDetect;
+
+ sess->UdpAccel->PlainTextMode = !encryption;
+
+ sess->UseHMacOnUdpAcceleration = PackGetBool(p, "use_hmac_on_udp_acceleration");
+
+ if (sess->UseHMacOnUdpAcceleration)
+ {
+ sess->UdpAccel->UseHMac = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ Unlock(c->Session->lock);
+
+ Debug("UseUdpAcceleration = %u\n", sess->UseUdpAcceleration);
+
+ if (sess->UseUdpAcceleration == false)
+ {
+ if (sess->UdpAccel != NULL)
+ {
+ FreeUdpAccel(sess->UdpAccel);
+ sess->UdpAccel = NULL;
+ }
+ }
+
+ Lock(c->lock);
+ {
+ if (c->Name != NULL)
+ {
+ Free(c->Name);
+ }
+ c->Name = CopyStr(connection_name);
+
+ // Save the name of a cryptographic algorithm
+ if (c->CipherName != NULL)
+ {
+ Free(c->CipherName);
+ }
+
+ c->CipherName = CopyStr(c->FirstSock->CipherName);
+ }
+ Unlock(c->lock);
+
+ Lock(c->Session->lock);
+ {
+ if (c->Session->Name != NULL)
+ {
+ Free(c->Session->Name);
+ }
+ c->Session->Name = CopyStr(session_name);
+
+ c->Session->Policy = policy;
+ }
+ Unlock(c->Session->lock);
+
+ // Discard the Welcome packet
+ FreePack(p);
+ p = NULL;
+
+
+ // Connection establishment
+ c->Session->ClientStatus = CLIENT_STATUS_ESTABLISHED;
+
+ // Save the server certificate
+ if (c->ServerX == NULL)
+ {
+ c->ServerX = CloneX(c->FirstSock->RemoteX);
+ }
+
+ PrintStatus(sess, _UU("STATUS_9"));
+
+ // Shift the connection to the tunneling mode
+ StartTunnelingMode(c);
+ s = NULL;
+
+ if (c->Session->HalfConnection)
+ {
+ // Processing in the case of half-connection
+ TCPSOCK *ts = (TCPSOCK *)LIST_DATA(c->Tcp->TcpSockList, 0);
+ ts->Direction = TCP_CLIENT_TO_SERVER;
+ }
+
+ if (c->Session->UseFastRC4)
+ {
+ // Set the high-speed RC4 encryption key
+ TCPSOCK *ts = (TCPSOCK *)LIST_DATA(c->Tcp->TcpSockList, 0);
+ Copy(&ts->Rc4KeyPair, &key_pair, sizeof(key_pair));
+
+ InitTcpSockRc4Key(ts, false);
+ }
+
+ // SSL encryption flag
+ if (c->Session->UseEncrypt && c->Session->UseFastRC4 == false)
+ {
+ c->Session->UseSSLDataEncryption = true;
+ }
+ else
+ {
+ c->Session->UseSSLDataEncryption = false;
+ }
+
+ PrintStatus(sess, L"free");
+
+ CLog(c->Cedar->Client, "LC_CONNECT_2", c->Session->ClientOption->AccountName,
+ session_name);
+
+ if (c->Session->LinkModeClient && c->Session->Link != NULL)
+ {
+ HLog(c->Session->Link->Hub, "LH_CONNECT_2", c->Session->ClientOption->AccountName, session_name);
+ }
+
+ // Main routine of the session
+ SessionMain(c->Session);
+
+ ok = true;
+
+ if (c->Err == ERR_USER_CANCEL)
+ {
+ ret = true;
+ }
+
+CLEANUP:
+ c->FirstSock = NULL;
+
+ if (sess->UdpAccel != NULL)
+ {
+ FreeUdpAccel(sess->UdpAccel);
+ sess->UdpAccel = NULL;
+ }
+
+ if (p != NULL)
+ {
+ FreePack(p);
+ }
+
+ Disconnect(s);
+ ReleaseSock(s);
+
+ Debug("Error: %u\n", c->Err);
+
+ if (ok == false)
+ {
+ PrintStatus(sess, L"free");
+ }
+
+ return ret;
+}
+
+// Parse the Welcome packet
+bool ParseWelcomeFromPack(PACK *p, char *session_name, UINT session_name_size,
+ char *connection_name, UINT connection_name_size,
+ POLICY **policy)
+{
+ // Validate arguments
+ if (p == NULL || session_name == NULL || connection_name == NULL || policy == NULL)
+ {
+ return false;
+ }
+
+ // Session name
+ if (PackGetStr(p, "session_name", session_name, session_name_size) == false)
+ {
+ return false;
+ }
+
+ // Connection name
+ if (PackGetStr(p, "connection_name", connection_name, connection_name_size) == false)
+ {
+ return false;
+ }
+
+ // Policy
+ *policy = PackGetPolicy(p);
+ if (*policy == NULL)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Generate the Welcome packet
+PACK *PackWelcome(SESSION *s)
+{
+ PACK *p;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+
+ // Session name
+ PackAddStr(p, "session_name", s->Name);
+
+ // Connection name
+ PackAddStr(p, "connection_name", s->Connection->Name);
+
+ // Parameters
+ PackAddInt(p, "max_connection", s->MaxConnection);
+ PackAddInt(p, "use_encrypt", s->UseEncrypt == false ? 0 : 1);
+ PackAddInt(p, "use_fast_rc4", s->UseFastRC4 == false ? 0 : 1);
+ PackAddInt(p, "use_compress", s->UseCompress == false ? 0 : 1);
+ PackAddInt(p, "half_connection", s->HalfConnection == false ? 0 : 1);
+ PackAddInt(p, "timeout", s->Timeout);
+ PackAddInt(p, "qos", s->QoS ? 1 : 0);
+ PackAddInt(p, "is_azure_session", s->IsAzureSession);
+
+ // Session key
+ PackAddData(p, "session_key", s->SessionKey, SHA1_SIZE);
+ PackAddInt(p, "session_key_32", s->SessionKey32);
+
+ // Policy
+ PackAddPolicy(p, s->Policy);
+
+ // VLAN ID
+ PackAddInt(p, "vlan_id", s->VLanId);
+
+ if (s->Connection->Protocol == CONNECTION_UDP)
+ {
+ // In the case of UDP protocol, generate 2 pairs of key
+ Rand(s->UdpSendKey, sizeof(s->UdpSendKey));
+ Rand(s->UdpRecvKey, sizeof(s->UdpRecvKey));
+
+ // Send to client by exchanging 2 keys
+ PackAddData(p, "udp_send_key", s->UdpRecvKey, sizeof(s->UdpRecvKey));
+ PackAddData(p, "udp_recv_key", s->UdpSendKey, sizeof(s->UdpSendKey));
+ }
+
+ // no_send_signature
+ if (s->NoSendSignature)
+ {
+ PackAddBool(p, "no_send_signature", true);
+ }
+
+ if (s->InProcMode)
+ {
+ // MAC address for IPC
+ PackAddData(p, "IpcMacAddress", s->IpcMacAddress, 6);
+
+ // Virtual HUB name
+ PackAddStr(p, "IpcHubName", s->Hub->Name);
+ }
+
+ if (s->UdpAccel != NULL)
+ {
+ // UDP acceleration function
+ PackAddBool(p, "use_udp_acceleration", true);
+ PackAddIp(p, "udp_acceleration_server_ip", &s->UdpAccel->MyIp);
+ PackAddInt(p, "udp_acceleration_server_port", s->UdpAccel->MyPort);
+ PackAddData(p, "udp_acceleration_server_key", s->UdpAccel->MyKey, UDP_ACCELERATION_COMMON_KEY_SIZE);
+ PackAddInt(p, "udp_acceleration_server_cookie", s->UdpAccel->MyCookie);
+ PackAddInt(p, "udp_acceleration_client_cookie", s->UdpAccel->YourCookie);
+ PackAddBool(p, "udp_acceleration_use_encryption", !s->UdpAccel->PlainTextMode);
+ PackAddBool(p, "use_hmac_on_udp_acceleration", s->UdpAccel->UseHMac);
+ PackAddBool(p, "udp_accel_fast_disconnect_detect", s->UdpAccelFastDisconnectDetect);
+ }
+
+ if (s->EnableBulkOnRUDP)
+ {
+ // Allow bulk transfer on R-UDP
+ PackAddBool(p, "enable_bulk_on_rudp", true);
+ PackAddBool(p, "enable_hmac_on_bulk_of_rudp", s->EnableHMacOnBulkOfRUDP);
+
+ PackAddData(p, "bulk_on_rudp_send_key", s->Connection->FirstSock->BulkRecvKey->Data, SHA1_SIZE);
+ PackAddData(p, "bulk_on_rudp_recv_key", s->Connection->FirstSock->BulkSendKey->Data, SHA1_SIZE);
+ }
+
+ if (s->IsAzureSession)
+ {
+ if (s->Connection != NULL && s->Connection->FirstSock != NULL)
+ {
+ SOCK *sock = s->Connection->FirstSock;
+
+ PackAddIp(p, "azure_real_server_global_ip", &sock->Reverse_MyServerGlobalIp);
+ }
+ }
+
+ PackAddBool(p, "enable_udp_recovery", s->EnableUdpRecovery);
+
+ return p;
+}
+
+#define PACK_ADD_POLICY_BOOL(name, value) \
+ PackAddInt(p, "policy:" name, y->value == false ? 0 : 1)
+#define PACK_ADD_POLICY_UINT(name, value) \
+ PackAddInt(p, "policy:" name, y->value)
+#define PACK_GET_POLICY_BOOL(name, value) \
+ y->value = (PackGetInt(p, "policy:" name) == 0 ? false : true)
+#define PACK_GET_POLICY_UINT(name, value) \
+ y->value = PackGetInt(p, "policy:" name)
+
+// Get a PACK from the session key
+bool GetSessionKeyFromPack(PACK *p, UCHAR *session_key, UINT *session_key_32)
+{
+ // Validate arguments
+ if (p == NULL || session_key == NULL || session_key_32 == NULL)
+ {
+ return false;
+ }
+
+ if (PackGetDataSize(p, "session_key") != SHA1_SIZE)
+ {
+ return false;
+ }
+ if (PackGetData(p, "session_key", session_key) == false)
+ {
+ return false;
+ }
+ *session_key_32 = PackGetInt(p, "session_key_32");
+
+ return true;
+}
+
+// Get the policy from the PACK
+POLICY *PackGetPolicy(PACK *p)
+{
+ POLICY *y;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return NULL;
+ }
+
+ y = ZeroMalloc(sizeof(POLICY));
+
+ // Bool value
+ // Ver 2
+ PACK_GET_POLICY_BOOL("Access", Access);
+ PACK_GET_POLICY_BOOL("DHCPFilter", DHCPFilter);
+ PACK_GET_POLICY_BOOL("DHCPNoServer", DHCPNoServer);
+ PACK_GET_POLICY_BOOL("DHCPForce", DHCPForce);
+ PACK_GET_POLICY_BOOL("NoBridge", NoBridge);
+ PACK_GET_POLICY_BOOL("NoRouting", NoRouting);
+ PACK_GET_POLICY_BOOL("PrivacyFilter", PrivacyFilter);
+ PACK_GET_POLICY_BOOL("NoServer", NoServer);
+ PACK_GET_POLICY_BOOL("CheckMac", CheckMac);
+ PACK_GET_POLICY_BOOL("CheckIP", CheckIP);
+ PACK_GET_POLICY_BOOL("ArpDhcpOnly", ArpDhcpOnly);
+ PACK_GET_POLICY_BOOL("MonitorPort", MonitorPort);
+ PACK_GET_POLICY_BOOL("NoBroadcastLimiter", NoBroadcastLimiter);
+ PACK_GET_POLICY_BOOL("FixPassword", FixPassword);
+ PACK_GET_POLICY_BOOL("NoQoS", NoQoS);
+ // Ver 3
+ PACK_GET_POLICY_BOOL("RSandRAFilter", RSandRAFilter);
+ PACK_GET_POLICY_BOOL("RAFilter", RAFilter);
+ PACK_GET_POLICY_BOOL("DHCPv6Filter", DHCPv6Filter);
+ PACK_GET_POLICY_BOOL("DHCPv6NoServer", DHCPv6NoServer);
+ PACK_GET_POLICY_BOOL("NoRoutingV6", NoRoutingV6);
+ PACK_GET_POLICY_BOOL("CheckIPv6", CheckIPv6);
+ PACK_GET_POLICY_BOOL("NoServerV6", NoServerV6);
+ PACK_GET_POLICY_BOOL("NoSavePassword", NoSavePassword);
+ PACK_GET_POLICY_BOOL("FilterIPv4", FilterIPv4);
+ PACK_GET_POLICY_BOOL("FilterIPv6", FilterIPv6);
+ PACK_GET_POLICY_BOOL("FilterNonIP", FilterNonIP);
+ PACK_GET_POLICY_BOOL("NoIPv6DefaultRouterInRA", NoIPv6DefaultRouterInRA);
+ PACK_GET_POLICY_BOOL("NoIPv6DefaultRouterInRAWhenIPv6", NoIPv6DefaultRouterInRAWhenIPv6);
+
+ // UINT value
+ // Ver 2
+ PACK_GET_POLICY_UINT("MaxConnection", MaxConnection);
+ PACK_GET_POLICY_UINT("TimeOut", TimeOut);
+ PACK_GET_POLICY_UINT("MaxMac", MaxMac);
+ PACK_GET_POLICY_UINT("MaxIP", MaxIP);
+ PACK_GET_POLICY_UINT("MaxUpload", MaxUpload);
+ PACK_GET_POLICY_UINT("MaxDownload", MaxDownload);
+ PACK_GET_POLICY_UINT("MultiLogins", MultiLogins);
+ // Ver 3
+ PACK_GET_POLICY_UINT("MaxIPv6", MaxIPv6);
+ PACK_GET_POLICY_UINT("AutoDisconnect", AutoDisconnect);
+ PACK_GET_POLICY_UINT("VLanId", VLanId);
+
+ // Ver 3 flag
+ PACK_GET_POLICY_BOOL("Ver3", Ver3);
+
+ return y;
+}
+
+// Insert the policy into the PACK
+void PackAddPolicy(PACK *p, POLICY *y)
+{
+ // Validate arguments
+ if (p == NULL || y == NULL)
+ {
+ return;
+ }
+
+ // Bool value
+ // Ver 2
+ PACK_ADD_POLICY_BOOL("Access", Access);
+ PACK_ADD_POLICY_BOOL("DHCPFilter", DHCPFilter);
+ PACK_ADD_POLICY_BOOL("DHCPNoServer", DHCPNoServer);
+ PACK_ADD_POLICY_BOOL("DHCPForce", DHCPForce);
+ PACK_ADD_POLICY_BOOL("NoBridge", NoBridge);
+ PACK_ADD_POLICY_BOOL("NoRouting", NoRouting);
+ PACK_ADD_POLICY_BOOL("PrivacyFilter", PrivacyFilter);
+ PACK_ADD_POLICY_BOOL("NoServer", NoServer);
+ PACK_ADD_POLICY_BOOL("CheckMac", CheckMac);
+ PACK_ADD_POLICY_BOOL("CheckIP", CheckIP);
+ PACK_ADD_POLICY_BOOL("ArpDhcpOnly", ArpDhcpOnly);
+ PACK_ADD_POLICY_BOOL("MonitorPort", MonitorPort);
+ PACK_ADD_POLICY_BOOL("NoBroadcastLimiter", NoBroadcastLimiter);
+ PACK_ADD_POLICY_BOOL("FixPassword", FixPassword);
+ PACK_ADD_POLICY_BOOL("NoQoS", NoQoS);
+ // Ver 3
+ PACK_ADD_POLICY_BOOL("RSandRAFilter", RSandRAFilter);
+ PACK_ADD_POLICY_BOOL("RAFilter", RAFilter);
+ PACK_ADD_POLICY_BOOL("DHCPv6Filter", DHCPv6Filter);
+ PACK_ADD_POLICY_BOOL("DHCPv6NoServer", DHCPv6NoServer);
+ PACK_ADD_POLICY_BOOL("NoRoutingV6", NoRoutingV6);
+ PACK_ADD_POLICY_BOOL("CheckIPv6", CheckIPv6);
+ PACK_ADD_POLICY_BOOL("NoServerV6", NoServerV6);
+ PACK_ADD_POLICY_BOOL("NoSavePassword", NoSavePassword);
+ PACK_ADD_POLICY_BOOL("FilterIPv4", FilterIPv4);
+ PACK_ADD_POLICY_BOOL("FilterIPv6", FilterIPv6);
+ PACK_ADD_POLICY_BOOL("FilterNonIP", FilterNonIP);
+ PACK_ADD_POLICY_BOOL("NoIPv6DefaultRouterInRA", NoIPv6DefaultRouterInRA);
+ PACK_ADD_POLICY_BOOL("NoIPv6DefaultRouterInRAWhenIPv6", NoIPv6DefaultRouterInRAWhenIPv6);
+
+ // UINT value
+ // Ver 2
+ PACK_ADD_POLICY_UINT("MaxConnection", MaxConnection);
+ PACK_ADD_POLICY_UINT("TimeOut", TimeOut);
+ PACK_ADD_POLICY_UINT("MaxMac", MaxMac);
+ PACK_ADD_POLICY_UINT("MaxIP", MaxIP);
+ PACK_ADD_POLICY_UINT("MaxUpload", MaxUpload);
+ PACK_ADD_POLICY_UINT("MaxDownload", MaxDownload);
+ PACK_ADD_POLICY_UINT("MultiLogins", MultiLogins);
+ // Ver 3
+ PACK_ADD_POLICY_UINT("MaxIPv6", MaxIPv6);
+ PACK_ADD_POLICY_UINT("AutoDisconnect", AutoDisconnect);
+ PACK_ADD_POLICY_UINT("VLanId", VLanId);
+
+ // Ver 3 flag
+ PackAddBool(p, "policy:Ver3", true);
+}
+
+// Upload the authentication data for the additional connection
+bool ClientUploadAuth2(CONNECTION *c, SOCK *s)
+{
+ PACK *p = NULL;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ p = PackAdditionalConnect(c->Session->SessionKey);
+
+ PackAddClientVersion(p, c);
+
+ if (HttpClientSend(s, p) == false)
+ {
+ FreePack(p);
+ return false;
+ }
+ FreePack(p);
+
+ return true;
+}
+
+// Send a NOOP
+void ClientUploadNoop(CONNECTION *c)
+{
+ PACK *p;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ p = PackError(0);
+ PackAddInt(p, "noop", 1);
+ HttpClientSend(c->FirstSock, p);
+ FreePack(p);
+
+ p = HttpClientRecv(c->FirstSock);
+ if (p != NULL)
+ {
+ FreePack(p);
+ }
+}
+
+// Add client version information to the PACK
+void PackAddClientVersion(PACK *p, CONNECTION *c)
+{
+ // Validate arguments
+ if (p == NULL || c == NULL)
+ {
+ return;
+ }
+
+ PackAddStr(p, "client_str", c->ClientStr);
+ PackAddInt(p, "client_ver", c->ClientVer);
+ PackAddInt(p, "client_build", c->ClientBuild);
+}
+
+// Upload the certificate data for the new connection
+bool ClientUploadAuth(CONNECTION *c)
+{
+ PACK *p = NULL;
+ CLIENT_AUTH *a;
+ CLIENT_OPTION *o;
+ X *x;
+ bool ret;
+ NODE_INFO info;
+ UCHAR secure_password[SHA1_SIZE];
+ UCHAR sign[4096 / 8];
+ UCHAR unique[SHA1_SIZE];
+ RPC_WINVER v;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ Zero(sign, sizeof(sign));
+
+ a = c->Session->ClientAuth;
+ o = c->Session->ClientOption;
+
+ if (c->UseTicket == false)
+ {
+ switch (a->AuthType)
+ {
+ case CLIENT_AUTHTYPE_ANONYMOUS:
+ // Anonymous authentication
+ p = PackLoginWithAnonymous(o->HubName, a->Username);
+ break;
+
+ case CLIENT_AUTHTYPE_PASSWORD:
+ // Password authentication
+ SecurePassword(secure_password, a->HashedPassword, c->Random);
+ p = PackLoginWithPassword(o->HubName, a->Username, secure_password);
+ break;
+
+ case CLIENT_AUTHTYPE_PLAIN_PASSWORD:
+ // Plaintext password authentication
+ p = PackLoginWithPlainPassword(o->HubName, a->Username, a->PlainPassword);
+ break;
+
+ case CLIENT_AUTHTYPE_CERT:
+ // Certificate authentication
+ if (a->ClientX != NULL && a->ClientX->is_compatible_bit &&
+ a->ClientX->bits != 0 && (a->ClientX->bits / 8) <= sizeof(sign))
+ {
+ if (RsaSignEx(sign, c->Random, SHA1_SIZE, a->ClientK, a->ClientX->bits))
+ {
+ p = PackLoginWithCert(o->HubName, a->Username, a->ClientX, sign, a->ClientX->bits / 8);
+ c->ClientX = CloneX(a->ClientX);
+ }
+ }
+ break;
+
+ case CLIENT_AUTHTYPE_SECURE:
+ // Authentication by secure device
+ if (ClientSecureSign(c, sign, c->Random, &x))
+ {
+ p = PackLoginWithCert(o->HubName, a->Username, x, sign, 128);
+ c->ClientX = CloneX(x);
+ FreeX(x);
+ }
+ else
+ {
+ c->Err = ERR_SECURE_DEVICE_OPEN_FAILED;
+ c->Session->ForceStopFlag = true;
+ }
+ break;
+ }
+ }
+ else
+ {
+ // Ticket
+ p = NewPack();
+ PackAddStr(p, "method", "login");
+ PackAddStr(p, "hubname", o->HubName);
+ PackAddStr(p, "username", a->Username);
+ PackAddInt(p, "authtype", AUTHTYPE_TICKET);
+ PackAddData(p, "ticket", c->Ticket, SHA1_SIZE);
+ }
+
+ // Current time
+ PackAddInt64(p, "timestamp", SystemTime64());
+
+ if (p == NULL)
+ {
+ // Error
+ if (c->Err != ERR_SECURE_DEVICE_OPEN_FAILED)
+ {
+ c->Err = ERR_PROTOCOL_ERROR;
+ }
+ return false;
+ }
+
+ PackAddClientVersion(p, c);
+
+ // Protocol
+ PackAddInt(p, "protocol", c->Protocol);
+
+ // Version, etc.
+ PackAddStr(p, "hello", c->ClientStr);
+ PackAddInt(p, "version", c->ClientVer);
+ PackAddInt(p, "build", c->ClientBuild);
+ PackAddInt(p, "client_id", c->Cedar->ClientId);
+
+ // The maximum number of connections
+ PackAddInt(p, "max_connection", o->MaxConnection);
+ // Flag to use of cryptography
+ PackAddInt(p, "use_encrypt", o->UseEncrypt == false ? 0 : 1);
+ // Fast encryption using flag
+ // PackAddInt(p, "use_fast_rc4", o->UseFastRC4 == false ? 0 : 1);
+ // Data compression flag
+ PackAddInt(p, "use_compress", o->UseCompress == false ? 0 : 1);
+ // Half connection flag
+ PackAddInt(p, "half_connection", o->HalfConnection == false ? 0 : 1);
+
+ // Bridge / routing mode flag
+ PackAddBool(p, "require_bridge_routing_mode", o->RequireBridgeRoutingMode);
+
+ // Monitor mode flag
+ PackAddBool(p, "require_monitor_mode", o->RequireMonitorMode);
+
+ // VoIP / QoS flag
+ PackAddBool(p, "qos", o->DisableQoS ? false : true);
+
+ // Bulk transfer support
+ PackAddBool(p, "support_bulk_on_rudp", true);
+ PackAddBool(p, "support_hmac_on_bulk_of_rudp", true);
+
+ // UDP recovery support
+ PackAddBool(p, "support_udp_recovery", true);
+
+ // Unique ID
+ GenerateMachineUniqueHash(unique);
+ PackAddData(p, "unique_id", unique, SHA1_SIZE);
+
+ // UDP acceleration function using flag
+ if (o->NoUdpAcceleration == false && c->Session->UdpAccel != NULL)
+ {
+ PackAddBool(p, "use_udp_acceleration", true);
+ PackAddIp(p, "udp_acceleration_client_ip", &c->Session->UdpAccel->MyIp);
+ PackAddInt(p, "udp_acceleration_client_port", c->Session->UdpAccel->MyPort);
+ PackAddData(p, "udp_acceleration_client_key", c->Session->UdpAccel->MyKey, UDP_ACCELERATION_COMMON_KEY_SIZE);
+ PackAddBool(p, "support_hmac_on_udp_acceleration", true);
+ PackAddBool(p, "support_udp_accel_fast_disconnect_detect", true);
+ }
+
+ // Brand string for the connection limit
+ {
+ char *branded_ctos = _SS("BRANDED_C_TO_S");
+ if(StrLen(branded_ctos) > 0)
+ {
+ PackAddStr(p, "branded_ctos", branded_ctos);
+ }
+ }
+
+ // Node information
+ CreateNodeInfo(&info, c);
+ OutRpcNodeInfo(p, &info);
+
+ // OS information
+ GetWinVer(&v);
+ OutRpcWinVer(p, &v);
+
+ ret = HttpClientSend(c->FirstSock, p);
+ if (ret == false)
+ {
+ c->Err = ERR_DISCONNECTED;
+ }
+
+ FreePack(p);
+
+ return ret;
+}
+
+// Upload the Hello packet
+bool ServerUploadHello(CONNECTION *c)
+{
+ PACK *p;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ // Random number generation
+ Rand(c->Random, SHA1_SIZE);
+
+ p = PackHello(c->Random, c->ServerVer, c->ServerBuild, c->ServerStr);
+ if (HttpServerSend(c->FirstSock, p) == false)
+ {
+ FreePack(p);
+ c->Err = ERR_DISCONNECTED;
+ return false;
+ }
+
+ FreePack(p);
+
+ return true;
+}
+
+// Download the Hello packet
+bool ClientDownloadHello(CONNECTION *c, SOCK *s)
+{
+ PACK *p;
+ UINT err;
+ UCHAR random[SHA1_SIZE];
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ // Data reception
+ p = HttpClientRecv(s);
+ if (p == NULL)
+ {
+ c->Err = ERR_SERVER_IS_NOT_VPN;
+ return false;
+ }
+
+ if (err = GetErrorFromPack(p))
+ {
+ // An error has occured
+ c->Err = err;
+ FreePack(p);
+ return false;
+ }
+
+ // Packet interpretation
+ if (GetHello(p, random, &c->ServerVer, &c->ServerBuild, c->ServerStr, sizeof(c->ServerStr)) == false)
+ {
+ c->Err = ERR_SERVER_IS_NOT_VPN;
+ FreePack(p);
+ return false;
+ }
+
+ if (c->FirstSock == s)
+ {
+ Copy(c->Random, random, SHA1_SIZE);
+ }
+
+ FreePack(p);
+
+ return true;
+}
+
+// Download the signature
+bool ServerDownloadSignature(CONNECTION *c, char **error_detail_str)
+{
+ HTTP_HEADER *h;
+ UCHAR *data;
+ UINT data_size;
+ SOCK *s;
+ UINT num = 0, max = 19;
+ SERVER *server;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return false;
+ }
+
+ server = c->Cedar->Server;
+
+ s = c->FirstSock;
+
+ while (true)
+ {
+ num++;
+ if (num > max)
+ {
+ // Disconnect
+ Disconnect(s);
+ c->Err = ERR_CLIENT_IS_NOT_VPN;
+
+ *error_detail_str = "HTTP_TOO_MANY_REQUEST";
+ return false;
+ }
+ // Receive a header
+ h = RecvHttpHeader(s);
+ if (h == NULL)
+ {
+ c->Err = ERR_CLIENT_IS_NOT_VPN;
+ return false;
+ }
+
+ // Interpret
+ if (StrCmpi(h->Method, "POST") == 0)
+ {
+ // Receive the data since it's POST
+ data_size = GetContentLength(h);
+ if ((data_size > MAX_WATERMARK_SIZE || data_size < SizeOfWaterMark()) && (data_size != StrLen(HTTP_VPN_TARGET_POSTDATA)))
+ {
+ // Data is too large
+ HttpSendForbidden(s, h->Target, NULL);
+ FreeHttpHeader(h);
+ c->Err = ERR_CLIENT_IS_NOT_VPN;
+ *error_detail_str = "POST_Recv_TooLong";
+ return false;
+ }
+ data = Malloc(data_size);
+ if (RecvAll(s, data, data_size, s->SecureMode) == false)
+ {
+ // Data reception failure
+ Free(data);
+ FreeHttpHeader(h);
+ c->Err = ERR_DISCONNECTED;
+ *error_detail_str = "POST_Recv_Failed";
+ return false;
+ }
+ // Check the Target
+ if (StrCmpi(h->Target, HTTP_VPN_TARGET2) != 0)
+ {
+ // Target is invalid
+ HttpSendNotFound(s, h->Target);
+ Free(data);
+ FreeHttpHeader(h);
+ *error_detail_str = "POST_Target_Wrong";
+ }
+ else
+ {
+ // Compare posted data with the WaterMark
+ if ((data_size == StrLen(HTTP_VPN_TARGET_POSTDATA) && (Cmp(data, HTTP_VPN_TARGET_POSTDATA, data_size) == 0))
+ || (Cmp(data, WaterMark, SizeOfWaterMark()) == 0))
+ {
+ // Check the WaterMark
+ Free(data);
+ FreeHttpHeader(h);
+ return true;
+ }
+ else
+ {
+ // WaterMark is incorrect
+ HttpSendForbidden(s, h->Target, NULL);
+ FreeHttpHeader(h);
+ *error_detail_str = "POST_WaterMark_Error";
+ }
+ }
+ }
+ else if (StrCmpi(h->Method, "SSTP_DUPLEX_POST") == 0 && (server->DisableSSTPServer == false || s->IsReverseAcceptedSocket
+ ) &&
+ GetServerCapsBool(server, "b_support_sstp") && GetNoSstp() == false)
+ {
+ // SSTP client is connected
+ c->WasSstp = true;
+
+ if (StrCmpi(h->Target, SSTP_URI) == 0)
+ {
+ bool sstp_ret;
+ // Accept the SSTP connection
+ c->Type = CONNECTION_TYPE_SSTP;
+
+ sstp_ret = AcceptSstp(c);
+
+ c->Err = ERR_DISCONNECTED;
+ FreeHttpHeader(h);
+
+ if (sstp_ret)
+ {
+ *error_detail_str = "";
+ }
+ else
+ {
+ *error_detail_str = "SSTP_ABORT";
+ }
+
+ return false;
+ }
+ else
+ {
+ // URI is invalid
+ HttpSendNotFound(s, h->Target);
+ *error_detail_str = "SSTP_URL_WRONG";
+ }
+
+ FreeHttpHeader(h);
+ }
+ else
+ {
+ // This should not be a VPN client, but interpret a bit more
+ if (StrCmpi(h->Method, "GET") != 0)
+ {
+ // Unsupported method calls
+ HttpSendNotImplemented(s, h->Method, h->Target, h->Version);
+ *error_detail_str = "HTTP_BAD_METHOD";
+ }
+ else
+ {
+
+ if (StrCmpi(h->Target, "/") == 0)
+ {
+ // Root directory
+ SERVER *s = c->Cedar->Server;
+ bool is_free = false;
+
+ *error_detail_str = "HTTP_ROOT";
+
+ if (s != NULL && s->UseWebTimePage)
+ {
+ // Generate a page that shows the current time as the top page automatically
+ BUF *b = ReadDump("|time.htm");
+
+ if (b != NULL)
+ {
+ char *src = ZeroMalloc(b->Size + 1);
+ UINT dst_size = b->Size * 2 + 64;
+ char *dst = ZeroMalloc(dst_size);
+ char host[MAX_PATH];
+ char portstr[64];
+ char now_str[MAX_PATH];
+
+ GetDateTimeStr64(now_str, sizeof(now_str), LocalTime64());
+
+ GetMachineName(host, sizeof(host));
+ ToStr(portstr, c->FirstSock->LocalPort);
+
+ Copy(src, b->Buf, b->Size);
+ ReplaceStrEx(dst, dst_size, src,
+ "$HOST$", host, false);
+ ReplaceStrEx(dst, dst_size, dst,
+ "$PORT$", portstr, false);
+ ReplaceStrEx(dst, dst_size, dst,
+ "$NOW$", now_str, false);
+
+ FreeHttpHeader(h);
+ h = NewHttpHeader("HTTP/1.1", "202", "OK");
+ AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE4));
+ AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));
+ AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));
+ PostHttp(c->FirstSock, h, dst, StrLen(dst));
+
+ Free(src);
+ Free(dst);
+
+ FreeBuf(b);
+ }
+ }
+ else
+ {
+ if (is_free == false)
+ {
+ // Other than free version
+ HttpSendForbidden(c->FirstSock, h->Target, "");
+ }
+ else
+ {
+ // Free version
+ BUF *b = ReadDump("|free.htm");
+
+ if (b != NULL)
+ {
+ char *src = ZeroMalloc(b->Size + 1);
+ UINT dst_size = b->Size * 2 + 64;
+ char *dst = ZeroMalloc(dst_size);
+ char host[MAX_PATH];
+ char portstr[64];
+
+ GetMachineName(host, sizeof(host));
+ ToStr(portstr, c->FirstSock->LocalPort);
+
+ Copy(src, b->Buf, b->Size);
+ ReplaceStrEx(dst, dst_size, src,
+ "$HOST$", host, false);
+ ReplaceStrEx(dst, dst_size, dst,
+ "$PORT$", portstr, false);
+
+ FreeHttpHeader(h);
+ h = NewHttpHeader("HTTP/1.1", "202", "OK");
+ AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE4));
+ AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));
+ AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));
+ PostHttp(c->FirstSock, h, dst, StrLen(dst));
+
+ Free(src);
+ Free(dst);
+
+ FreeBuf(b);
+ }
+ }
+ }
+ }
+ else
+ {
+ bool b = false;
+
+ // Show the WebUI if the configuration allow to use the WebUI
+ if (c->Cedar->Server != NULL && c->Cedar->Server->UseWebUI)
+ {
+ WU_WEBPAGE *page;
+
+ // Show the WebUI
+ page = WuGetPage(h->Target, c->Cedar->WebUI);
+
+ if (page != NULL)
+ {
+ PostHttp(s, page->header, page->data, page->size);
+ b = true;
+ WuFreeWebPage(page);
+ }
+
+ }
+
+ if (c->FirstSock->RemoteIP.addr[0] == 127)
+ {
+ if (StrCmpi(h->Target, HTTP_SAITAMA) == 0)
+ {
+ // Saitama (joke)
+ FreeHttpHeader(h);
+ h = NewHttpHeader("HTTP/1.1", "202", "OK");
+ AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE3));
+ AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));
+ AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));
+ PostHttp(s, h, Saitama, SizeOfSaitama());
+ b = true;
+ }
+ else if (StartWith(h->Target, HTTP_PICTURES))
+ {
+ BUF *buf;
+
+ // Lots of photos
+ buf = ReadDump("|Pictures.mht");
+
+ if (buf != NULL)
+ {
+ FreeHttpHeader(h);
+ h = NewHttpHeader("HTTP/1.1", "202", "OK");
+ AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE5));
+ AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));
+ AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));
+ PostHttp(s, h, buf->Buf, buf->Size);
+ b = true;
+
+ FreeBuf(buf);
+ }
+ }
+ }
+
+ if (b == false)
+ {
+ // Not Found
+ HttpSendNotFound(s, h->Target);
+
+ *error_detail_str = "HTTP_NOT_FOUND";
+ }
+ }
+ }
+ FreeHttpHeader(h);
+ }
+ }
+}
+
+// Upload a signature
+bool ClientUploadSignature(SOCK *s)
+{
+ HTTP_HEADER *h;
+ UINT water_size, rand_size;
+ UCHAR *water;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ h = NewHttpHeader("POST", HTTP_VPN_TARGET2, "HTTP/1.1");
+ AddHttpValue(h, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE3));
+ AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));
+
+ // Generate a watermark
+ rand_size = Rand32() % (HTTP_PACK_RAND_SIZE_MAX * 2);
+ water_size = SizeOfWaterMark() + rand_size;
+ water = Malloc(water_size);
+ Copy(water, WaterMark, SizeOfWaterMark());
+ Rand(&water[SizeOfWaterMark()], rand_size);
+
+ // Upload the watermark data
+ if (PostHttp(s, h, water, water_size) == false)
+ {
+ Free(water);
+ FreeHttpHeader(h);
+ return false;
+ }
+
+ Free(water);
+ FreeHttpHeader(h);
+
+ return true;
+}
+
+// Establish a connection to the server
+SOCK *ClientConnectToServer(CONNECTION *c)
+{
+ SOCK *s = NULL;
+ X *x = NULL;
+ K *k = NULL;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ if (c->Halt)
+ {
+ c->Err = ERR_USER_CANCEL;
+ return NULL;
+ }
+
+ // Get the socket by connecting
+ s = ClientConnectGetSocket(c, false, (c->DontUseTls1 ? false : true));
+ if (s == NULL)
+ {
+ // Connection failure
+ return NULL;
+ }
+
+ c->FirstSock = s;
+
+ if (c->Halt)
+ {
+ c->Err = ERR_USER_CANCEL;
+ ReleaseSock(s);
+ c->FirstSock = NULL;
+ return NULL;
+ }
+
+ // Time-out
+ SetTimeout(s, CONNECTING_TIMEOUT);
+
+ // Start the SSL communication
+ if (StartSSLEx(s, x, k, (c->DontUseTls1 ? false : true), 0, c->ServerName) == false)
+ {
+ // SSL communication start failure
+ Disconnect(s);
+ ReleaseSock(s);
+ c->FirstSock = NULL;
+ c->Err = ERR_SERVER_IS_NOT_VPN;
+ return NULL;
+ }
+
+ if (s->RemoteX == NULL)
+ {
+ // SSL communication start failure
+ Disconnect(s);
+ ReleaseSock(s);
+ c->FirstSock = NULL;
+ c->Err = ERR_SERVER_IS_NOT_VPN;
+ return NULL;
+ }
+
+ return s;
+}
+
+// Return a socket by connecting to the server
+SOCK *ClientConnectGetSocket(CONNECTION *c, bool additional_connect, bool no_tls)
+{
+ SOCK *s = NULL;
+ CLIENT_OPTION *o;
+ char *host_for_direct_connection;
+ UINT port_for_direct_connection;
+ wchar_t tmp[MAX_SIZE];
+ SESSION *sess;
+ volatile bool *cancel_flag = NULL;
+ void *hWnd;
+ UINT nat_t_err = 0;
+ bool is_additonal_rudp_session = false;
+ UCHAR uc = 0;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ sess = c->Session;
+
+ if (sess != NULL)
+ {
+ cancel_flag = &sess->CancelConnect;
+ is_additonal_rudp_session = sess->IsRUDPSession;
+ }
+
+ hWnd = c->hWndForUI;
+
+ o = c->Session->ClientOption;
+
+ if (c->RestoreServerNameAndPort && additional_connect)
+ {
+ // Restore to the original server name and port number
+ c->RestoreServerNameAndPort = false;
+
+ StrCpy(c->ServerName, sizeof(c->ServerName), o->Hostname);
+ c->ServerPort = o->Port;
+ }
+
+ host_for_direct_connection = c->ServerName;
+ port_for_direct_connection = c->ServerPort;
+
+ switch (o->ProxyType)
+ {
+ case PROXY_DIRECT: // TCP/IP
+ UniFormat(tmp, sizeof(tmp), _UU("STATUS_4"), c->ServerName);
+ PrintStatus(sess, tmp);
+ // Production job
+ if (o->PortUDP == 0)
+ {
+ {
+ // If additional_connect == false, enable trying to NAT-T connection
+ // If additional_connect == true, follow the IsRUDPSession setting in this session
+ s = TcpIpConnectEx(host_for_direct_connection, port_for_direct_connection,
+ (bool *)cancel_flag, hWnd, &nat_t_err, (additional_connect ? (!is_additonal_rudp_session) : false),
+ true, no_tls);
+ }
+ }
+ else
+ {
+ // Mode to connect with R-UDP directly without using NAT-T server when using UDP
+ IP ip;
+
+ Zero(&ip, sizeof(ip));
+
+ StrToIP(&ip, o->Hostname);
+
+
+ s = NewRUDPClientDirect(VPN_RUDP_SVC_NAME, &ip, o->PortUDP, &nat_t_err,
+ TIMEOUT_TCP_PORT_CHECK, (bool *)cancel_flag, NULL, NULL, 0, false);
+
+ if (s != NULL)
+ {
+ StrCpy(s->UnderlayProtocol, sizeof(s->UnderlayProtocol), SOCK_UNDERLAY_NAT_T);
+ }
+ }
+ if (s == NULL)
+ {
+ // Connection failure
+ if (nat_t_err != RUDP_ERROR_NAT_T_TWO_OR_MORE)
+ {
+ c->Err = ERR_CONNECT_FAILED;
+ }
+ else
+ {
+ c->Err = ERR_NAT_T_TWO_OR_MORE;
+ }
+ return NULL;
+ }
+ break;
+
+ case PROXY_HTTP: // HTTP Proxy
+ host_for_direct_connection = o->ProxyName;
+ port_for_direct_connection = o->ProxyPort;
+
+ UniFormat(tmp, sizeof(tmp), _UU("STATUS_2"), c->ServerName, o->ProxyName);
+ PrintStatus(sess, tmp);
+
+
+ // Proxy connection
+ s = ProxyConnectEx(c, host_for_direct_connection, port_for_direct_connection,
+ c->ServerName, c->ServerPort, o->ProxyUsername, o->ProxyPassword,
+ additional_connect, (bool *)cancel_flag, hWnd);
+ if (s == NULL)
+ {
+ // Connection failure
+ return NULL;
+ }
+ break;
+
+ case PROXY_SOCKS: // SOCKS Proxy
+ host_for_direct_connection = o->ProxyName;
+
+ port_for_direct_connection = o->ProxyPort;
+
+ UniFormat(tmp, sizeof(tmp), _UU("STATUS_2"), c->ServerName, o->ProxyName);
+ PrintStatus(sess, tmp);
+
+
+ // SOCKS connection
+ s = SocksConnectEx(c, host_for_direct_connection, port_for_direct_connection,
+ c->ServerName, c->ServerPort, o->ProxyUsername,
+ additional_connect, (bool *)cancel_flag, hWnd);
+ if (s == NULL)
+ {
+ // Connection failure
+ return NULL;
+ }
+ break;
+ }
+
+ if (s == NULL)
+ {
+ // Connection failure
+ c->Err = ERR_CONNECT_FAILED;
+ }
+ else
+ {
+ // Success to connect
+ // Keep a note of the IP address
+ if (additional_connect == false || IsZeroIP(&s->RemoteIP))
+ {
+ if (((s->IsRUDPSocket || s->IPv6) && IsZeroIP(&s->RemoteIP) == false && o->ProxyType == PROXY_DIRECT) || GetIP(&c->Session->ServerIP, host_for_direct_connection) == false)
+ {
+ Copy(&c->Session->ServerIP, &s->RemoteIP, sizeof(IP));
+ }
+ }
+ }
+
+ return s;
+}
+
+// Connect via SOCKS
+SOCK *SocksConnect(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, bool additional_connect)
+{
+ return SocksConnectEx(c, proxy_host_name, proxy_port,
+ server_host_name, server_port, username, additional_connect, NULL, NULL);
+}
+SOCK *SocksConnectEx(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, bool additional_connect,
+ bool *cancel_flag, void *hWnd)
+{
+ return SocksConnectEx2(c, proxy_host_name, proxy_port,
+ server_host_name, server_port, username, additional_connect, cancel_flag,
+ hWnd, 0);
+}
+SOCK *SocksConnectEx2(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, bool additional_connect,
+ bool *cancel_flag, void *hWnd, UINT timeout)
+{
+ SOCK *s = NULL;
+ IP ip;
+ // Validate arguments
+ if (c == NULL || proxy_host_name == NULL || proxy_port == 0 || server_host_name == NULL
+ || server_port == 0)
+ {
+ c->Err = ERR_PROXY_CONNECT_FAILED;
+ return NULL;
+ }
+
+ // Get the IP address of the destination server
+ if (GetIP(&ip, server_host_name) == false)
+ {
+ // Failure
+ c->Err = ERR_CONNECT_FAILED;
+ return NULL;
+ }
+
+ if (c->Halt)
+ {
+ // Stop
+ c->Err = ERR_USER_CANCEL;
+ return NULL;
+ }
+
+ // Connection
+ s = TcpConnectEx3(proxy_host_name, proxy_port, timeout, cancel_flag, hWnd, true, NULL, false, false);
+ if (s == NULL)
+ {
+ // Failure
+ c->Err = ERR_PROXY_CONNECT_FAILED;
+ return NULL;
+ }
+
+ // Timeout setting
+ SetTimeout(s, MIN(CONNECTING_TIMEOUT_PROXY, (timeout == 0 ? INFINITE : timeout)));
+
+ if (additional_connect == false)
+ {
+ c->FirstSock = s;
+ }
+
+ // Request packet transmission
+ if (SocksSendRequestPacket(c, s, server_port, &ip, username) == false)
+ {
+ // Failure
+ if (additional_connect == false)
+ {
+ c->FirstSock = NULL;
+ }
+ Disconnect(s);
+ ReleaseSock(s);
+ return NULL;
+ }
+
+ // Receive a response packet
+ if (SocksRecvResponsePacket(c, s) == false)
+ {
+ // Failure
+ if (additional_connect == false)
+ {
+ c->FirstSock = NULL;
+ }
+ Disconnect(s);
+ ReleaseSock(s);
+ return NULL;
+ }
+
+ SetTimeout(s, INFINITE);
+
+ return s;
+}
+
+// Receive a SOCKS response packet
+bool SocksRecvResponsePacket(CONNECTION *c, SOCK *s)
+{
+ BUF *b;
+ UINT size = 8;
+ UCHAR tmp[8];
+ UCHAR vn, cd;
+ // Validate arguments
+ if (c == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ if (RecvAll(s, tmp, sizeof(tmp), false) == false)
+ {
+ c->Err = ERR_DISCONNECTED;
+ return false;
+ }
+
+ b = NewBuf();
+ WriteBuf(b, tmp, sizeof(tmp));
+ SeekBuf(b, 0, 0);
+
+ ReadBuf(b, &vn, 1);
+ ReadBuf(b, &cd, 1);
+
+ FreeBuf(b);
+
+ if (vn != 0)
+ {
+ c->Err = ERR_PROXY_ERROR;
+ return false;
+ }
+
+ switch (cd)
+ {
+ case 90:
+ // Success
+ return true;
+
+ case 93:
+ // Authentication failure
+ c->Err = ERR_PROXY_AUTH_FAILED;
+ return false;
+
+ default:
+ // Connection to the server failure
+ c->Err = ERR_CONNECT_FAILED;
+ return false;
+ }
+}
+
+// Send a SOCKS request packet
+bool SocksSendRequestPacket(CONNECTION *c, SOCK *s, UINT dest_port, IP *dest_ip, char *userid)
+{
+ BUF *b;
+ UCHAR vn, cd;
+ USHORT port;
+ UINT ip;
+ bool ret;
+ // Validate arguments
+ if (s == NULL || dest_port == 0 || dest_ip == NULL || c == NULL)
+ {
+ return false;
+ }
+ if (userid == NULL)
+ {
+ userid = "";
+ }
+
+ b = NewBuf();
+ vn = 4;
+ cd = 1;
+ WriteBuf(b, &vn, 1);
+ WriteBuf(b, &cd, 1);
+ port = Endian16((USHORT)dest_port);
+ ip = IPToUINT(dest_ip);
+ WriteBuf(b, &port, 2);
+ WriteBuf(b, &ip, 4);
+ WriteBuf(b, userid, StrLen(userid) + 1);
+
+ ret = SendAll(s, b->Buf, b->Size, false);
+ if (ret == false)
+ {
+ c->Err = ERR_DISCONNECTED;
+ }
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Connect through a proxy
+SOCK *ProxyConnect(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, char *password, bool additional_connect)
+{
+ return ProxyConnectEx(c, proxy_host_name, proxy_port,
+ server_host_name, server_port, username, password, additional_connect, NULL, NULL);
+}
+SOCK *ProxyConnectEx(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, char *password, bool additional_connect,
+ bool *cancel_flag, void *hWnd)
+{
+ return ProxyConnectEx2(c, proxy_host_name, proxy_port,
+ server_host_name, server_port, username, password, additional_connect,
+ cancel_flag, hWnd, 0);
+}
+SOCK *ProxyConnectEx2(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, char *password, bool additional_connect,
+ bool *cancel_flag, void *hWnd, UINT timeout)
+{
+ SOCK *s = NULL;
+ bool use_auth = false;
+ char tmp[MAX_SIZE];
+ char auth_tmp_str[MAX_SIZE], auth_b64_str[MAX_SIZE * 2];
+ char basic_str[MAX_SIZE * 2];
+ UINT http_error_code;
+ HTTP_HEADER *h;
+ // Validate arguments
+ if (c == NULL || proxy_host_name == NULL || proxy_port == 0 || server_host_name == NULL ||
+ server_port == 0)
+ {
+ c->Err = ERR_PROXY_CONNECT_FAILED;
+ return NULL;
+ }
+ if (username != NULL && password != NULL &&
+ (StrLen(username) != 0 || StrLen(password) != 0))
+ {
+ use_auth = true;
+ }
+
+ if (c->Halt)
+ {
+ // Stop
+ c->Err = ERR_USER_CANCEL;
+ return NULL;
+ }
+
+ // Connection
+ s = TcpConnectEx3(proxy_host_name, proxy_port, timeout, cancel_flag, hWnd, true, NULL, false, false);
+ if (s == NULL)
+ {
+ // Failure
+ c->Err = ERR_PROXY_CONNECT_FAILED;
+ return NULL;
+ }
+
+ // Timeout setting
+ SetTimeout(s, MIN(CONNECTING_TIMEOUT_PROXY, (timeout == 0 ? INFINITE : timeout)));
+
+ if (additional_connect == false)
+ {
+ c->FirstSock = s;
+ }
+
+ // HTTP header generation
+ if (IsStrIPv6Address(server_host_name))
+ {
+ IP ip;
+ char iptmp[MAX_PATH];
+
+ StrToIP(&ip, server_host_name);
+ IPToStr(iptmp, sizeof(iptmp), &ip);
+
+ Format(tmp, sizeof(tmp), "[%s]:%u", iptmp, server_port);
+ }
+ else
+ {
+ Format(tmp, sizeof(tmp), "%s:%u", server_host_name, server_port);
+ }
+
+ h = NewHttpHeader("CONNECT", tmp, "HTTP/1.0");
+ AddHttpValue(h, NewHttpValue("User-Agent", (c->Cedar == NULL ? DEFAULT_USER_AGENT : c->Cedar->HttpUserAgent)));
+ AddHttpValue(h, NewHttpValue("Host", server_host_name));
+ AddHttpValue(h, NewHttpValue("Content-Length", "0"));
+ AddHttpValue(h, NewHttpValue("Proxy-Connection", "Keep-Alive"));
+ AddHttpValue(h, NewHttpValue("Pragma", "no-cache"));
+
+ if (use_auth)
+ {
+ wchar_t tmp[MAX_SIZE];
+ UniFormat(tmp, sizeof(tmp), _UU("STATUS_3"), server_host_name);
+ // Generate the authentication string
+ Format(auth_tmp_str, sizeof(auth_tmp_str), "%s:%s",
+ username, password);
+
+ // Base64 encode
+ Zero(auth_b64_str, sizeof(auth_b64_str));
+ Encode64(auth_b64_str, auth_tmp_str);
+ Format(basic_str, sizeof(basic_str), "Basic %s", auth_b64_str);
+
+ AddHttpValue(h, NewHttpValue("Proxy-Authorization", basic_str));
+ }
+
+ // Transmission
+ if (SendHttpHeader(s, h) == false)
+ {
+ // Failure
+ if (additional_connect == false)
+ {
+ c->FirstSock = NULL;
+ }
+ FreeHttpHeader(h);
+ Disconnect(s);
+ ReleaseSock(s);
+ c->Err = ERR_PROXY_ERROR;
+ return NULL;
+ }
+
+ FreeHttpHeader(h);
+
+ if (c->Halt)
+ {
+ // Stop
+ if (additional_connect == false)
+ {
+ c->FirstSock = NULL;
+ }
+ Disconnect(s);
+ ReleaseSock(s);
+ c->Err = ERR_USER_CANCEL;
+ return NULL;
+ }
+
+ // Receive the results
+ h = RecvHttpHeader(s);
+ if (h == NULL)
+ {
+ // Failure
+ if (additional_connect == false)
+ {
+ c->FirstSock = NULL;
+ }
+ FreeHttpHeader(h);
+ Disconnect(s);
+ ReleaseSock(s);
+ c->Err = ERR_PROXY_ERROR;
+ return NULL;
+ }
+
+ http_error_code = 0;
+ if (StrLen(h->Method) == 8)
+ {
+ if (Cmp(h->Method, "HTTP/1.", 7) == 0)
+ {
+ http_error_code = ToInt(h->Target);
+ }
+ }
+ FreeHttpHeader(h);
+
+ // Check the code
+ switch (http_error_code)
+ {
+ case 401:
+ case 403:
+ case 407:
+ // Authentication failure
+ if (additional_connect == false)
+ {
+ c->FirstSock = NULL;
+ }
+ Disconnect(s);
+ ReleaseSock(s);
+ c->Err = ERR_PROXY_AUTH_FAILED;
+ return NULL;
+
+ default:
+ if ((http_error_code / 100) == 2)
+ {
+ // Success
+ SetTimeout(s, INFINITE);
+ return s;
+ }
+ else
+ {
+ // Receive an unknown result
+ if (additional_connect == false)
+ {
+ c->FirstSock = NULL;
+ }
+ Disconnect(s);
+ ReleaseSock(s);
+ c->Err = ERR_PROXY_ERROR;
+ return NULL;
+ }
+ }
+}
+
+// TCP connection function
+SOCK *TcpConnectEx2(char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd, bool try_start_ssl, bool ssl_no_tls)
+{
+ return TcpConnectEx3(hostname, port, timeout, cancel_flag, hWnd, false, NULL, try_start_ssl, ssl_no_tls);
+}
+SOCK *TcpConnectEx3(char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd, bool no_nat_t, UINT *nat_t_error_code, bool try_start_ssl, bool ssl_no_tls)
+{
+#ifdef OS_WIN32
+ if (hWnd == NULL)
+ {
+#endif // OS_WIN32
+ return ConnectEx3(hostname, port, timeout, cancel_flag, (no_nat_t ? NULL : VPN_RUDP_SVC_NAME), nat_t_error_code, try_start_ssl, ssl_no_tls, false);
+#ifdef OS_WIN32
+ }
+ else
+ {
+ return WinConnectEx3((HWND)hWnd, hostname, port, timeout, 0, NULL, NULL, nat_t_error_code, (no_nat_t ? NULL : VPN_RUDP_SVC_NAME), try_start_ssl, ssl_no_tls);
+ }
+#endif // OS_WIN32
+}
+
+// Connect with TCP/IP
+SOCK *TcpIpConnect(char *hostname, UINT port, bool try_start_ssl, bool ssl_no_tls)
+{
+ return TcpIpConnectEx(hostname, port, NULL, NULL, NULL, false, try_start_ssl, ssl_no_tls);
+}
+SOCK *TcpIpConnectEx(char *hostname, UINT port, bool *cancel_flag, void *hWnd, UINT *nat_t_error_code, bool no_nat_t, bool try_start_ssl, bool ssl_no_tls)
+{
+ SOCK *s = NULL;
+ UINT dummy_int = 0;
+ // Validate arguments
+ if (nat_t_error_code == NULL)
+ {
+ nat_t_error_code = &dummy_int;
+ }
+ *nat_t_error_code = 0;
+ if (hostname == NULL || port == 0)
+ {
+ return NULL;
+ }
+
+ s = TcpConnectEx3(hostname, port, 0, cancel_flag, hWnd, no_nat_t, nat_t_error_code, try_start_ssl, ssl_no_tls);
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ return s;
+}
+
+// Protocol routine initialization
+void InitProtocol()
+{
+}
+
+// Release the protocol routine
+void FreeProtocol()
+{
+}
+
+// Create a Hello packet
+PACK *PackHello(void *random, UINT ver, UINT build, char *server_str)
+{
+ PACK *p;
+ // Validate arguments
+ if (random == NULL || server_str == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "hello", server_str);
+ PackAddInt(p, "version", ver);
+ PackAddInt(p, "build", build);
+ PackAddData(p, "random", random, SHA1_SIZE);
+
+ return p;
+}
+
+// Interpret the Hello packet
+bool GetHello(PACK *p, void *random, UINT *ver, UINT *build, char *server_str, UINT server_str_size)
+{
+ // Validate arguments
+ if (p == NULL || random == NULL || ver == NULL || server_str == NULL)
+ {
+ return false;
+ }
+
+ if (PackGetStr(p, "hello", server_str, server_str_size) == false)
+ {
+ return false;
+ }
+ *ver = PackGetInt(p, "version");
+ *build = PackGetInt(p, "build");
+ if (PackGetDataSize(p, "random") != SHA1_SIZE)
+ {
+ return false;
+ }
+ if (PackGetData(p, "random", random) == false)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Get the authentication method from PACK
+UINT GetAuthTypeFromPack(PACK *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return 0;
+ }
+
+ return PackGetInt(p, "authtype");
+}
+
+// Get the HUB name and the user name from the PACK
+bool GetHubnameAndUsernameFromPack(PACK *p, char *username, UINT username_size,
+ char *hubname, UINT hubname_size)
+{
+ // Validate arguments
+ if (p == NULL || username == NULL || hubname == NULL)
+ {
+ return false;
+ }
+
+ if (PackGetStr(p, "username", username, username_size) == false)
+ {
+ return false;
+ }
+ if (PackGetStr(p, "hubname", hubname, hubname_size) == false)
+ {
+ return false;
+ }
+ return true;
+}
+
+// Get the protocol from PACK
+UINT GetProtocolFromPack(PACK *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return 0;
+ }
+
+#if 0
+ return PackGetInt(p, "protocol");
+#else
+ // Limit to the TCP protocol in the current version
+ return CONNECTION_TCP;
+#endif
+}
+
+// Get the method from the PACK
+bool GetMethodFromPack(PACK *p, char *method, UINT size)
+{
+ // Validate arguments
+ if (p == NULL || method == NULL || size == 0)
+ {
+ return false;
+ }
+
+ return PackGetStr(p, "method", method, size);
+}
+
+// Generate a packet of certificate authentication login
+PACK *PackLoginWithCert(char *hubname, char *username, X *x, void *sign, UINT sign_size)
+{
+ PACK *p;
+ BUF *b;
+ // Validate arguments
+ if (hubname == NULL || username == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "method", "login");
+ PackAddStr(p, "hubname", hubname);
+ PackAddStr(p, "username", username);
+ PackAddInt(p, "authtype", CLIENT_AUTHTYPE_CERT);
+
+ // Certificate
+ b = XToBuf(x, false);
+ PackAddData(p, "cert", b->Buf, b->Size);
+ FreeBuf(b);
+
+ // Signature data
+ PackAddData(p, "sign", sign, sign_size);
+
+ return p;
+}
+
+// Generate a packet of plain text password authentication login
+PACK *PackLoginWithPlainPassword(char *hubname, char *username, void *plain_password)
+{
+ PACK *p;
+ // Validate arguments
+ if (hubname == NULL || username == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "method", "login");
+ PackAddStr(p, "hubname", hubname);
+ PackAddStr(p, "username", username);
+ PackAddInt(p, "authtype", CLIENT_AUTHTYPE_PLAIN_PASSWORD);
+ PackAddStr(p, "plain_password", plain_password);
+
+ return p;
+}
+
+// Create a packet of password authentication login
+PACK *PackLoginWithPassword(char *hubname, char *username, void *secure_password)
+{
+ PACK *p;
+ // Validate arguments
+ if (hubname == NULL || username == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "method", "login");
+ PackAddStr(p, "hubname", hubname);
+ PackAddStr(p, "username", username);
+ PackAddInt(p, "authtype", CLIENT_AUTHTYPE_PASSWORD);
+ PackAddData(p, "secure_password", secure_password, SHA1_SIZE);
+
+ return p;
+}
+
+// Create a packet for anonymous login
+PACK *PackLoginWithAnonymous(char *hubname, char *username)
+{
+ PACK *p;
+ // Validate arguments
+ if (hubname == NULL || username == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "method", "login");
+ PackAddStr(p, "hubname", hubname);
+ PackAddStr(p, "username", username);
+ PackAddInt(p, "authtype", CLIENT_AUTHTYPE_ANONYMOUS);
+
+ return p;
+}
+
+// Create a packet for the additional connection
+PACK *PackAdditionalConnect(UCHAR *session_key)
+{
+ PACK *p;
+ // Validate arguments
+ if (session_key == NULL)
+ {
+ return NULL;
+ }
+
+ p = NewPack();
+ PackAddStr(p, "method", "additional_connect");
+ PackAddData(p, "session_key", session_key, SHA1_SIZE);
+
+ return p;
+}
+
+
+// Generate a RC4 key pair
+void GenerateRC4KeyPair(RC4_KEY_PAIR *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ Rand(k->ClientToServerKey, sizeof(k->ClientToServerKey));
+ Rand(k->ServerToClientKey, sizeof(k->ServerToClientKey));
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Protocol.h b/src/Cedar/Protocol.h
new file mode 100644
index 00000000..45827d82
--- /dev/null
+++ b/src/Cedar/Protocol.h
@@ -0,0 +1,270 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Protocol.h
+// Header of Protocol.c
+
+#ifndef PROTOCOL_H
+#define PROTOCOL_H
+
+// The parameters that will be passed to the certificate confirmation thread
+struct CHECK_CERT_THREAD_PROC
+{
+ CONNECTION *Connection;
+ X *ServerX;
+ CHECK_CERT_PROC *CheckCertProc;
+ bool UserSelected;
+ bool Exipred;
+ bool Ok;
+};
+
+// The parameters that will be passed to the secure device signature thread
+struct SECURE_SIGN_THREAD_PROC
+{
+ SECURE_SIGN_PROC *SecureSignProc;
+ CONNECTION *Connection;
+ SECURE_SIGN *SecureSign;
+ bool UserFinished;
+ bool Ok;
+};
+
+// Signature sending thread parameters
+struct SEND_SIGNATURE_PARAM
+{
+ char Hostname[MAX_PATH]; // Host name
+ UINT Port; // Port number
+ BUF *Buffer; // Packet contents
+};
+
+// Software update client callback
+typedef void (UPDATE_NOTIFY_PROC)(UPDATE_CLIENT *c, UINT latest_build, UINT64 latest_date, char *latest_ver, char *url, volatile bool *halt_flag, void *param);
+typedef bool (UPDATE_ISFOREGROUND_PROC)(UPDATE_CLIENT *c, void *param);
+
+// Configure the software update client
+struct UPDATE_CLIENT_SETTING
+{
+ bool DisableCheck; // Disable the update check
+ UINT LatestIgnoreBuild; // Ignore for earlier or identical to this build number
+};
+
+// Software update client
+struct UPDATE_CLIENT
+{
+ char FamilyName[MAX_SIZE]; // Product family name
+ char SoftwareName[MAX_SIZE]; // Software Name
+ wchar_t SoftwareTitle[MAX_SIZE]; // Software display name
+ char ClientId[128]; // Client ID
+ UINT MyBuild; // Build number of myself
+ UINT64 MyDate; // Build date of myself
+ char MyLanguage[MAX_SIZE]; // My language
+ UPDATE_CLIENT_SETTING Setting; // Setting
+ UINT LatestBuild; // Latest build number that was successfully acquired
+ volatile bool HaltFlag; // Halting flag
+ EVENT *HaltEvent; // Halting event
+ void *Param; // Any parameters
+ THREAD *Thread; // Thread
+ UPDATE_NOTIFY_PROC *Callback; // Callback function
+ UPDATE_ISFOREGROUND_PROC *IsForegroundCb; // Callback function for retrieving whether foreground
+};
+
+//// Constant related to updating of the software
+
+// Family
+#define UPDATE_FAMILY_NAME _SS("PRODUCT_FAMILY_NAME")
+
+// Software update server certificate hash
+#define UPDATE_SERVER_CERT_HASH "EFAC5FA0CDD14E0F864EED58A73C35D7E33B62F3"
+
+// URL
+#define UPDATE_SERVER_URL_GLOBAL "https://update-check.softether-network.net/update/update.aspx?family=%s&software=%s&mybuild=%u&lang=%s"
+#define UPDATE_SERVER_URL_CHINA "https://update-check.uxcom.jp/update/update.aspx?family=%s&software=%s&mybuild=%u&lang=%s"
+
+// Update check interval
+#define UPDATE_CHECK_INTERVAL_MIN (12 * 3600 * 1000)
+#define UPDATE_CHECK_INTERVAL_MAX (24 * 7200 * 1000)
+
+// Connection parameters
+#define UPDATE_CONNECT_TIMEOUT 5000
+#define UPDATE_COMM_TIMEOUT 5000
+
+
+
+// Function prototype
+UPDATE_CLIENT *NewUpdateClient(UPDATE_NOTIFY_PROC *cb, UPDATE_ISFOREGROUND_PROC *isforeground_cb, void *param, char *family_name, char *software_name, wchar_t *software_title, UINT my_build, UINT64 my_date, char *my_lang, UPDATE_CLIENT_SETTING *current_setting, char *client_id);
+void FreeUpdateClient(UPDATE_CLIENT *c);
+void UpdateClientThreadProc(THREAD *thread, void *param);
+void UpdateClientThreadMain(UPDATE_CLIENT *c);
+void UpdateClientThreadProcessResults(UPDATE_CLIENT *c, BUF *b);
+void SetUpdateClientSetting(UPDATE_CLIENT *c, UPDATE_CLIENT_SETTING *s);
+UINT64 ShortStrToDate64(char *str);
+
+
+bool ServerAccept(CONNECTION *c);
+bool ClientConnect(CONNECTION *c);
+SOCK *ClientConnectToServer(CONNECTION *c);
+SOCK *TcpIpConnect(char *hostname, UINT port, bool try_start_ssl, bool ssl_no_tls);
+SOCK *TcpIpConnectEx(char *hostname, UINT port, bool *cancel_flag, void *hWnd, UINT *nat_t_error_code, bool no_nat_t, bool try_start_ssl, bool ssl_no_tls);
+bool ClientUploadSignature(SOCK *s);
+bool ClientDownloadHello(CONNECTION *c, SOCK *s);
+bool ServerDownloadSignature(CONNECTION *c, char **error_detail_str);
+bool ServerUploadHello(CONNECTION *c);
+bool ClientUploadAuth(CONNECTION *c);
+SOCK *ClientConnectGetSocket(CONNECTION *c, bool additional_connect, bool no_tls);
+SOCK *TcpConnectEx2(char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd, bool try_start_ssl, bool ssl_no_tls);
+SOCK *TcpConnectEx3(char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd, bool no_nat_t, UINT *nat_t_error_code, bool try_start_ssl, bool ssl_no_tls);
+
+void InitProtocol();
+void FreeProtocol();
+
+
+
+POLICY *PackGetPolicy(PACK *p);
+void PackAddPolicy(PACK *p, POLICY *y);
+PACK *PackWelcome(SESSION *s);
+PACK *PackHello(void *random, UINT ver, UINT build, char *server_str);
+bool GetHello(PACK *p, void *random, UINT *ver, UINT *build, char *server_str, UINT server_str_size);
+PACK *PackLoginWithAnonymous(char *hubname, char *username);
+PACK *PackLoginWithPassword(char *hubname, char *username, void *secure_password);
+PACK *PackLoginWithPlainPassword(char *hubname, char *username, void *plain_password);
+PACK *PackLoginWithCert(char *hubname, char *username, X *x, void *sign, UINT sign_size);
+bool GetMethodFromPack(PACK *p, char *method, UINT size);
+bool GetHubnameAndUsernameFromPack(PACK *p, char *username, UINT username_size,
+ char *hubname, UINT hubname_size);
+PACK *PackAdditionalConnect(UCHAR *session_key);
+UINT GetAuthTypeFromPack(PACK *p);
+UINT GetProtocolFromPack(PACK *p);
+bool ParseWelcomeFromPack(PACK *p, char *session_name, UINT session_name_size,
+ char *connection_name, UINT connection_name_size,
+ POLICY **policy);
+
+
+bool ClientAdditionalConnect(CONNECTION *c, THREAD *t);
+SOCK *ClientAdditionalConnectToServer(CONNECTION *c);
+bool ClientUploadAuth2(CONNECTION *c, SOCK *s);
+bool GetSessionKeyFromPack(PACK *p, UCHAR *session_key, UINT *session_key_32);
+void GenerateRC4KeyPair(RC4_KEY_PAIR *k);
+
+SOCK *ProxyConnect(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, char *password, bool additional_connect);
+SOCK *ProxyConnectEx(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, char *password, bool additional_connect,
+ bool *cancel_flag, void *hWnd);
+SOCK *ProxyConnectEx2(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, char *password, bool additional_connect,
+ bool *cancel_flag, void *hWnd, UINT timeout);
+SOCK *SocksConnect(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, bool additional_connect);
+SOCK *SocksConnectEx(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, bool additional_connect,
+ bool *cancel_flag, void *hWnd);
+SOCK *SocksConnectEx2(CONNECTION *c, char *proxy_host_name, UINT proxy_port,
+ char *server_host_name, UINT server_port,
+ char *username, bool additional_connect,
+ bool *cancel_flag, void *hWnd, UINT timeout);
+bool SocksSendRequestPacket(CONNECTION *c, SOCK *s, UINT dest_port, IP *dest_ip, char *userid);
+bool SocksRecvResponsePacket(CONNECTION *c, SOCK *s);
+void CreateNodeInfo(NODE_INFO *info, CONNECTION *c);
+UINT SecureSign(SECURE_SIGN *sign, UINT device_id, char *pin);
+void ClientUploadNoop(CONNECTION *c);
+bool ClientCheckServerCert(CONNECTION *c, bool *expired);
+void ClientCheckServerCertThread(THREAD *thread, void *param);
+bool ClientSecureSign(CONNECTION *c, UCHAR *sign, UCHAR *random, X **x);
+void ClientSecureSignThread(THREAD *thread, void *param);
+UINT SecureWrite(UINT device_id, char *cert_name, X *x, char *key_name, K *k, char *pin);
+UINT SecureEnum(UINT device_id, char *pin, TOKEN_LIST **cert_list, TOKEN_LIST **key_list);
+UINT SecureDelete(UINT device_id, char *pin, char *cert_name, char *key_name);
+TOKEN_LIST *EnumHub(SESSION *s);
+UINT ChangePasswordAccept(CONNECTION *c, PACK *p);
+UINT ChangePassword(CEDAR *cedar, CLIENT_OPTION *o, char *hubname, char *username, char *old_pass, char *new_pass);
+void PackAddClientVersion(PACK *p, CONNECTION *c);
+void NodeInfoToStr(wchar_t *str, UINT size, NODE_INFO *info);
+void GenerateMachineUniqueHash(void *data);
+
+
+#endif // PROTOCOL_H
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Radius.c b/src/Cedar/Radius.c
new file mode 100644
index 00000000..24ac5751
--- /dev/null
+++ b/src/Cedar/Radius.c
@@ -0,0 +1,90 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Radius.c
+// Radius authentication module
+
+#include "CedarPch.h"
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Radius.h b/src/Cedar/Radius.h
new file mode 100644
index 00000000..681e2a56
--- /dev/null
+++ b/src/Cedar/Radius.h
@@ -0,0 +1,99 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Radius.h
+// Header of Radius.c
+
+#ifndef RADIUS_H
+#define RADIUS_H
+
+#define RADIUS_DEFAULT_PORT 1812 // The default port number
+#define RADIUS_RETRY_INTERVAL 500 // Retransmission interval
+#define RADIUS_RETRY_TIMEOUT (10 * 1000) // Time-out period
+
+
+#endif // RADIUS_H
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Remote.c b/src/Cedar/Remote.c
new file mode 100644
index 00000000..b8ab70b8
--- /dev/null
+++ b/src/Cedar/Remote.c
@@ -0,0 +1,448 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Remote.c
+// Remote Procedure Call
+
+#include "CedarPch.h"
+
+// End of RPC
+void EndRpc(RPC *rpc)
+{
+ RpcFree(rpc);
+}
+
+// Release the RPC
+void RpcFree(RPC *rpc)
+{
+ // Validate arguments
+ if (rpc == NULL)
+ {
+ return;
+ }
+
+ Disconnect(rpc->Sock);
+ ReleaseSock(rpc->Sock);
+
+ DeleteLock(rpc->Lock);
+
+ Free(rpc);
+}
+
+// Get error
+UINT RpcGetError(PACK *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return ERR_DISCONNECTED;
+ }
+
+ return PackGetInt(p, "error_code");
+}
+
+// Error checking
+bool RpcIsOk(PACK *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return false;
+ }
+
+ if (PackGetInt(p, "error") == 0)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// Error code setting
+void RpcError(PACK *p, UINT err)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ PackAddInt(p, "error", 1);
+ PackAddInt(p, "error_code", err);
+}
+
+// Start the RPC dispatcher
+PACK *CallRpcDispatcher(RPC *r, PACK *p)
+{
+ char func_name[MAX_SIZE];
+ // Validate arguments
+ if (r == NULL || p == NULL)
+ {
+ return NULL;
+ }
+
+ if (PackGetStr(p, "function_name", func_name, sizeof(func_name)) == false)
+ {
+ return NULL;
+ }
+
+ return r->Dispatch(r, func_name, p);
+}
+
+// Wait for the next RPC call
+bool RpcRecvNextCall(RPC *r)
+{
+ UINT size;
+ void *tmp;
+ SOCK *s;
+ BUF *b;
+ PACK *p;
+ PACK *ret;
+ // Validate arguments
+ if (r == NULL)
+ {
+ return false;
+ }
+
+ s = r->Sock;
+
+ if (RecvAll(s, &size, sizeof(UINT), s->SecureMode) == false)
+ {
+ return false;
+ }
+
+ size = Endian32(size);
+
+ if (size > MAX_PACK_SIZE)
+ {
+ return false;
+ }
+
+ tmp = MallocEx(size, true);
+
+ if (RecvAll(s, tmp, size, s->SecureMode) == false)
+ {
+ Free(tmp);
+ return false;
+ }
+
+ b = NewBuf();
+ WriteBuf(b, tmp, size);
+ SeekBuf(b, 0, 0);
+ Free(tmp);
+
+ p = BufToPack(b);
+ FreeBuf(b);
+
+ if (p == NULL)
+ {
+ return false;
+ }
+
+ ret = CallRpcDispatcher(r, p);
+ FreePack(p);
+
+ if (ret == NULL)
+ {
+ ret = PackError(ERR_NOT_SUPPORTED);
+ }
+
+ b = PackToBuf(ret);
+ FreePack(ret);
+
+ size = Endian32(b->Size);
+ SendAdd(s, &size, sizeof(UINT));
+ SendAdd(s, b->Buf, b->Size);
+
+ if (SendNow(s, s->SecureMode) == false)
+ {
+ FreeBuf(b);
+ return false;
+ }
+
+ FreeBuf(b);
+
+ return true;
+}
+
+// RPC server operation
+void RpcServer(RPC *r)
+{
+ SOCK *s;
+ // Validate arguments
+ if (r == NULL)
+ {
+ return;
+ }
+
+ s = r->Sock;
+
+ while (true)
+ {
+ // Wait for the next RPC call
+ if (RpcRecvNextCall(r) == false)
+ {
+ // Communication error
+ break;
+ }
+ }
+}
+
+// RPC call
+PACK *RpcCall(RPC *r, char *function_name, PACK *p)
+{
+ PACK *ret;
+ UINT num_retry = 0;
+ UINT err = 0;
+ // Validate arguments
+ if (r == NULL || function_name == NULL)
+ {
+ return NULL;
+ }
+
+// Debug("RpcCall: %s\n", function_name);
+
+ Lock(r->Lock);
+ {
+ if (p == NULL)
+ {
+ p = NewPack();
+ }
+
+ PackAddStr(p, "function_name", function_name);
+
+RETRY:
+ err = 0;
+ ret = RpcCallInternal(r, p);
+
+ if (ret == NULL)
+ {
+ if (r->IsVpnServer && r->Sock != NULL)
+ {
+ if (num_retry < 1)
+ {
+ num_retry++;
+
+ // Attempt to reconnect the RPC to the VPN Server
+ err = AdminReconnect(r);
+
+ if (err == ERR_NO_ERROR)
+ {
+ goto RETRY;
+ }
+ }
+ }
+ }
+
+ FreePack(p);
+
+ if (ret == NULL)
+ {
+ if (err == 0)
+ {
+ err = ERR_DISCONNECTED;
+ }
+
+ ret = PackError(err);
+ PackAddInt(ret, "error_code", err);
+ }
+ }
+ Unlock(r->Lock);
+
+ return ret;
+}
+
+// RPC internal call
+PACK *RpcCallInternal(RPC *r, PACK *p)
+{
+ BUF *b;
+ UINT size;
+ PACK *ret;
+ void *tmp;
+ // Validate arguments
+ if (r == NULL || p == NULL)
+ {
+ return NULL;
+ }
+
+ if (r->Sock == NULL)
+ {
+ return NULL;
+ }
+
+ b = PackToBuf(p);
+
+ size = Endian32(b->Size);
+ SendAdd(r->Sock, &size, sizeof(UINT));
+ SendAdd(r->Sock, b->Buf, b->Size);
+ FreeBuf(b);
+
+ if (SendNow(r->Sock, r->Sock->SecureMode) == false)
+ {
+ return NULL;
+ }
+
+ if (RecvAll(r->Sock, &size, sizeof(UINT), r->Sock->SecureMode) == false)
+ {
+ return NULL;
+ }
+
+ size = Endian32(size);
+ if (size > MAX_PACK_SIZE)
+ {
+ return NULL;
+ }
+
+ tmp = MallocEx(size, true);
+ if (RecvAll(r->Sock, tmp, size, r->Sock->SecureMode) == false)
+ {
+ Free(tmp);
+ return NULL;
+ }
+
+ b = NewBuf();
+ WriteBuf(b, tmp, size);
+ SeekBuf(b, 0, 0);
+ Free(tmp);
+
+ ret = BufToPack(b);
+ if (ret == NULL)
+ {
+ FreeBuf(b);
+ return NULL;
+ }
+
+ FreeBuf(b);
+
+ return ret;
+}
+
+// Start the RPC server
+RPC *StartRpcServer(SOCK *s, RPC_DISPATCHER *dispatch, void *param)
+{
+ RPC *r;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ r = ZeroMallocEx(sizeof(RPC), true);
+ r->Sock = s;
+ r->Param = param;
+ r->Lock = NewLock();
+ AddRef(s->ref);
+
+ r->ServerMode = true;
+ r->Dispatch = dispatch;
+
+ // Name generation
+ Format(r->Name, sizeof(r->Name), "RPC-%u", s->socket);
+
+ return r;
+}
+
+// Start the RPC client
+RPC *StartRpcClient(SOCK *s, void *param)
+{
+ RPC *r;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ r = ZeroMalloc(sizeof(RPC));
+ r->Sock = s;
+ r->Param = param;
+ r->Lock = NewLock();
+ AddRef(s->ref);
+
+ r->ServerMode = false;
+
+ return r;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Remote.h b/src/Cedar/Remote.h
new file mode 100644
index 00000000..2081e70b
--- /dev/null
+++ b/src/Cedar/Remote.h
@@ -0,0 +1,127 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Remote.h
+// Header of Remote.c
+
+#ifndef REMOTE_H
+#define REMOTE_H
+
+// RPC execution function
+typedef PACK *(RPC_DISPATCHER)(RPC *r, char *function_name, PACK *p);
+
+// RPC object
+struct RPC
+{
+ SOCK *Sock; // Socket
+ bool ServerMode; // Server mode
+ RPC_DISPATCHER *Dispatch; // Execution routine
+ void *Param; // Parameters
+ bool ServerAdminMode; // Server management mode
+ char HubName[MAX_HUBNAME_LEN + 1]; // Managing HUB name
+ char Name[MAX_SIZE]; // RPC session name
+ LOCK *Lock; // Lock
+ bool IsVpnServer; // Whether VPN Server management RPC
+ CLIENT_OPTION VpnServerClientOption;
+ char VpnServerHubName[MAX_HUBNAME_LEN + 1];
+ UCHAR VpnServerHashedPassword[SHA1_SIZE];
+ char VpnServerClientName[MAX_PATH];
+};
+
+// Function prototype
+RPC *StartRpcClient(SOCK *s, void *param);
+RPC *StartRpcServer(SOCK *s, RPC_DISPATCHER *dispatch, void *param);
+PACK *RpcCallInternal(RPC *r, PACK *p);
+PACK *RpcCall(RPC *r, char *function_name, PACK *p);
+void RpcServer(RPC *r);
+bool RpcRecvNextCall(RPC *r);
+PACK *CallRpcDispatcher(RPC *r, PACK *p);
+void RpcError(PACK *p, UINT err);
+bool RpcIsOk(PACK *p);
+UINT RpcGetError(PACK *p);
+void EndRpc(RPC *rpc);
+void RpcFree(RPC *rpc);
+
+#endif // REMOTE_H
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/SM.c b/src/Cedar/SM.c
new file mode 100644
index 00000000..1aba59e2
--- /dev/null
+++ b/src/Cedar/SM.c
@@ -0,0 +1,20505 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// SM.c
+// VPN Server Manager for Win32
+
+#include <GlobalConst.h>
+
+#ifdef WIN32
+
+#define SM_C
+#define CM_C
+#define NM_C
+
+#define _WIN32_WINNT 0x0502
+#define WINVER 0x0502
+#include <winsock2.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <wininet.h>
+#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+#include "CMInner.h"
+#include "SMInner.h"
+#include "NMInner.h"
+#include "EMInner.h"
+#include "../PenCore/resource.h"
+
+// Global variable
+static SM *sm = NULL;
+static bool link_create_now = false;
+
+
+// Proxy Settings dialog initialization
+void SmProxyDlgInit(HWND hWnd, INTERNET_SETTING *t)
+{
+ // Validate arguments
+ if (hWnd == NULL || t == NULL)
+ {
+ return;
+ }
+
+ Check(hWnd, R_DIRECT_TCP, t->ProxyType == PROXY_DIRECT);
+ Check(hWnd, R_HTTPS, t->ProxyType == PROXY_HTTP);
+ Check(hWnd, R_SOCKS, t->ProxyType == PROXY_SOCKS);
+
+ SmProxyDlgUpdate(hWnd, t);
+}
+
+// Proxy Settings dialog update
+void SmProxyDlgUpdate(HWND hWnd, INTERNET_SETTING *t)
+{
+ bool ok = false;
+ // Validate arguments
+ if (hWnd == NULL || t == NULL)
+ {
+ return;
+ }
+
+ if (t->ProxyType == PROXY_DIRECT)
+ {
+ ok = true;
+ }
+ else
+ {
+ if (IsEmptyStr(t->ProxyHostName) == false &&
+ t->ProxyPort != 0)
+ {
+ ok = true;
+ }
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+
+ SetEnable(hWnd, B_PROXY_CONFIG, !IsChecked(hWnd, R_DIRECT_TCP));
+}
+
+// Proxy settings generic dialog procedure
+UINT SmProxyDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ INTERNET_SETTING *t = (INTERNET_SETTING *)param;
+ CLIENT_OPTION a;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmProxyDlgInit(hWnd, t);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ EndDialog(hWnd, 1);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case R_DIRECT_TCP:
+ case R_HTTPS:
+ case R_SOCKS:
+ if (IsChecked(hWnd, R_HTTPS))
+ {
+ t->ProxyType = PROXY_HTTP;
+ }
+ else if (IsChecked(hWnd, R_SOCKS))
+ {
+ t->ProxyType = PROXY_SOCKS;
+ }
+ else
+ {
+ t->ProxyType = PROXY_DIRECT;
+ }
+
+ SmProxyDlgUpdate(hWnd, t);
+ break;
+
+ case B_PROXY_CONFIG:
+ Zero(&a, sizeof(a));
+
+ a.ProxyType = t->ProxyType;
+ StrCpy(a.ProxyName, sizeof(a.ProxyName), t->ProxyHostName);
+ a.ProxyPort = t->ProxyPort;
+ StrCpy(a.ProxyUsername, sizeof(a.ProxyUsername), t->ProxyUsername);
+ StrCpy(a.ProxyPassword, sizeof(a.ProxyPassword), t->ProxyPassword);
+
+ if (CmProxyDlg(hWnd, &a))
+ {
+ t->ProxyType = a.ProxyType;
+ StrCpy(t->ProxyHostName, sizeof(t->ProxyHostName), a.ProxyName);
+ t->ProxyPort = a.ProxyPort;
+ StrCpy(t->ProxyUsername, sizeof(t->ProxyUsername), a.ProxyUsername);
+ StrCpy(t->ProxyPassword, sizeof(t->ProxyPassword), a.ProxyPassword);
+ }
+
+ SmProxyDlgUpdate(hWnd, t);
+
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Proxy Settings generic dialog
+bool SmProxy(HWND hWnd, INTERNET_SETTING *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return false;
+ }
+
+ return Dialog(hWnd, D_SM_PROXY, SmProxyDlg, t);
+}
+
+// VPN Azure dialog procedure
+UINT SmAzureDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_AZURE *a = (SM_AZURE *)param;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmAzureDlgOnInit(hWnd, a);
+
+ SetTimer(hWnd, 1, 1000, NULL);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_CHANGE:
+ if (SmDDns(hWnd, a->s, false, true))
+ {
+ SmAzureDlgRefresh(hWnd, a);
+ }
+ break;
+
+ case B_WEB:
+ MsExecute(_SS("SE_VPNAZURE_URL"), NULL);
+ break;
+
+ case R_ENABLE:
+ case R_DISABLE:
+ if (IsChecked(hWnd, R_ENABLE) || IsChecked(hWnd, R_DISABLE))
+ {
+ Enable(hWnd, IDCANCEL);
+ EnableClose(hWnd);
+ }
+
+ SmAzureSetStatus(hWnd, a);
+ break;
+
+ case IDOK:
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ if (IsEnable(hWnd, 0))
+ {
+ KillTimer(hWnd, 1);
+
+ SmAzureDlgRefresh(hWnd, a);
+
+ SetTimer(hWnd, 1, 1000, NULL);
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Set the status
+void SmAzureSetStatus(HWND hWnd, SM_AZURE *a)
+{
+ RPC_AZURE_STATUS st;
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+ Zero(&st, sizeof(st));
+
+ st.IsEnabled = IsChecked(hWnd, R_ENABLE);
+
+ if (CALL(hWnd, ScSetAzureStatus(a->s->Rpc, &st)) == false)
+ {
+ EndDialog(hWnd, 0);
+ return;
+ }
+
+ SmAzureDlgRefresh(hWnd, a);
+}
+
+// Initialize the dialog
+void SmAzureDlgOnInit(HWND hWnd, SM_AZURE *a)
+{
+ RPC_AZURE_STATUS st;
+ UINT current_lang_id;
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_AZURE);
+
+ DlgFont(hWnd, S_TITLE, 14, true);
+ DlgFont(hWnd, R_ENABLE, 0, true);
+
+ SetFont(hWnd, E_HOST, GetFont("Verdana", 10, false, false, false, false));
+
+ current_lang_id = GetCurrentLangId();
+
+ // Japanese
+ SetShow(hWnd, S_BMP_JA, current_lang_id == SE_LANG_JAPANESE);
+
+ // Chinese
+ SetShow(hWnd, S_BMP_CN, current_lang_id == SE_LANG_CHINESE_ZH);
+
+ // Other languages
+ SetShow(hWnd, S_BMP_EN, (current_lang_id != SE_LANG_JAPANESE) && (current_lang_id != SE_LANG_CHINESE_ZH));
+
+ // Apply the current settings
+ Zero(&st, sizeof(st));
+
+ if (CALL(hWnd, ScGetAzureStatus(a->s->Rpc, &st)) == false)
+ {
+ EndDialog(hWnd, 0);
+ return;
+ }
+
+ if (a->OnSetup == false || st.IsEnabled)
+ {
+ Check(hWnd, R_ENABLE, st.IsEnabled);
+ Check(hWnd, R_DISABLE, !st.IsEnabled);
+ }
+ else
+ {
+ Disable(hWnd, IDCANCEL);
+ DisableClose(hWnd);
+ }
+
+ SmAzureDlgRefresh(hWnd, a);
+}
+
+// Update the dialog
+void SmAzureDlgRefresh(HWND hWnd, SM_AZURE *a)
+{
+ RPC_AZURE_STATUS st;
+ DDNS_CLIENT_STATUS ddns;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+ Zero(&st, sizeof(st));
+ Zero(&ddns, sizeof(ddns));
+
+ if (CALL(hWnd, ScGetAzureStatus(a->s->Rpc, &st)) == false)
+ {
+ EndDialog(hWnd, 0);
+ return;
+ }
+
+ if (CALL(hWnd, ScGetDDnsClientStatus(a->s->Rpc, &ddns)) == false)
+ {
+ EndDialog(hWnd, 0);
+ return;
+ }
+
+ if (st.IsEnabled == false)
+ {
+ SetText(hWnd, S_STATUS, _UU("SM_AZURE_STATUS_NOT_CONNECTED"));
+ Disable(hWnd, S_STATUS);
+ }
+ else
+ {
+ SetText(hWnd, S_STATUS, (st.IsConnected ? _UU("SM_AZURE_STATUS_CONNECTED") : _UU("SM_AZURE_STATUS_NOT_CONNECTED")));
+ Enable(hWnd, S_STATUS);
+ }
+
+ SetShow(hWnd, S_HOSTNAME_BORDER, st.IsEnabled);
+ SetShow(hWnd, S_HOSTNAME_INFO, st.IsEnabled);
+ SetShow(hWnd, B_CHANGE, st.IsEnabled);
+
+ if (st.IsEnabled == false || IsEmptyStr(ddns.CurrentHostName))
+ {
+ Hide(hWnd, E_HOST);
+ }
+ else
+ {
+ StrCpy(tmp, sizeof(tmp), ddns.CurrentHostName);
+ StrCat(tmp, sizeof(tmp), AZURE_DOMAIN_SUFFIX);
+
+ SetTextA(hWnd, E_HOST, tmp);
+
+ Show(hWnd, E_HOST);
+ }
+}
+
+// VPN Azure Setup screen
+void SmAzure(HWND hWnd, SM_SERVER *s, bool on_setup)
+{
+ SM_AZURE a;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Zero(&a, sizeof(a));
+
+ a.s = s;
+ a.OnSetup = on_setup;
+
+ Dialog(hWnd, D_SM_AZURE, SmAzureDlg, &a);
+}
+
+// Notification screen about the bridge in VM
+UINT SmVmBridgeDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ DlgFont(hWnd, S_TITLE, 14, true);
+ SetIcon(hWnd, 0, ICO_NIC_ONLINE);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Setting screen of VPN over ICMP, etc.
+void SmSpecialListener(HWND hWnd, SM_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_SM_SPECIALLISTENER, SmSpecialListenerDlg, s);
+}
+UINT SmSpecialListenerDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_SERVER *s = (SM_SERVER *)param;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmSpecialListenerDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ SmSpecialListenerDlgOnOk(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+void SmSpecialListenerDlgInit(HWND hWnd, SM_SERVER *s)
+{
+ RPC_SPECIAL_LISTENER t;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_SPECIALLISTENER);
+
+ DlgFont(hWnd, S_TITLE, 14, true);
+ DlgFont(hWnd, S_1, 0, true);
+ DlgFont(hWnd, R_OVER_ICMP, 0, true);
+ DlgFont(hWnd, R_OVER_DNS, 0, true);
+
+ Zero(&t, sizeof(t));
+
+ if (CALL(hWnd, ScGetSpecialListener(s->Rpc, &t)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ Check(hWnd, R_OVER_ICMP, t.VpnOverIcmpListener);
+ Check(hWnd, R_OVER_DNS, t.VpnOverDnsListener);
+}
+void SmSpecialListenerDlgOnOk(HWND hWnd, SM_SERVER *s)
+{
+ RPC_SPECIAL_LISTENER t;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+
+ t.VpnOverIcmpListener = IsChecked(hWnd, R_OVER_ICMP);
+ t.VpnOverDnsListener = IsChecked(hWnd, R_OVER_DNS);
+
+ if (CALL(hWnd, ScSetSpecialListener(s->Rpc, &t)) == false)
+ {
+ return;
+ }
+
+ EndDialog(hWnd, 1);
+}
+
+
+// DDNS dialog
+bool SmDDns(HWND hWnd, SM_SERVER *s, bool silent, bool no_change_cert)
+{
+ SM_DDNS d;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ Zero(&d, sizeof(d));
+ d.s = s;
+ d.Silent = silent;
+ d.NoChangeCert = no_change_cert;
+
+ Dialog(hWnd, D_SM_DDNS, SmDDnsDlg, &d);
+
+ return d.Changed;
+}
+UINT SmDDnsDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_DDNS *d = (SM_DDNS *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmDDnsDlgInit(hWnd, d);
+
+ SetTimer(hWnd, 1, 1000, NULL);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_NEWHOST:
+ SmDDnsDlgUpdate(hWnd, d);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ SmDDnsDlgOnOk(hWnd, d);
+ break;
+
+ case B_RESTORE:
+ // Restore to original
+ if (d->Status.Err_IPv4 == ERR_NO_ERROR || d->Status.Err_IPv6 == ERR_NO_ERROR)
+ {
+ SetTextA(hWnd, E_NEWHOST, d->Status.CurrentHostName);
+ SmDDnsDlgUpdate(hWnd, d);
+ FocusEx(hWnd, E_NEWHOST);
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case B_DISABLE:
+ d->DoNotPoll = true;
+
+ OnceMsg(hWnd, _UU("SM_DISABLE_DDNS_HINT_CAPTION"), _UU("SM_DISABLE_DDNS_HINT"), false, ICO_INFORMATION);
+
+ d->DoNotPoll = false;
+ break;
+
+ case B_HINT:
+ // Hint
+ if (d->Status.Err_IPv4 == ERR_NO_ERROR || d->Status.Err_IPv6 == ERR_NO_ERROR)
+ {
+ wchar_t tmp[MAX_SIZE * 4];
+ wchar_t ipv4[MAX_SIZE], ipv6[MAX_SIZE];
+
+ StrToUni(ipv4, sizeof(ipv4), d->Status.CurrentIPv4);
+ StrToUni(ipv6, sizeof(ipv6), d->Status.CurrentIPv6);
+
+ if (UniIsEmptyStr(ipv4))
+ {
+ UniStrCpy(ipv4, sizeof(ipv4), _UU("SM_DDNS_FQDN_EMPTY"));
+ }
+
+ if (UniIsEmptyStr(ipv6))
+ {
+ UniStrCpy(ipv6, sizeof(ipv6), _UU("SM_DDNS_FQDN_EMPTY"));
+ }
+
+ UniFormat(tmp, sizeof(tmp),
+ _UU("SM_DDNS_OK_MSG"),
+ d->Status.CurrentHostName, d->Status.DnsSuffix,
+ ipv4, ipv6,
+ d->Status.CurrentHostName, d->Status.DnsSuffix,
+ d->Status.CurrentHostName, d->Status.DnsSuffix);
+
+ d->DoNotPoll = true;
+
+ OnceMsg(hWnd, _UU("SM_DDNS_OK_TITLE"), tmp, false, ICO_DISPLAY);
+
+ d->DoNotPoll = false;
+ }
+ break;
+
+ case B_PROXY:
+ // Proxy settings
+ if (true)
+ {
+ INTERNET_SETTING t;
+
+ if (CALL(hWnd, ScGetDDnsInternetSetting(d->s->Rpc, &t)))
+ {
+ if (SmProxy(hWnd, &t))
+ {
+ if (CALL(hWnd, ScSetDDnsInternetSetting(d->s->Rpc, &t)))
+ {
+ SmDDnsRefresh(hWnd, d);
+ }
+ }
+ }
+ }
+ break;
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ if (IsEnable(hWnd, 0))
+ {
+ KillTimer(hWnd, 1);
+
+ SmDDnsRefresh(hWnd, d);
+
+ SetTimer(hWnd, 1, 1000, NULL);
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ if (d->Changed || d->Silent)
+ {
+ // Check the server certificate if the host name has been changed
+ RPC_KEY_PAIR t;
+ char fqdn[MAX_SIZE];
+ bool is_vgs_enabled = false;
+
+
+ StrCpy(fqdn, sizeof(fqdn), d->Status.CurrentFqdn);
+
+ if (IsEmptyStr(fqdn) == false)
+ {
+ Zero(&t, sizeof(t));
+ if (ScGetServerCert(d->s->Rpc, &t) == ERR_NO_ERROR)
+ {
+ if (t.Cert != NULL && t.Cert->root_cert && t.Cert->subject_name != NULL && is_vgs_enabled == false)
+ {
+ char cn[MAX_SIZE];
+
+ UniToStr(cn, sizeof(cn), t.Cert->subject_name->CommonName);
+
+ if ((StrCmpi(cn, fqdn) != 0) && (d->NoChangeCert == false))
+ {
+ // Confirm whether the user want to replace the server certificate
+ if (d->Silent || (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO,
+ _UU("SM_DDNS_SERVER_CERT_MSG"),
+ fqdn, fqdn) == IDYES))
+ {
+ // Re-generate the server certificate
+ RPC_TEST tt;
+
+ Zero(&tt, sizeof(tt));
+
+ StrCpy(tt.StrValue, sizeof(tt.StrValue), fqdn);
+
+ SetText(hWnd, IDCANCEL, _UU("CM_VLAN_INSTALLING"));
+ Refresh(DlgItem(hWnd, IDCANCEL));
+ Refresh(hWnd);
+ DoEvents(NULL);
+
+ if (CALL(hWnd, ScRegenerateServerCert(d->s->Rpc, &tt)))
+ {
+ // Confirm whether the user want to save the server certificate
+ if ((d->Silent == false) && (
+ MsgBoxEx(hWnd, MB_ICONINFORMATION | MB_YESNO,
+ _UU("SM_DDNS_SERVER_CERT_OK"),
+ fqdn) == IDYES))
+ {
+ // Get the server certificate
+ RPC_KEY_PAIR t2;
+
+ Zero(&t2, sizeof(t2));
+ if (CALL(hWnd, ScGetServerCert(d->s->Rpc, &t2)))
+ {
+ wchar_t *name;
+ wchar_t defname[MAX_PATH];
+
+ StrToUni(defname, sizeof(defname), fqdn);
+ UniStrCat(defname, sizeof(defname), L".cer");
+
+ name = SaveDlg(hWnd, _UU("DLG_CERT_FILES"), _UU("DLG_SAVE_CERT"), defname, L".cer");
+
+ if (name != NULL)
+ {
+ if (XToFileW(t2.Cert, name, true))
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("DLG_CERT_SAVE_OK"));
+ }
+ else
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("DLG_CERT_SAVE_ERROR"));
+ }
+
+ Free(name);
+ }
+
+ FreeRpcKeyPair(&t2);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ FreeRpcKeyPair(&t);
+ }
+ }
+ }
+
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+void SmDDnsDlgInit(HWND hWnd, SM_DDNS *d)
+{
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ d->DoNotPoll = false;
+
+ SetIcon(hWnd, 0, ICO_DISPLAY);
+
+ DlgFont(hWnd, S_TITLE, 14, true);
+
+ DlgFont(hWnd, S_BOLD, 0, true);
+ DlgFont(hWnd, S_STATUS3, 0, true);
+ DlgFont(hWnd, S_STATUS4, 0, true);
+ DlgFont(hWnd, S_STATUS5, 0, true);
+ DlgFont(hWnd, S_STATUS6, 0, true);
+
+ SetFont(hWnd, S_SUFFIX, GetFont("Verdana", 10, false, false, false, false));
+ SetFont(hWnd, E_NEWHOST, GetFont("Verdana", 10, false, false, false, false));
+
+ SetFont(hWnd, E_HOST, GetFont((MsIsWinXPOrGreater() ? "Verdana" : NULL), 10, false, false, false, false));
+ SetFont(hWnd, E_IPV4, GetFont((MsIsWinXPOrGreater() ? "Verdana" : NULL), 10, false, false, false, false));
+ SetFont(hWnd, E_IPV6, GetFont((MsIsWinXPOrGreater() ? "Verdana" : NULL), 10, false, false, false, false));
+
+ DlgFont(hWnd, IDOK, 0, true);
+
+ if (d->Silent)
+ {
+ Hide(hWnd, B_DISABLE);
+ }
+
+ Hide(hWnd, B_PROXY);
+
+ SmDDnsRefresh(hWnd, d);
+}
+
+void SmDDnsRefresh(HWND hWnd, SM_DDNS *d)
+{
+ DDNS_CLIENT_STATUS st;
+ INTERNET_SETTING t;
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ if (d->DoNotPoll)
+ {
+ return;
+ }
+
+ Zero(&st, sizeof(st));
+ Zero(&t, sizeof(t));
+
+ // Get the status
+ if (CALL(hWnd, ScGetDDnsClientStatus(d->s->Rpc, &st)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ ScGetDDnsInternetSetting(d->s->Rpc, &t);
+
+ Copy(&d->Status, &st, sizeof(st));
+
+ if (IsEmptyStr(st.CurrentFqdn) == false)
+ {
+ SetTextA(hWnd, E_HOST, st.CurrentFqdn);
+ }
+ else
+ {
+ SetText(hWnd, E_HOST, _UU("SM_DDNS_FQDN_EMPTY"));
+ }
+
+ if (st.Err_IPv4 == ERR_NO_ERROR)
+ {
+ SetTextA(hWnd, E_IPV4, st.CurrentIPv4);
+ }
+ else
+ {
+ if (st.Err_IPv4 == ERR_CONNECT_FAILED)
+ {
+ SetText(hWnd, E_IPV4, _UU("SM_DDNS_IPV4_ERROR"));
+ }
+ else
+ {
+ SetText(hWnd, E_IPV4, _E(st.Err_IPv4));
+ }
+ }
+
+ if (st.Err_IPv6 == ERR_NO_ERROR)
+ {
+ SetTextA(hWnd, E_IPV6, st.CurrentIPv6);
+ }
+ else
+ {
+ if (st.Err_IPv6 == ERR_CONNECT_FAILED)
+ {
+ SetText(hWnd, E_IPV6, _UU("SM_DDNS_IPV6_ERROR"));
+ }
+ else
+ {
+ SetText(hWnd, E_IPV6, _E(st.Err_IPv6));
+ }
+ }
+
+ if (st.Err_IPv4 == ERR_NO_ERROR || st.Err_IPv6 == ERR_NO_ERROR)
+ {
+ if (IsEmptyStr(st.DnsSuffix) == false)
+ {
+ SetTextA(hWnd, S_SUFFIX, st.DnsSuffix);
+ }
+
+ Enable(hWnd, S_STATUS6);
+ Enable(hWnd, E_NEWHOST);
+ Enable(hWnd, S_SUFFIX);
+ Enable(hWnd, S_STATUS7);
+ Enable(hWnd, B_HINT);
+ }
+ else
+ {
+ SetTextA(hWnd, S_SUFFIX, "");
+
+ Disable(hWnd, S_STATUS6);
+ Disable(hWnd, E_NEWHOST);
+ Disable(hWnd, S_SUFFIX);
+ Disable(hWnd, S_STATUS7);
+ Disable(hWnd, B_HINT);
+ }
+
+ if (GetCapsBool(d->s->CapsList, "b_support_ddns_proxy"))
+ {
+ // Show the proxy button
+ Show(hWnd, B_PROXY);
+ }
+ else
+ {
+ // Hide the proxy button
+ Hide(hWnd, B_PROXY);
+ }
+
+ SmDDnsDlgUpdate(hWnd, d);
+
+ if (d->Flag == false)
+ {
+ d->Flag = true;
+ }
+
+ if (IsEmptyStr(st.CurrentHostName) == false)
+ {
+ if (d->HostnameSetFlag == false)
+ {
+ d->HostnameSetFlag = true;
+
+ SetTextA(hWnd, E_NEWHOST, st.CurrentHostName);
+
+ FocusEx(hWnd, E_NEWHOST);
+ }
+ }
+}
+void SmDDnsDlgUpdate(HWND hWnd, SM_DDNS *d)
+{
+ char tmp[MAX_SIZE];
+ bool b = false;
+
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ if (GetTxtA(hWnd, E_NEWHOST, tmp, sizeof(tmp)))
+ {
+ Trim(tmp);
+
+ // Get whether the host name have changed
+ if (IsEmptyStr(tmp) == false)
+ {
+ if (StrCmpi(d->Status.CurrentHostName, tmp) != 0)
+ {
+ if (d->Status.Err_IPv4 == ERR_NO_ERROR || d->Status.Err_IPv6 == ERR_NO_ERROR)
+ {
+ b = true;
+ }
+ }
+ }
+ }
+
+ SetEnable(hWnd, IDOK, b);
+ SetEnable(hWnd, B_RESTORE, b);
+}
+void SmDDnsDlgOnOk(HWND hWnd, SM_DDNS *d)
+{
+ RPC_TEST t;
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ GetTxtA(hWnd, E_NEWHOST, t.StrValue, sizeof(t.StrValue));
+
+ if (CALL(hWnd, ScChangeDDnsClientHostname(d->s->Rpc, &t)) == false)
+ {
+ return;
+ }
+
+ d->Changed = true;
+
+ SmDDnsRefresh(hWnd, d);
+ FocusEx(hWnd, E_NEWHOST);
+
+ MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("SM_DDNS_OK_MSG2"), t.StrValue);
+ FocusEx(hWnd, E_NEWHOST);
+}
+
+// Open the OpenVPN dialog
+void SmOpenVpn(HWND hWnd, SM_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_SM_OPENVPN, SmOpenVpnDlg, s);
+}
+
+// OpenVPN dialog
+UINT SmOpenVpnDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_SERVER *s = (SM_SERVER *)param;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmOpenVpnDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case R_OPENVPN:
+ case E_UDP:
+ case R_SSTP:
+ SmOpenVpnDlgUpdate(hWnd, s);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ SmOpenVpnDlgOnOk(hWnd, s, false);
+ break;
+
+ case B_DEFAULT:
+ ToStr(tmp, OPENVPN_UDP_PORT);
+ SetTextA(hWnd, E_UDP, tmp);
+ FocusEx(hWnd, E_UDP);
+ break;
+
+ case B_CONFIG:
+ // Create an OpenVPN configuration
+ {
+ OPENVPN_SSTP_CONFIG t2;
+ RPC_READ_LOG_FILE t;
+
+ Zero(&t2, sizeof(t2));
+
+ if (CALL(hWnd, ScGetOpenVpnSstpConfig(s->Rpc, &t2)))
+ {
+ if (t2.EnableOpenVPN == false)
+ {
+ // Enable the OpenVPN first
+ SmOpenVpnDlgOnOk(hWnd, s, true);
+
+ Disable(hWnd, IDCANCEL);
+ }
+ }
+ else
+ {
+ break;
+ }
+
+ Zero(&t, sizeof(t));
+
+ if (CALL(hWnd, ScMakeOpenVpnConfigFile(s->Rpc, &t)))
+ {
+ // Generate a file name
+ wchar_t filename[MAX_SIZE];
+ char safe_hostname[MAX_SIZE];
+ SYSTEMTIME st;
+ wchar_t *dst;
+
+ MakeSafeFileName(safe_hostname, sizeof(safe_hostname), s->ServerName);
+
+ LocalTime(&st);
+
+ UniFormat(filename, sizeof(filename),
+ L"OpenVPN_Sample_Config_%S_%04u%02u%02u_%02u%02u%02u.zip",
+ safe_hostname,
+ st.wYear, st.wMonth, st.wDay,
+ st.wHour, st.wMinute, st.wSecond);
+
+ dst = SaveDlg(hWnd, _UU("DLG_ZIP_FILER"), _UU("DLG_SAVE_OPENVPN_CONFIG"),
+ filename, L".zip");
+
+ if (dst != NULL)
+ {
+ // Save
+ if (DumpBufW(t.Buffer, dst) == false)
+ {
+ // Failure
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("SM_OPENVPN_CONFIG_SAVE_NG"), dst);
+ }
+ else
+ {
+ // Success
+ if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("SM_OPENVPN_CONFIG_SAVE_OK"), dst) == IDYES)
+ {
+ if (MsExecuteW(dst, L"") == false)
+ {
+ MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("SM_OPENVPN_CONFIG_OPEN_NG"), dst);
+ }
+ }
+ }
+
+ Free(dst);
+ }
+
+ FreeRpcReadLogFile(&t);
+ }
+ }
+ break;
+
+ case B_IPSEC:
+ SmIPsec(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+void SmOpenVpnDlgInit(HWND hWnd, SM_SERVER *s)
+{
+ OPENVPN_SSTP_CONFIG t;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ if (CALL(hWnd, ScGetOpenVpnSstpConfig(s->Rpc, &t)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ Check(hWnd, R_OPENVPN, t.EnableOpenVPN);
+ SetTextA(hWnd, E_UDP, t.OpenVPNPortList);
+ Check(hWnd, R_SSTP, t.EnableSSTP);
+
+ SetIcon(hWnd, 0, ICO_OPENVPN);
+
+ DlgFont(hWnd, S_TITLE, 14, true);
+ SetFont(hWnd, E_UDP, GetFont("Verdana", 10, false, false, false, false));
+
+ DlgFont(hWnd, R_OPENVPN, 0, true);
+ DlgFont(hWnd, S_TOOL, 11, true);
+ DlgFont(hWnd, R_SSTP, 0, true);
+
+ SmOpenVpnDlgUpdate(hWnd, s);
+}
+void SmOpenVpnDlgUpdate(HWND hWnd, SM_SERVER *s)
+{
+ bool b1, b2;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ b1 = IsChecked(hWnd, R_OPENVPN);
+ b2 = IsChecked(hWnd, R_SSTP);
+
+ SetEnable(hWnd, S_UDP, b1);
+ SetEnable(hWnd, E_UDP, b1);
+ SetEnable(hWnd, B_DEFAULT, b1);
+ SetEnable(hWnd, S_UDP2, b1);
+ SetEnable(hWnd, S_TOOL, b1);
+ SetEnable(hWnd, S_TOOL2, b1);
+ SetEnable(hWnd, B_CONFIG, b1);
+
+ SetEnable(hWnd, S_SSTP, b2);
+}
+void SmOpenVpnDlgOnOk(HWND hWnd, SM_SERVER *s, bool no_close)
+{
+ OPENVPN_SSTP_CONFIG t;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+
+ t.EnableOpenVPN = IsChecked(hWnd, R_OPENVPN);
+ GetTxtA(hWnd, E_UDP, t.OpenVPNPortList, sizeof(t.OpenVPNPortList));
+ t.EnableSSTP = IsChecked(hWnd, R_SSTP);
+
+ if (CALL(hWnd, ScSetOpenVpnSstpConfig(s->Rpc, &t)) == false)
+ {
+ return;
+ }
+
+ if (no_close == false)
+ {
+ EndDialog(hWnd, 1);
+ }
+}
+
+// Open the EtherIP ID edit dialog
+bool SmEtherIpId(HWND hWnd, SM_ETHERIP_ID *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return false;
+ }
+
+ if (Dialog(hWnd, D_SM_ETHERIP_ID, SmEtherIpIdDlg, t) == 0)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// EtherIP ID edit dialog procedure
+UINT SmEtherIpIdDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_ETHERIP_ID *t = (SM_ETHERIP_ID *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmEtherIpIdDlgInit(hWnd, t);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_ID:
+ case L_HUBNAME:
+ case E_USERNAME:
+ SmEtherIpIdDlgUpdate(hWnd, t);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ SmEtherIpIdDlgOnOk(hWnd, t);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Initialize the EtherIP ID edit dialog
+void SmEtherIpIdDlgInit(HWND hWnd, SM_ETHERIP_ID *t)
+{
+ RPC_ENUM_HUB tt;
+ UINT sel_index;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || t == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_KEY);
+
+ // Get the current data in the case of edit mode
+ if (t->EditMode)
+ {
+ Zero(&t->Data, sizeof(t->Data));
+ StrCpy(t->Data.Id, sizeof(t->Data.Id), t->EditId);
+
+ if (CALL(hWnd, ScGetEtherIpId(t->s->Rpc, &t->Data)) == false)
+ {
+ EndDialog(hWnd, 0);
+ return;
+ }
+ }
+
+ // Enumerate the Virtual HUBs
+ Zero(&tt, sizeof(tt));
+ if (CALL(hWnd, ScEnumHub(t->s->Rpc, &tt)) == false)
+ {
+ EndDialog(hWnd, 0);
+ return;
+ }
+
+ CbReset(hWnd, L_HUBNAME);
+ CbSetHeight(hWnd, L_HUBNAME, 18);
+ sel_index = INFINITE;
+
+ for (i = 0;i < tt.NumHub;i++)
+ {
+ RPC_ENUM_HUB_ITEM *e = &tt.Hubs[i];
+ UINT index;
+
+ index = CbAddStrA(hWnd, L_HUBNAME, e->HubName, 0);
+ if (sel_index == INFINITE)
+ {
+ sel_index = index;
+ }
+
+ if (t->EditMode)
+ {
+ if (StrCmpi(e->HubName, t->Data.HubName) == 0)
+ {
+ sel_index = index;
+ }
+ }
+ }
+
+ if (sel_index != INFINITE)
+ {
+ CbSelectIndex(hWnd, L_HUBNAME, sel_index);
+ }
+
+ if (t->EditMode)
+ {
+ SetTextA(hWnd, E_ID, t->Data.Id);
+ SetTextA(hWnd, E_USERNAME, t->Data.UserName);
+ SetTextA(hWnd, E_PASSWORD, t->Data.Password);
+
+ FocusEx(hWnd, E_PASSWORD);
+ }
+ else
+ {
+ Focus(hWnd, E_ID);
+ }
+
+ FreeRpcEnumHub(&tt);
+
+ t->InitCompleted = true;
+ SmEtherIpIdDlgUpdate(hWnd, t);
+}
+
+// EtherIP ID edit dialog: Click the OK button
+void SmEtherIpIdDlgOnOk(HWND hWnd, SM_ETHERIP_ID *t)
+{
+ // Validate arguments
+ if (hWnd == NULL || t == NULL)
+ {
+ return;
+ }
+
+ SmEtherIpIdDlgGetSetting(hWnd, t);
+
+ if (t->EditMode)
+ {
+ ETHERIP_ID d;
+ // Delete old items
+ Zero(&d, sizeof(d));
+
+ StrCpy(d.Id, sizeof(d.Id), t->EditId);
+
+ ScDeleteEtherIpId(t->s->Rpc, &d);
+ }
+
+ if (CALL(hWnd, ScAddEtherIpId(t->s->Rpc, &t->Data)) == false)
+ {
+ return;
+ }
+
+ if (t->EditMode == false)
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_ETHERIP_ADD_OK"));
+ }
+
+ EndDialog(hWnd, 1);
+}
+
+// EtherIP ID edit dialog: Update the controls
+void SmEtherIpIdDlgUpdate(HWND hWnd, SM_ETHERIP_ID *t)
+{
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL || t == NULL)
+ {
+ return;
+ }
+
+ if (t->InitCompleted == false)
+ {
+ return;
+ }
+
+ SmEtherIpIdDlgGetSetting(hWnd, t);
+
+ if (IsEmptyStr(t->Data.Id) ||
+ IsEmptyStr(t->Data.HubName) ||
+ IsEmptyStr(t->Data.UserName))
+ {
+ ok = false;
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// EtherIP ID edit dialog: Get the current settings
+void SmEtherIpIdDlgGetSetting(HWND hWnd, SM_ETHERIP_ID *t)
+{
+ wchar_t *ws;
+ // Validate arguments
+ if (hWnd == NULL || t == NULL)
+ {
+ return;
+ }
+
+ Zero(&t->Data, sizeof(t->Data));
+
+ GetTxtA(hWnd, E_ID, t->Data.Id, sizeof(t->Data.Id));
+ GetTxtA(hWnd, E_USERNAME, t->Data.UserName, sizeof(t->Data.UserName));
+ GetTxtA(hWnd, E_PASSWORD, t->Data.Password, sizeof(t->Data.Password));
+
+ ws = CbGetStr(hWnd, L_HUBNAME);
+
+ if (ws != NULL && IsEmptyUniStr(ws) == false)
+ {
+ UniToStr(t->Data.HubName, sizeof(t->Data.HubName), ws);
+ }
+
+ Free(ws);
+}
+
+
+// Open the EtherIP settings dialog
+void SmEtherIp(HWND hWnd, SM_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_SM_ETHERIP, SmEtherIpDlg, s);
+}
+
+// EtherIP Setup dialog procedure
+UINT SmEtherIpDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_SERVER *s = (SM_SERVER *)param;
+ NMHDR *n;
+ char *id;
+ SM_ETHERIP_ID t;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmEtherIpDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ // Edit
+ id = LvGetSelectedStrA(hWnd, L_LIST, 0);
+ if (id != NULL)
+ {
+ Zero(&t, sizeof(t));
+ StrCpy(t.EditId, sizeof(t.EditId), id);
+ t.EditMode = true;
+ t.s = s;
+
+ if (SmEtherIpId(hWnd, &t))
+ {
+ SmEtherIpDlgRefresh(hWnd, s);
+ }
+
+ Free(id);
+ }
+ break;
+
+ case B_ADD:
+ // Add
+ Zero(&t, sizeof(t));
+ t.s = s;
+ if (SmEtherIpId(hWnd, &t))
+ {
+ SmEtherIpDlgRefresh(hWnd, s);
+ }
+ break;
+
+ case B_DELETE:
+ // Delete
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("SM_CRL_DELETE_MSG")) == IDYES)
+ {
+ id = LvGetSelectedStrA(hWnd, L_LIST, 0);
+ if (id != NULL)
+ {
+ ETHERIP_ID d;
+
+ Zero(&d, sizeof(d));
+
+ StrCpy(d.Id, sizeof(d.Id), id);
+
+ if (CALL(hWnd, ScDeleteEtherIpId(s->Rpc, &d)))
+ {
+ SmEtherIpDlgRefresh(hWnd, s);
+ }
+
+ Free(id);
+ }
+ }
+ break;
+
+ case IDCANCEL:
+ // Close
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ SmEtherIpDlgUpdate(hWnd, s);
+ break;
+
+ case NM_DBLCLK:
+ Command(hWnd, IDOK);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// EtherIP Setup dialog data update
+void SmEtherIpDlgRefresh(HWND hWnd, SM_SERVER *s)
+{
+ RPC_ENUM_ETHERIP_ID t;
+ UINT i;
+ LVB *b;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ // Data update
+ Zero(&t, sizeof(t));
+
+ if (CALL(hWnd, ScEnumEtherIpId(s->Rpc, &t)) == false)
+ {
+ EndDialog(hWnd, 0);
+ return;
+ }
+
+ b = LvInsertStart();
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ ETHERIP_ID *d = &t.IdList[i];
+ wchar_t id[MAX_SIZE], hubname[MAX_SIZE], username[MAX_SIZE];
+
+ StrToUni(id, sizeof(id), d->Id);
+ StrToUni(hubname, sizeof(hubname), d->HubName);
+ StrToUni(username, sizeof(username), d->UserName);
+
+ LvInsertAdd(b, ICO_CASCADE, NULL, 3, id, hubname, username);
+ }
+
+ LvInsertEnd(b, hWnd, L_LIST);
+
+ FreeRpcEnumEtherIpId(&t);
+
+ SmEtherIpDlgUpdate(hWnd, s);
+}
+
+// Initialize the EtherIP settings dialog
+void SmEtherIpDlgInit(HWND hWnd, SM_SERVER *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_MACHINE);
+ DlgFont(hWnd, S_TITLE, 14, true);
+ DlgFont(hWnd, S_BOLD, 0, true);
+
+ LvInit(hWnd, L_LIST);
+ LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_ETHERIP_COLUMN_0"), 205);
+ LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_ETHERIP_COLUMN_1"), 179);
+ LvInsertColumn(hWnd, L_LIST, 2, _UU("SM_ETHERIP_COLUMN_2"), 154);
+
+ SmEtherIpDlgRefresh(hWnd, s);
+}
+
+// EtherIP Settings dialog controls update
+void SmEtherIpDlgUpdate(HWND hWnd, SM_SERVER *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetEnable(hWnd, IDOK, LvIsSingleSelected(hWnd, L_LIST));
+ SetEnable(hWnd, B_DELETE, LvIsSingleSelected(hWnd, L_LIST));
+}
+
+// IPsec Settings dialog procedure
+UINT SmIPsecDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_SERVER *s = (SM_SERVER *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmIPsecDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case R_L2TP_OVER_IPSEC:
+ case R_L2TP_RAW:
+ case R_ETHERIP:
+ case E_SECRET:
+ case L_HUBNAME:
+ SmIPsecDlgUpdate(hWnd, s);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ SmIPsecDlgOnOk(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case B_DETAIL:
+ // Advanced Settings dialog for EtherIP function
+ SmEtherIp(hWnd, s);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// IPsec Settings dialog: controls update
+void SmIPsecDlgUpdate(HWND hWnd, SM_SERVER *s)
+{
+ IPSEC_SERVICES sl;
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SmIPsecDlgGetSetting(hWnd, &sl);
+
+ //SetEnable(hWnd, S_1, sl.L2TP_IPsec || sl.L2TP_Raw);
+ //SetEnable(hWnd, S_2, sl.L2TP_IPsec || sl.L2TP_Raw);
+ //SetEnable(hWnd, L_HUBNAME, sl.L2TP_IPsec || sl.L2TP_Raw);
+
+ SetEnable(hWnd, S_PSK, sl.L2TP_IPsec || sl.EtherIP_IPsec);
+ SetEnable(hWnd, S_PSK2, sl.L2TP_IPsec || sl.EtherIP_IPsec);
+ SetEnable(hWnd, E_SECRET, sl.L2TP_IPsec || sl.EtherIP_IPsec);
+
+ SetEnable(hWnd, B_DETAIL, sl.EtherIP_IPsec);
+
+ if ((sl.L2TP_IPsec || sl.EtherIP_IPsec) && IsEmptyStr(sl.IPsec_Secret))
+ {
+ ok = false;
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Get the IPsec configuration into the structure
+void SmIPsecDlgGetSetting(HWND hWnd, IPSEC_SERVICES *sl)
+{
+ wchar_t *ws;
+ // Validate arguments
+ if (hWnd == NULL || sl == NULL)
+ {
+ return;
+ }
+
+ Zero(sl, sizeof(IPSEC_SERVICES));
+
+ sl->L2TP_IPsec = IsChecked(hWnd, R_L2TP_OVER_IPSEC);
+ sl->L2TP_Raw = IsChecked(hWnd, R_L2TP_RAW);
+ sl->EtherIP_IPsec = IsChecked(hWnd, R_ETHERIP);
+
+ ws = CbGetStr(hWnd, L_HUBNAME);
+ if (ws != NULL && IsEmptyUniStr(ws) == false)
+ {
+ UniToStr(sl->L2TP_DefaultHub, sizeof(sl->L2TP_DefaultHub), ws);
+ }
+
+ Free(ws);
+
+ GetTxtA(hWnd, E_SECRET, sl->IPsec_Secret, sizeof(sl->IPsec_Secret));
+}
+
+// IPsec Settings dialog initialization
+void SmIPsecDlgInit(HWND hWnd, SM_SERVER *s)
+{
+ IPSEC_SERVICES sl;
+ RPC_ENUM_HUB t;
+ UINT i;
+ UINT sel_index;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_IPSEC);
+
+ DlgFont(hWnd, S_TITLE, 14, true);
+ SetFont(hWnd, E_SECRET, GetFont("Verdana", 10, false, false, false, false));
+
+ DlgFont(hWnd, R_L2TP_OVER_IPSEC, 0, true);
+ DlgFont(hWnd, R_L2TP_RAW, 0, true);
+ DlgFont(hWnd, R_ETHERIP, 0, true);
+
+ // Get the configuration
+ Zero(&sl, sizeof(sl));
+ if (CALL(hWnd, ScGetIPsecServices(s->Rpc, &sl)) == false)
+ {
+ EndDialog(hWnd, 0);
+ return;
+ }
+
+ SetTextA(hWnd, E_SECRET, sl.IPsec_Secret);
+
+ Check(hWnd, R_L2TP_OVER_IPSEC, sl.L2TP_IPsec);
+ Check(hWnd, R_L2TP_RAW, sl.L2TP_Raw);
+ Check(hWnd, R_ETHERIP, sl.EtherIP_IPsec);
+
+ // Enumerate the Virtual HUBs
+ Zero(&t, sizeof(t));
+ if (CALL(hWnd, ScEnumHub(s->Rpc, &t)) == false)
+ {
+ EndDialog(hWnd, 0);
+ return;
+ }
+
+ CbReset(hWnd, L_HUBNAME);
+ CbSetHeight(hWnd, L_HUBNAME, 18);
+
+ sel_index = INFINITE;
+ for (i = 0;i < t.NumHub;i++)
+ {
+ RPC_ENUM_HUB_ITEM *e = &t.Hubs[i];
+ UINT index;
+
+ index = CbAddStrA(hWnd, L_HUBNAME, e->HubName, 0);
+ if (sel_index == INFINITE)
+ {
+ sel_index = index;
+ }
+
+ if (StrCmpi(e->HubName, sl.L2TP_DefaultHub) == 0)
+ {
+ sel_index = index;
+ }
+ }
+
+ if (sel_index != INFINITE)
+ {
+ CbSelectIndex(hWnd, L_HUBNAME, sel_index);
+ }
+
+ FreeRpcEnumHub(&t);
+
+ SmIPsecDlgUpdate(hWnd, s);
+}
+
+// IPsec Settings dialog: on click the OK button
+void SmIPsecDlgOnOk(HWND hWnd, SM_SERVER *s)
+{
+ IPSEC_SERVICES sl;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SmIPsecDlgGetSetting(hWnd, &sl);
+
+ // Confirm the length of the PSK
+ if (StrLen(sl.IPsec_Secret) >= 10)
+ {
+ IPSEC_SERVICES sl_old;
+ if (ScGetIPsecServices(s->Rpc, &sl_old) == ERR_NO_ERROR)
+ {
+ if (StrCmp(sl_old.IPsec_Secret, sl.IPsec_Secret) != 0 || ((sl_old.EtherIP_IPsec == false && sl_old.L2TP_IPsec == false)))
+ {
+ if (sl.EtherIP_IPsec || sl.L2TP_IPsec)
+ {
+ // Show a warning message if it exceeds 10 characters (Only if there is a change)
+ if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_YESNO, _UU("SM_IPSEC_PSK_TOO_LONG")) == IDYES)
+ {
+ FocusEx(hWnd, E_SECRET);
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ if (CALL(hWnd, ScSetIPsecServices(s->Rpc, &sl)) == false)
+ {
+ return;
+ }
+
+ EndDialog(hWnd, 1);
+}
+
+// Start the IPsec Settings dialog
+void SmIPsec(HWND hWnd, SM_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_SM_IPSEC, SmIPsecDlg, s);
+}
+
+// Message Settings
+void SmHubMsg(HWND hWnd, SM_EDIT_HUB *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_SM_MSG, SmHubMsgDlg, s);
+}
+
+// Message dialog procedure
+UINT SmHubMsgDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_EDIT_HUB *s = (SM_EDIT_HUB *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmHubMsgDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_TEXT:
+ SmHubMsgDlgUpdate(hWnd, s);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ SmHubMsgDlgOnOk(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case C_USEMSG:
+ SmHubMsgDlgUpdate(hWnd, s);
+
+ if (IsChecked(hWnd, C_USEMSG))
+ {
+ FocusEx(hWnd, E_TEXT);
+ }
+ break;
+ }
+
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Message dialog initialization
+void SmHubMsgDlgInit(HWND hWnd, SM_EDIT_HUB *s)
+{
+ RPC_MSG t;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (MsIsVista())
+ {
+ SetFont(hWnd, E_TEXT, GetMeiryoFont());
+ }
+ else
+ {
+ DlgFont(hWnd, E_TEXT, 11, false);
+ }
+
+ FormatText(hWnd, S_MSG_2, s->HubName);
+
+ LimitText(hWnd, E_TEXT, HUB_MAXMSG_LEN);
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+ if (CALL(hWnd, ScGetHubMsg(s->p->Rpc, &t)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ if (UniIsEmptyStr(t.Msg) == false)
+ {
+ SetText(hWnd, E_TEXT, t.Msg);
+
+ Check(hWnd, C_USEMSG, true);
+ }
+ else
+ {
+ Check(hWnd, C_USEMSG, false);
+ }
+
+ FreeRpcMsg(&t);
+
+ SmHubMsgDlgUpdate(hWnd, s);
+}
+
+// [OK] button
+void SmHubMsgDlgOnOk(HWND hWnd, SM_EDIT_HUB *s)
+{
+ RPC_MSG t;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+ if (IsChecked(hWnd, C_USEMSG) == false)
+ {
+ t.Msg = CopyUniStr(L"");
+ }
+ else
+ {
+ t.Msg = GetText(hWnd, E_TEXT);
+ }
+
+ if (CALL(hWnd, ScSetHubMsg(s->p->Rpc, &t)) == false)
+ {
+ return;
+ }
+
+ FreeRpcMsg(&t);
+
+ EndDialog(hWnd, 1);
+}
+
+// Message dialog update
+void SmHubMsgDlgUpdate(HWND hWnd, SM_EDIT_HUB *s)
+{
+ bool b = true;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetEnable(hWnd, E_TEXT, IsChecked(hWnd, C_USEMSG));
+
+ if (IsChecked(hWnd, C_USEMSG))
+ {
+ wchar_t *s = GetText(hWnd, E_TEXT);
+
+ b = !IsEmptyUniStr(s);
+
+ Free(s);
+ }
+
+ SetEnable(hWnd, IDOK, b);
+}
+
+// VLAN utility
+void SmVLan(HWND hWnd, SM_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_SM_VLAN, SmVLanDlg, s);
+}
+
+// VLAN dialog
+UINT SmVLanDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_SERVER *s = (SM_SERVER *)param;
+ NMHDR *n;
+
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmVLanDlgInit(hWnd, s);
+
+ if (LvNum(hWnd, L_LIST) == 0)
+ {
+ Disable(hWnd, L_LIST);
+ SetTimer(hWnd, 1, 100, NULL);
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+
+ MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("SM_VLAN_NOTHING"),
+ s->CurrentSetting->ClientOption.Hostname);
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case B_ENABLE:
+ case B_DISABLE:
+ {
+ UINT i = LvGetSelected(hWnd, L_LIST);
+ if (i != INFINITE)
+ {
+ char *name = LvGetStrA(hWnd, L_LIST, i, 0);
+
+ if (IsEmptyStr(name) == false)
+ {
+ RPC_TEST t;
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.StrValue, sizeof(t.StrValue), name);
+ t.IntValue = BOOL_TO_INT(wParam == B_ENABLE);
+
+ if (CALL(hWnd, ScSetEnableEthVLan(s->Rpc, &t)))
+ {
+ SmVLanDlgRefresh(hWnd, s);
+
+ if (wParam == B_ENABLE)
+ {
+ MsgBoxEx(hWnd, MB_ICONINFORMATION,
+ _UU("SM_VLAN_MSG_1"),
+ name, name, name);
+ }
+ else
+ {
+ MsgBoxEx(hWnd, MB_ICONINFORMATION,
+ _UU("SM_VLAN_MSG_2"),
+ name);
+ }
+ }
+ }
+
+ Free(name);
+ }
+ break;
+ }
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ SmVLanDlgUpdate(hWnd, s);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// VLAN dialog initialization
+void SmVLanDlgInit(HWND hWnd, SM_SERVER *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ LvInit(hWnd, L_LIST);
+ LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_VLAN_COLUMN_0"), 245);
+ LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_VLAN_COLUMN_1"), 75);
+ LvInsertColumn(hWnd, L_LIST, 2, _UU("SM_VLAN_COLUMN_2"), 100);
+ LvInsertColumn(hWnd, L_LIST, 3, _UU("SM_VLAN_COLUMN_3"), 100);
+ LvInsertColumn(hWnd, L_LIST, 4, _UU("SM_VLAN_COLUMN_4"), 290);
+ LvInsertColumn(hWnd, L_LIST, 5, _UU("SM_VLAN_COLUMN_5"), 430);
+
+ SmVLanDlgRefresh(hWnd, s);
+}
+
+// VLAN dialog content update
+void SmVLanDlgRefresh(HWND hWnd, SM_SERVER *s)
+{
+ LVB *b;
+ RPC_ENUM_ETH_VLAN t;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ if (CALL(hWnd, ScEnumEthVLan(s->Rpc, &t)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ b = LvInsertStart();
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_ETH_VLAN_ITEM *e = &t.Items[i];
+
+ if (e->Support)
+ {
+ wchar_t tmp0[MAX_SIZE];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t *tmp3;
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t tmp5[MAX_SIZE];
+
+ StrToUni(tmp0, sizeof(tmp0), e->DeviceName);
+ StrToUni(tmp1, sizeof(tmp1), e->DriverType);
+ StrToUni(tmp2, sizeof(tmp2), e->DriverName);
+ tmp3 = (e->Enabled ? _UU("SM_VLAN_YES") : _UU("SM_VLAN_NO"));
+ StrToUni(tmp4, sizeof(tmp4), e->Guid);
+ StrToUni(tmp5, sizeof(tmp5), e->DeviceInstanceId);
+
+ LvInsertAdd(b,
+ e->Enabled ? ICO_NIC_ONLINE : ICO_NIC_OFFLINE, 0, 6,
+ tmp0, tmp1, tmp2, tmp3, tmp4, tmp5);
+ }
+ }
+
+ LvInsertEnd(b, hWnd, L_LIST);
+
+ FreeRpcEnumEthVLan(&t);
+
+ SmVLanDlgUpdate(hWnd, s);
+}
+
+// VLAN dialog control update
+void SmVLanDlgUpdate(HWND hWnd, SM_SERVER *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (LvIsSingleSelected(hWnd, L_LIST) == false)
+ {
+ Disable(hWnd, B_ENABLE);
+ Disable(hWnd, B_DISABLE);
+ }
+ else
+ {
+ UINT i = LvGetSelected(hWnd, L_LIST);
+ if (i != INFINITE)
+ {
+ wchar_t *s = LvGetStr(hWnd, L_LIST, i, 3);
+
+ if (UniStrCmpi(s, _UU("SM_VLAN_YES")) != 0)
+ {
+ Enable(hWnd, B_ENABLE);
+ Disable(hWnd, B_DISABLE);
+ }
+ else
+ {
+ Enable(hWnd, B_DISABLE);
+ Disable(hWnd, B_ENABLE);
+ }
+
+ Free(s);
+ }
+ }
+}
+
+// Examine whether the current state of VPN Server / VPN Bridge is the initial state
+bool SmSetupIsNew(SM_SERVER *s)
+{
+ RPC *rpc;
+ bool is_bridge;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ bool check_hub = false;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ if (s->ServerAdminMode == false)
+ {
+ return false;
+ }
+
+ rpc = s->Rpc;
+ is_bridge =s->Bridge;
+
+ // Server type
+ if (is_bridge == false)
+ {
+ bool b = false;
+ RPC_SERVER_INFO t;
+
+ Zero(&t, sizeof(t));
+ if (ScGetServerInfo(rpc, &t) == ERR_NO_ERROR)
+ {
+ if (t.ServerType != SERVER_TYPE_STANDALONE)
+ {
+ b = true;
+ }
+
+ FreeRpcServerInfo(&t);
+ }
+ else
+ {
+ return false;
+ }
+
+ if (b)
+ {
+ return false;
+ }
+ }
+
+ // Local bridge
+ if (true)
+ {
+ RPC_ENUM_LOCALBRIDGE t;
+ bool b = false;
+
+ Zero(&t, sizeof(t));
+ if (ScEnumLocalBridge(rpc, &t) == ERR_NO_ERROR)
+ {
+ if (t.NumItem != 0)
+ {
+ b = true;
+ }
+ FreeRpcEnumLocalBridge(&t);
+ }
+
+ if (b)
+ {
+ return false;
+ }
+ }
+
+ // Virtual HUB
+
+ check_hub = false;
+
+ if (is_bridge == false)
+ {
+ RPC_ENUM_HUB t;
+ bool b = false;
+
+ Zero(&t, sizeof(t));
+ if (ScEnumHub(rpc, &t) == ERR_NO_ERROR)
+ {
+ if (t.NumHub >= 2)
+ {
+ b = true;
+ }
+ else if (t.NumHub == 1)
+ {
+ if (StrCmpi(t.Hubs[0].HubName, SERVER_DEFAULT_HUB_NAME) != 0)
+ {
+ b = true;
+ }
+ else
+ {
+ check_hub = true;
+ }
+ }
+
+ FreeRpcEnumHub(&t);
+ }
+
+ if (b)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ check_hub = true;
+ }
+
+ // Status of the virtual HUB
+ if (is_bridge == false)
+ {
+ StrCpy(hubname, sizeof(hubname), SERVER_DEFAULT_HUB_NAME);
+ }
+ else
+ {
+ StrCpy(hubname, sizeof(hubname), SERVER_DEFAULT_BRIDGE_NAME);
+ }
+
+ if (check_hub)
+ {
+ if (true)
+ {
+ // Number of objects in the Virtual HUB
+ RPC_HUB_STATUS t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+ if (ScGetHubStatus(rpc, &t) == ERR_NO_ERROR)
+ {
+ if (t.NumSessions != 0 || t.NumAccessLists != 0 ||
+ t.NumUsers != 0 || t.NumGroups != 0 ||
+ t.NumMacTables != 0 || t.NumIpTables != 0 ||
+ t.SecureNATEnabled)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ if (true)
+ {
+ // Cascade connection
+ RPC_ENUM_LINK t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+ if (ScEnumLink(rpc, &t) == ERR_NO_ERROR)
+ {
+ bool b = false;
+
+ if (t.NumLink != 0)
+ {
+ b = true;
+ }
+
+ FreeRpcEnumLink(&t);
+
+ if (b)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ if (is_bridge == false)
+ {
+ // Certificate list to trust
+ RPC_HUB_ENUM_CA t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+ if (ScEnumCa(rpc, &t) == ERR_NO_ERROR)
+ {
+ bool b = false;
+
+ if (t.NumCa != 0)
+ {
+ b = true;
+ }
+
+ FreeRpcHubEnumCa(&t);
+
+ if (b)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ if (is_bridge == false)
+ {
+ // Certificate revocation list
+ RPC_ENUM_CRL t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+ if (ScEnumCrl(rpc, &t) == ERR_NO_ERROR)
+ {
+ bool b = false;
+
+ if (t.NumItem != 0)
+ {
+ b = true;
+ }
+
+ FreeRpcEnumCrl(&t);
+
+ if (b)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ if (is_bridge == false)
+ {
+ // Authentication server configuration
+ RPC_RADIUS t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+ if (ScGetHubRadius(rpc, &t) == ERR_NO_ERROR)
+ {
+ if (IsEmptyStr(t.RadiusServerName) == false)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ if (is_bridge == false)
+ {
+ // Virtual HUB configuration
+ RPC_CREATE_HUB t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+ if (ScGetHub(rpc, &t) == ERR_NO_ERROR)
+ {
+ if (t.HubOption.NoEnum || t.HubOption.MaxSession != 0 ||
+ t.Online == false)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ if (is_bridge == false)
+ {
+ // IP access control list
+ RPC_AC_LIST t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+ if (ScGetAcList(rpc, &t) == ERR_NO_ERROR)
+ {
+ bool b = false;
+ if (LIST_NUM(t.o) != 0)
+ {
+ b = true;
+ }
+ FreeRpcAcList(&t);
+
+ if (b)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ if (is_bridge == false)
+ {
+ // AO
+ RPC_ADMIN_OPTION t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+ if (ScGetHubAdminOptions(rpc, &t) == ERR_NO_ERROR)
+ {
+ bool b = false;
+ UINT i;
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ if (t.Items[i].Value != 0)
+ {
+ b = true;
+ }
+ }
+
+ FreeRpcAdminOption(&t);
+
+ if (b)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ // Virtual layer 3 switch
+ if (is_bridge == false)
+ {
+ RPC_ENUM_L3SW t;
+ bool b = false;
+
+ Zero(&t, sizeof(t));
+ if (ScEnumL3Switch(rpc, &t) == ERR_NO_ERROR)
+ {
+ if (t.NumItem != 0)
+ {
+ b = true;
+ }
+
+ FreeRpcEnumL3Sw(&t);
+ }
+ else
+ {
+ return false;
+ }
+
+ if (b)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Setup procedure dialog initialization
+void SmSetupStepDlgInit(HWND hWnd, SM_SETUP *s)
+{
+ bool b;
+ RPC_ENUM_ETH t;
+ UINT i;
+ RPC_BRIDGE_SUPPORT bs;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_SETUP);
+
+ DlgFont(hWnd, S_1_1, 0, true);
+ DlgFont(hWnd, S_2_1, 0, true);
+ DlgFont(hWnd, S_3_1, 0, true);
+
+ b = false;
+ if (s->UseRemote)
+ {
+ b = true;
+ }
+ if (s->UseSite && s->UseSiteEdge == false)
+ {
+ b = true;
+ }
+
+ SetEnable(hWnd, S_1_1, b);
+ SetEnable(hWnd, S_1_2, b);
+ SetEnable(hWnd, B_USER, b);
+
+ b = false;
+ if (s->UseSiteEdge)
+ {
+ b = true;
+ }
+
+ SetEnable(hWnd, S_2_1, b);
+ SetEnable(hWnd, S_2_2, b);
+ SetEnable(hWnd, B_CASCADE, b);
+
+ CbReset(hWnd, C_DEVICE);
+ CbSetHeight(hWnd, C_DEVICE, 18);
+
+ Zero(&t, sizeof(t));
+
+ CbAddStr(hWnd, C_DEVICE, _UU("SM_SETUP_SELECT"), 0);
+
+ Zero(&bs, sizeof(bs));
+ if (CALL(hWnd, ScGetBridgeSupport(s->Rpc, &bs)) == false)
+ {
+ return;
+ }
+
+ if (bs.IsBridgeSupportedOs)
+ {
+ // Enumerate the local bridges
+ if (ScEnumEthernet(s->Rpc, &t) == ERR_NO_ERROR)
+ {
+ for (i = 0;i < t.NumItem;i++)
+ {
+ wchar_t tmp[MAX_PATH];
+ RPC_ENUM_ETH_ITEM *e = &t.Items[i];
+
+ if (GetCapsBool(s->s->CapsList, "b_support_network_connection_name"))
+ {
+ UniFormat(tmp, sizeof(tmp), BRIDGE_NETWORK_CONNECTION_STR, e->NetworkConnectionName, e->DeviceName);
+ }
+ else
+ {
+ StrToUni(tmp, sizeof(tmp), e->DeviceName);
+ }
+
+ CbAddStr(hWnd, C_DEVICE, tmp, 1);
+ }
+
+ FreeRpcEnumEth(&t);
+ }
+ Show(hWnd, C_DEVICE);
+ Hide(hWnd, B_SECURENAT);
+ }
+ else
+ {
+ RPC_HUB t;
+
+ // Enable the SecureNAT automatically if the local bridge does not work in this environment
+ SetText(hWnd, S_3_2, _UU("SM_SETUP_STEP_SECURENAT"));
+ SetText(hWnd, S_3_1, _UU("SM_SETUP_STEP_SECURENAT_TITLE"));
+ Hide(hWnd, C_DEVICE);
+ Show(hWnd, B_SECURENAT);
+ SetIcon(hWnd, S_ICON, ICO_ROUTER);
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+ ScEnableSecureNAT(s->Rpc, &t);
+ }
+
+ s->Flag1 = false;
+ s->Flag2 = false;
+}
+
+// Close
+void SmSetupOnClose(HWND hWnd, SM_SETUP *s)
+{
+ wchar_t *tmp;
+ char name[MAX_PATH];
+ RPC_BRIDGE_SUPPORT bs;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&bs, sizeof(bs));
+ if (CALL(hWnd, ScGetBridgeSupport(s->Rpc, &bs)) == false)
+ {
+ return;
+ }
+
+ if (bs.IsBridgeSupportedOs)
+ {
+ // Add a Local Bridge
+ tmp = CbGetStr(hWnd, C_DEVICE);
+
+ if (tmp != NULL)
+ {
+ UniToStr(name, sizeof(name), tmp);
+
+ if (CbGetSelect(hWnd, C_DEVICE) != 0)
+ {
+ // Show a warning message if the VPN Server is running in a VM
+ if (GetCapsBool(s->s->CapsList, "b_is_in_vm"))
+ {
+ Dialog(hWnd, D_SM_VMBRIDGE, SmVmBridgeDlg, NULL);
+ }
+
+ if (GetCapsBool(s->s->CapsList, "b_support_network_connection_name") == false)
+ {
+ RPC_LOCALBRIDGE t;
+
+ Zero(&t, sizeof(t));
+ t.Active = true;
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), name);
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ t.Online = true;
+ t.TapMode = false;
+
+ if (CALL(hWnd, ScAddLocalBridge(s->Rpc, &t)) == false)
+ {
+ Free(tmp);
+ return;
+ }
+ }
+ else
+ {
+ RPC_ENUM_ETH tt;
+ UINT i;
+
+ Zero(&tt, sizeof(tt));
+ if (CALL(hWnd, ScEnumEthernet(s->Rpc, &tt)) == false)
+ {
+ Free(tmp);
+ return;
+ }
+
+ for (i = 0;i < tt.NumItem;i++)
+ {
+ RPC_ENUM_ETH_ITEM *ti = &tt.Items[i];
+ wchar_t fullname[MAX_SIZE];
+
+ UniFormat(fullname, sizeof(fullname), BRIDGE_NETWORK_CONNECTION_STR, ti->NetworkConnectionName, ti->DeviceName);
+
+ if (UniStrCmpi(fullname, tmp) == 0)
+ {
+ RPC_LOCALBRIDGE t;
+
+ Zero(&t, sizeof(t));
+ t.Active = true;
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), ti->DeviceName);
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ t.Online = true;
+ t.TapMode = false;
+
+ if (CALL(hWnd, ScAddLocalBridge(s->Rpc, &t)) == false)
+ {
+ FreeRpcEnumEth(&tt);
+ Free(tmp);
+ return;
+ }
+ break;
+ }
+ }
+
+ FreeRpcEnumEth(&tt);
+ }
+
+ }
+ Free(tmp);
+ }
+ }
+ else
+ {
+ // Enable the SecureNAT
+ }
+
+ EndDialog(hWnd, 0);
+}
+
+// Setup Procedure dialog procedure
+UINT SmSetupStepDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_SETUP *s = (SM_SETUP *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmSetupStepDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_USER:
+ // User creation
+ if (true)
+ {
+ SM_HUB h;
+
+ Zero(&h, sizeof(h));
+ h.HubName = s->HubName;
+ h.p = s->s;
+ h.Rpc = s->Rpc;
+
+ SmUserListDlgEx(hWnd, &h, NULL, s->Flag1 ? false : true);
+
+ s->Flag1 = true;
+ }
+ break;
+
+ case B_CASCADE:
+ // Create a cascade connection
+ if (true)
+ {
+ SM_HUB h;
+
+ Zero(&h, sizeof(h));
+ h.HubName = s->HubName;
+ h.p = s->s;
+ h.Rpc = s->Rpc;
+
+ SmLinkDlgEx(hWnd, &h, s->Flag2 ? false : true);
+ s->Flag2 = true;
+ }
+ break;
+
+ case B_SECURENAT:
+ // Setting the SecureNAT
+ if (true)
+ {
+ SM_HUB h;
+
+ Zero(&h, sizeof(h));
+ h.p = s->s;
+ h.Rpc = s->Rpc;
+ h.HubName = s->HubName;
+
+ Dialog(hWnd, D_SM_SNAT, SmSNATDlgProc, &h);
+ }
+ break;
+
+ case IDCANCEL:
+ // Close button
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ // Exit
+ SmSetupOnClose(hWnd, s);
+ break;
+ }
+
+ return 0;
+}
+
+// Setup procedure dialog
+void SmSetupStep(HWND hWnd, SM_SETUP *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_SM_SETUP_STEP, SmSetupStepDlg, s);
+}
+
+// Initialize by setup
+bool SmSetupInit(HWND hWnd, SM_SETUP *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ if (s->IsBridge == false)
+ {
+ if (SmSetupDeleteAllLayer3(hWnd, s) == false)
+ {
+ return false;
+ }
+
+ if (SmSetupDeleteAllHub(hWnd, s) == false)
+ {
+ return false;
+ }
+ }
+ else
+ {
+ if (SmSetupDeleteAllObjectInBridgeHub(hWnd, s) == false)
+ {
+ return false;
+ }
+ }
+
+ SmSetupDeleteAllLocalBridge(hWnd, s);
+
+ if (s->IsBridge == false)
+ {
+ // Create a Virtual HUB
+ RPC_CREATE_HUB t;
+ char *password = "";
+
+ Zero(&t, sizeof(t));
+ Hash(t.HashedPassword, password, StrLen(password), true);
+ HashPassword(t.SecurePassword, ADMINISTRATOR_USERNAME, password);
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ t.HubType = HUB_TYPE_STANDALONE;
+ t.Online = true;
+
+ if (CALL(hWnd, ScCreateHub(s->Rpc, &t)) == false)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Remove all objects in the Virtual HUB of the VPN Bridge
+bool SmSetupDeleteAllObjectInBridgeHub(HWND hWnd, SM_SETUP *s)
+{
+ char *hubname = SERVER_DEFAULT_BRIDGE_NAME;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ if (true)
+ {
+ RPC_ENUM_LINK t;
+ UINT i;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+ if (CALL(hWnd, ScEnumLink(s->Rpc, &t)) == false)
+ {
+ return false;
+ }
+
+ for (i = 0;i < t.NumLink;i++)
+ {
+ RPC_ENUM_LINK_ITEM *e = &t.Links[i];
+ RPC_LINK a;
+
+ Zero(&a, sizeof(a));
+ StrCpy(a.HubName, sizeof(a.HubName), hubname);
+ UniStrCpy(a.AccountName, sizeof(a.AccountName), e->AccountName);
+
+ if (CALL(hWnd, ScDeleteLink(s->Rpc, &a)) == false)
+ {
+ FreeRpcEnumLink(&t);
+ return false;
+ }
+ }
+
+ FreeRpcEnumLink(&t);
+ }
+
+ if (true)
+ {
+ RPC_HUB t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+ if (CALL(hWnd, ScDisableSecureNAT(s->Rpc, &t)) == false)
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Delete all Virtual Layer 3 Switches
+bool SmSetupDeleteAllLayer3(HWND hWnd, SM_SETUP *s)
+{
+ RPC_ENUM_L3SW t;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+ if(CALL(hWnd, ScEnumL3Switch(s->Rpc, &t)) == false)
+ {
+ return false;
+ }
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_L3SW_ITEM *e = &t.Items[i];
+ RPC_L3SW tt;
+
+ Zero(&tt, sizeof(tt));
+ StrCpy(tt.Name, sizeof(tt.Name), e->Name);
+
+ if (CALL(hWnd, ScDelL3Switch(s->Rpc, &tt)) == false)
+ {
+ FreeRpcEnumL3Sw(&t);
+ return false;
+ }
+ }
+
+ FreeRpcEnumL3Sw(&t);
+
+ return true;
+}
+
+// Delete all local bridges
+bool SmSetupDeleteAllLocalBridge(HWND hWnd, SM_SETUP *s)
+{
+ RPC_ENUM_LOCALBRIDGE t;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+ if (ScEnumLocalBridge(s->Rpc, &t) != ERR_NO_ERROR)
+ {
+ return false;
+ }
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_LOCALBRIDGE *e = &t.Items[i];
+
+ if (CALL(hWnd, ScDeleteLocalBridge(s->Rpc, e)) == false)
+ {
+ FreeRpcEnumLocalBridge(&t);
+ return false;
+ }
+ }
+
+ FreeRpcEnumLocalBridge(&t);
+
+ return true;
+}
+
+// Delete all Virtual HUBs
+bool SmSetupDeleteAllHub(HWND hWnd, SM_SETUP *s)
+{
+ RPC_ENUM_HUB t;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+ if (CALL(hWnd, ScEnumHub(s->Rpc, &t)) == false)
+ {
+ return false;
+ }
+
+ for (i = 0;i < t.NumHub;i++)
+ {
+ RPC_ENUM_HUB_ITEM *e = &t.Hubs[i];
+ RPC_DELETE_HUB tt;
+
+ Zero(&tt, sizeof(tt));
+ StrCpy(tt.HubName, sizeof(tt.HubName), e->HubName);
+
+ if (CALL(hWnd, ScDeleteHub(s->Rpc, &tt)) == false)
+ {
+ FreeRpcEnumHub(&t);
+ return false;
+ }
+ }
+
+ FreeRpcEnumHub(&t);
+
+ return true;
+}
+
+// Update the control of the Virtual HUB
+void SmSetupHubDlgUpdate(HWND hWnd, SM_SETUP *s)
+{
+ bool ok = true;
+ char tmp[MAX_HUBNAME_LEN + 1];
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ GetTxtA(hWnd, E_HUBNAME, tmp, sizeof(tmp));
+
+ if (IsEmptyStr(tmp) || IsSafeStr(tmp) == false)
+ {
+ ok = false;
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Virtual HUB creation dialog
+UINT SmSetupHubDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_SETUP *s = (SM_SETUP *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetTextA(hWnd, E_HUBNAME, "VPN");
+ FocusEx(hWnd, E_HUBNAME);
+ SmSetupHubDlgUpdate(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ SmSetupHubDlgUpdate(hWnd, s);
+
+ switch (wParam)
+ {
+ case IDOK:
+ GetTxtA(hWnd, E_HUBNAME, s->HubName, sizeof(s->HubName));
+ EndDialog(hWnd, true);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Setup dialog: [Next] button
+void SmSetupDlgOnOk(HWND hWnd, SM_SETUP *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (MsgBox(hWnd, MB_YESNO | MB_ICONEXCLAMATION, _UU("SM_SETUP_WARNING")) == IDNO)
+ {
+ return;
+ }
+
+ s->UseRemote = IsChecked(hWnd, C_REMOTE);
+ s->UseSite = IsChecked(hWnd, C_SITE);
+ s->UseSiteEdge = IsChecked(hWnd, C_EDGE);
+
+ if (s->IsBridge)
+ {
+ StrCpy(s->HubName, sizeof(s->HubName), SERVER_DEFAULT_BRIDGE_NAME);
+ }
+ else
+ {
+ if (Dialog(hWnd, D_SM_SETUP_HUB, SmSetupHubDlg, s) == false)
+ {
+ return;
+ }
+ }
+
+ // Initialize (Wipe existing objects)
+ if (SmSetupInit(hWnd, s) == false)
+ {
+ return;
+ }
+
+ if (s->IsBridge == false)
+ {
+ if (GetCapsBool(s->s->CapsList, "b_support_ddns"))
+ {
+ if (s->UseRemote || (s->UseSite && s->UseSiteEdge == false))
+ {
+ DDNS_CLIENT_STATUS st;
+
+ Zero(&st, sizeof(st));
+
+ if (ScGetDDnsClientStatus(s->s->Rpc, &st) == ERR_NO_ERROR &&
+ IsEmptyStr(st.CurrentHostName) == false)
+ {
+ // Display the Dynamic DNS setting screen
+ SmDDns(hWnd, s->s, true, false);
+ }
+ }
+ }
+
+ // Configure the IPsec if the IPsec feature is available
+ if (GetCapsBool(s->s->CapsList, "b_support_ipsec") && s->s->IPsecMessageDisplayed == false)
+ {
+ // Display a message about IPsec
+ RPC_TEST flag;
+
+ if (s->UseRemote || (s->UseSite && s->UseSiteEdge == false))
+ {
+ SmIPsec(hWnd, s->s);
+ }
+
+ Zero(&flag, sizeof(flag));
+ flag.IntValue = 9;
+ ToStr(flag.StrValue, 1);
+
+ ScDebug(s->s->Rpc, &flag);
+
+ s->s->IPsecMessageDisplayed = true;
+ }
+
+ // Confgure the VPN Azure if VPN Azure feature is available
+ if (GetCapsBool(s->s->CapsList, "b_support_azure"))
+ {
+ SmAzure(hWnd, s->s, true);
+ }
+
+ }
+
+ // Execute the procedure
+ SmSetupStep(hWnd, s);
+
+ // Close the dialog
+ EndDialog(hWnd, true);
+}
+
+// Setup dialog: initialization
+void SmSetupDlgInit(HWND hWnd, SM_SETUP *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_SETUP);
+ DlgFont(hWnd, S_TITLE, 14, true);
+ DlgFont(hWnd, C_REMOTE, 0, true);
+ DlgFont(hWnd, C_SITE, 0, true);
+ DlgFont(hWnd, C_OTHER, 0, true);
+
+ if (s->IsBridge)
+ {
+ SetText(hWnd, B_BOLD, _UU("SM_SETUP_BRIDGE_ONLY"));
+ SetText(hWnd, C_EDGE, _UU("SM_SETUP_BRIDGE_EDGE"));
+
+ Check(hWnd, C_SITE, true);
+ Check(hWnd, C_EDGE, true);
+ Focus(hWnd, C_SITE);
+ }
+
+ SmSetupDlgUpdate(hWnd, s);
+}
+
+// Setup dialog: update
+void SmSetupDlgUpdate(HWND hWnd, SM_SETUP *s)
+{
+ bool enable_remote = true;
+ bool enable_site = true;
+ bool enable_site_center = true;
+ bool enable_detail = true;
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (s->IsBridge)
+ {
+ enable_remote = false;
+ enable_site_center = false;
+ enable_detail = false;
+ }
+
+ if (IsChecked(hWnd, C_OTHER))
+ {
+ ok = false;
+ }
+
+ SetEnable(hWnd, C_REMOTE, enable_remote && IsChecked(hWnd, C_OTHER) == false);
+ SetEnable(hWnd, S_REMOTE_1, enable_remote && IsChecked(hWnd, C_OTHER) == false);
+
+ SetEnable(hWnd, C_SITE, enable_site && IsChecked(hWnd, C_OTHER) == false);
+ SetEnable(hWnd, S_SITE_1, enable_site && IsChecked(hWnd, C_OTHER) == false);
+ SetEnable(hWnd, S_SITE_2, enable_site && IsChecked(hWnd, C_SITE) && IsChecked(hWnd, C_OTHER) == false);
+ SetEnable(hWnd, C_CENTER, enable_site && enable_site_center && IsChecked(hWnd, C_SITE) && IsChecked(hWnd, C_OTHER) == false);
+ SetEnable(hWnd, C_EDGE, enable_site && IsChecked(hWnd, C_SITE) && IsChecked(hWnd, C_OTHER) == false);
+
+ SetEnable(hWnd, C_OTHER, enable_detail);
+ SetEnable(hWnd, S_OTHER, enable_detail);
+
+ if (IsChecked(hWnd, C_REMOTE) == false && IsChecked(hWnd, C_SITE) == false)
+ {
+ ok = false;
+ }
+
+ if (IsChecked(hWnd, C_SITE))
+ {
+ if (IsChecked(hWnd, C_CENTER) == false && IsChecked(hWnd, C_EDGE) == false)
+ {
+ ok = false;
+ }
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+
+ SetText(hWnd, S_INFO,
+ IsChecked(hWnd, C_OTHER) ? _UU("SM_SETUP_INFO_2") : _UU("SM_SETUP_INFO_1"));
+}
+
+// Setup dialog
+UINT SmSetupDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_SETUP *s = (SM_SETUP *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmSetupDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ SmSetupDlgUpdate(hWnd, s);
+
+ switch (wParam)
+ {
+ case IDOK:
+ SmSetupDlgOnOk(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Setup
+bool SmSetup(HWND hWnd, SM_SERVER *s)
+{
+ SM_SETUP ss;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ Zero(&ss, sizeof(ss));
+ ss.s = s;
+ ss.IsBridge = ss.s->Bridge;
+ ss.Rpc = s->Rpc;
+
+ if (Dialog(hWnd, D_SM_SETUP, SmSetupDlg, &ss) == false)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// License registration process
+void SmLicenseAddDlgOnOk(HWND hWnd, SM_SERVER *s)
+{
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SmLicenseAddDlgGetText(hWnd, tmp, sizeof(tmp));
+
+ if (LiIsLicenseKey(tmp))
+ {
+ RPC_TEST t;
+
+ Disable(hWnd, IDOK);
+ Disable(hWnd, IDCANCEL);
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.StrValue, sizeof(t.StrValue), tmp);
+
+ if (CALL(hWnd, ScAddLicenseKey(s->Rpc, &t)) == false)
+ {
+ FocusEx(hWnd, B_KEY6);
+ }
+ else
+ {
+ EndDialog(hWnd, true);
+ }
+
+ Enable(hWnd, IDOK);
+ Enable(hWnd, IDCANCEL);
+ }
+}
+
+// Shift treatment of text input
+void SmLicenseAddDlgShiftTextItem(HWND hWnd, UINT id1, UINT id2, UINT *next_focus)
+{
+ char *s;
+ // Validate arguments
+ if (hWnd == NULL || next_focus == NULL)
+ {
+ return;
+ }
+
+ s = GetTextA(hWnd, id1);
+ if (StrLen(s) >= 6)
+ {
+ char *s2 = CopyStr(s);
+ char tmp[MAX_SIZE];
+ s2[6] = 0;
+ SetTextA(hWnd, id1, s2);
+ Free(s2);
+
+ if (id2 != 0)
+ {
+ GetTxtA(hWnd, id2, tmp, sizeof(tmp));
+
+ StrCat(tmp, sizeof(tmp), s + 6);
+ ReplaceStrEx(tmp, sizeof(tmp), tmp, "-", "", false);
+
+ SetTextA(hWnd, id2, tmp);
+
+ *next_focus = id2;
+ }
+ else
+ {
+ *next_focus = IDOK;
+ }
+ }
+
+ Free(s);
+}
+
+// Make a text from the input data
+void SmLicenseAddDlgGetText(HWND hWnd, char *str, UINT size)
+{
+ char *k1, *k2, *k3, *k4, *k5, *k6;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return;
+ }
+
+ k1 = GetTextA(hWnd, B_KEY1);
+ k2 = GetTextA(hWnd, B_KEY2);
+ k3 = GetTextA(hWnd, B_KEY3);
+ k4 = GetTextA(hWnd, B_KEY4);
+ k5 = GetTextA(hWnd, B_KEY5);
+ k6 = GetTextA(hWnd, B_KEY6);
+
+ Format(str, size, "%s-%s-%s-%s-%s-%s", k1, k2, k3, k4, k5, k6);
+
+ Free(k1);
+ Free(k2);
+ Free(k3);
+ Free(k4);
+ Free(k5);
+ Free(k6);
+}
+
+// License addition dialog update
+void SmLicenseAddDlgUpdate(HWND hWnd, SM_SERVER *s)
+{
+ UINT next_focus = 0;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (s == NULL || hWnd == NULL)
+ {
+ return;
+ }
+
+ SmLicenseAddDlgShiftTextItem(hWnd, B_KEY1, B_KEY2, &next_focus);
+ SmLicenseAddDlgShiftTextItem(hWnd, B_KEY2, B_KEY3, &next_focus);
+ SmLicenseAddDlgShiftTextItem(hWnd, B_KEY3, B_KEY4, &next_focus);
+ SmLicenseAddDlgShiftTextItem(hWnd, B_KEY4, B_KEY5, &next_focus);
+ SmLicenseAddDlgShiftTextItem(hWnd, B_KEY5, B_KEY6, &next_focus);
+ SmLicenseAddDlgShiftTextItem(hWnd, B_KEY6, 0, &next_focus);
+
+ if ((IsFocus(hWnd, B_KEY1) && GetTextLen(hWnd, B_KEY1, true) <= 5) ||
+ (IsFocus(hWnd, B_KEY2) && GetTextLen(hWnd, B_KEY2, true) <= 5) ||
+ (IsFocus(hWnd, B_KEY3) && GetTextLen(hWnd, B_KEY3, true) <= 5) ||
+ (IsFocus(hWnd, B_KEY4) && GetTextLen(hWnd, B_KEY4, true) <= 5) ||
+ (IsFocus(hWnd, B_KEY5) && GetTextLen(hWnd, B_KEY5, true) <= 5) ||
+ (IsFocus(hWnd, B_KEY6) && GetTextLen(hWnd, B_KEY6, true) <= 5))
+ {
+ next_focus = 0;
+ }
+
+ if (next_focus != 0)
+ {
+ Focus(hWnd, next_focus);
+ }
+
+ SmLicenseAddDlgGetText(hWnd, tmp, sizeof(tmp));
+
+ SetEnable(hWnd, IDOK, LiIsLicenseKey(tmp));
+}
+
+// License addition dialog initialization
+void SmLicenseAddDlgInit(HWND hWnd, SM_SERVER *s)
+{
+ HFONT h;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ h = GetFont("Arial", 10, true, false, false, false);
+ SetFont(hWnd, B_KEY1, h);
+ SetFont(hWnd, B_KEY2, h);
+ SetFont(hWnd, B_KEY3, h);
+ SetFont(hWnd, B_KEY4, h);
+ SetFont(hWnd, B_KEY5, h);
+ SetFont(hWnd, B_KEY6, h);
+
+ DlgFont(hWnd, S_INFO, 10, true);
+
+ SmLicenseAddDlgUpdate(hWnd, s);
+}
+
+// License addition dialog
+UINT SmLicenseAddDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_SERVER *s = (SM_SERVER *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmLicenseAddDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case B_KEY1:
+ case B_KEY2:
+ case B_KEY3:
+ case B_KEY4:
+ case B_KEY5:
+ case B_KEY6:
+ switch (HIWORD(wParam))
+ {
+ case EN_CHANGE:
+ SmLicenseAddDlgUpdate(hWnd, s);
+
+ switch (LOWORD(wParam))
+ {
+ case B_KEY2:
+ if (GetTextLen(hWnd, B_KEY2, true) == 0)
+ {
+ FocusEx(hWnd, B_KEY1);
+ }
+ break;
+ case B_KEY3:
+ if (GetTextLen(hWnd, B_KEY3, true) == 0)
+ {
+ FocusEx(hWnd, B_KEY2);
+ }
+ break;
+ case B_KEY4:
+ if (GetTextLen(hWnd, B_KEY4, true) == 0)
+ {
+ FocusEx(hWnd, B_KEY3);
+ }
+ break;
+ case B_KEY5:
+ if (GetTextLen(hWnd, B_KEY5, true) == 0)
+ {
+ FocusEx(hWnd, B_KEY4);
+ }
+ break;
+ case B_KEY6:
+ if (GetTextLen(hWnd, B_KEY6, true) == 0)
+ {
+ FocusEx(hWnd, B_KEY5);
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ SmLicenseAddDlgOnOk(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Add a license
+bool SmLicenseAdd(HWND hWnd, SM_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ return Dialog(hWnd, D_SM_LICENSE_ADD, SmLicenseAddDlg, s);
+}
+
+// License dialog initialization
+void SmLicenseDlgInit(HWND hWnd, SM_SERVER *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_CERT);
+
+ DlgFont(hWnd, S_BOLD, 0, true);
+ DlgFont(hWnd, S_BOLD2, 0, true);
+
+ LvInit(hWnd, L_LIST);
+ LvSetStyle(hWnd, L_LIST, LVS_EX_GRIDLINES);
+ LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_LICENSE_COLUMN_1"), 50);
+ LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_LICENSE_COLUMN_2"), 100);
+ LvInsertColumn(hWnd, L_LIST, 2, _UU("SM_LICENSE_COLUMN_3"), 290);
+ LvInsertColumn(hWnd, L_LIST, 3, _UU("SM_LICENSE_COLUMN_4"), 150);
+ LvInsertColumn(hWnd, L_LIST, 4, _UU("SM_LICENSE_COLUMN_5"), 120);
+ LvInsertColumn(hWnd, L_LIST, 5, _UU("SM_LICENSE_COLUMN_6"), 250);
+ LvInsertColumn(hWnd, L_LIST, 6, _UU("SM_LICENSE_COLUMN_7"), 100);
+ LvInsertColumn(hWnd, L_LIST, 7, _UU("SM_LICENSE_COLUMN_8"), 100);
+ LvInsertColumn(hWnd, L_LIST, 8, _UU("SM_LICENSE_COLUMN_9"), 100);
+
+ LvInitEx(hWnd, L_STATUS, true);
+ LvInsertColumn(hWnd, L_STATUS, 0, _UU("SM_STATUS_COLUMN_1"), 100);
+ LvInsertColumn(hWnd, L_STATUS, 1, _UU("SM_STATUS_COLUMN_2"), 100);
+
+ SmLicenseDlgRefresh(hWnd, s);
+}
+
+// License dialog update
+void SmLicenseDlgRefresh(HWND hWnd, SM_SERVER *s)
+{
+ RPC_ENUM_LICENSE_KEY t;
+ RPC_LICENSE_STATUS st;
+ UINT i;
+ wchar_t tmp[MAX_SIZE];
+ LVB *b;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+
+ if (CALL(hWnd, ScEnumLicenseKey(s->Rpc, &t)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ b = LvInsertStart();
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ wchar_t tmp1[32], tmp2[LICENSE_KEYSTR_LEN + 1], tmp3[LICENSE_MAX_PRODUCT_NAME_LEN + 1],
+ *tmp4, tmp5[128], tmp6[LICENSE_LICENSEID_STR_LEN + 1], tmp7[64],
+ tmp8[64], tmp9[64];
+ RPC_ENUM_LICENSE_KEY_ITEM *e = &t.Items[i];
+
+ UniToStru(tmp1, e->Id);
+ StrToUni(tmp2, sizeof(tmp2), e->LicenseKey);
+ StrToUni(tmp3, sizeof(tmp3), e->LicenseName);
+ tmp4 = LiGetLicenseStatusStr(e->Status);
+ if (e->Expires == 0)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_LICENSE_NO_EXPIRES"));
+ }
+ else
+ {
+ GetDateStrEx64(tmp5, sizeof(tmp5), e->Expires, NULL);
+ }
+ StrToUni(tmp6, sizeof(tmp6), e->LicenseId);
+ UniToStru(tmp7, e->ProductId);
+ UniFormat(tmp8, sizeof(tmp8), L"%I64u", e->SystemId);
+ UniToStru(tmp9, e->SerialId);
+
+ LvInsertAdd(b,
+ e->Status == LICENSE_STATUS_OK ? ICO_PASS : ICO_DISCARD,
+ (void *)e->Id, 9,
+ tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9);
+ }
+
+ LvInsertEnd(b, hWnd, L_LIST);
+
+ FreeRpcEnumLicenseKey(&t);
+
+ Zero(&st, sizeof(st));
+
+ if (CALL(hWnd, ScGetLicenseStatus(s->Rpc, &st)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ b = LvInsertStart();
+
+ if (st.EditionId == LICENSE_EDITION_VPN3_NO_LICENSE)
+ {
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_NO_LICENSE_COLUMN"), _UU("SM_NO_LICENSE"));
+ }
+ else
+ {
+ // Product edition name
+ StrToUni(tmp, sizeof(tmp), st.EditionStr);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_EDITION"), tmp);
+
+ // Release date
+ if (st.ReleaseDate != 0)
+ {
+ GetDateStrEx64(tmp, sizeof(tmp), st.ReleaseDate, NULL);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_RELEASE"), tmp);
+ }
+
+ // Current system ID
+ UniFormat(tmp, sizeof(tmp), L"%I64u", st.SystemId);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_SYSTEM_ID"), tmp);
+
+ // Expiration date of the current product license
+ if (st.SystemExpires == 0)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_NO_EXPIRES"));
+ }
+ else
+ {
+ GetDateStrEx64(tmp, sizeof(tmp), st.SystemExpires, NULL);
+ }
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_EXPIRES"), tmp);
+
+ // Subscription (support) contract
+ if (st.NeedSubscription == false)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_STATUS_SUBSCRIPTION_NONEED"));
+ }
+ else
+ {
+ if (st.SubscriptionExpires == 0)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_STATUS_SUBSCRIPTION_NONE"));
+ }
+ else
+ {
+ wchar_t dtstr[MAX_PATH];
+
+ GetDateStrEx64(dtstr, sizeof(dtstr), st.SubscriptionExpires, NULL);
+
+ UniFormat(tmp, sizeof(tmp),
+ st.IsSubscriptionExpired ? _UU("SM_LICENSE_STATUS_SUBSCRIPTION_EXPIRED") : _UU("SM_LICENSE_STATUS_SUBSCRIPTION_VALID"),
+ dtstr);
+ }
+ }
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_SUBSCRIPTION"), tmp);
+
+ if (st.NeedSubscription == false && st.SubscriptionExpires != 0)
+ {
+ wchar_t dtstr[MAX_PATH];
+
+ GetDateStrEx64(dtstr, sizeof(dtstr), st.SubscriptionExpires, NULL);
+
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_SUBSCRIPTION_BUILD_STR"), tmp);
+ }
+
+ if (st.NeedSubscription && st.SubscriptionExpires != 0)
+ {
+ wchar_t dtstr[MAX_PATH];
+
+ GetDateStrEx64(dtstr, sizeof(dtstr), st.SubscriptionExpires, NULL);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_LICENSE_STATUS_SUBSCRIPTION_BUILD_STR"), dtstr);
+
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_SUBSCRIPTION_BUILD"), tmp);
+ }
+
+ if (GetCapsBool(s->CapsList, "b_vpn3"))
+ {
+ // Maximum number of users
+ if (st.NumUserCreationLicense == INFINITE)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_INFINITE"));
+ }
+ else
+ {
+ UniToStru(tmp, st.NumUserCreationLicense);
+ }
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_NUM_USER"), tmp);
+ }
+
+ // Available number of concurrent client connections
+ if (st.NumClientConnectLicense == INFINITE)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_INFINITE"));
+ }
+ else
+ {
+ UniToStru(tmp, st.NumClientConnectLicense);
+ }
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_NUM_CLIENT"), tmp);
+
+ // Available number of concurrent Bridge connections
+ if (st.NumBridgeConnectLicense == INFINITE)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_LICENSE_INFINITE"));
+ }
+ else
+ {
+ UniToStru(tmp, st.NumBridgeConnectLicense);
+ }
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_NUM_BRIDGE"), tmp);
+
+ // Availability of enterprise features
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_LICENSE_STATUS_ENTERPRISE"),
+ st.AllowEnterpriseFunction ? _UU("SM_LICENSE_STATUS_ENTERPRISE_YES") : _UU("SM_LICENSE_STATUS_ENTERPRISE_NO"));
+ }
+
+ LvInsertEnd(b, hWnd, L_STATUS);
+
+ if (LvNum(hWnd, L_STATUS) >= 1)
+ {
+ LvAutoSize(hWnd, L_STATUS);
+ }
+
+ SmLicenseDlgUpdate(hWnd, s);
+}
+
+// License dialog control update
+void SmLicenseDlgUpdate(HWND hWnd, SM_SERVER *s)
+{
+ bool b = false;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ b = LvIsSingleSelected(hWnd, L_LIST);
+
+ SetEnable(hWnd, B_DEL, b);
+ SetEnable(hWnd, IDOK, b);
+}
+
+// License dialog
+UINT SmLicenseDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_SERVER *s = (SM_SERVER *)param;
+ NMHDR *n;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmLicenseDlgInit(hWnd, s);
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ case L_STATUS:
+ SmLicenseDlgUpdate(hWnd, s);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ if (IsEnable(hWnd, IDOK))
+ {
+ UINT i = LvGetSelected(hWnd, L_LIST);
+
+ if (i != INFINITE)
+ {
+ char *s = LvGetStrA(hWnd, L_LIST, i, 1);
+ char tmp[MAX_SIZE];
+
+ Format(tmp, sizeof(tmp), _SS("LICENSE_SUPPORT_URL"), s);
+ ShellExecute(hWnd, "open", tmp, NULL, NULL, SW_SHOW);
+
+ Free(s);
+ }
+ }
+ break;
+
+ case B_OBTAIN:
+ ShellExecute(hWnd, "open", _SS("LICENSE_INFO_URL"), NULL, NULL, SW_SHOW);
+ break;
+
+ case B_ADD:
+ if (SmLicenseAdd(hWnd, s))
+ {
+ SmLicenseDlgRefresh(hWnd, s);
+ }
+ break;
+
+ case B_DEL:
+ if (IsEnable(hWnd, B_DEL))
+ {
+ UINT id = (UINT)LvGetParam(hWnd, L_LIST, LvGetSelected(hWnd, L_LIST));
+
+ if (id != 0)
+ {
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("SM_LICENSE_DELETE_MSG")) == IDYES)
+ {
+ RPC_TEST t;
+
+ Zero(&t, sizeof(t));
+ t.IntValue = id;
+
+ if (CALL(hWnd, ScDelLicenseKey(s->Rpc, &t)))
+ {
+ SmLicenseDlgRefresh(hWnd, s);
+ }
+ }
+ }
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_LIST);
+
+ return 0;
+}
+
+// Add or Remove license
+void SmLicense(HWND hWnd, SM_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_SM_LICENSE, SmLicenseDlg, s);
+
+ FreeCapsList(s->CapsList);
+ s->CapsList = ScGetCapsEx(s->Rpc);
+}
+
+// Log storing procedure
+UINT SmSaveLogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_READ_LOG_FILE *p = (SM_READ_LOG_FILE *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ FormatText(hWnd, S_INFO, p->filepath);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ case B_SAVE:
+ if (p->Buffer != NULL)
+ {
+ char filename[MAX_PATH];
+
+ Format(filename, sizeof(filename), "%s_%s", p->server_name, p->filepath);
+ ConvertSafeFileName(filename, sizeof(filename), filename);
+
+ if (wParam == IDOK)
+ {
+ // Open with an editor
+ char fullpath[MAX_PATH];
+
+ Format(fullpath, sizeof(fullpath), "%s\\%s",
+ MsGetMyTempDir(), filename);
+
+ if (DumpBuf(p->Buffer, fullpath) == false)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("SM_READ_SAVE_TMP_FAILED"),
+ fullpath);
+ }
+ else
+ {
+ if (((UINT)ShellExecute(hWnd, "open", fullpath, NULL, NULL, SW_SHOWNORMAL)) > 32)
+ {
+ EndDialog(hWnd, true);
+ }
+ else
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SM_READ_SAVE_OPEN_ERROR"), fullpath);
+ }
+ }
+ }
+ else
+ {
+ // Save to a file
+ wchar_t def[MAX_PATH];
+ wchar_t *uni_path;
+
+ StrToUni(def, sizeof(def), filename);
+
+ uni_path = SaveDlg(hWnd, _UU("SM_READ_SAVE_DLG_FILTER"), _UU("SM_READ_SAVE_DLG_TITLE"),
+ def, L".log");
+
+ if (uni_path != NULL)
+ {
+ char path[MAX_PATH];
+
+ UniToStr(path, sizeof(path), uni_path);
+ Free(uni_path);
+
+ if (DumpBuf(p->Buffer, path) == false)
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("SM_READ_SAVE_FAILED"));
+ }
+ else
+ {
+ EndDialog(hWnd, true);
+ }
+ }
+ }
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Download callback procedure
+bool SmReadLogFileProc(DOWNLOAD_PROGRESS *g)
+{
+ wchar_t tmp[MAX_SIZE];
+ char size1[64], size2[64];
+ SM_READ_LOG_FILE *p;
+ HWND hWnd;
+ // Validate arguments
+ if (g == NULL)
+ {
+ return false;
+ }
+
+ p = (SM_READ_LOG_FILE *)g->Param;
+ hWnd = p->hWnd;
+
+ SetPos(hWnd, P_PROGRESS, g->ProgressPercent);
+
+ ToStrByte(size1, sizeof(size1), g->CurrentSize);
+ ToStrByte(size2, sizeof(size2), g->TotalSize);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_READ_LOG_FILE_INFO_2"), size2, size1);
+
+ SetText(hWnd, S_INFO, tmp);
+
+ DoEvents(hWnd);
+
+ return p->cancel_flag ? false : true;
+}
+
+// Log file download dialog procedure
+UINT SmReadLogFile(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_READ_LOG_FILE *p = (SM_READ_LOG_FILE *)param;
+ BUF *buf;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ p->hWnd = hWnd;
+ SetFont(hWnd, S_INFO, Font(11, true));
+ SetText(hWnd, S_INFO, _UU("SM_READ_LOG_FILE_INFO_1"));
+ DisableClose(hWnd);
+ FormatText(hWnd, S_INFO2, p->filepath);
+ SetRange(hWnd, P_PROGRESS, 0, 100);
+
+ SetTimer(hWnd, 1, 100, NULL);
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+ buf = DownloadFileFromServer(p->s->Rpc, p->server_name, p->filepath, p->totalsize, SmReadLogFileProc, p);
+ if (buf == NULL)
+ {
+ if (p->cancel_flag == false)
+ {
+ // Download failure
+ MsgBox(hWnd, MB_ICONSTOP, _UU("SM_READ_LOG_FILE_ERROR"));
+ }
+ EndDialog(hWnd, false);
+ }
+ else
+ {
+ // Download success
+ p->Buffer = buf;
+ Dialog(hWnd, D_SM_SAVE_LOG, SmSaveLogProc, p);
+ FreeBuf(buf);
+ EndDialog(hWnd, true);
+ }
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDCANCEL:
+ p->cancel_flag = true;
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Start the download of the log file
+void SmLogFileStartDownload(HWND hWnd, SM_SERVER *s, char *server_name, char *filepath, UINT totalsize)
+{
+ SM_READ_LOG_FILE p;
+ // Validate arguments
+ if (hWnd == NULL || server_name == NULL || filepath == NULL || totalsize == 0)
+ {
+ return;
+ }
+
+ Zero(&p, sizeof(p));
+ p.filepath = filepath;
+ p.s = s;
+ p.server_name = server_name;
+ p.totalsize = totalsize;
+
+ Dialog(hWnd, D_SM_READ_LOG_FILE, SmReadLogFile, &p);
+}
+
+// Initialize the dialog
+void SmLogFileDlgInit(HWND hWnd, SM_SERVER *p)
+{
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_LOG2);
+
+ LvInit(hWnd, L_LIST);
+
+ LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_LOG_FILE_COLUMN_1"), 250);
+ LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_LOG_FILE_COLUMN_2"), 100);
+ LvInsertColumn(hWnd, L_LIST, 2, _UU("SM_LOG_FILE_COLUMN_3"), 130);
+ LvInsertColumn(hWnd, L_LIST, 3, _UU("SM_LOG_FILE_COLUMN_4"), 110);
+
+ SmLogFileDlgRefresh(hWnd, p);
+}
+
+// Dialog content update
+void SmLogFileDlgRefresh(HWND hWnd, SM_SERVER *p)
+{
+ UINT i;
+ LVB *v;
+ RPC_ENUM_LOG_FILE t;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ if (CALL(hWnd, ScEnumLogFile(p->Rpc, &t)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ v = LvInsertStart();
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_LOG_FILE_ITEM *e = &t.Items[i];
+ wchar_t tmp1[MAX_PATH], tmp2[128], tmp3[128], tmp4[MAX_HOST_NAME_LEN + 1];
+ char tmp[MAX_SIZE];
+
+ StrToUni(tmp1, sizeof(tmp1), e->FilePath);
+
+ ToStrByte(tmp, sizeof(tmp), e->FileSize);
+ StrToUni(tmp2, sizeof(tmp2), tmp);
+
+ GetDateTimeStr64Uni(tmp3, sizeof(tmp3), SystemToLocal64(e->UpdatedTime));
+
+ StrToUni(tmp4, sizeof(tmp4), e->ServerName);
+
+ LvInsertAdd(v, ICO_LOG2, (void *)e->FileSize, 4, tmp1, tmp2, tmp3, tmp4);
+ }
+
+ LvInsertEndEx(v, hWnd, L_LIST, true);
+
+ if (t.NumItem != 0)
+ {
+ LvAutoSize(hWnd, L_LIST);
+ }
+
+ FreeRpcEnumLogFile(&t);
+
+ SmLogFileDlgUpdate(hWnd, p);
+}
+
+// Update the dialog control
+void SmLogFileDlgUpdate(HWND hWnd, SM_SERVER *p)
+{
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ SetEnable(hWnd, IDOK, LvIsSingleSelected(hWnd, L_LIST));
+}
+
+// Log file dialog procedure
+UINT SmLogFileDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ NMHDR *n;
+ SM_SERVER *p = (SM_SERVER *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmLogFileDlgInit(hWnd, p);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ if (IsEnable(hWnd, IDOK))
+ {
+ UINT i = LvGetSelected(hWnd, L_LIST);
+ if (i != INFINITE)
+ {
+ UINT size = (UINT)LvGetParam(hWnd, L_LIST, i);
+ char *server_name;
+ char *filepath;
+
+ server_name = LvGetStrA(hWnd, L_LIST, i, 3);
+ filepath = LvGetStrA(hWnd, L_LIST, i, 0);
+ SmLogFileStartDownload(hWnd, p, server_name, filepath, size);
+ Free(filepath);
+ Free(server_name);
+ }
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case B_REFRESH:
+ SmLogFileDlgRefresh(hWnd, p);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ SmLogFileDlgUpdate(hWnd, p);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_LIST);
+
+ return 0;
+}
+
+// Initialize the dialog
+void SmHubEditAcDlgInit(HWND hWnd, SM_EDIT_AC *p)
+{
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ SetEnable(hWnd, R_IPV6, GetCapsBool(p->e->s->p->CapsList, "b_support_ipv6_ac"));
+
+ if (p->id == 0)
+ {
+ UINT i, v;
+
+ Check(hWnd, R_SINGLE, true);
+ Check(hWnd, R_PASS, true);
+ Check(hWnd, R_IPV4, true);
+
+ v = 0;
+
+ for (i = 0;i < LIST_NUM(p->e->AcList);i++)
+ {
+ AC *ac = LIST_DATA(p->e->AcList, i);
+
+ v = MAX(v, ac->Priority);
+ }
+
+ v += 100;
+
+ SetInt(hWnd, E_PRIORITY, v);
+ }
+ else
+ {
+ AC *ac = GetAc(p->e->AcList, p->id);
+
+ if (ac == NULL)
+ {
+ EndDialog(hWnd, false);
+ return;
+ }
+
+ Check(hWnd, R_SINGLE, ac->Masked == false);
+ Check(hWnd, R_MASKED, ac->Masked);
+ Check(hWnd, R_IPV4, IsIP4(&ac->IpAddress));
+ Check(hWnd, R_IPV6, IsIP6(&ac->IpAddress));
+
+ if (IsIP4(&ac->IpAddress))
+ {
+ IpSet(hWnd, E_IP, IPToUINT(&ac->IpAddress));
+ }
+ else
+ {
+ char tmp[MAX_SIZE];
+
+ IPToStr(tmp, sizeof(tmp), &ac->IpAddress);
+ SetTextA(hWnd, E_IPV6, tmp);
+ }
+
+ if (ac->Masked)
+ {
+ if (IsIP4(&ac->IpAddress))
+ {
+ IpSet(hWnd, E_MASK, IPToUINT(&ac->SubnetMask));
+ }
+ else
+ {
+ char tmp[MAX_SIZE];
+
+ MaskToStrEx(tmp, sizeof(tmp), &ac->SubnetMask, false);
+
+ if (IsNum(tmp))
+ {
+ StrCatLeft(tmp, sizeof(tmp), "/");
+ }
+
+ SetTextA(hWnd, E_MASKV6, tmp);
+ }
+ }
+
+ Check(hWnd, R_PASS, ac->Deny == false);
+ Check(hWnd, R_DENY, ac->Deny);
+ SetInt(hWnd, E_PRIORITY, ac->Priority);
+
+ Free(ac);
+ }
+
+ Focus(hWnd, E_IP);
+
+ SmHubEditAcDlgUpdate(hWnd, p);
+}
+
+// Dialog update
+void SmHubEditAcDlgUpdate(HWND hWnd, SM_EDIT_AC *p)
+{
+ bool b = true;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (IsChecked(hWnd, R_SINGLE))
+ {
+ if (IsChecked(hWnd, R_IPV6) == false)
+ {
+ Show(hWnd, E_IP);
+ Hide(hWnd, E_IPV6);
+
+ if (IpIsFilled(hWnd, E_IP) == false)
+ {
+ b = false;
+ }
+
+ if (IpGet(hWnd, E_IP) == 0 || IpGet(hWnd, E_IP) == 0xffffffff)
+ {
+ b = false;
+ }
+ }
+ else
+ {
+ Show(hWnd, E_IPV6);
+ Hide(hWnd, E_IP);
+
+ GetTxtA(hWnd, E_IPV6, tmp, sizeof(tmp));
+
+ if (IsStrIPv6Address(tmp) == false)
+ {
+ b = false;
+ }
+ }
+
+ Hide(hWnd, S_MASK);
+ Hide(hWnd, E_MASK);
+ Hide(hWnd, E_MASKV6);
+ }
+ else
+ {
+ if (IsChecked(hWnd, R_IPV6) == false)
+ {
+ Show(hWnd, E_IP);
+ Hide(hWnd, E_IPV6);
+
+ if (IpIsFilled(hWnd, E_IP) == false || IpIsFilled(hWnd, E_MASK) == false)
+ {
+ b = false;
+ }
+
+ if (IpGet(hWnd, E_IP) == 0xffffffff)
+ {
+ b = false;
+ }
+ }
+ else
+ {
+ char tmp1[MAX_SIZE], tmp2[MAX_SIZE];
+
+ Show(hWnd, E_IPV6);
+ Hide(hWnd, E_IP);
+
+ GetTxtA(hWnd, E_IPV6, tmp1, sizeof(tmp1));
+ GetTxtA(hWnd, E_MASKV6, tmp2, sizeof(tmp2));
+
+ if (!(IsIpStr6(tmp1) && IsIpMask6(tmp2)))
+ {
+ b = false;
+ }
+ }
+
+ Show(hWnd, S_MASK);
+ SetShow(hWnd, E_MASK, !IsChecked(hWnd, R_IPV6));
+ SetShow(hWnd, E_MASKV6, IsChecked(hWnd, R_IPV6));
+ }
+
+ if (GetInt(hWnd, E_PRIORITY) == 0)
+ {
+ b = false;
+ }
+
+ SetIcon(hWnd, S_ICON, IsChecked(hWnd, R_PASS) ? ICO_INTERNET : ICO_INTERNET_X);
+
+ SetEnable(hWnd, IDOK, b);
+}
+
+// OK button is clicked in the dialog
+void SmHubEditAcDlgOnOk(HWND hWnd, SM_EDIT_AC *p)
+{
+ AC ac;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(&ac, sizeof(ac));
+ ac.Deny = IsChecked(hWnd, R_DENY);
+ ac.Priority = GetInt(hWnd, E_PRIORITY);
+
+ if (IsChecked(hWnd, R_IPV6) == false)
+ {
+ UINTToIP(&ac.IpAddress, IpGet(hWnd, E_IP));
+ }
+ else
+ {
+ GetTxtA(hWnd, E_IPV6, tmp, sizeof(tmp));
+
+ StrToIP6(&ac.IpAddress, tmp);
+ }
+
+ ac.Masked = IsChecked(hWnd, R_MASKED);
+
+ if (ac.Masked)
+ {
+ if (IsChecked(hWnd, R_IPV6) == false)
+ {
+ UINTToIP(&ac.SubnetMask, IpGet(hWnd, E_MASK));
+ }
+ else
+ {
+ GetTxtA(hWnd, E_MASKV6, tmp, sizeof(tmp));
+
+ StrToMask6(&ac.SubnetMask, tmp);
+ }
+ }
+
+ if (p->id != 0)
+ {
+ SetAc(p->e->AcList, p->id, &ac);
+ }
+ else
+ {
+ AddAc(p->e->AcList, &ac);
+ }
+
+ EndDialog(hWnd, true);
+}
+
+// AC edit dialog
+UINT SmHubEditAcDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_EDIT_AC *p = (SM_EDIT_AC *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmHubEditAcDlgInit(hWnd, p);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case R_SINGLE:
+ case R_MASKED:
+ case E_IP:
+ case E_MASK:
+ case R_PASS:
+ case R_DENY:
+ case E_PRIORITY:
+ case R_IPV4:
+ case R_IPV6:
+ case E_IPV6:
+ case E_MASKV6:
+ SmHubEditAcDlgUpdate(hWnd, p);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case R_IPV4:
+ case R_IPV6:
+ case R_SINGLE:
+ case R_MASKED:
+ if (IsChecked(hWnd, R_IPV6) == false)
+ {
+ if (IpIsFilled(hWnd, E_IP))
+ {
+ Focus(hWnd, E_MASK);
+ }
+ else
+ {
+ Focus(hWnd, E_IP);
+ }
+ }
+ else
+ {
+ char tmp[MAX_SIZE];
+
+ GetTxtA(hWnd, E_IPV6, tmp, sizeof(tmp));
+
+ if (IsStrIPv6Address(tmp))
+ {
+ FocusEx(hWnd, E_MASKV6);
+ }
+ else
+ {
+ FocusEx(hWnd, E_IPV6);
+ }
+ }
+ break;
+
+ case IDOK:
+ SmHubEditAcDlgOnOk(hWnd, p);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Initialize the dialog
+void SmHubAcDlgInit(HWND hWnd, SM_EDIT_AC_LIST *p)
+{
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_INTERNET);
+
+ FormatText(hWnd, S_TITLE, p->s->HubName);
+
+ LvInit(hWnd, L_LIST);
+ LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_AC_COLUMN_1"), 40);
+ LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_AC_COLUMN_2"), 80);
+ LvInsertColumn(hWnd, L_LIST, 2, _UU("SM_AC_COLUMN_3"), 90);
+ LvInsertColumn(hWnd, L_LIST, 3, _UU("SM_AC_COLUMN_4"), 170);
+
+ SmHubAcDlgRefresh(hWnd, p);
+}
+
+// Update the dialog control
+void SmHubAcDlgUpdate(HWND hWnd, SM_EDIT_AC_LIST *p)
+{
+ bool b;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ b = LvIsSingleSelected(hWnd, L_LIST);
+
+ SetEnable(hWnd, IDOK, b);
+ SetEnable(hWnd, B_DELETE, b);
+}
+
+// Dialog content update
+void SmHubAcDlgRefresh(HWND hWnd, SM_EDIT_AC_LIST *p)
+{
+ UINT i;
+ LVB *v;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ v = LvInsertStart();
+
+ for (i = 0;i < LIST_NUM(p->AcList);i++)
+ {
+ wchar_t tmp1[32], *tmp2, tmp3[MAX_SIZE], tmp4[32];
+ char *tmp_str;
+ AC *ac = LIST_DATA(p->AcList, i);
+
+ UniToStru(tmp1, ac->Id);
+ tmp2 = ac->Deny ? _UU("SM_AC_DENY") : _UU("SM_AC_PASS");
+ tmp_str = GenerateAcStr(ac);
+ StrToUni(tmp3, sizeof(tmp3), tmp_str);
+
+ Free(tmp_str);
+
+ UniToStru(tmp4, ac->Priority);
+
+ LvInsertAdd(v, ac->Deny ? ICO_INTERNET_X : ICO_INTERNET,
+ (void *)ac->Id, 4, tmp1, tmp4, tmp2, tmp3);
+ }
+
+ LvInsertEnd(v, hWnd, L_LIST);
+ LvSortEx(hWnd, L_LIST, 0, false, true);
+
+
+ SmHubAcDlgUpdate(hWnd, p);
+}
+
+// Access control list editing dialog
+UINT SmHubAcDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ NMHDR *n;
+ SM_EDIT_AC_LIST *p = (SM_EDIT_AC_LIST *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmHubAcDlgInit(hWnd, p);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ if (IsEnable(hWnd, IDOK))
+ {
+ SM_EDIT_AC s;
+ Zero(&s, sizeof(s));
+
+ s.e = p;
+ s.id = (UINT)LvGetParam(hWnd, L_LIST, LvGetSelected(hWnd, L_LIST));
+
+ if (Dialog(hWnd, D_SM_AC, SmHubEditAcDlgProc, &s))
+ {
+ SmHubAcDlgRefresh(hWnd, p);
+ }
+ }
+ break;
+
+ case B_ADD:
+ if (IsEnable(hWnd, B_ADD))
+ {
+ SM_EDIT_AC s;
+ Zero(&s, sizeof(s));
+
+ s.e = p;
+
+ if (Dialog(hWnd, D_SM_AC, SmHubEditAcDlgProc, &s))
+ {
+ SmHubAcDlgRefresh(hWnd, p);
+ }
+ }
+ break;
+
+ case B_DELETE:
+ if (IsEnable(hWnd, B_DELETE))
+ {
+ UINT id = (UINT)LvGetParam(hWnd, L_LIST, LvGetSelected(hWnd, L_LIST));
+
+ if (DelAc(p->AcList, id))
+ {
+ SmHubAcDlgRefresh(hWnd, p);
+ }
+ }
+ break;
+
+ case B_SAVE:
+ if (IsEnable(hWnd, B_SAVE))
+ {
+ RPC_AC_LIST t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), p->s->HubName);
+ t.o = CloneAcList(p->AcList);
+
+ if (CALL(hWnd, ScSetAcList(p->s->p->Rpc, &t)))
+ {
+ EndDialog(hWnd, true);
+ }
+
+ FreeRpcAcList(&t);
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ SmHubAcDlgUpdate(hWnd, p);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_LIST);
+
+ return 0;
+}
+
+// Access control list editing
+void SmHubAc(HWND hWnd, SM_EDIT_HUB *s)
+{
+ SM_EDIT_AC_LIST p;
+ RPC_AC_LIST t;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+ if (CALL(hWnd, ScGetAcList(s->p->Rpc, &t)) == false)
+ {
+ return;
+ }
+
+ Zero(&p, sizeof(p));
+ p.s = s;
+ p.AcList = CloneAcList(t.o);
+
+ FreeRpcAcList(&t);
+
+ Dialog(hWnd, D_SM_AC_LIST, SmHubAcDlgProc, &p);
+
+ FreeAcList(p.AcList);
+}
+
+// Initialize the dialog
+void SmEditCrlDlgInit(HWND hWnd, SM_EDIT_CRL *c)
+{
+ // Validate arguments
+ if (hWnd == NULL || c == NULL)
+ {
+ return;
+ }
+
+ if (c->NewCrl == false)
+ {
+ RPC_CRL t;
+ CRL *crl;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), c->s->HubName);
+ t.Key = c->Key;
+
+ if (CALL(hWnd, ScGetCrl(c->s->Rpc, &t)) == false)
+ {
+ EndDialog(hWnd, false);
+ return;
+ }
+
+ crl = t.Crl;
+
+ SmEditCrlDlgSetName(hWnd, crl->Name);
+ SmEditCrlDlgSetSerial(hWnd, crl->Serial);
+ SmEditCrlDlgSetHash(hWnd, crl->DigestMD5, crl->DigestSHA1);
+
+ FreeRpcCrl(&t);
+ }
+
+ SmEditCrlDlgUpdate(hWnd, c);
+}
+
+// Update the controls
+void SmEditCrlDlgUpdate(HWND hWnd, SM_EDIT_CRL *c)
+{
+ bool b = true;
+ // Validate arguments
+ if (hWnd == NULL || c == NULL)
+ {
+ return;
+ }
+
+ SetEnable(hWnd, E_CN, IsChecked(hWnd, R_CN));
+ SetEnable(hWnd, E_O, IsChecked(hWnd, R_O));
+ SetEnable(hWnd, E_OU, IsChecked(hWnd, R_OU));
+ SetEnable(hWnd, E_C, IsChecked(hWnd, R_C));
+ SetEnable(hWnd, E_ST, IsChecked(hWnd, R_ST));
+ SetEnable(hWnd, E_L, IsChecked(hWnd, R_L));
+ SetEnable(hWnd, E_SERI, IsChecked(hWnd, R_SERI));
+ SetEnable(hWnd, E_MD5_HASH, IsChecked(hWnd, R_MD5_HASH));
+ SetEnable(hWnd, E_SHA1_HASH, IsChecked(hWnd, R_SHA1_HASH));
+
+ if (IsChecked(hWnd, R_CN))
+ {
+ if (IsEmpty(hWnd, E_CN))
+ {
+ b = false;
+ }
+ }
+
+ if (IsChecked(hWnd, R_O))
+ {
+ if (IsEmpty(hWnd, E_O))
+ {
+ b = false;
+ }
+ }
+
+ if (IsChecked(hWnd, R_OU))
+ {
+ if (IsEmpty(hWnd, E_OU))
+ {
+ b = false;
+ }
+ }
+
+ if (IsChecked(hWnd, R_C))
+ {
+ if (IsEmpty(hWnd, E_C))
+ {
+ b = false;
+ }
+ }
+
+ if (IsChecked(hWnd, R_ST))
+ {
+ if (IsEmpty(hWnd, E_ST))
+ {
+ b = false;
+ }
+ }
+
+ if (IsChecked(hWnd, R_L))
+ {
+ if (IsEmpty(hWnd, E_L))
+ {
+ b = false;
+ }
+ }
+
+ if (IsChecked(hWnd, R_SERI))
+ {
+ char tmp[MAX_SIZE];
+ BUF *buf;
+
+ GetTxtA(hWnd, E_SERI, tmp, sizeof(tmp));
+ buf = StrToBin(tmp);
+
+ if (buf->Size == 0)
+ {
+ b = false;
+ }
+
+ FreeBuf(buf);
+ }
+
+ if (IsChecked(hWnd, R_MD5_HASH))
+ {
+ char tmp[MAX_SIZE];
+ BUF *buf;
+
+ GetTxtA(hWnd, E_MD5_HASH, tmp, sizeof(tmp));
+ buf = StrToBin(tmp);
+
+ if (buf->Size != MD5_SIZE)
+ {
+ b = false;
+ }
+
+ FreeBuf(buf);
+ }
+
+ if (IsChecked(hWnd, R_SHA1_HASH))
+ {
+ char tmp[MAX_SIZE];
+ BUF *buf;
+
+ GetTxtA(hWnd, E_SHA1_HASH, tmp, sizeof(tmp));
+ buf = StrToBin(tmp);
+
+ if (buf->Size != SHA1_SIZE)
+ {
+ b = false;
+ }
+
+ FreeBuf(buf);
+ }
+
+ SetEnable(hWnd, IDOK, b);
+}
+
+// On click the OK button
+void SmEditCrlDlgOnOk(HWND hWnd, SM_EDIT_CRL *c)
+{
+ CRL *crl;
+ NAME *n;
+ RPC_CRL t;
+ bool empty = true;
+ // Validate arguments
+ if (hWnd == NULL || c == NULL)
+ {
+ return;
+ }
+
+ crl = ZeroMalloc(sizeof(CRL));
+ crl->Name = ZeroMalloc(sizeof(NAME));
+ n = crl->Name;
+
+ if (IsChecked(hWnd, R_CN))
+ {
+ n->CommonName = GetText(hWnd, E_CN);
+ empty = false;
+ }
+
+ if (IsChecked(hWnd, R_O))
+ {
+ n->Organization = GetText(hWnd, E_O);
+ empty = false;
+ }
+
+ if (IsChecked(hWnd, R_OU))
+ {
+ n->Unit = GetText(hWnd, E_OU);
+ empty = false;
+ }
+
+ if (IsChecked(hWnd, R_C))
+ {
+ n->Country = GetText(hWnd, E_C);
+ empty = false;
+ }
+
+ if (IsChecked(hWnd, R_ST))
+ {
+ n->State = GetText(hWnd, E_ST);
+ empty = false;
+ }
+
+ if (IsChecked(hWnd, R_L))
+ {
+ n->Local = GetText(hWnd, E_L);
+ empty = false;
+ }
+
+ if (IsChecked(hWnd, R_SERI))
+ {
+ char tmp[MAX_SIZE];
+ BUF *b;
+
+ GetTxtA(hWnd, E_SERI, tmp, sizeof(tmp));
+ b = StrToBin(tmp);
+
+ if (b != NULL && b->Size >= 1)
+ {
+ crl->Serial = NewXSerial(b->Buf, b->Size);
+ }
+
+ FreeBuf(b);
+
+ empty = false;
+ }
+
+ if (IsChecked(hWnd, R_MD5_HASH))
+ {
+ char tmp[MAX_SIZE];
+ BUF *b;
+
+ GetTxtA(hWnd, E_MD5_HASH, tmp, sizeof(tmp));
+ b = StrToBin(tmp);
+
+ if (b != NULL && b->Size == MD5_SIZE)
+ {
+ Copy(crl->DigestMD5, b->Buf, MD5_SIZE);
+ }
+
+ FreeBuf(b);
+
+ empty = false;
+ }
+
+ if (IsChecked(hWnd, R_SHA1_HASH))
+ {
+ char tmp[MAX_SIZE];
+ BUF *b;
+
+ GetTxtA(hWnd, E_SHA1_HASH, tmp, sizeof(tmp));
+ b = StrToBin(tmp);
+
+ if (b != NULL && b->Size == SHA1_SIZE)
+ {
+ Copy(crl->DigestSHA1, b->Buf, SHA1_SIZE);
+ }
+
+ FreeBuf(b);
+
+ empty = false;
+ }
+
+ if (empty)
+ {
+ if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, _UU("SM_CRL_EMPTY_MSG")) == IDNO)
+ {
+ return;
+ }
+ }
+
+ if (c->NewCrl)
+ {
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), c->s->HubName);
+ t.Crl = crl;
+
+ if (CALL(hWnd, ScAddCrl(c->s->Rpc, &t)))
+ {
+ EndDialog(hWnd, true);
+ }
+
+ FreeRpcCrl(&t);
+ }
+ else
+ {
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), c->s->HubName);
+ t.Crl = crl;
+ t.Key = c->Key;
+
+ if (CALL(hWnd, ScSetCrl(c->s->Rpc, &t)))
+ {
+ EndDialog(hWnd, true);
+ }
+
+ FreeRpcCrl(&t);
+ }
+}
+
+// Read the certificate
+void SmEditCrlDlgOnLoad(HWND hWnd, SM_EDIT_CRL *c)
+{
+ X *x;
+ // Validate arguments
+ if (hWnd == NULL || c == NULL)
+ {
+ return;
+ }
+
+ if (CmLoadXFromFileOrSecureCard(hWnd, &x))
+ {
+ UCHAR md5[MD5_SIZE], sha1[SHA1_SIZE];
+
+ SmEditCrlDlgSetName(hWnd, x->subject_name);
+ SmEditCrlDlgSetSerial(hWnd, x->serial);
+ GetXDigest(x, md5, false);
+ GetXDigest(x, sha1, true);
+ SmEditCrlDlgSetHash(hWnd, md5, sha1);
+
+ FreeX(x);
+
+ SmEditCrlDlgUpdate(hWnd, c);
+ }
+}
+
+// Set the hash information to the dialog
+void SmEditCrlDlgSetHash(HWND hWnd, UCHAR *hash_md5, UCHAR *hash_sha1)
+{
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (hash_md5 != NULL && IsZero(hash_md5, MD5_SIZE) == false)
+ {
+ Check(hWnd, R_MD5_HASH, true);
+ BinToStrEx(tmp, sizeof(tmp), hash_md5, MD5_SIZE);
+ SetTextA(hWnd, E_MD5_HASH, tmp);
+ }
+ else
+ {
+ Check(hWnd, R_MD5_HASH, false);
+ }
+
+ if (hash_sha1 != NULL && IsZero(hash_sha1, SHA1_SIZE) == false)
+ {
+ Check(hWnd, R_SHA1_HASH, true);
+ BinToStrEx(tmp, sizeof(tmp), hash_sha1, SHA1_SIZE);
+ SetTextA(hWnd, E_SHA1_HASH, tmp);
+ }
+ else
+ {
+ Check(hWnd, R_SHA1_HASH, false);
+ }
+}
+
+// Set the serial number to the dialog
+void SmEditCrlDlgSetSerial(HWND hWnd, X_SERIAL *serial)
+{
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || serial == NULL)
+ {
+ return;
+ }
+
+ BinToStrEx(tmp, sizeof(tmp), serial->data, serial->size);
+
+ Check(hWnd, R_SERI, true);
+
+ SetTextA(hWnd, E_SERI, tmp);
+}
+
+// Set the name situation to the dialog
+void SmEditCrlDlgSetName(HWND hWnd, NAME *name)
+{
+ // Validate arguments
+ if (hWnd == NULL || name == NULL)
+ {
+ return;
+ }
+
+ // CN
+ if (UniIsEmptyStr(name->CommonName))
+ {
+ Check(hWnd, R_CN, false);
+ }
+ else
+ {
+ Check(hWnd, R_CN, true);
+ SetText(hWnd, E_CN, name->CommonName);
+ }
+
+ // O
+ if (UniIsEmptyStr(name->Organization))
+ {
+ Check(hWnd, R_O, false);
+ }
+ else
+ {
+ Check(hWnd, R_O, true);
+ SetText(hWnd, E_O, name->Organization);
+ }
+
+ // OU
+ if (UniIsEmptyStr(name->Unit))
+ {
+ Check(hWnd, R_OU, false);
+ }
+ else
+ {
+ Check(hWnd, R_OU, true);
+ SetText(hWnd, E_OU, name->Unit);
+ }
+
+ // C
+ if (UniIsEmptyStr(name->Country))
+ {
+ Check(hWnd, R_C, false);
+ }
+ else
+ {
+ Check(hWnd, R_C, true);
+ SetText(hWnd, E_C, name->Country);
+ }
+
+ // ST
+ if (UniIsEmptyStr(name->State))
+ {
+ Check(hWnd, R_ST, false);
+ }
+ else
+ {
+ Check(hWnd, R_ST, true);
+ SetText(hWnd, E_ST, name->State);
+ }
+
+ // L
+ if (UniIsEmptyStr(name->Local))
+ {
+ Check(hWnd, R_L, false);
+ }
+ else
+ {
+ Check(hWnd, R_L, true);
+ SetText(hWnd, E_L, name->Local);
+ }
+}
+
+// CRL edit dialog procedure
+UINT SmEditCrlDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_EDIT_CRL *c = (SM_EDIT_CRL *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmEditCrlDlgInit(hWnd, c);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case R_CN:
+ case E_CN:
+ case R_O:
+ case E_O:
+ case R_OU:
+ case E_OU:
+ case R_C:
+ case E_C:
+ case R_ST:
+ case E_ST:
+ case R_L:
+ case E_L:
+ case R_SERI:
+ case E_SERI:
+ case R_MD5_HASH:
+ case E_MD5_HASH:
+ case R_SHA1_HASH:
+ case E_SHA1_HASH:
+ SmEditCrlDlgUpdate(hWnd, c);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case B_LOAD:
+ SmEditCrlDlgOnLoad(hWnd, c);
+ break;
+
+ case IDOK:
+ SmEditCrlDlgOnOk(hWnd, c);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case R_CN:
+ FocusEx(hWnd, E_CN);
+ break;
+
+ case R_O:
+ FocusEx(hWnd, E_O);
+ break;
+
+ case R_OU:
+ FocusEx(hWnd, E_OU);
+ break;
+
+ case R_C:
+ FocusEx(hWnd, E_C);
+ break;
+
+ case R_ST:
+ FocusEx(hWnd, E_ST);
+ break;
+
+ case R_L:
+ FocusEx(hWnd, E_L);
+ break;
+
+ case R_SERI:
+ FocusEx(hWnd, E_SERI);
+ break;
+
+ case R_MD5_HASH:
+ FocusEx(hWnd, E_MD5_HASH);
+ break;
+
+ case R_SHA1_HASH:
+ FocusEx(hWnd, E_SHA1_HASH);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Initialize the dialog
+void SmCrlDlgInit(HWND hWnd, SM_HUB *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_CERT_X);
+
+ LvInit(hWnd, L_LIST);
+ LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_CRL_COLUMN_1"), 555);
+
+ SmCrlDlgRefresh(hWnd, s);
+}
+
+// Update the control
+void SmCrlDlgUpdate(HWND hWnd, SM_HUB *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetEnable(hWnd, IDOK, LvIsSingleSelected(hWnd, L_LIST));
+ SetEnable(hWnd, B_DELETE, LvIsSingleSelected(hWnd, L_LIST));
+}
+
+// Content update
+void SmCrlDlgRefresh(HWND hWnd, SM_HUB *s)
+{
+ UINT i;
+ RPC_ENUM_CRL t;
+ LVB *v;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+ if (CALL(hWnd, ScEnumCrl(s->Rpc, &t)) == false)
+ {
+ EndDialog(hWnd, false);
+ return;
+ }
+
+ v = LvInsertStart();
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_CRL_ITEM *e = &t.Items[i];
+ LvInsertAdd(v, ICO_CERT_X, (void *)e->Key, 1, e->CrlInfo);
+ }
+
+ LvInsertEndEx(v, hWnd, L_LIST, true);
+
+ if (t.NumItem >= 1)
+ {
+ LvAutoSize(hWnd, L_LIST);
+ }
+
+ FreeRpcEnumCrl(&t);
+
+ SmCrlDlgUpdate(hWnd, s);
+}
+
+// Certificate revocation list dialog procedure
+UINT SmCrlDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_EDIT_CRL c;
+ SM_HUB *s = (SM_HUB *)param;
+ NMHDR *n;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmCrlDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_ADD:
+ Zero(&c, sizeof(c));
+ c.NewCrl = true;
+ c.s = s;
+
+ if (Dialog(hWnd, D_SM_EDIT_CRL, SmEditCrlDlgProc, &c))
+ {
+ SmCrlDlgRefresh(hWnd, s);
+ }
+ break;
+
+ case B_DELETE:
+ if (IsEnable(hWnd, B_DELETE))
+ {
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("SM_CRL_DELETE_MSG")) == IDYES)
+ {
+ RPC_CRL t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ t.Key = (UINT)LvGetParam(hWnd, L_LIST, LvGetSelected(hWnd, L_LIST));
+
+ if (CALL(hWnd, ScDelCrl(s->Rpc, &t)))
+ {
+ SmCrlDlgRefresh(hWnd, s);
+ }
+
+ FreeRpcCrl(&t);
+ }
+ }
+ break;
+
+ case IDOK:
+ if (IsEnable(hWnd, IDOK))
+ {
+ SM_EDIT_CRL c;
+
+ Zero(&c, sizeof(c));
+ c.NewCrl = false;
+ c.s = s;
+ c.Key = (UINT)LvGetParam(hWnd, L_LIST, LvGetSelected(hWnd, L_LIST));
+
+ if (Dialog(hWnd, D_SM_EDIT_CRL, SmEditCrlDlgProc, &c))
+ {
+ SmCrlDlgRefresh(hWnd, s);
+ }
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ SmCrlDlgUpdate(hWnd, s);
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_LIST);
+
+ return 0;
+}
+
+// Smart Card Manager
+void SmSecureManager(HWND hWnd)
+{
+ UINT id = SmGetCurrentSecureIdFromReg();
+
+ if (id == 0)
+ {
+ id = SmSelectSecureId(hWnd);
+ }
+
+ if (id == 0)
+ {
+ return;
+ }
+
+ CmSecureManager(hWnd, id);
+}
+
+// Initialize the dialog
+void SmSelectKeyPairDlgInit(HWND hWnd, SM_SECURE_KEYPAIR *k)
+{
+ SECURE_DEVICE *dev;
+ // Validate arguments
+ if (hWnd == NULL || k == NULL)
+ {
+ return;
+ }
+
+ dev = GetSecureDevice(k->Id);
+ if (dev != NULL)
+ {
+ FormatText(hWnd, S_INFO, dev->DeviceName);
+ }
+
+ LvInit(hWnd, L_CERT);
+ LvInsertColumn(hWnd, L_CERT, 0, _UU("SEC_MGR_COLUMN1"), 200);
+ LvInsertColumn(hWnd, L_CERT, 1, _UU("SEC_MGR_COLUMN2"), 110);
+
+ LvInit(hWnd, L_KEY);
+ LvInsertColumn(hWnd, L_KEY, 0, _UU("SEC_MGR_COLUMN1"), 200);
+ LvInsertColumn(hWnd, L_KEY, 1, _UU("SEC_MGR_COLUMN2"), 110);
+
+ SetEnable(hWnd, L_CERT, k->UseCert);
+ SetEnable(hWnd, B_BOLD1, k->UseCert);
+ SetEnable(hWnd, L_KEY, k->UseKey);
+ SetEnable(hWnd, B_BOLD2, k->UseKey);
+
+ SetFont(hWnd, B_BOLD1, Font(0, true));
+ SetFont(hWnd, B_BOLD2, Font(0, true));
+
+ SmSelectKeyPairDlgUpdate(hWnd, k);
+}
+
+// Update the dialog control
+void SmSelectKeyPairDlgUpdate(HWND hWnd, SM_SECURE_KEYPAIR *k)
+{
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL || k == NULL)
+ {
+ return;
+ }
+
+ if (k->UseCert)
+ {
+ if (LvIsSingleSelected(hWnd, L_CERT) == false)
+ {
+ ok = false;
+ }
+ else
+ {
+ char *name = LvGetSelectedStrA(hWnd, L_CERT, 0);
+ if (name != NULL)
+ {
+ if (LvIsSingleSelected(hWnd, L_KEY) == false)
+ {
+ if ((k->Flag++) == 0)
+ {
+ LvSelect(hWnd, L_KEY, LvSearchStrA(hWnd, L_KEY, 0, name));
+ }
+ }
+ Free(name);
+ }
+ }
+ }
+
+ if (k->UseKey)
+ {
+ if (LvIsSingleSelected(hWnd, L_KEY) == false)
+ {
+ ok = false;
+ }
+ else
+ {
+ char *name = LvGetSelectedStrA(hWnd, L_KEY, 0);
+ if (name != NULL)
+ {
+ if (LvIsSingleSelected(hWnd, L_CERT) == false)
+ {
+ if ((k->Flag++) == 0)
+ {
+ LvSelect(hWnd, L_CERT, LvSearchStrA(hWnd, L_CERT, 0, name));
+ }
+ }
+ Free(name);
+ }
+ }
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Update the contents
+void SmSelectKeyPairDlgRefresh(HWND hWnd, SM_SECURE_KEYPAIR *k)
+{
+ bool ret;
+ LIST *o;
+ WINUI_SECURE_BATCH batch[] =
+ {
+ {WINUI_SECURE_ENUM_OBJECTS, NULL, false, NULL, NULL, NULL, NULL, NULL, NULL},
+ };
+ // Validate arguments
+ if (hWnd == NULL || k == NULL)
+ {
+ return;
+ }
+
+ ret = SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), k->Id, k->BitmapId);
+
+ if (ret == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ o = batch[0].EnumList;
+ if (o != NULL)
+ {
+ if (k->UseCert)
+ {
+ CmSecureManagerDlgPrintListEx(hWnd, L_CERT, o, SEC_X);
+ }
+
+ if (k->UseKey)
+ {
+ CmSecureManagerDlgPrintListEx(hWnd, L_KEY, o, SEC_K);
+ }
+
+ FreeEnumSecObject(o);
+ }
+
+ // Update the control
+ SmSelectKeyPairDlgUpdate(hWnd, k);
+}
+
+// Key pair import dialog procedure
+UINT SmSelectKeyPairDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ NMHDR *n;
+ SM_SECURE_KEYPAIR *k = (SM_SECURE_KEYPAIR *)param;
+ char *s1, *s2;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmSelectKeyPairDlgInit(hWnd, k);
+
+ SetTimer(hWnd, 1, 1, NULL);
+ SetTimer(hWnd, 2, 100, NULL);
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+ SmSelectKeyPairDlgRefresh(hWnd, k);
+ break;
+
+ case 2:
+ SmSelectKeyPairDlgUpdate(hWnd, k);
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ s1 = LvGetSelectedStrA(hWnd, L_CERT, 0);
+ s2 = LvGetSelectedStrA(hWnd, L_KEY, 0);
+ if (k->UseCert)
+ {
+ StrCpy(k->CertName, sizeof(k->CertName), s1);
+ }
+ if (k->UseKey)
+ {
+ StrCpy(k->KeyName, sizeof(k->KeyName), s2);
+ }
+ Free(s1);
+ Free(s2);
+ EndDialog(hWnd, true);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_CERT:
+ case L_KEY:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ SmSelectKeyPairDlgUpdate(hWnd, k);
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Read a key pair from the smart card
+bool SmSelectKeyPair(HWND hWnd, char *cert_name, UINT cert_name_size, char *key_name, UINT key_name_size)
+{
+ return SmSelectKeyPairEx(hWnd, cert_name, cert_name_size, key_name, key_name_size, 0);
+}
+bool SmSelectKeyPairEx(HWND hWnd, char *cert_name, UINT cert_name_size, char *key_name, UINT key_name_size, UINT bitmap_id)
+{
+ SM_SECURE_KEYPAIR p;
+ // Validate arguments
+ if (hWnd == NULL || (cert_name == NULL && key_name == NULL))
+ {
+ return false;
+ }
+
+ Zero(&p, sizeof(p));
+ p.Id = SmGetCurrentSecureId(hWnd);
+ if (p.Id == 0)
+ {
+ return false;
+ }
+
+ p.UseCert = (cert_name == NULL) ? false : true;
+ p.UseKey = (key_name == NULL) ? false : true;
+ p.BitmapId = bitmap_id;
+
+ if (Dialog(hWnd, D_SM_SELECT_KEYPAIR, SmSelectKeyPairDlg, &p) == false)
+ {
+ return false;
+ }
+
+ if (p.UseCert)
+ {
+ StrCpy(cert_name, cert_name_size, p.CertName);
+ }
+ if (p.UseKey)
+ {
+ StrCpy(key_name, key_name_size, p.KeyName);
+ }
+
+ return true;
+}
+
+// Make the user select the smart card number
+UINT SmSelectSecureId(HWND hWnd)
+{
+ UINT id = MsRegReadInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "DeviceId");
+ UINT ret;
+
+ if (id != 0 && CheckSecureDeviceId(id) == false)
+ {
+ id = 0;
+ }
+
+ ret = CmSelectSecure(hWnd, id);
+ if (ret == 0)
+ {
+ return 0;
+ }
+
+ SmWriteSelectSecureIdReg(ret);
+
+ return ret;
+}
+
+// Write the current smart card number to the registry
+void SmWriteSelectSecureIdReg(UINT id)
+{
+ MsRegWriteInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "DeviceId", id);
+}
+
+// Get the current smart card number
+UINT SmGetCurrentSecureId(HWND hWnd)
+{
+ // Load the current settings
+ UINT id = MsRegReadInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "DeviceId");
+
+ // Check whether it's valid
+ if (id == 0 || CheckSecureDeviceId(id) == false)
+ {
+ // Select a smart card device number if it's invalid
+ id = SmSelectSecureId(hWnd);
+ }
+
+ return id;
+}
+
+// Get the current smart card number from the registry
+UINT SmGetCurrentSecureIdFromReg()
+{
+ // Load the current settings
+ UINT id = MsRegReadInt(REG_CURRENT_USER, SECURE_MANAGER_KEY, "DeviceId");
+
+ // Check whether normal
+ if (id == 0 || CheckSecureDeviceId(id) == false)
+ {
+ id = 0;
+ }
+
+ return id;
+}
+
+// Get whether the specified L3 switch started
+bool SmL3IsSwActive(SM_SERVER *s, char *name)
+{
+ bool ret = false;
+ UINT i;
+ RPC_ENUM_L3SW t;
+ // Validate arguments
+ if (s == NULL || name == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+ if (ScEnumL3Switch(s->Rpc, &t) == ERR_NO_ERROR)
+ {
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_L3SW_ITEM *e = &t.Items[i];
+ if (StrCmpi(e->Name, name) == 0)
+ {
+ if (e->Active)
+ {
+ ret = true;
+ break;
+ }
+ }
+ }
+ FreeRpcEnumL3Sw(&t);
+ }
+
+ return ret;
+}
+
+// Initialize the dialog
+void SmL3SwTableDlgInit(HWND hWnd, SM_L3SW *w)
+{
+ // Validate arguments
+ if (hWnd == NULL || w == NULL)
+ {
+ return;
+ }
+
+ SmL3SwTableDlgUpdate(hWnd, w);
+}
+
+// Update the control
+void SmL3SwTableDlgUpdate(HWND hWnd, SM_L3SW *w)
+{
+ bool b = true;
+ UINT ip;
+ // Validate arguments
+ if (hWnd == NULL || w == NULL)
+ {
+ return;
+ }
+
+ if (IpIsFilled(hWnd, E_NETWORK) == false ||
+ IpIsFilled(hWnd, E_MASK) == false ||
+ IpIsFilled(hWnd, E_GATEWAY) == false)
+ {
+ b = false;
+ }
+
+ ip = IpGet(hWnd, E_GATEWAY);
+ if (ip == 0 || ip == 0xffffffff)
+ {
+ b = false;
+ }
+
+ if (GetInt(hWnd, E_METRIC) == 0)
+ {
+ b = false;
+ }
+
+ if (IsNetworkAddress32(IpGet(hWnd, E_NETWORK), IpGet(hWnd, E_MASK)) == false)
+ {
+ b = false;
+ }
+
+ SetEnable(hWnd, IDOK, b);
+}
+
+UINT SmL3SwTableDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_L3SW *w = (SM_L3SW *)param;
+ RPC_L3TABLE t;
+
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmL3SwTableDlgInit(hWnd, w);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_NETWORK:
+ case E_MASK:
+ case E_GATEWAY:
+ case E_METRIC:
+ SmL3SwTableDlgUpdate(hWnd, w);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), w->SwitchName);
+ t.NetworkAddress = IpGet(hWnd, E_NETWORK);
+ t.SubnetMask = IpGet(hWnd, E_MASK);
+ t.GatewayAddress = IpGet(hWnd, E_GATEWAY);
+ t.Metric = GetInt(hWnd, E_METRIC);
+
+ if (CALL(hWnd, ScAddL3Table(w->s->Rpc, &t)))
+ {
+ EndDialog(hWnd, 1);
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Initialize the dialog
+void SmL3SwIfDlgInit(HWND hWnd, SM_L3SW *w)
+{
+ RPC_ENUM_HUB t;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || w == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+
+ if (CALL(hWnd, ScEnumHub(w->s->Rpc, &t)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ CbReset(hWnd, E_HUBNAME);
+ CbSetHeight(hWnd, E_HUBNAME, 18);
+
+ for (i = 0;i < t.NumHub;i++)
+ {
+ RPC_ENUM_HUB_ITEM *e = &t.Hubs[i];
+
+ if (e->HubType != HUB_TYPE_FARM_DYNAMIC)
+ {
+ CbAddStrA(hWnd, E_HUBNAME, e->HubName, 0);
+ }
+ }
+
+ FreeRpcEnumHub(&t);
+
+ SetTextA(hWnd, E_HUBNAME, "");
+
+ SmL3SwIfDlgUpdate(hWnd, w);
+}
+
+// Update the control
+void SmL3SwIfDlgUpdate(HWND hWnd, SM_L3SW *w)
+{
+ bool b = true;
+ // Validate arguments
+ if (hWnd == NULL || w == NULL)
+ {
+ return;
+ }
+
+ if (IsEmpty(hWnd, E_HUBNAME))
+ {
+ b = false;
+ }
+
+ if (IpIsFilled(hWnd, E_IP) == false || IpIsFilled(hWnd, E_MASK) == false)
+ {
+ b = false;
+ }
+
+ if (IpGet(hWnd, E_IP) == 0 || IpGet(hWnd, E_IP) == 0xffffffff)
+ {
+ b = false;
+ }
+
+ if (IsSubnetMask32(IpGet(hWnd, E_MASK)) == false)
+ {
+ b = false;
+ }
+
+ SetEnable(hWnd, IDOK, b);
+}
+
+// Dialog for adding a virtual interface
+UINT SmL3SwIfDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_L3SW *w = (SM_L3SW *)param;
+ char *hubname;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmL3SwIfDlgInit(hWnd, w);
+
+ SetTimer(hWnd, 1, 250, NULL);
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ if (IsEnable(hWnd, 0))
+ {
+ SmL3SwIfDlgUpdate(hWnd, w);
+ }
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_HUBNAME:
+ case E_IP:
+ case E_MASK:
+ SmL3SwIfDlgUpdate(hWnd, w);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ hubname = GetTextA(hWnd, E_HUBNAME);
+ if (hubname != NULL)
+ {
+ RPC_L3IF t;
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+ t.IpAddress = IpGet(hWnd, E_IP);
+ t.SubnetMask = IpGet(hWnd, E_MASK);
+ StrCpy(t.Name, sizeof(t.Name), w->SwitchName);
+
+ if (CALL(hWnd, ScAddL3If(w->s->Rpc, &t)))
+ {
+ EndDialog(hWnd, 1);
+ }
+
+ Free(hubname);
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Initialize
+void SmL3SwDlgInit(HWND hWnd, SM_L3SW *w)
+{
+ // Validate arguments
+ if (hWnd == NULL || w == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_SWITCH_OFFLINE);
+
+ FormatText(hWnd, 0, w->SwitchName);
+
+ SetFont(hWnd, S_BOLD1, Font(0, true));
+ SetFont(hWnd, S_BOLD2, Font(0, true));
+
+ LvInit(hWnd, L_IF);
+ LvInsertColumn(hWnd, L_IF, 0, _UU("SM_L3_SW_IF_COLUMN1"), 150);
+ LvInsertColumn(hWnd, L_IF, 1, _UU("SM_L3_SW_IF_COLUMN2"), 150);
+ LvInsertColumn(hWnd, L_IF, 2, _UU("SM_L3_SW_IF_COLUMN3"), 180);
+
+ LvInit(hWnd, L_TABLE);
+ LvInsertColumn(hWnd, L_TABLE, 0, _UU("SM_L3_SW_TABLE_COLUMN1"), 130);
+ LvInsertColumn(hWnd, L_TABLE, 1, _UU("SM_L3_SW_TABLE_COLUMN2"), 130);
+ LvInsertColumn(hWnd, L_TABLE, 2, _UU("SM_L3_SW_TABLE_COLUMN3"), 130);
+ LvInsertColumn(hWnd, L_TABLE, 3, _UU("SM_L3_SW_TABLE_COLUMN4"), 100);
+
+ w->Enable = SmL3IsSwActive(w->s, w->SwitchName) ? false : true;
+
+ SmL3SwDlgRefresh(hWnd, w);
+}
+
+// Update the control
+void SmL3SwDlgUpdate(HWND hWnd, SM_L3SW *w)
+{
+ // Validate arguments
+ if (hWnd == NULL || w == NULL)
+ {
+ return;
+ }
+
+ SetEnable(hWnd, B_ADD_IF, w->s->ServerAdminMode && w->Enable);
+ SetEnable(hWnd, B_ADD_TABLE, w->s->ServerAdminMode && w->Enable);
+ SetEnable(hWnd, B_DEL_IF, LvIsSingleSelected(hWnd, L_IF) && w->s->ServerAdminMode && w->Enable);
+ SetEnable(hWnd, B_DEL_TABLE, LvIsSingleSelected(hWnd, L_TABLE) && w->s->ServerAdminMode && w->Enable);
+ SetEnable(hWnd, B_START, w->s->ServerAdminMode && w->Enable);
+ SetEnable(hWnd, B_STOP, w->s->ServerAdminMode && (w->Enable == false));
+}
+
+// Content update
+void SmL3SwDlgRefresh(HWND hWnd, SM_L3SW *w)
+{
+ UINT i;
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || w == NULL)
+ {
+ return;
+ }
+
+ // Virtual interface list
+ {
+ RPC_ENUM_L3IF t;
+ LVB *v;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), w->SwitchName);
+
+ if (CALL(hWnd, ScEnumL3If(w->s->Rpc, &t)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ v = LvInsertStart();
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_L3IF *e = &t.Items[i];
+
+ IPToUniStr32(tmp1, sizeof(tmp1), e->IpAddress);
+ IPToUniStr32(tmp2, sizeof(tmp2), e->SubnetMask);
+ StrToUni(tmp3, sizeof(tmp3), e->HubName);
+
+ LvInsertAdd(v, ICO_NIC_ONLINE, NULL, 3, tmp1, tmp2, tmp3);
+ }
+
+ LvReset(hWnd, L_IF);
+
+ LvInsertEnd(v, hWnd, L_IF);
+
+ FreeRpcEnumL3If(&t);
+ }
+
+ // Routing Table Entry List
+ {
+ RPC_ENUM_L3TABLE t;
+ LVB *v;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), w->SwitchName);
+
+ if (CALL(hWnd, ScEnumL3Table(w->s->Rpc, &t)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ v = LvInsertStart();
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_L3TABLE *e = &t.Items[i];
+
+ IPToUniStr32(tmp1, sizeof(tmp1), e->NetworkAddress);
+ IPToUniStr32(tmp2, sizeof(tmp2), e->SubnetMask);
+ IPToUniStr32(tmp3, sizeof(tmp3), e->GatewayAddress);
+ UniToStru(tmp4, e->Metric);
+
+ LvInsertAdd(v, ICO_PROTOCOL, NULL, 4, tmp1, tmp2, tmp3, tmp4);
+ }
+
+ LvReset(hWnd, L_TABLE);
+
+ LvInsertEnd(v, hWnd, L_TABLE);
+
+ FreeRpcEnumL3Table(&t);
+ }
+
+ SmL3SwDlgUpdate(hWnd, w);
+}
+
+// Edit dialog of L3 switch
+UINT SmL3SwDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_L3SW *w = (SM_L3SW *)param;
+ NMHDR *n;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmL3SwDlgInit(hWnd, w);
+
+ SetTimer(hWnd, 1, 1000, NULL);
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ if (IsEnable(hWnd, 0))
+ {
+ KillTimer(hWnd, 1);
+ w->Enable = SmL3IsSwActive(w->s, w->SwitchName) ? false : true;
+ SmL3SwDlgUpdate(hWnd, w);
+ SetTimer(hWnd, 1, 1000, NULL);
+ }
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_START:
+ if (IsEnable(hWnd, B_START))
+ {
+ RPC_L3SW t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), w->SwitchName);
+
+ if (CALL(hWnd, ScStartL3Switch(w->s->Rpc, &t)))
+ {
+ SmL3SwDlgUpdate(hWnd, w);
+ }
+ }
+ break;
+
+ case B_STOP:
+ if (IsEnable(hWnd, B_STOP))
+ {
+ RPC_L3SW t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), w->SwitchName);
+
+ if (CALL(hWnd, ScStopL3Switch(w->s->Rpc, &t)))
+ {
+ SmL3SwDlgUpdate(hWnd, w);
+ }
+ }
+ break;
+
+ case B_ADD_IF:
+ if (Dialog(hWnd, D_SM_L3_SW_IF, SmL3SwIfDlg, w))
+ {
+ SmL3SwDlgRefresh(hWnd, w);
+ }
+ break;
+
+ case B_DEL_IF:
+ if (LvIsSingleSelected(hWnd, L_IF))
+ {
+ RPC_L3IF t;
+ char *tmp1, *tmp2, *tmp3;
+
+ tmp1 = LvGetSelectedStrA(hWnd, L_IF, 0);
+ tmp2 = LvGetSelectedStrA(hWnd, L_IF, 1);
+ tmp3 = LvGetSelectedStrA(hWnd, L_IF, 2);
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), w->SwitchName);
+ t.IpAddress = StrToIP32(tmp1);
+ t.SubnetMask = StrToIP32(tmp2);
+ StrCpy(t.HubName, sizeof(t.HubName), tmp3);
+
+ if (CALL(hWnd, ScDelL3If(w->s->Rpc, &t)))
+ {
+ SmL3SwDlgRefresh(hWnd, w);
+ }
+
+ Free(tmp1);
+ Free(tmp2);
+ Free(tmp3);
+ }
+ break;
+
+ case B_ADD_TABLE:
+ if (Dialog(hWnd, D_SM_L3_SW_TABLE, SmL3SwTableDlg, w))
+ {
+ SmL3SwDlgRefresh(hWnd, w);
+ }
+ break;
+
+ case B_DEL_TABLE:
+ if (LvIsSingleSelected(hWnd, L_TABLE))
+ {
+ RPC_L3TABLE t;
+ char *tmp1, *tmp2, *tmp3, *tmp4;
+
+ tmp1 = LvGetSelectedStrA(hWnd, L_TABLE, 0);
+ tmp2 = LvGetSelectedStrA(hWnd, L_TABLE, 1);
+ tmp3 = LvGetSelectedStrA(hWnd, L_TABLE, 2);
+ tmp4 = LvGetSelectedStrA(hWnd, L_TABLE, 3);
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), w->SwitchName);
+ t.NetworkAddress = StrToIP32(tmp1);
+ t.SubnetMask = StrToIP32(tmp2);
+ t.GatewayAddress = StrToIP32(tmp3);
+ t.Metric = ToInt(tmp4);
+
+ if (CALL(hWnd, ScDelL3Table(w->s->Rpc, &t)))
+ {
+ SmL3SwDlgRefresh(hWnd, w);
+ }
+
+ Free(tmp1);
+ Free(tmp2);
+ Free(tmp3);
+ Free(tmp4);
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_IF:
+ case L_TABLE:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ SmL3SwDlgUpdate(hWnd, w);
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Update the control
+void SmL3AddDlgUpdate(HWND hWnd, SM_SERVER *s)
+{
+ char *tmp;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ tmp = GetTextA(hWnd, E_NAME);
+
+ SetEnable(hWnd, IDOK, IsEmptyStr(tmp) == false && IsSafeStr(tmp));
+
+ Free(tmp);
+}
+
+// The dialog box to create a new L3 switch
+UINT SmL3AddDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_SERVER *s = (SM_SERVER *)param;
+ RPC_L3SW t;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ LimitText(hWnd, E_NAME, MAX_HUBNAME_LEN);
+ SmL3AddDlgUpdate(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_NAME:
+ SmL3AddDlgUpdate(hWnd, s);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ Zero(&t, sizeof(t));
+ GetTxtA(hWnd, E_NAME, t.Name, sizeof(t.Name));
+ if (CALL(hWnd, ScAddL3Switch(s->Rpc, &t)))
+ {
+ EndDialog(hWnd, 1);
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Initialize the dialog
+void SmL3DlgInit(HWND hWnd, SM_SERVER *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetFont(hWnd, S_BOLD, Font(0, true));
+
+ SetIcon(hWnd, 0, ICO_SWITCH);
+
+ LvInit(hWnd, L_LIST);
+ LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_L3_SW_COLUMN1"), 150);
+ LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_L3_SW_COLUMN2"), 120);
+ LvInsertColumn(hWnd, L_LIST, 2, _UU("SM_L3_SW_COLUMN3"), 100);
+ LvInsertColumn(hWnd, L_LIST, 3, _UU("SM_L3_SW_COLUMN4"), 100);
+
+ SmL3DlgRefresh(hWnd, s);
+}
+
+// Update the dialog control
+void SmL3DlgUpdate(HWND hWnd, SM_SERVER *s)
+{
+ bool b = false;
+ bool active = false;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (LvIsSingleSelected(hWnd, L_LIST))
+ {
+ wchar_t *tmp;
+ UINT i;
+ b = true;
+ i = LvGetSelected(hWnd, L_LIST);
+ if (i != INFINITE)
+ {
+ tmp = LvGetStr(hWnd, L_LIST, i, 1);
+ if (UniStrCmpi(tmp, _UU("SM_L3_SW_ST_F_F")) != 0)
+ {
+ active = true;
+ }
+ Free(tmp);
+ }
+ }
+
+ SetEnable(hWnd, B_START, b && (active == false));
+ SetEnable(hWnd, B_STOP, b && (active != false));
+ SetEnable(hWnd, IDOK, b);
+ SetEnable(hWnd, B_DELETE, b);
+}
+
+// Dialog content update
+void SmL3DlgRefresh(HWND hWnd, SM_SERVER *s)
+{
+ RPC_ENUM_L3SW t;
+ UINT i;
+ LVB *v;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ if (CALL(hWnd, ScEnumL3Switch(s->Rpc, &t)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ v = LvInsertStart();
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_L3SW_ITEM *e = &t.Items[i];
+ wchar_t tmp1[MAX_SIZE], *tmp2, tmp3[64], tmp4[64];
+
+ StrToUni(tmp1, sizeof(tmp1), e->Name);
+ if (e->Active == false)
+ {
+ tmp2 = _UU("SM_L3_SW_ST_F_F");
+ }
+ else if (e->Online == false)
+ {
+ tmp2 = _UU("SM_L3_SW_ST_T_F");
+ }
+ else
+ {
+ tmp2 = _UU("SM_L3_SW_ST_T_T");
+ }
+ UniToStru(tmp3, e->NumInterfaces);
+ UniToStru(tmp4, e->NumTables);
+
+ LvInsertAdd(v, e->Active ? ICO_SWITCH : ICO_SWITCH_OFFLINE, NULL,
+ 4, tmp1, tmp2, tmp3, tmp4);
+ }
+
+ LvInsertEnd(v, hWnd, L_LIST);
+
+ FreeRpcEnumL3Sw(&t);
+
+ SmL3DlgUpdate(hWnd, s);
+}
+
+// L3 dialog procedure
+UINT SmL3Dlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ NMHDR *n;
+ SM_SERVER *s = (SM_SERVER *)param;
+ RPC_L3SW t;
+ char *name;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmL3DlgInit(hWnd, s);
+
+ SetTimer(hWnd, 1, 1000, NULL);
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ if (IsEnable(hWnd, 0))
+ {
+ KillTimer(hWnd, 1);
+ SmL3DlgRefresh(hWnd, s);
+ SetTimer(hWnd, 1, 1000, NULL);
+ }
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_ADD:
+ // Add
+ if (Dialog(hWnd, D_SM_L3_ADD, SmL3AddDlg, s))
+ {
+ SmL3DlgRefresh(hWnd, s);
+ }
+ break;
+
+ case B_START:
+ // Operation start
+ name = LvGetSelectedStrA(hWnd, L_LIST, 0);
+ if (name != NULL)
+ {
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), name);
+
+ if (CALL(hWnd, ScStartL3Switch(s->Rpc, &t)))
+ {
+ SmL3DlgRefresh(hWnd, s);
+ }
+
+ Free(name);
+ }
+ break;
+
+ case B_STOP:
+ // Operation stop
+ name = LvGetSelectedStrA(hWnd, L_LIST, 0);
+ if (name != NULL)
+ {
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), name);
+
+ if (CALL(hWnd, ScStopL3Switch(s->Rpc, &t)))
+ {
+ SmL3DlgRefresh(hWnd, s);
+ }
+
+ Free(name);
+ }
+ break;
+
+ case IDOK:
+ // Edit
+ if (IsEnable(hWnd, IDOK))
+ {
+ name = LvGetSelectedStrA(hWnd, L_LIST, 0);
+ if (name != NULL)
+ {
+ SM_L3SW w;
+ Zero(&w, sizeof(w));
+ w.s = s;
+ w.SwitchName = name;
+
+ Dialog(hWnd, D_SM_L3_SW, SmL3SwDlg, &w);
+
+ Free(name);
+ }
+ }
+ break;
+
+ case B_DELETE:
+ // Delete
+ name = LvGetSelectedStrA(hWnd, L_LIST, 0);
+ if (name != NULL)
+ {
+ if (MsgBoxEx(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2,
+ _UU("SM_L3_SW_DEL_MSG"), name) == IDYES)
+ {
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), name);
+
+ if (CALL(hWnd, ScDelL3Switch(s->Rpc, &t)))
+ {
+ SmL3DlgRefresh(hWnd, s);
+ }
+ }
+
+ Free(name);
+ }
+ break;
+
+ case IDCANCEL:
+ // Close
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ SmL3DlgUpdate(hWnd, s);
+ break;
+
+ case NM_DBLCLK:
+ Command(hWnd, IDOK);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// L3 dialog
+void SmL3(HWND hWnd, SM_SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_SM_L3, SmL3Dlg, s);
+}
+
+// Dialog for management option value
+UINT SmHubAdminOptionValueDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_EDIT_AO *a = (SM_EDIT_AO *)param;
+ UINT i;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ CbReset(hWnd, C_NAME);
+ for (i = 0;i < a->DefaultOptions.NumItem;i++)
+ {
+ wchar_t tmp[MAX_PATH];
+ StrToUni(tmp, sizeof(tmp), a->DefaultOptions.Items[i].Name);
+ CbAddStr(hWnd, C_NAME, tmp, 0);
+ }
+ if (a->NewMode == false)
+ {
+ char tmp[MAX_SIZE];
+
+ SetTextA(hWnd, C_NAME, a->Name);
+ ToStr(tmp, a->Value);
+
+ SetTextA(hWnd, E_VALUE, tmp);
+ }
+ else
+ {
+ SetTextA(hWnd, C_NAME, "");
+ }
+ SmHubAdminOptionValueDlgUpdate(hWnd, a);
+ if (a->NewMode == false)
+ {
+ FocusEx(hWnd, E_VALUE);
+ Disable(hWnd, C_NAME);
+ }
+ else
+ {
+ FocusEx(hWnd, C_NAME);
+ }
+
+ SetTimer(hWnd, 1, 100, NULL);
+ break;
+
+ case WM_TIMER:
+ if (IsEnable(hWnd, 0))
+ {
+ SmHubAdminOptionValueDlgUpdate(hWnd, a);
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ if (a->NewMode)
+ {
+ GetTxtA(hWnd, C_NAME, a->Name, sizeof(a->Name));
+ }
+
+ GetTxtA(hWnd, E_VALUE, tmp, sizeof(tmp));
+ a->Value = ToInt(tmp);
+
+ Trim(a->Name);
+
+ if (StartWith(a->Name, "no") || StartWith(a->Name, "allow") || StartWith(a->Name, "deny")
+ || StartWith(a->Name, "filter") || StartWith(a->Name, "fix") || StartWith(a->Name, "force")
+ || StartWith(a->Name, "use") || StartWith(a->Name, "b_") || StartWith(a->Name, "is")
+ || StartWith(a->Name, "manage") || StartWith(a->Name, "yield")
+ || StartWith(a->Name, "permit") || StartWith(a->Name, "yes") || StartWith(a->Name, "ok")
+ || StartWith(a->Name, "do") || StartWith(a->Name, "only") || StartWith(a->Name, "disable"))
+ {
+ if (StrCmpi(tmp, "0") != 0 && StrCmpi(tmp, "1") != 0)
+ {
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SM_TRUE_OR_FALSE"));
+ FocusEx(hWnd, E_VALUE);
+ break;
+ }
+ }
+
+ EndDialog(hWnd, true);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+
+ SmHubAdminOptionValueDlgUpdate(hWnd, a);
+
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Update the dialog controls for management option value
+void SmHubAdminOptionValueDlgUpdate(HWND hWnd, SM_EDIT_AO *a)
+{
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+ GetTxtA(hWnd, C_NAME, tmp, sizeof(tmp));
+
+ SetEnable(hWnd, IDOK, IsEmpty(hWnd, C_NAME) == false && IsEmpty(hWnd, E_VALUE) == false &&
+ IsSafeStr(tmp));
+}
+
+// Initialize
+void SmHubAdminOptionDlgInit(HWND hWnd, SM_EDIT_AO *a)
+{
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_USER_ADMIN);
+
+ if (a->e->p->ServerAdminMode)
+ {
+ a->CanChange = true;
+ }
+ else
+ {
+ if (a->ExtOption == false)
+ {
+ for (i = 0;i < a->CurrentOptions.NumItem;i++)
+ {
+ if (StrCmpi(a->CurrentOptions.Items[i].Name, "allow_hub_admin_change_option") == 0)
+ {
+ if (a->CurrentOptions.Items[i].Value != 0)
+ {
+ a->CanChange = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ a->CanChange = true;
+ }
+ }
+
+ FormatText(hWnd, S_INFO, a->e->HubName);
+
+ DlgFont(hWnd, S_BOLD, 0, true);
+
+ LvInit(hWnd, L_LIST);
+ LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_AO_COLUMN_1"), 260);
+ LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_AO_COLUMN_2"), 100);
+
+ for (i = 0;i < a->CurrentOptions.NumItem;i++)
+ {
+ ADMIN_OPTION *e = &a->CurrentOptions.Items[i];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+
+ StrToUni(tmp1, sizeof(tmp1), e->Name);
+ UniToStru(tmp2, e->Value);
+
+ LvInsert(hWnd, L_LIST, ICO_LOG, NULL, 2, tmp1, tmp2);
+
+ }
+
+ if (a->ExtOption)
+ {
+ SetIcon(hWnd, S_ICON, ICO_LINK2);
+ SetIcon(hWnd, 0, ICO_LINK2);
+
+ SetText(hWnd, 0, _UU("SM_HUBEXT_OPTION_TITLE"));
+ SetText(hWnd, S_STATIC1, _UU("SM_HUBEXT_OPTION_STATIC1"));
+ SetText(hWnd, S_STATIC2, _UU("SM_HUBEXT_OPTION_STATIC2"));
+ }
+
+ // Update the control
+ SmHubAdminOptionDlgUpdate(hWnd, a);
+}
+
+// Update the control
+void SmHubAdminOptionDlgUpdate(HWND hWnd, SM_EDIT_AO *a)
+{
+ bool b = false;
+ wchar_t *helpstr;
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+ helpstr = _UU("HUB_AO_CLICK");
+
+ SetEnable(hWnd, IDOK, a->CanChange);
+ SetEnable(hWnd, B_ADD, a->CanChange);
+ SetEnable(hWnd, B_EDIT, a->CanChange && (LvIsMasked(hWnd, L_LIST) && LvIsMultiMasked(hWnd, L_LIST) == false));
+
+ if (LvIsMasked(hWnd, L_LIST) && LvIsMultiMasked(hWnd, L_LIST) == false)
+ {
+ UINT i;
+ i = LvGetSelected(hWnd, L_LIST);
+
+ if (a->CanChange)
+ {
+
+ b = true;
+
+ if (i != INFINITE)
+ {
+ char *name = LvGetStrA(hWnd, L_LIST, i, 0);
+ if (name != NULL)
+ {
+ UINT j;
+
+ for (j = 0;j < a->DefaultOptions.NumItem;j++)
+ {
+ if (StrCmpi(a->DefaultOptions.Items[j].Name, name) == 0)
+ {
+ b = false;
+ }
+ }
+ Free(name);
+ }
+ }
+ }
+
+ if (i != INFINITE)
+ {
+ char *name = LvGetStrA(hWnd, L_LIST, i, 0);
+ if (name != NULL)
+ {
+ helpstr = GetHubAdminOptionHelpString(name);
+ }
+ Free(name);
+ }
+ }
+ SetEnable(hWnd, B_DELETE, b);
+
+ SetText(hWnd, E_HELP, helpstr);
+}
+
+// Save
+void SmHubAdminOptionDlgOk(HWND hWnd, SM_EDIT_AO *a)
+{
+ UINT i, num;
+ RPC_ADMIN_OPTION t;
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+ num = LvNum(hWnd, L_LIST);
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), a->e->HubName);
+ t.NumItem = num;
+ t.Items = ZeroMalloc(sizeof(ADMIN_OPTION) * num);
+
+ for (i = 0;i < num;i++)
+ {
+ char *name = LvGetStrA(hWnd, L_LIST, i, 0);
+ char *s_value = LvGetStrA(hWnd, L_LIST, i, 1);
+ ADMIN_OPTION *a = &t.Items[i];
+
+ StrCpy(a->Name, sizeof(a->Name), name);
+ a->Value = ToInt(s_value);
+
+ Free(name);
+ Free(s_value);
+ }
+
+ if (a->ExtOption == false)
+ {
+ if (CALL(hWnd, ScSetHubAdminOptions(a->e->p->Rpc, &t)))
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_AO_SET_OK"));
+ EndDialog(hWnd, true);
+ }
+ }
+ else
+ {
+ if (CALL(hWnd, ScSetHubExtOptions(a->e->p->Rpc, &t)))
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_EXT_OPTION_SET_OK"));
+ EndDialog(hWnd, true);
+ }
+ }
+
+ FreeRpcAdminOption(&t);
+}
+
+// Virtual HUB Management Options dialog
+UINT SmHubAdminOptionDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_EDIT_AO *a = (SM_EDIT_AO *)param;
+ NMHDR *n;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmHubAdminOptionDlgInit(hWnd, a);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_ADD:
+ a->NewMode = true;
+ StrCpy(a->Name, sizeof(a->Name), "");
+ a->Value = 0;
+ if (Dialog(hWnd, D_SM_AO_VALUE, SmHubAdminOptionValueDlg,
+ a))
+ {
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ StrToUni(tmp1, sizeof(tmp1), a->Name);
+ UniToStru(tmp2, a->Value);
+
+ LvInsert(hWnd, L_LIST, ICO_LOG, NULL, 2, tmp1, tmp2);
+ }
+ break;
+
+ case B_EDIT:
+ i = LvGetSelected(hWnd, L_LIST);
+ if (i != INFINITE && a->CanChange)
+ {
+ char *name, *value;
+ name = LvGetStrA(hWnd, L_LIST, i, 0);
+ value = LvGetStrA(hWnd, L_LIST, i, 1);
+ a->NewMode = false;
+ StrCpy(a->Name, sizeof(a->Name), name);
+ a->Value = ToInt(value);
+
+ if (Dialog(hWnd, D_SM_AO_VALUE, SmHubAdminOptionValueDlg,
+ a))
+ {
+ char tmp[MAX_PATH];
+ ToStr(tmp, a->Value);
+ LvSetItemA(hWnd, L_LIST, i, 1, tmp);
+ }
+
+ Free(name);
+ Free(value);
+ }
+ break;
+
+ case B_DELETE:
+ i = LvGetSelected(hWnd, L_LIST);
+ if (i != INFINITE)
+ {
+ LvDeleteItem(hWnd, L_LIST, i);
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case IDOK:
+ SmHubAdminOptionDlgOk(hWnd, a);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ SmHubAdminOptionDlgUpdate(hWnd, a);
+ break;
+
+ case NM_DBLCLK:
+ Command(hWnd, B_EDIT);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Virtual HUB extended options
+void SmHubExtOption(HWND hWnd, SM_EDIT_HUB *e)
+{
+ SM_EDIT_AO a;
+ // Validate arguments
+ if (hWnd == NULL || e == NULL)
+ {
+ return;
+ }
+
+ Zero(&a, sizeof(a));
+ a.e = e;
+ a.ExtOption = true;
+
+ StrCpy(a.CurrentOptions.HubName, sizeof(a.CurrentOptions.HubName), e->HubName);
+
+ // Get the current options on the server
+ if (CALL(hWnd, ScGetHubExtOptions(e->p->Rpc, &a.CurrentOptions)) == false)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_SM_ADMIN_OPTION, SmHubAdminOptionDlg, &a);
+
+ FreeRpcAdminOption(&a.CurrentOptions);
+ FreeRpcAdminOption(&a.DefaultOptions);
+}
+
+// Virtual HUB management options
+void SmHubAdminOption(HWND hWnd, SM_EDIT_HUB *e)
+{
+ SM_EDIT_AO a;
+ // Validate arguments
+ if (hWnd == NULL || e == NULL)
+ {
+ return;
+ }
+
+ Zero(&a, sizeof(a));
+ a.e = e;
+
+ StrCpy(a.CurrentOptions.HubName, sizeof(a.CurrentOptions.HubName), e->HubName);
+
+ // Get the current options on the server
+ if (CALL(hWnd, ScGetHubAdminOptions(e->p->Rpc, &a.CurrentOptions)) == false)
+ {
+ return;
+ }
+
+ ScGetDefaultHubAdminOptions(e->p->Rpc, &a.DefaultOptions);
+
+ Dialog(hWnd, D_SM_ADMIN_OPTION, SmHubAdminOptionDlg, &a);
+
+ FreeRpcAdminOption(&a.CurrentOptions);
+ FreeRpcAdminOption(&a.DefaultOptions);
+}
+
+// Initialize
+void SmConfigDlgInit(HWND hWnd, SM_CONFIG *c)
+{
+ wchar_t *tmp;
+ UINT tmp_size;
+ // Validate arguments
+ if (hWnd == NULL || c == NULL)
+ {
+ return;
+ }
+
+ Focus(hWnd, IDCANCEL);
+
+ SetIcon(hWnd, 0, ICO_MACHINE);
+
+ SetFont(hWnd, E_CONFIG, GetFont(_SS("DEFAULT_FONT_2"), 0, false, false,
+ false, false));
+
+ FormatText(hWnd, IDC_INFO, c->s->ServerName);
+
+ // Convert from UTF-8 to Unicode
+ tmp_size = CalcUtf8ToUni(c->Config.FileData, StrLen(c->Config.FileData)) + 1;
+ tmp = ZeroMalloc(tmp_size);
+ Utf8ToUni(tmp, tmp_size, c->Config.FileData, StrLen(c->Config.FileData));
+
+ SetText(hWnd, E_CONFIG, tmp);
+
+ Free(tmp);
+}
+
+// Config edit dialog
+UINT SmConfigDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_CONFIG *c = (SM_CONFIG *)param;
+ char *filename;
+ wchar_t *filename_unicode;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmConfigDlgInit(hWnd, c);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_EXPORT:
+ StrToUni(tmp, sizeof(tmp), c->Config.FileName);
+ filename_unicode = SaveDlg(hWnd, _UU("DLG_CONFIG_FILES"), _UU("DLG_SAVE_CONFIG"), tmp, L".config");
+ if (filename_unicode != NULL)
+ {
+ BUF *b = NewBuf();
+ filename = CopyUniToStr(filename_unicode);
+ WriteBuf(b, c->Config.FileData, StrLen(c->Config.FileData));
+ if (DumpBuf(b, filename))
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_CONFIG_SAVED"));
+ }
+ else
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("SM_CONFIG_SAVE_FAILED"));
+ }
+ FreeBuf(b);
+ Free(filename);
+ Free(filename_unicode);
+ }
+ break;
+
+ case B_IMPORT:
+ filename_unicode = OpenDlg(hWnd, _UU("DLG_CONFIG_FILES"), _UU("DLG_OPEN_CONFIG"));
+ if (filename_unicode != NULL)
+ {
+ BUF *b;
+ filename = CopyUniToStr(filename_unicode);
+ b = ReadDump(filename);
+ if (b != NULL)
+ {
+ RPC_CONFIG t;
+
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("SM_CONFIG_CONFIRM")) == IDYES)
+ {
+ Zero(&t, sizeof(t));
+ t.FileData = ZeroMalloc(b->Size + 1);
+ Copy(t.FileData, b->Buf, b->Size);
+
+ if (CALL(hWnd, ScSetConfig(c->s->Rpc, &t)))
+ {
+ // Success
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_CONFIG_WRITE_OK"));
+ _exit(0);
+ }
+
+ FreeRpcConfig(&t);
+
+ FreeRpcConfig(&t);
+ FreeBuf(b);
+ }
+ }
+ else
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("SM_CONFIG_OPEN_FAILED"));
+ }
+ Free(filename);
+ Free(filename_unicode);
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case B_FACTORY:
+ if (MsgBox(hWnd, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2, _UU("SM_FACTORY_DEFAULT_WARNING")) == IDYES)
+ {
+ RPC_TEST t;
+ UINT ret;
+
+ Zero(&t, sizeof(t));
+
+ t.IntValue = 1;
+ ret = ScRebootServer(c->s->Rpc, &t);
+
+ if (ret == ERR_DISCONNECTED || ret == ERR_NO_ERROR)
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_FACTORY_DEFAULT_PERFORMED"));
+
+ exit(0);
+ }
+ else
+ {
+ CALL(hWnd, ret);
+ }
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Show the config edit dialog
+void SmConfig(HWND hWnd, SM_SERVER *s)
+{
+ SM_CONFIG c;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&c, sizeof(c));
+
+ c.s = s;
+
+ // Get current config from the server
+ if (CALL(hWnd, ScGetConfig(s->Rpc, &c.Config)) == false)
+ {
+ return;
+ }
+
+ // Show the dialog
+ Dialog(hWnd, D_SM_CONFIG, SmConfigDlg, &c);
+
+ // Release
+ FreeRpcConfig(&c.Config);
+}
+
+// Bridge dialog initialization
+UINT SmBridgeDlgInit(HWND hWnd, SM_SERVER *s)
+{
+ UINT i;
+ RPC_ENUM_ETH t;
+ RPC_SERVER_INFO si;
+ UINT num = 0;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return 0;
+ }
+
+ LvInit(hWnd, L_LIST);
+ LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_BRIDGE_COLUMN_1"), 50);
+ LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_BRIDGE_COLUMN_2"), 145);
+ LvInsertColumn(hWnd, L_LIST, 2, _UU("SM_BRIDGE_COLUMN_3"), 300);
+ LvInsertColumn(hWnd, L_LIST, 3, _UU("SM_BRIDGE_COLUMN_4"), 100);
+
+ SmBridgeDlgRefresh(hWnd, s);
+
+ SetShow(hWnd, B_VLAN, GetCapsBool(s->CapsList, "b_support_eth_vlan"));
+
+ SetIcon(hWnd, 0, ICO_BRIDGE);
+
+ // Get the server information
+ Zero(&si, sizeof(si));
+ ScGetServerInfo(s->Rpc, &si);
+ if (GetCapsBool(s->CapsList, "b_tap_supported") == false)
+ {
+ // Tap does not supported
+ Hide(hWnd, R_TAP);
+ Hide(hWnd, S_TAP_1);
+ Hide(hWnd, E_TAPNAME);
+ Hide(hWnd, S_TAP_2);
+ Hide(hWnd, R_BRIDGE);
+ Hide(hWnd, S_STATIC5);
+ }
+ Check(hWnd, R_BRIDGE, true);
+ FreeRpcServerInfo(&si);
+
+ // Enumerate the Ethernet devices
+ Zero(&t, sizeof(t));
+ ScEnumEthernet(s->Rpc, &t);
+
+ CbReset(hWnd, E_NICNAME);
+ CbSetHeight(hWnd, E_NICNAME, 18);
+
+ num = t.NumItem;
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_ENUM_ETH_ITEM *e = &t.Items[i];
+ if (GetCapsBool(s->CapsList, "b_support_network_connection_name"))
+ {
+ wchar_t ncname[MAX_SIZE * 2];
+ UniFormat(ncname, sizeof(ncname), BRIDGE_NETWORK_CONNECTION_STR, e->NetworkConnectionName, e->DeviceName);
+ CbAddStr(hWnd, E_NICNAME, ncname, 0);
+ }
+ else
+ {
+ wchar_t *s = CopyStrToUni(e->DeviceName);
+ CbAddStr(hWnd, E_NICNAME, s, 0);
+ Free(s);
+ }
+ }
+
+ FreeRpcEnumEth(&t);
+
+ // Enumerate the Virtual HUBs
+ {
+ RPC_ENUM_HUB t;
+ Zero(&t, sizeof(t));
+
+ ScEnumHub(s->Rpc, &t);
+
+ CbReset(hWnd, E_HUBNAME);
+ CbSetHeight(hWnd, E_HUBNAME, 18);
+
+ for (i = 0;i < t.NumHub;i++)
+ {
+ RPC_ENUM_HUB_ITEM *e = &t.Hubs[i];
+ wchar_t *s = CopyStrToUni(e->HubName);
+
+ if (e->HubType != HUB_TYPE_FARM_DYNAMIC)
+ {
+ CbAddStr(hWnd, E_HUBNAME, s, 0);
+ }
+ Free(s);
+ }
+
+ SetText(hWnd, E_HUBNAME, L"");
+
+ FreeRpcEnumHub(&t);
+ }
+
+ if (s->Bridge)
+ {
+ SetTextA(hWnd, E_HUBNAME, "BRIDGE");
+ }
+
+ Focus(hWnd, E_HUBNAME);
+
+ SmBridgeDlgUpdate(hWnd, s);
+
+ SetTimer(hWnd, 1, 1000, NULL);
+
+ return num;
+}
+
+// Bridge dialog control update
+void SmBridgeDlgUpdate(HWND hWnd, SM_SERVER *s)
+{
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (LvIsMasked(hWnd, L_LIST) && LvIsMultiMasked(hWnd, L_LIST) == false)
+ {
+ Enable(hWnd, B_DELETE);
+ }
+ else
+ {
+ Disable(hWnd, B_DELETE);
+ }
+
+ if (IsEmpty(hWnd, E_HUBNAME))
+ {
+ ok = false;
+ }
+
+ if (IsChecked(hWnd, R_TAP) == false)
+ {
+ // Bridge mode
+ Enable(hWnd, S_ETH_1);
+ Enable(hWnd, E_NICNAME);
+ Disable(hWnd, S_TAP_1);
+ Disable(hWnd, S_TAP_2);
+ Disable(hWnd, E_TAPNAME);
+ SetText(hWnd, S_INFO, _UU("SM_BRIDGE_INFO_1"));
+ SetIcon(hWnd, S_ICON, ICO_NIC_ONLINE);
+ if (IsEmpty(hWnd, E_NICNAME))
+ {
+ ok = false;
+ }
+ }
+ else
+ {
+ char tmp[MAX_SIZE];
+ // Tap mode
+ Disable(hWnd, S_ETH_1);
+ Disable(hWnd, E_NICNAME);
+ Enable(hWnd, S_TAP_1);
+ Enable(hWnd, S_TAP_2);
+ Enable(hWnd, E_TAPNAME);
+ SetText(hWnd, S_INFO, _UU("SM_BRIDGE_INFO_2"));
+ SetIcon(hWnd, S_ICON, ICO_PROTOCOL);
+ GetTxtA(hWnd, E_TAPNAME, tmp, sizeof(tmp));
+ if (IsEmptyStr(tmp))
+ {
+ ok = false;
+ }
+ else
+ {
+ if (IsSafeStr(tmp) == false)
+ {
+ ok = false;
+ }
+ if (StrLen(tmp) >= 12)
+ {
+ ok = false;
+ }
+ }
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Bridge dialog update
+void SmBridgeDlgRefresh(HWND hWnd, SM_SERVER *s)
+{
+ LVB *lvb;
+ RPC_ENUM_LOCALBRIDGE t;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ lvb = LvInsertStart();
+
+ Zero(&t, sizeof(t));
+
+ ScEnumLocalBridge(s->Rpc, &t);
+
+ for (i = 0;i < t.NumItem;i++)
+ {
+ RPC_LOCALBRIDGE *e = &t.Items[i];
+ wchar_t name[MAX_SIZE];
+ wchar_t nic[MAX_SIZE];
+ wchar_t hub[MAX_SIZE];
+ wchar_t *status = _UU("SM_BRIDGE_OFFLINE");
+
+ UniToStru(name, i + 1);
+ StrToUni(nic, sizeof(nic), e->DeviceName);
+ StrToUni(hub, sizeof(hub), e->HubName);
+
+ if (e->Online)
+ {
+ status = e->Active ? _UU("SM_BRIDGE_ONLINE") : _UU("SM_BRIDGE_ERROR");
+ }
+
+ LvInsertAdd(lvb, e->TapMode == false ? (e->Active ? ICO_NIC_ONLINE : ICO_NIC_OFFLINE) : ICO_PROTOCOL,
+ NULL, 4, name, hub, nic, status);
+ }
+
+ FreeRpcEnumLocalBridge(&t);
+
+ LvInsertEnd(lvb, hWnd, L_LIST);
+
+ SmBridgeDlgUpdate(hWnd, s);
+}
+
+// Add a Local Bridge
+void SmBridgeDlgOnOk(HWND hWnd, SM_SERVER *s)
+{
+ char nic[MAX_SIZE];
+ char hub[MAX_SIZE];
+ RPC_LOCALBRIDGE t;
+ bool tapmode = false;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ GetTxtA(hWnd, E_HUBNAME, hub, sizeof(hub));
+
+ Zero(nic, sizeof(nic));
+
+ if (IsChecked(hWnd, R_TAP) == false)
+ {
+ wchar_t nctmp[MAX_SIZE * 2];
+ if(GetCapsBool(s->CapsList, "b_support_network_connection_name") && GetTxt(hWnd, E_NICNAME, nctmp, sizeof(nctmp)))
+ {
+ RPC_ENUM_ETH et;
+ UINT i;
+ Zero(&et, sizeof(et));
+ ScEnumEthernet(s->Rpc, &et);
+ for(i = 0; i < et.NumItem; i++)
+ {
+ RPC_ENUM_ETH_ITEM *e = &et.Items[i];
+ if(UniIsEmptyStr(e->NetworkConnectionName) == false)
+ {
+ wchar_t ncname[MAX_SIZE * 2];
+ UniFormat(ncname, sizeof(ncname), BRIDGE_NETWORK_CONNECTION_STR, e->NetworkConnectionName, e->DeviceName);
+ if(UniStrCmp(ncname, nctmp) == 0)
+ {
+ StrCpy(nic, sizeof(nic), e->DeviceName);
+ break;
+ }
+ }
+ }
+ FreeRpcEnumEth(&et);
+
+ if (IsEmptyStr(nic))
+ {
+ GetTxtA(hWnd, E_NICNAME, nic, sizeof(nic));
+ }
+ }
+ else
+ {
+ GetTxtA(hWnd, E_NICNAME, nic, sizeof(nic));
+ }
+ }
+ else
+ {
+ tapmode = true;
+ GetTxtA(hWnd, E_TAPNAME, nic, sizeof(nic));
+ }
+
+ Trim(hub);
+ Trim(nic);
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), nic);
+ StrCpy(t.HubName, sizeof(t.HubName), hub);
+ t.TapMode = tapmode;
+
+ if (InStrEx(t.DeviceName, "vpn", false) || InStrEx(t.DeviceName, "tun", false)
+ || InStrEx(t.DeviceName, "tap", false))
+ {
+ // Trying to make a local bridge to the VPN device
+ if (MsgBoxEx(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2,
+ _UU("SM_BRIDGE_VPN"),
+ t.DeviceName) == IDNO)
+ {
+ return;
+ }
+ }
+
+ // Show a warning message if the VPN Server is running in a VM
+ if (GetCapsBool(s->CapsList, "b_is_in_vm"))
+ {
+ Dialog(hWnd, D_SM_VMBRIDGE, SmVmBridgeDlg, NULL);
+ }
+
+ // Warning for such as Intel LAN cards
+ if (tapmode == false)
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_BRIDGE_INTEL"));
+ }
+
+ if (CALL(hWnd, ScAddLocalBridge(s->Rpc, &t)) == false)
+ {
+ Focus(hWnd, E_HUBNAME);
+ return;
+ }
+
+ SetText(hWnd, E_HUBNAME, L"");
+ Focus(hWnd, E_HUBNAME);
+
+ if (tapmode)
+ {
+ SetTextA(hWnd, E_TAPNAME, "");
+ }
+
+ SmBridgeDlgRefresh(hWnd, s);
+
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_BRIDGE_OK"));
+}
+
+// Bridge dialog procedure
+UINT SmBridgeDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ NMHDR *n;
+ SM_SERVER *s = (SM_SERVER *)param;
+ UINT i;
+ UINT num;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ num = SmBridgeDlgInit(hWnd, s);
+
+ if (num == 0)
+ {
+ SetTimer(hWnd, 2, 500, NULL);
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_HUBNAME:
+ case E_NICNAME:
+ case R_BRIDGE:
+ case R_TAP:
+ case E_TAPNAME:
+ SmBridgeDlgUpdate(hWnd, s);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case R_BRIDGE:
+ Focus(hWnd, E_NICNAME);
+ break;
+
+ case R_TAP:
+ FocusEx(hWnd, E_TAPNAME);
+ break;
+
+ case IDOK:
+ // Add
+ SmBridgeDlgOnOk(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ // Close
+ Close(hWnd);
+ break;
+
+ case B_VLAN:
+ // VLAN utility
+ SmVLan(hWnd, s);
+ break;
+
+ case B_DELETE:
+ // Delete
+ i = LvGetSelected(hWnd, L_LIST);
+ if (i != INFINITE)
+ {
+ wchar_t *nic, *hub;
+ wchar_t tmp[MAX_SIZE];
+ RPC_LOCALBRIDGE t;
+
+ hub = LvGetStr(hWnd, L_LIST, i, 1);
+ nic = LvGetStr(hWnd, L_LIST, i, 2);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_BRIDGE_DELETE"),
+ hub, nic);
+
+ if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, tmp) == IDYES)
+ {
+ Zero(&t, sizeof(t));
+ UniToStr(t.DeviceName, sizeof(t.DeviceName), nic);
+ UniToStr(t.HubName, sizeof(t.HubName), hub);
+
+ if (CALL(hWnd, ScDeleteLocalBridge(s->Rpc, &t)))
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_BRIDGE_DELETE_OK"));
+ SmBridgeDlgRefresh(hWnd, s);
+ }
+ }
+
+ Free(hub);
+ Free(nic);
+ }
+ break;
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ if (IsEnable(hWnd, 0))
+ {
+ KillTimer(hWnd, 1);
+ SmBridgeDlgRefresh(hWnd, s);
+ SetTimer(hWnd, 1, 1000, NULL);
+ }
+ break;
+
+ case 2:
+ KillTimer(hWnd, 2);
+
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_NO_BRIDGE_NICS"));
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ SmBridgeDlgUpdate(hWnd, s);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Installation of WinPcap
+void SmInstallWinPcap(HWND hWnd, SM_SERVER *s)
+{
+ wchar_t temp_name[MAX_SIZE];
+ IO *io;
+ BUF *buf;
+
+ // Ask whether the user want to start the installation
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("SM_BRIDGE_WPCAP_INSTALL")) == IDNO)
+ {
+ return;
+ }
+
+ // Generate a temporary file name
+ UniFormat(temp_name, sizeof(temp_name), L"%s\\winpcap_installer.exe", MsGetTempDirW());
+
+ // Read from hamcore
+ buf = ReadDump(MsIsNt() ? "|winpcap_installer.exe" : "|winpcap_installer_win9x.exe");
+ if (buf == NULL)
+ {
+RES_ERROR:
+ MsgBox(hWnd, MB_ICONSTOP, _UU("SM_BRIDGE_RESOURCE"));
+ return;
+ }
+
+ // Write to a temporary file
+ io = FileCreateW(temp_name);
+ if (io == NULL)
+ {
+ FreeBuf(buf);
+ goto RES_ERROR;
+ }
+
+ FileWrite(io, buf->Buf, buf->Size);
+ FileClose(io);
+
+ FreeBuf(buf);
+
+ // Run
+ if (RunW(temp_name, NULL, false, true) == false)
+ {
+ // Failure
+ FileDeleteW(temp_name);
+ goto RES_ERROR;
+ }
+
+ FileDeleteW(temp_name);
+
+ if (s == NULL)
+ {
+ return;
+ }
+
+ // Message after completed
+ if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) == false)
+ {
+ // Need to restart the computer
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_BRIDGE_WPCAP_REBOOT1"));
+ }
+ else
+ {
+ // Need to restart the service
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("SM_BRIDGE_WPCAP_REBOOT2")) == IDNO)
+ {
+ // Not restart
+ }
+ else
+ {
+ // Restart
+ RPC_TEST t;
+ Zero(&t, sizeof(t));
+ ScRebootServer(s->Rpc, &t);
+
+ SleepThread(500);
+
+ Zero(&t, sizeof(t));
+ CALL(hWnd, ScTest(s->Rpc, &t));
+ }
+ }
+}
+
+// Bridge dialog
+void SmBridgeDlg(HWND hWnd, SM_SERVER *s)
+{
+ RPC_BRIDGE_SUPPORT t;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ // Examine the bridge support status of the server side first
+ Zero(&t, sizeof(t));
+ if (CALLEX(hWnd, ScGetBridgeSupport(s->Rpc, &t)) != ERR_NO_ERROR)
+ {
+ // Not supported because it is old version
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SM_BRIDGE_TOO_OLD_VER"));
+ return;
+ }
+
+ if (t.IsBridgeSupportedOs == false)
+ {
+ // OS does not support the bridge
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SM_BRIDGE_UNSUPPORTED"));
+ return;
+ }
+
+ if (t.IsWinPcapNeeded)
+ {
+ if (s->Rpc->Sock->RemoteIP.addr[0] != 127)
+ {
+ // WinPcap is required, but can not do anything because it is in remote control mode
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_BRIDGE_WPCAP_REMOTE"));
+ return;
+ }
+ else
+ {
+ // WinPcap is required, and it's in local management mode
+ if (MsIsAdmin())
+ {
+ // The user is an Administrators
+ SmInstallWinPcap(hWnd, s);
+ return;
+ }
+ else
+ {
+ // The user is a non-Administrators
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_BRIDGE_WPCAP_ROOT"));
+ return;
+ }
+ }
+ }
+
+ Dialog(hWnd, D_SM_BRIDGE, SmBridgeDlgProc, s);
+}
+
+// SecureNAT screen update
+void SmSNATDlgUpdate(HWND hWnd, SM_HUB *s)
+{
+ bool b;
+ RPC_HUB_STATUS t;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ if (CALL(hWnd, ScGetHubStatus(s->Rpc, &t)) == false)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ b = t.SecureNATEnabled;
+
+ if (b)
+ {
+ Disable(hWnd, B_ENABLE);
+ Enable(hWnd, B_DISABLE);
+ Enable(hWnd, B_NAT);
+ Enable(hWnd, B_DHCP);
+ Enable(hWnd, B_STATUS);
+ }
+ else
+ {
+ Enable(hWnd, B_ENABLE);
+ Disable(hWnd, B_DISABLE);
+ Disable(hWnd, B_NAT);
+ Disable(hWnd, B_DHCP);
+ Disable(hWnd, B_STATUS);
+ }
+}
+
+// SecureNAT configuration screen
+UINT SmSNATDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_HUB *s = (SM_HUB *)param;
+ RPC_HUB t;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetIcon(hWnd, 0, ICO_ROUTER);
+ DlgFont(hWnd, S_WARNING, (_GETLANG() == 0 || _GETLANG() == 2) ? 13 : 10, true);
+ FormatText(hWnd, S_TITLE, s->HubName);
+ SmSNATDlgUpdate(hWnd, s);
+
+ SetTimer(hWnd, 1, 1000, NULL);
+ break;
+
+ case WM_TIMER:
+ if (wParam == 1)
+ {
+ if (IsEnable(hWnd, 0))
+ {
+ KillTimer(hWnd, 1);
+
+ SmSNATDlgUpdate(hWnd, s);
+
+ SetTimer(hWnd, 1, 1000, NULL);
+ }
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case B_ENABLE:
+ if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_OKCANCEL | MB_DEFBUTTON2,
+ _UU("SM_SECURE_NAT_MSG")) == IDOK)
+ {
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ CALL(hWnd, ScEnableSecureNAT(s->Rpc, &t));
+ SmSNATDlgUpdate(hWnd, s);
+ }
+ break;
+
+ case B_DISABLE:
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ CALL(hWnd, ScDisableSecureNAT(s->Rpc, &t));
+ SmSNATDlgUpdate(hWnd, s);
+ break;
+
+ case B_CONFIG:
+ NmEditVhOption(hWnd, s);
+ break;
+
+ case B_NAT:
+ NmNat(hWnd, s);
+ break;
+
+ case B_DHCP:
+ NmDhcp(hWnd, s);
+ break;
+
+ case B_STATUS:
+ SmStatusDlg(hWnd, s->p, s, false, true, _UU("SM_SNAT_STATUS"), ICO_ROUTER,
+ NULL, NmStatus);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Initialize
+void SmCreateCertDlgInit(HWND hWnd, SM_CERT *s)
+{
+ UINT cert_sign;
+ UINT cert_days;
+ char *reg_o, *reg_ou, *reg_c, *reg_st, *reg_l;
+ UINT bits[] = {1024, 1536, 2048, 3072, 4096 };
+ UINT i;
+ UINT last_bit;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetTextA(hWnd, E_CN, s->default_cn);
+
+ last_bit = MsRegReadInt(REG_CURRENT_USER, SM_CERT_REG_KEY, "Bits");
+ if (last_bit == 0)
+ {
+ last_bit = 2048;
+ }
+
+ CbReset(hWnd, C_BITS);
+ for (i = 0;i < sizeof(bits) / sizeof(bits[0]);i++)
+ {
+ char tmp[MAX_PATH];
+ UINT index;
+
+ ToStr(tmp, bits[i]);
+
+ index = CbAddStrA(hWnd, C_BITS, tmp, bits[i]);
+ }
+
+ CbSelect(hWnd, C_BITS, 1024);
+ CbSelect(hWnd, C_BITS, last_bit);
+
+ reg_o = MsRegReadStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "O");
+ reg_ou = MsRegReadStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "OU");
+ reg_c = MsRegReadStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "C");
+ reg_st = MsRegReadStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "ST");
+ reg_l = MsRegReadStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "L");
+ SetTextA(hWnd, E_O, reg_o);
+ SetTextA(hWnd, E_OU, reg_ou);
+ SetTextA(hWnd, E_C, reg_c);
+ SetTextA(hWnd, E_ST, reg_st);
+ SetTextA(hWnd, E_L, reg_l);
+ Free(reg_o);
+ Free(reg_ou);
+ Free(reg_c);
+ Free(reg_st);
+ Free(reg_l);
+
+ LimitText(hWnd, E_C, 2);
+
+ cert_sign = MsRegReadInt(REG_CURRENT_USER, SM_CERT_REG_KEY, "Sign");
+ cert_days = MsRegReadInt(REG_CURRENT_USER, SM_CERT_REG_KEY, "Days");
+
+ Check(hWnd, R_ROOT_CERT, cert_sign ? false : true);
+ Check(hWnd, R_SIGNED_CERT, cert_sign ? true : false);
+
+ if (cert_days == 0)
+ {
+ cert_days = 3650;
+ }
+
+ SetIntEx(hWnd, E_EXPIRE, cert_days);
+
+ SmCreateCertDlgUpdate(hWnd, s);
+
+ if (s->root_only)
+ {
+ Disable(hWnd, R_SIGNED_CERT);
+ }
+
+ // Font
+ SetFont(hWnd, E_CN, GetFont((MsIsWinXPOrGreater() ? "Verdana" : NULL), 0, false, false, false, false));
+ SetFont(hWnd, E_O, GetFont((MsIsWinXPOrGreater() ? "Verdana" : NULL), 0, false, false, false, false));
+ SetFont(hWnd, E_OU, GetFont((MsIsWinXPOrGreater() ? "Verdana" : NULL), 0, false, false, false, false));
+ SetFont(hWnd, E_C, GetFont((MsIsWinXPOrGreater() ? "Verdana" : NULL), 0, false, false, false, false));
+ SetFont(hWnd, E_ST, GetFont((MsIsWinXPOrGreater() ? "Verdana" : NULL), 0, false, false, false, false));
+ SetFont(hWnd, E_L, GetFont((MsIsWinXPOrGreater() ? "Verdana" : NULL), 0, false, false, false, false));
+ SetFont(hWnd, E_SERIAL, GetFont((MsIsWinXPOrGreater() ? "Verdana" : NULL), 0, false, false, false, false));
+ SetFont(hWnd, E_EXPIRE, GetFont((MsIsWinXPOrGreater() ? "Verdana" : NULL), 0, false, false, false, false));
+ SetFont(hWnd, C_BITS, GetFont("Verdana", 0, false, false, false, false));
+
+ FocusEx(hWnd, E_CN);
+}
+
+// Update
+void SmCreateCertDlgUpdate(HWND hWnd, SM_CERT *s)
+{
+ bool ok = true;
+ bool b;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (IsEmpty(hWnd, E_CN) && IsEmpty(hWnd, E_O) && IsEmpty(hWnd, E_OU) &&
+ IsEmpty(hWnd, E_ST) && IsEmpty(hWnd, E_L))
+ {
+ ok = false;
+ }
+
+ i = GetInt(hWnd, E_EXPIRE);
+ if (i == 0 || i >= (365 * 30))
+ {
+ ok = false;
+ }
+
+ b = IsChecked(hWnd, R_SIGNED_CERT);
+
+ SetEnable(hWnd, S_LOAD_1, b);
+ SetEnable(hWnd, B_LOAD, b);
+ SetEnable(hWnd, S_LOAD_2, b);
+
+ if (b && (s->root_k == NULL || s->root_x == NULL))
+ {
+ ok = false;
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// [OK] button
+void SmCreateCertDlgOnOk(HWND hWnd, SM_CERT *s)
+{
+ wchar_t cn[MAX_SIZE], o[MAX_SIZE], ou[MAX_SIZE], c[MAX_SIZE], st[MAX_SIZE], l[MAX_SIZE];
+ char *reg_o, *reg_ou, *reg_c, *reg_st, *reg_l;
+ UINT days;
+ bool sign;
+ char serial[MAX_SIZE * 2];
+ X *x;
+ K *pub;
+ K *pri;
+ NAME *n;
+ X_SERIAL *x_serial;
+ BUF *buf;
+ UINT bits;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ GetTxt(hWnd, E_CN, cn, sizeof(cn));
+ GetTxt(hWnd, E_O, o, sizeof(o));
+ GetTxt(hWnd, E_OU, ou, sizeof(ou));
+ GetTxt(hWnd, E_C, c, sizeof(c));
+ GetTxt(hWnd, E_ST, st, sizeof(st));
+ GetTxt(hWnd, E_L, l, sizeof(l));
+ GetTxtA(hWnd, E_SERIAL, serial, sizeof(serial));
+
+ bits = CbGetSelect(hWnd, C_BITS);
+ if (bits == INFINITE)
+ {
+ bits = 1024;
+ }
+
+ buf = StrToBin(serial);
+ if (buf == NULL)
+ {
+ return;
+ }
+
+ if (buf->Size > 1)
+ {
+ x_serial = NewXSerial(buf->Buf, buf->Size);
+ }
+ else
+ {
+ x_serial = NULL;
+ }
+
+ FreeBuf(buf);
+
+ n = NewName(UniStrLen(cn) ? cn : NULL,
+ UniStrLen(o) ? o : NULL,
+ UniStrLen(ou) ? ou : NULL,
+ UniStrLen(c) ? c : NULL,
+ UniStrLen(st) ? st : NULL,
+ UniStrLen(l) ? l : NULL);
+
+ days = GetInt(hWnd, E_EXPIRE);
+
+ sign = IsChecked(hWnd, R_SIGNED_CERT);
+
+ MsRegWriteInt(REG_CURRENT_USER, SM_CERT_REG_KEY, "Sign", sign);
+ MsRegWriteInt(REG_CURRENT_USER, SM_CERT_REG_KEY, "Days", days);
+ MsRegWriteInt(REG_CURRENT_USER, SM_CERT_REG_KEY, "Bits", bits);
+
+ RsaGen(&pri, &pub, bits);
+
+ if (sign == false)
+ {
+ x = NewRootX(pub, pri, n, days, x_serial);
+ }
+ else
+ {
+ x = NewX(pub, s->root_k, s->root_x, n, days, x_serial);
+ }
+
+ FreeName(n);
+
+ FreeXSerial(x_serial);
+
+ if (x == NULL)
+ {
+ FreeX(x);
+ FreeK(pub);
+ FreeK(pri);
+ return;
+ }
+
+ if (s->do_not_save == false)
+ {
+ if (SmSaveKeyPairDlg(hWnd, x, pri) == false)
+ {
+ FreeX(x);
+ FreeK(pub);
+ FreeK(pri);
+ return;
+ }
+ }
+
+ s->x = x;
+ s->k = pri;
+ FreeK(pub);
+
+ reg_o = GetTextA(hWnd, E_O);
+ reg_ou = GetTextA(hWnd, E_OU);
+ reg_c = GetTextA(hWnd, E_C);
+ reg_st = GetTextA(hWnd, E_ST);
+ reg_l = GetTextA(hWnd, E_L);
+ MsRegWriteStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "O", reg_o);
+ MsRegWriteStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "OU", reg_ou);
+ MsRegWriteStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "C", reg_c);
+ MsRegWriteStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "ST", reg_st);
+ MsRegWriteStr(REG_CURRENT_USER, SM_CERT_REG_KEY, "L", reg_l);
+ Free(reg_o);
+ Free(reg_ou);
+ Free(reg_c);
+ Free(reg_st);
+ Free(reg_l);
+
+ EndDialog(hWnd, true);
+}
+
+// Certificate creation screen
+UINT SmCreateCertDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_CERT *s = (SM_CERT *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmCreateCertDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case R_ROOT_CERT:
+ case R_SIGNED_CERT:
+ case B_LOAD:
+ case E_CN:
+ case E_O:
+ case E_OU:
+ case E_C:
+ case E_ST:
+ case E_L:
+ case E_EXPIRE:
+ SmCreateCertDlgUpdate(hWnd, s);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ // [OK] button
+ SmCreateCertDlgOnOk(hWnd, s);
+ break;
+
+ case R_ROOT_CERT:
+ if (IsChecked(hWnd, R_ROOT_CERT))
+ {
+ FocusEx(hWnd, E_CN);
+ }
+ break;
+
+ case B_LOAD:
+ // Read a certificate
+ if (1)
+ {
+ X *x;
+ K *k;
+ if (CmLoadXAndK(hWnd, &x, &k))
+ {
+ wchar_t tmp[MAX_SIZE];
+ FreeX(s->root_x);
+ FreeK(s->root_k);
+ s->root_x = x;
+ s->root_k = k;
+
+ SmGetCertInfoStr(tmp, sizeof(tmp), x);
+ SetText(hWnd, S_LOAD_2, tmp);
+ SmCreateCertDlgUpdate(hWnd, s);
+ }
+ }
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Certificate tool
+bool SmCreateCert(HWND hWnd, X **x, K **k, bool do_not_save, char *default_cn, bool root_only)
+{
+ bool ret;
+ SM_CERT s;
+ Zero(&s, sizeof(s));
+
+ if (default_cn == NULL)
+ {
+ default_cn = "";
+ }
+
+ s.default_cn = default_cn;
+
+ s.do_not_save = do_not_save;
+
+ s.root_only = root_only;
+
+ ret = Dialog(hWnd, D_SM_CREATE_CERT, SmCreateCertDlgProc, &s);
+
+ if (ret)
+ {
+ if (x != NULL)
+ {
+ *x = CloneX(s.x);
+ }
+
+ if (k != NULL)
+ {
+ *k = CloneK(s.k);
+ }
+ }
+
+ FreeX(s.x);
+ FreeK(s.k);
+ FreeX(s.root_x);
+ FreeK(s.root_k);
+
+ return ret;
+}
+
+// Initialize
+void SmIpTableDlgInit(HWND hWnd, SM_TABLE *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_PROTOCOL);
+ FormatText(hWnd, S_TITLE, s->Hub->HubName);
+
+ if (s->SessionName != NULL)
+ {
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ GetTxt(hWnd, S_TITLE, tmp, sizeof(tmp));
+ UniFormat(tmp2, sizeof(tmp2), _UU("SM_SESSION_FILTER"), s->SessionName);
+ UniStrCat(tmp, sizeof(tmp), tmp2);
+ SetText(hWnd, S_TITLE, tmp);
+ }
+
+ LvInit(hWnd, L_TABLE);
+ LvInsertColumn(hWnd, L_TABLE, 0, _UU("SM_IP_COLUMN_1"), 190);
+ LvInsertColumn(hWnd, L_TABLE, 1, _UU("SM_IP_COLUMN_2"), 140);
+ LvInsertColumn(hWnd, L_TABLE, 2, _UU("SM_IP_COLUMN_3"), 133);
+ LvInsertColumn(hWnd, L_TABLE, 3, _UU("SM_IP_COLUMN_4"), 133);
+ LvInsertColumn(hWnd, L_TABLE, 4, _UU("SM_IP_COLUMN_5"), 133);
+ LvSetStyle(hWnd, L_TABLE, LVS_EX_GRIDLINES);
+
+ SmIpTableDlgRefresh(hWnd, s);
+}
+
+// Update the control
+void SmIpTableDlgUpdate(HWND hWnd, SM_TABLE *s)
+{
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (LvIsSelected(hWnd, L_TABLE) == false || LvIsMultiMasked(hWnd, L_TABLE))
+ {
+ ok = false;
+ }
+
+ SetEnable(hWnd, B_DELETE, ok);
+}
+
+// Content update
+void SmIpTableDlgRefresh(HWND hWnd, SM_TABLE *s)
+{
+ UINT i;
+ RPC_ENUM_IP_TABLE t;
+ UINT old_selected = 0;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->Hub->HubName);
+
+ if (CALL(hWnd, ScEnumIpTable(s->Rpc, &t)) == false)
+ {
+ EndDialog(hWnd, false);
+ return;
+ }
+
+ i = LvGetSelected(hWnd, L_TABLE);
+ if (i != INFINITE)
+ {
+ old_selected = (UINT)LvGetParam(hWnd, L_TABLE, i);
+ }
+
+ LvReset(hWnd, L_TABLE);
+
+ for (i = 0;i < t.NumIpTable;i++)
+ {
+ char str[MAX_SIZE];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t tmp5[MAX_SIZE];
+ RPC_ENUM_IP_TABLE_ITEM *e = &t.IpTables[i];
+
+ if (s->SessionName == NULL || StrCmpi(e->SessionName, s->SessionName) == 0)
+ {
+ StrToUni(tmp1, sizeof(tmp1), e->SessionName);
+
+ if (e->DhcpAllocated == false)
+ {
+ IPToStr(str, sizeof(str), &e->IpV6);
+ StrToUni(tmp2, sizeof(tmp2), str);
+ }
+ else
+ {
+ IPToStr(str, sizeof(str), &e->IpV6);
+ UniFormat(tmp2, sizeof(tmp2), _UU("SM_MAC_IP_DHCP"), str);
+ }
+
+ GetDateTimeStr64Uni(tmp3, sizeof(tmp3), SystemToLocal64(e->CreatedTime));
+
+ GetDateTimeStr64Uni(tmp4, sizeof(tmp4), SystemToLocal64(e->UpdatedTime));
+
+ if (StrLen(e->RemoteHostname) == 0)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_MACIP_LOCAL"));
+ }
+ else
+ {
+ UniFormat(tmp5, sizeof(tmp5), _UU("SM_MACIP_SERVER"), e->RemoteHostname);
+ }
+
+ LvInsert(hWnd, L_TABLE, e->DhcpAllocated ? ICO_PROTOCOL_DHCP : ICO_PROTOCOL, (void *)e->Key, 5,
+ tmp1, tmp2, tmp3, tmp4, tmp5);
+ }
+ }
+
+ FreeRpcEnumIpTable(&t);
+
+ if (old_selected != 0)
+ {
+ LvSelect(hWnd, L_TABLE, LvSearchParam(hWnd, L_TABLE, (void *)old_selected));
+ }
+
+ SmIpTableDlgUpdate(hWnd, s);
+}
+
+// IP address table dialog procedure
+UINT SmIpTableDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_TABLE *s = (SM_TABLE *)param;
+ NMHDR *n;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmIpTableDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_DELETE:
+ // Delete
+ i = LvGetSelected(hWnd, L_TABLE);
+ if (i != INFINITE)
+ {
+ RPC_DELETE_TABLE t;
+ UINT key = (UINT)LvGetParam(hWnd, L_TABLE, i);
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->Hub->HubName);
+ t.Key = key;
+ if (CALL(hWnd, ScDeleteIpTable(s->Rpc, &t)))
+ {
+ LvDeleteItem(hWnd, L_TABLE, i);
+ }
+ }
+ break;
+
+ case B_REFRESH:
+ // Update
+ SmIpTableDlgRefresh(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_TABLE:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ SmIpTableDlgUpdate(hWnd, s);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_TABLE);
+
+ return 0;
+}
+
+// IP address table dialog
+void SmIpTableDlg(HWND hWnd, SM_HUB *s, char *session_name)
+{
+ SM_TABLE t;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ t.Hub = s;
+ t.Rpc = s->Rpc;
+ t.SessionName = session_name;
+
+ Dialog(hWnd, D_SM_IP, SmIpTableDlgProc, &t);
+}
+
+
+// Initialize
+void SmMacTableDlgInit(HWND hWnd, SM_TABLE *s)
+{
+ UINT i = 0;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_NIC_ONLINE);
+ FormatText(hWnd, S_TITLE, s->Hub->HubName);
+
+ if (s->SessionName != NULL)
+ {
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ GetTxt(hWnd, S_TITLE, tmp, sizeof(tmp));
+ UniFormat(tmp2, sizeof(tmp2), _UU("SM_SESSION_FILTER"), s->SessionName);
+ UniStrCat(tmp, sizeof(tmp), tmp2);
+ SetText(hWnd, S_TITLE, tmp);
+ }
+
+ LvInit(hWnd, L_TABLE);
+ LvInsertColumn(hWnd, L_TABLE, i++, _UU("SM_MAC_COLUMN_1"), 190);
+ if (GetCapsBool(s->Hub->p->CapsList, "b_support_vlan"))
+ {
+ LvInsertColumn(hWnd, L_TABLE, i++, _UU("SM_MAC_COLUMN_1A"), 65);
+ }
+ LvInsertColumn(hWnd, L_TABLE, i++, _UU("SM_MAC_COLUMN_2"), 140);
+ LvInsertColumn(hWnd, L_TABLE, i++, _UU("SM_MAC_COLUMN_3"), 133);
+ LvInsertColumn(hWnd, L_TABLE, i++, _UU("SM_MAC_COLUMN_4"), 133);
+ LvInsertColumn(hWnd, L_TABLE, i++, _UU("SM_MAC_COLUMN_5"), 133);
+ LvSetStyle(hWnd, L_TABLE, LVS_EX_GRIDLINES);
+
+ SmMacTableDlgRefresh(hWnd, s);
+}
+
+// Update the control
+void SmMacTableDlgUpdate(HWND hWnd, SM_TABLE *s)
+{
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (LvIsSelected(hWnd, L_TABLE) == false || LvIsMultiMasked(hWnd, L_TABLE))
+ {
+ ok = false;
+ }
+
+ SetEnable(hWnd, B_DELETE, ok);
+}
+
+// Content update
+void SmMacTableDlgRefresh(HWND hWnd, SM_TABLE *s)
+{
+ UINT i;
+ RPC_ENUM_MAC_TABLE t;
+ UINT old_selected = 0;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->Hub->HubName);
+
+ if (CALL(hWnd, ScEnumMacTable(s->Rpc, &t)) == false)
+ {
+ EndDialog(hWnd, false);
+ return;
+ }
+
+ i = LvGetSelected(hWnd, L_TABLE);
+ if (i != INFINITE)
+ {
+ old_selected = (UINT)LvGetParam(hWnd, L_TABLE, i);
+ }
+
+ LvReset(hWnd, L_TABLE);
+
+ for (i = 0;i < t.NumMacTable;i++)
+ {
+ char str[MAX_SIZE];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t tmp5[MAX_SIZE];
+ wchar_t tmp6[MAX_SIZE];
+ RPC_ENUM_MAC_TABLE_ITEM *e = &t.MacTables[i];
+
+ if (s->SessionName == NULL || StrCmpi(e->SessionName, s->SessionName) == 0)
+ {
+ StrToUni(tmp1, sizeof(tmp1), e->SessionName);
+
+ MacToStr(str, sizeof(str), e->MacAddress);
+ StrToUni(tmp2, sizeof(tmp2), str);
+
+ GetDateTimeStr64Uni(tmp3, sizeof(tmp3), SystemToLocal64(e->CreatedTime));
+
+ GetDateTimeStr64Uni(tmp4, sizeof(tmp4), SystemToLocal64(e->UpdatedTime));
+
+ if (StrLen(e->RemoteHostname) == 0)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_MACIP_LOCAL"));
+ }
+ else
+ {
+ UniFormat(tmp5, sizeof(tmp5), _UU("SM_MACIP_SERVER"), e->RemoteHostname);
+ }
+
+ UniToStru(tmp6, e->VlanId);
+ if (e->VlanId == 0)
+ {
+ UniStrCpy(tmp6, sizeof(tmp6), _UU("CM_ST_NONE"));
+ }
+
+ if (GetCapsBool(s->Hub->p->CapsList, "b_support_vlan"))
+ {
+ LvInsert(hWnd, L_TABLE, ICO_NIC_ONLINE, (void *)e->Key, 6,
+ tmp1, tmp6, tmp2, tmp3, tmp4, tmp5);
+ }
+ else
+ {
+ LvInsert(hWnd, L_TABLE, ICO_NIC_ONLINE, (void *)e->Key, 5,
+ tmp1, tmp2, tmp3, tmp4, tmp5);
+ }
+ }
+ }
+
+ FreeRpcEnumMacTable(&t);
+
+ if (old_selected != 0)
+ {
+ LvSelect(hWnd, L_TABLE, LvSearchParam(hWnd, L_TABLE, (void *)old_selected));
+ }
+
+ SmMacTableDlgUpdate(hWnd, s);
+}
+
+// MAC address table dialog procedure
+UINT SmMacTableDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_TABLE *s = (SM_TABLE *)param;
+ NMHDR *n;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmMacTableDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_DELETE:
+ // Delete
+ i = LvGetSelected(hWnd, L_TABLE);
+ if (i != INFINITE)
+ {
+ RPC_DELETE_TABLE t;
+ UINT key = (UINT)LvGetParam(hWnd, L_TABLE, i);
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->Hub->HubName);
+ t.Key = key;
+ if (CALL(hWnd, ScDeleteMacTable(s->Rpc, &t)))
+ {
+ LvDeleteItem(hWnd, L_TABLE, i);
+ }
+ }
+ break;
+
+ case B_REFRESH:
+ // Update
+ SmMacTableDlgRefresh(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_TABLE:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ SmMacTableDlgUpdate(hWnd, s);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_TABLE);
+
+ return 0;
+}
+
+// MAC address table dialog
+void SmMacTableDlg(HWND hWnd, SM_HUB *s, char *session_name)
+{
+ SM_TABLE t;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ t.Hub = s;
+ t.Rpc = s->Rpc;
+ t.SessionName = session_name;
+
+ Dialog(hWnd, D_SM_MAC, SmMacTableDlgProc, &t);
+}
+
+// Initialize
+void SmSessionDlgInit(HWND hWnd, SM_HUB *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_VPN);
+ FormatText(hWnd, 0, s->HubName);
+ FormatText(hWnd, S_TITLE, s->HubName);
+
+ LvInit(hWnd, L_LIST);
+ LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_SESS_COLUMN_1"), 176);
+ LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_SESS_COLUMN_8"), 58);
+ LvInsertColumn(hWnd, L_LIST, 2, _UU("SM_SESS_COLUMN_2"), 62);
+ LvInsertColumn(hWnd, L_LIST, 3, _UU("SM_SESS_COLUMN_3"), 78);
+ LvInsertColumn(hWnd, L_LIST, 4, _UU("SM_SESS_COLUMN_4"), 122);
+ LvInsertColumn(hWnd, L_LIST, 5, _UU("SM_SESS_COLUMN_5"), 68);
+ LvInsertColumn(hWnd, L_LIST, 6, _UU("SM_SESS_COLUMN_6"), 100);
+ LvInsertColumn(hWnd, L_LIST, 7, _UU("SM_SESS_COLUMN_7"), 100);
+ LvSetStyle(hWnd, L_LIST, LVS_EX_GRIDLINES);
+
+ if (s->p->ServerType == SERVER_TYPE_FARM_CONTROLLER && GetCapsBool(s->p->CapsList, "b_support_cluster_admin") == false)
+ {
+ Show(hWnd, S_FARM_INFO_1);
+ Show(hWnd, S_FARM_INFO_2);
+ }
+
+ SmSessionDlgRefresh(hWnd, s);
+}
+
+// Update the control
+void SmSessionDlgUpdate(HWND hWnd, SM_HUB *s)
+{
+ bool ok = true;
+ bool ok2 = true;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (LvIsSelected(hWnd, L_LIST) == false || LvIsMultiMasked(hWnd, L_LIST))
+ {
+ ok = false;
+ ok2 = false;
+ }
+ else
+ {
+ UINT i = LvGetSelected(hWnd, L_LIST);
+ if (i != INFINITE)
+ {
+ void *p = LvGetParam(hWnd, L_LIST, i);
+ if (((bool)p) != false)
+ {
+ if (GetCapsBool(s->p->CapsList, "b_support_cluster_admin") == false)
+ {
+ ok = false;
+ }
+ }
+ }
+ }
+
+ if (s->p->ServerInfo.ServerBuildInt < 2844)
+ {
+ // Old version doen't support for remote management of the sessions
+ ok2 = ok;
+ }
+
+ SetEnable(hWnd, IDOK, ok2);
+ SetEnable(hWnd, B_DISCONNECT, ok2);
+ SetEnable(hWnd, B_SESSION_IP_TABLE, ok);
+ SetEnable(hWnd, B_SESSION_MAC_TABLE, ok);
+}
+
+// Update the list
+void SmSessionDlgRefresh(HWND hWnd, SM_HUB *s)
+{
+ LVB *b;
+ UINT i;
+ wchar_t *old_select;
+ RPC_ENUM_SESSION t;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+ if (CALL(hWnd, ScEnumSession(s->Rpc, &t)) == false)
+ {
+ EndDialog(hWnd, false);
+ return;
+ }
+
+ old_select = LvGetSelectedStr(hWnd, L_LIST, 0);
+
+ LvReset(hWnd, L_LIST);
+
+ b = LvInsertStart();
+
+ for (i = 0;i < t.NumSession;i++)
+ {
+ RPC_ENUM_SESSION_ITEM *e = &t.Sessions[i];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t *tmp2;
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ wchar_t tmp5[MAX_SIZE];
+ wchar_t tmp6[MAX_SIZE];
+ wchar_t tmp7[MAX_SIZE];
+ wchar_t tmp8[MAX_SIZE];
+ bool free_tmp2 = false;
+ UINT icon;
+
+ StrToUni(tmp1, sizeof(tmp1), e->Name);
+
+ tmp2 = _UU("SM_SESS_NORMAL");
+ icon = ICO_VPN;
+ if (s->p->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ if (e->RemoteSession)
+ {
+ tmp2 = ZeroMalloc(MAX_SIZE);
+ UniFormat(tmp2, MAX_SIZE, _UU("SM_SESS_REMOTE"), e->RemoteHostname);
+ icon = ICO_VPN;
+ free_tmp2 = true;
+ }
+ else
+ {
+ if (StrLen(e->RemoteHostname) == 0)
+ {
+ tmp2 = _UU("SM_SESS_LOCAL");
+ }
+ else
+ {
+ tmp2 = ZeroMalloc(MAX_SIZE);
+ UniFormat(tmp2, MAX_SIZE, _UU("SM_SESS_LOCAL_2"), e->RemoteHostname);
+ free_tmp2 = true;
+ }
+ }
+ }
+ if (e->LinkMode)
+ {
+ if (free_tmp2)
+ {
+ Free(tmp2);
+ free_tmp2 = false;
+ }
+ tmp2 = _UU("SM_SESS_LINK");
+ icon = ICO_CASCADE;
+ }
+ else if (e->SecureNATMode)
+ {
+ /*if (free_tmp2)
+ {
+ Free(tmp2);
+ free_tmp2 = false;
+ }
+ tmp2 = _UU("SM_SESS_SNAT");*/
+ icon = ICO_ROUTER;
+ }
+ else if (e->BridgeMode)
+ {
+ icon = ICO_BRIDGE;
+ }
+ else if (e->Layer3Mode)
+ {
+ icon = ICO_SWITCH;
+ }
+
+ StrToUni(tmp3, sizeof(tmp3), e->Username);
+
+ StrToUni(tmp4, sizeof(tmp4), e->Hostname);
+ if (e->LinkMode)
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_LINK_HOSTNAME"));
+ }
+ else if (e->SecureNATMode)
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_SNAT_HOSTNAME"));
+ }
+ else if (e->BridgeMode)
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_BRIDGE_HOSTNAME"));
+ }
+ else if (StartWith(e->Username, L3_USERNAME))
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_SESS_LAYER3_HOSTNAME"));
+ }
+
+ UniFormat(tmp5, sizeof(tmp5), L"%u / %u", e->CurrentNumTcp, e->MaxNumTcp);
+ if (e->LinkMode)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_SESS_LINK_TCP"));
+ }
+ else if (e->SecureNATMode)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_SESS_SNAT_TCP"));
+ }
+ else if (e->BridgeMode)
+ {
+ UniStrCpy(tmp5, sizeof(tmp5), _UU("SM_SESS_BRIDGE_TCP"));
+ }
+
+ if (e->VLanId == 0)
+ {
+ UniStrCpy(tmp8, sizeof(tmp8), _UU("CM_ST_NO_VLAN"));
+ }
+ else
+ {
+ UniToStru(tmp8, e->VLanId);
+ }
+
+ UniToStr3(tmp6, sizeof(tmp6), e->PacketSize);
+ UniToStr3(tmp7, sizeof(tmp7), e->PacketNum);
+
+ if (icon == ICO_VPN)
+ {
+ if (e->Client_BridgeMode)
+ {
+ icon = ICO_SESSION_BRIDGE;
+ }
+ else if (e->Client_MonitorMode)
+ {
+ icon = ICO_SESSION_MONITOR;
+ }
+ }
+
+ LvInsertAdd(b, icon, (void *)(e->RemoteSession), 8, tmp1, tmp8, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7);
+
+ if (free_tmp2)
+ {
+ Free(tmp2);
+ }
+ }
+
+ LvInsertEnd(b, hWnd, L_LIST);
+
+ if (old_select != NULL && UniStrLen(old_select) != 0)
+ {
+ UINT i = LvSearchStr(hWnd, L_LIST, 0, old_select);
+ if (i != INFINITE)
+ {
+ LvSelect(hWnd, L_LIST, i);
+ }
+ }
+
+ Free(old_select);
+
+ FreeRpcEnumSession(&t);
+
+ SmSessionDlgUpdate(hWnd, s);
+}
+
+// Display the NODE_INFO
+void SmPrintNodeInfo(LVB *b, NODE_INFO *info)
+{
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+ // Validate arguments
+ if (b == NULL || info == NULL)
+ {
+ return;
+ }
+
+ StrToUni(tmp, sizeof(tmp), info->ClientProductName);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_CLIENT_NAME"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), L"%u.%02u", Endian32(info->ClientProductVer) / 100, Endian32(info->ClientProductVer) % 100);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_CLIENT_VER"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), L"Build %u", Endian32(info->ClientProductBuild));
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_CLIENT_BUILD"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), info->ClientOsName);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_CLIENT_OS_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), info->ClientOsVer);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_CLIENT_OS_VER"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), info->ClientOsProductId);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_CLIENT_OS_PID"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), info->ClientHostname);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_CLIENT_HOST"), tmp);
+
+ IPToStr4or6(str, sizeof(str), info->ClientIpAddress, info->ClientIpAddress6);
+ StrToUni(tmp, sizeof(tmp), str);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_CLIENT_IP"), tmp);
+
+ UniToStru(tmp, Endian32(info->ClientPort));
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_CLIENT_PORT"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), info->ServerHostname);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_SERVER_HOST"), tmp);
+
+ IPToStr4or6(str, sizeof(str), info->ServerIpAddress, info->ServerIpAddress6);
+ StrToUni(tmp, sizeof(tmp), str);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_SERVER_IP"), tmp);
+
+ UniToStru(tmp, Endian32(info->ServerPort));
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_SERVER_PORT"), tmp);
+
+ if (StrLen(info->ProxyHostname) != 0)
+ {
+ StrToUni(tmp, sizeof(tmp), info->ProxyHostname);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_PROXY_HOSTNAME"), tmp);
+
+ IPToStr4or6(str, sizeof(str), info->ProxyIpAddress, info->ProxyIpAddress6);
+ StrToUni(tmp, sizeof(tmp), str);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_PROXY_IP"), tmp);
+
+ UniToStru(tmp, Endian32(info->ProxyPort));
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_NODE_PROXY_PORT"), tmp);
+ }
+}
+
+// Update the session status
+bool SmRefreshSessionStatus(HWND hWnd, SM_SERVER *s, void *param)
+{
+ LVB *b;
+ SM_SESSION_STATUS *status = (SM_SESSION_STATUS *)param;
+ RPC_SESSION_STATUS t;
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || s == NULL || param == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), status->Hub->HubName);
+ StrCpy(t.Name, sizeof(t.Name), status->SessionName);
+
+ if (CALL(hWnd, ScGetSessionStatus(s->Rpc, &t)) == false)
+ {
+ return false;
+ }
+
+ b = LvInsertStart();
+
+ if (t.ClientIp != 0)
+ {
+ IPToStr4or6(str, sizeof(str), t.ClientIp, t.ClientIp6);
+ StrToUni(tmp, sizeof(tmp), str);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_CLIENT_IP"), tmp);
+ }
+
+ if (StrLen(t.ClientHostName) != 0)
+ {
+ StrToUni(tmp, sizeof(tmp), t.ClientHostName);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_CLIENT_HOSTNAME"), tmp);
+ }
+
+ StrToUni(tmp, sizeof(tmp), t.Username);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_SESS_STATUS_USERNAME"), tmp);
+
+ if (StrCmpi(t.Username, LINK_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, SNAT_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, BRIDGE_USER_NAME_PRINT) != 0)
+ {
+ StrToUni(tmp, sizeof(tmp), t.RealUsername);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_SESS_STATUS_REALUSER"), tmp);
+ }
+
+ if (IsEmptyStr(t.GroupName) == false)
+ {
+ StrToUni(tmp, sizeof(tmp), t.GroupName);
+ LvInsertAdd(b, 0, NULL, 2, _UU("SM_SESS_STATUS_GROUPNAME"), tmp);
+ }
+
+ CmPrintStatusToListViewEx(b, &t.Status, true);
+
+ if (StrCmpi(t.Username, LINK_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, SNAT_USER_NAME_PRINT) != 0 && StrCmpi(t.Username, BRIDGE_USER_NAME_PRINT) != 0 &&
+ StartWith(t.Username, L3_USERNAME) == false)
+ {
+ SmPrintNodeInfo(b, &t.NodeInfo);
+ }
+
+ LvInsertEnd(b, hWnd, L_STATUS);
+
+ FreeRpcSessionStatus(&t);
+
+ return true;
+}
+
+// Session Management dialog procedure
+UINT SmSessionDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_HUB *s = (SM_HUB *)param;
+ wchar_t *tmp;
+ wchar_t tmp2[MAX_SIZE];
+ char name[MAX_SIZE];
+ NMHDR *n;
+ SM_SESSION_STATUS status;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ tmp = LvGetSelectedStr(hWnd, L_LIST, 0);
+ UniToStr(name, sizeof(name), tmp);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmSessionDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ if (IsEnable(hWnd, IDOK))
+ {
+ // Session status display
+ UniFormat(tmp2, sizeof(tmp2), _UU("SM_SESS_STATUS_CAPTION"), name);
+ Zero(&status, sizeof(status));
+ status.Hub = s;
+ status.SessionName = name;
+ SmStatusDlg(hWnd, s->p, &status, true, true, tmp2, ICO_VPN,
+ NULL, SmRefreshSessionStatus);
+ }
+ break;
+
+ case B_DISCONNECT:
+ // Disconnect
+ if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
+ _UU("SM_SESS_DISCONNECT_MSG"), name) == IDYES)
+ {
+ RPC_DELETE_SESSION t;
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ StrCpy(t.Name, sizeof(t.Name), name);
+
+ if (CALL(hWnd, ScDeleteSession(s->Rpc, &t)))
+ {
+ SmSessionDlgRefresh(hWnd, s);
+ }
+ }
+ break;
+
+ case B_REFRESH:
+ // Update
+ SmSessionDlgRefresh(hWnd, s);
+ break;
+
+ case B_SESSION_IP_TABLE:
+ // IP table
+ SmIpTableDlg(hWnd, s, name);
+ break;
+
+ case B_SESSION_MAC_TABLE:
+ // MAC table
+ SmMacTableDlg(hWnd, s, name);
+ break;
+
+ case B_MAC_TABLE:
+ // MAC Table List
+ SmMacTableDlg(hWnd, s, NULL);
+ break;
+
+ case B_IP_TABLE:
+ // IP Table List
+ SmIpTableDlg(hWnd, s, NULL);
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ SmSessionDlgUpdate(hWnd, s);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ Free(tmp);
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_LIST);
+
+ return 0;
+}
+
+// Session Management dialog
+void SmSessionDlg(HWND hWnd, SM_HUB *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_SM_SESSION, SmSessionDlgProc, s);
+}
+
+// Certificate List Update
+void SmCaDlgRefresh(HWND hWnd, SM_HUB *s)
+{
+ LVB *b;
+ UINT i;
+ RPC_HUB_ENUM_CA t;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ if (CALL(hWnd, ScEnumCa(s->Rpc, &t)) == false)
+ {
+ EndDialog(hWnd, false);
+ return;
+ }
+
+ b = LvInsertStart();
+
+ for (i = 0;i < t.NumCa;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ RPC_HUB_ENUM_CA_ITEM *e = &t.Ca[i];
+
+ GetDateStrEx64(tmp, sizeof(tmp), SystemToLocal64(e->Expires), NULL);
+
+ LvInsertAdd(b, ICO_SERVER_CERT, (void *)e->Key, 3,
+ e->SubjectName, e->IssuerName, tmp);
+ }
+
+ LvInsertEnd(b, hWnd, L_CERT);
+
+ FreeRpcHubEnumCa(&t);
+
+ SmCaDlgUpdate(hWnd, s);
+}
+
+// Initialize
+void SmCaDlgInit(HWND hWnd, SM_HUB *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_SERVER_CERT);
+
+ LvInit(hWnd, L_CERT);
+ LvInsertColumn(hWnd, L_CERT, 0, _UU("CM_CERT_COLUMN_1"), 190);
+ LvInsertColumn(hWnd, L_CERT, 1, _UU("CM_CERT_COLUMN_2"), 190);
+ LvInsertColumn(hWnd, L_CERT, 2, _UU("CM_CERT_COLUMN_3"), 160);
+
+ SmCaDlgRefresh(hWnd, s);
+}
+
+// Update the control
+void SmCaDlgUpdate(HWND hWnd, SM_HUB *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetEnable(hWnd, B_DELETE, LvIsSelected(hWnd, L_CERT));
+ SetEnable(hWnd, IDOK, LvIsSelected(hWnd, L_CERT));
+}
+
+// OK
+void SmCaDlgOnOk(HWND hWnd, SM_HUB *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+}
+
+// CA Adding dialog
+bool SmCaDlgAdd(HWND hWnd, SM_HUB *s)
+{
+ X *x;
+ RPC_HUB_ADD_CA t;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ if (CmLoadXFromFileOrSecureCard(hWnd, &x) == false)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ t.Cert = x;
+
+ if (CALL(hWnd, ScAddCa(s->Rpc, &t)) == false)
+ {
+ return false;
+ }
+
+ FreeRpcHubAddCa(&t);
+
+ return true;
+}
+
+// CA List dialog procedure
+UINT SmCaDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ NMHDR *n;
+ SM_HUB *s = (SM_HUB *)param;
+ UINT i, key;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmCaDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_IMPORT:
+ // Add
+ if (SmCaDlgAdd(hWnd, s))
+ {
+ SmCaDlgRefresh(hWnd, s);
+ }
+ break;
+
+ case B_DELETE:
+ // Delete
+ i = LvGetSelected(hWnd, L_CERT);
+ if (i != INFINITE)
+ {
+ key = (UINT)LvGetParam(hWnd, L_CERT, i);
+ if (key != 0)
+ {
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
+ _UU("CM_CERT_DELETE_MSG")) == IDYES)
+ {
+ RPC_HUB_DELETE_CA t;
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ t.Key = key;
+
+ if (CALL(hWnd, ScDeleteCa(s->Rpc, &t)))
+ {
+ SmCaDlgRefresh(hWnd, s);
+ }
+ }
+ }
+ }
+ break;
+
+ case IDOK:
+ // Display
+ i = LvGetSelected(hWnd, L_CERT);
+ if (i != INFINITE)
+ {
+ key = (UINT)LvGetParam(hWnd, L_CERT, i);
+ if (key != 0)
+ {
+ RPC_HUB_GET_CA t;
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ t.Key = key;
+
+ if (CALL(hWnd, ScGetCa(s->Rpc, &t)))
+ {
+ CertDlg(hWnd, t.Cert, NULL, true);
+ FreeRpcHubGetCa(&t);
+ }
+ }
+ }
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_CERT:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ SmCaDlgUpdate(hWnd, s);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_CERT);
+
+ return 0;
+}
+
+// CA List dialog box
+void SmCaDlg(HWND hWnd, SM_HUB *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_SM_CA, SmCaDlgProc, s);
+}
+
+// Initialize
+void SmLogDlgInit(HWND hWnd, SM_HUB *s)
+{
+ RPC_HUB_LOG t;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_LOG2);
+
+ FormatText(hWnd, S_TITLE, s->HubName);
+
+ CbSetHeight(hWnd, C_SEC_SWITCH, 18);
+ CbSetHeight(hWnd, C_PACKET_SWITCH, 18);
+
+ // Initialize the control
+ CbAddStr(hWnd, C_SEC_SWITCH, _UU("SM_LOG_SWITCH_0"), 0);
+ CbAddStr(hWnd, C_SEC_SWITCH, _UU("SM_LOG_SWITCH_1"), 1);
+ CbAddStr(hWnd, C_SEC_SWITCH, _UU("SM_LOG_SWITCH_2"), 2);
+ CbAddStr(hWnd, C_SEC_SWITCH, _UU("SM_LOG_SWITCH_3"), 3);
+ CbAddStr(hWnd, C_SEC_SWITCH, _UU("SM_LOG_SWITCH_4"), 4);
+ CbAddStr(hWnd, C_SEC_SWITCH, _UU("SM_LOG_SWITCH_5"), 5);
+ CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_0"), 0);
+ CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_1"), 1);
+ CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_2"), 2);
+ CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_3"), 3);
+ CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_4"), 4);
+ CbAddStr(hWnd, C_PACKET_SWITCH, _UU("SM_LOG_SWITCH_5"), 5);
+
+ // Get the log settings
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ if (CALL(hWnd, ScGetHubLog(s->Rpc, &t)) == false)
+ {
+ EndDialog(hWnd, false);
+ return;
+ }
+
+ Check(hWnd, B_SEC, t.LogSetting.SaveSecurityLog);
+ CbSelect(hWnd, C_SEC_SWITCH, t.LogSetting.SecurityLogSwitchType);
+
+ Check(hWnd, B_PACKET, t.LogSetting.SavePacketLog);
+ CbSelect(hWnd, C_PACKET_SWITCH, t.LogSetting.PacketLogSwitchType);
+
+ Check(hWnd, B_PACKET_0_0, t.LogSetting.PacketLogConfig[0] == 0);
+ Check(hWnd, B_PACKET_0_1, t.LogSetting.PacketLogConfig[0] == 1);
+ Check(hWnd, B_PACKET_0_2, t.LogSetting.PacketLogConfig[0] == 2);
+
+ Check(hWnd, B_PACKET_1_0, t.LogSetting.PacketLogConfig[1] == 0);
+ Check(hWnd, B_PACKET_1_1, t.LogSetting.PacketLogConfig[1] == 1);
+ Check(hWnd, B_PACKET_1_2, t.LogSetting.PacketLogConfig[1] == 2);
+
+ Check(hWnd, B_PACKET_2_0, t.LogSetting.PacketLogConfig[2] == 0);
+ Check(hWnd, B_PACKET_2_1, t.LogSetting.PacketLogConfig[2] == 1);
+ Check(hWnd, B_PACKET_2_2, t.LogSetting.PacketLogConfig[2] == 2);
+
+ Check(hWnd, B_PACKET_3_0, t.LogSetting.PacketLogConfig[3] == 0);
+ Check(hWnd, B_PACKET_3_1, t.LogSetting.PacketLogConfig[3] == 1);
+ Check(hWnd, B_PACKET_3_2, t.LogSetting.PacketLogConfig[3] == 2);
+
+ Check(hWnd, B_PACKET_4_0, t.LogSetting.PacketLogConfig[4] == 0);
+ Check(hWnd, B_PACKET_4_1, t.LogSetting.PacketLogConfig[4] == 1);
+ Check(hWnd, B_PACKET_4_2, t.LogSetting.PacketLogConfig[4] == 2);
+
+ Check(hWnd, B_PACKET_5_0, t.LogSetting.PacketLogConfig[5] == 0);
+ Check(hWnd, B_PACKET_5_1, t.LogSetting.PacketLogConfig[5] == 1);
+ Check(hWnd, B_PACKET_5_2, t.LogSetting.PacketLogConfig[5] == 2);
+
+ Check(hWnd, B_PACKET_6_0, t.LogSetting.PacketLogConfig[6] == 0);
+ Check(hWnd, B_PACKET_6_1, t.LogSetting.PacketLogConfig[6] == 1);
+ Check(hWnd, B_PACKET_6_2, t.LogSetting.PacketLogConfig[6] == 2);
+
+ Check(hWnd, B_PACKET_7_0, t.LogSetting.PacketLogConfig[7] == 0);
+ Check(hWnd, B_PACKET_7_1, t.LogSetting.PacketLogConfig[7] == 1);
+ Check(hWnd, B_PACKET_7_2, t.LogSetting.PacketLogConfig[7] == 2);
+
+ SmLogDlgUpdate(hWnd, s);
+}
+
+// Update the control
+void SmLogDlgUpdate(HWND hWnd, SM_HUB *s)
+{
+ bool b;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ b = IsChecked(hWnd, B_SEC);
+ SetEnable(hWnd, S_SEC, b);
+ SetEnable(hWnd, C_SEC_SWITCH, b);
+
+ b = IsChecked(hWnd, B_PACKET);
+ SetEnable(hWnd, S_PACKET, b);
+ SetEnable(hWnd, C_PACKET_SWITCH, b);
+ SetEnable(hWnd, S_PACKET_0, b);
+ SetEnable(hWnd, S_PACKET_1, b);
+ SetEnable(hWnd, S_PACKET_2, b);
+ SetEnable(hWnd, S_PACKET_3, b);
+ SetEnable(hWnd, S_PACKET_4, b);
+ SetEnable(hWnd, S_PACKET_5, b);
+ SetEnable(hWnd, S_PACKET_6, b);
+ SetEnable(hWnd, S_PACKET_7, b);
+ SetEnable(hWnd, B_PACKET_0_0, b); SetEnable(hWnd, B_PACKET_0_1, b); SetEnable(hWnd, B_PACKET_0_2, b);
+ SetEnable(hWnd, B_PACKET_1_0, b); SetEnable(hWnd, B_PACKET_1_1, b); SetEnable(hWnd, B_PACKET_1_2, b);
+ SetEnable(hWnd, B_PACKET_2_0, b); SetEnable(hWnd, B_PACKET_2_1, b); SetEnable(hWnd, B_PACKET_2_2, b);
+ SetEnable(hWnd, B_PACKET_3_0, b); SetEnable(hWnd, B_PACKET_3_1, b); SetEnable(hWnd, B_PACKET_3_2, b);
+ SetEnable(hWnd, B_PACKET_4_0, b); SetEnable(hWnd, B_PACKET_4_1, b); SetEnable(hWnd, B_PACKET_4_2, b);
+ SetEnable(hWnd, B_PACKET_5_0, b); SetEnable(hWnd, B_PACKET_5_1, b); SetEnable(hWnd, B_PACKET_5_2, b);
+ SetEnable(hWnd, B_PACKET_6_0, b); SetEnable(hWnd, B_PACKET_6_1, b); SetEnable(hWnd, B_PACKET_6_2, b);
+ SetEnable(hWnd, B_PACKET_7_0, b); SetEnable(hWnd, B_PACKET_7_1, b); SetEnable(hWnd, B_PACKET_7_2, b);
+}
+
+// OK
+void SmLogDlgOnOk(HWND hWnd, SM_HUB *s)
+{
+ HUB_LOG g;
+ RPC_HUB_LOG t;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&g, sizeof(g));
+ g.SaveSecurityLog = IsChecked(hWnd, B_SEC);
+ g.SavePacketLog = IsChecked(hWnd, B_PACKET);
+ g.SecurityLogSwitchType = CbGetSelect(hWnd, C_SEC_SWITCH);
+ g.PacketLogSwitchType = CbGetSelect(hWnd, C_PACKET_SWITCH);
+
+ g.PacketLogConfig[0] = IsChecked(hWnd, B_PACKET_0_0) ? 0 : IsChecked(hWnd, B_PACKET_0_1) ? 1 : 2;
+ g.PacketLogConfig[1] = IsChecked(hWnd, B_PACKET_1_0) ? 0 : IsChecked(hWnd, B_PACKET_1_1) ? 1 : 2;
+ g.PacketLogConfig[2] = IsChecked(hWnd, B_PACKET_2_0) ? 0 : IsChecked(hWnd, B_PACKET_2_1) ? 1 : 2;
+ g.PacketLogConfig[3] = IsChecked(hWnd, B_PACKET_3_0) ? 0 : IsChecked(hWnd, B_PACKET_3_1) ? 1 : 2;
+ g.PacketLogConfig[4] = IsChecked(hWnd, B_PACKET_4_0) ? 0 : IsChecked(hWnd, B_PACKET_4_1) ? 1 : 2;
+ g.PacketLogConfig[5] = IsChecked(hWnd, B_PACKET_5_0) ? 0 : IsChecked(hWnd, B_PACKET_5_1) ? 1 : 2;
+ g.PacketLogConfig[6] = IsChecked(hWnd, B_PACKET_6_0) ? 0 : IsChecked(hWnd, B_PACKET_6_1) ? 1 : 2;
+ g.PacketLogConfig[7] = IsChecked(hWnd, B_PACKET_7_0) ? 0 : IsChecked(hWnd, B_PACKET_7_1) ? 1 : 2;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ Copy(&t.LogSetting, &g, sizeof(HUB_LOG));
+
+ if (CALL(hWnd, ScSetHubLog(s->Rpc, &t)) == false)
+ {
+ return;
+ }
+
+ EndDialog(hWnd, true);
+}
+
+// Log storage settings dialog
+UINT SmLogDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_HUB *s = (SM_HUB *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmLogDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case B_SEC:
+ case B_PACKET:
+ SmLogDlgUpdate(hWnd, s);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ // [OK] button
+ SmLogDlgOnOk(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Show the status of the cascade connection
+bool SmRefreshLinkStatus(HWND hWnd, SM_SERVER *s, void *param)
+{
+ SM_LINK *k = (SM_LINK *)param;
+ RPC_LINK_STATUS t;
+ LVB *b;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL || param == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), k->Hub->HubName);
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), k->AccountName);
+
+ if (CALL(hWnd, ScGetLinkStatus(s->Rpc, &t)) == false)
+ {
+ return false;
+ }
+
+ b = LvInsertStart();
+
+ CmPrintStatusToListView(b, &t.Status);
+
+ LvInsertEnd(b, hWnd, L_STATUS);
+
+ FreeRpcLinkStatus(&t);
+
+ return true;
+}
+
+// Edit the link
+bool SmLinkEdit(HWND hWnd, SM_HUB *s, wchar_t *name)
+{
+ CM_ACCOUNT a;
+ RPC_CREATE_LINK t;
+ bool ret = false;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL || name == NULL)
+ {
+ return false;
+ }
+
+ Zero(&a, sizeof(a));
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ t.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ UniStrCpy(t.ClientOption->AccountName, sizeof(t.ClientOption->AccountName), name);
+
+ if (CALL(hWnd, ScGetLink(s->Rpc, &t)) == false)
+ {
+ return false;
+ }
+
+ a.Hub = s;
+ a.EditMode = true;
+ a.LinkMode = true;
+ a.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ a.OnlineFlag = t.Online;
+ Copy(a.ClientOption, t.ClientOption, sizeof(CLIENT_OPTION));
+ a.ClientAuth = CopyClientAuth(t.ClientAuth);
+ Copy(&a.Policy, &t.Policy, sizeof(POLICY));
+ a.CheckServerCert = t.CheckServerCert;
+ a.ServerCert = CloneX(t.ServerCert);
+ a.HideTrustCert = GetCapsBool(s->p->CapsList, "b_support_config_hub");
+ FreeRpcCreateLink(&t);
+
+ a.PolicyVer = s->p->PolicyVer;
+
+ if (GetCapsBool(s->p->CapsList, "b_support_cascade_client_cert") == false)
+ {
+ a.HideClientCertAuth = true;
+ }
+
+ a.HideSecureAuth = true;
+
+ ret = CmEditAccountDlg(hWnd, &a);
+
+ FreeX(a.ServerCert);
+ Free(a.ClientOption);
+ CiFreeClientAuth(a.ClientAuth);
+
+ return ret;
+}
+
+// Create a new link
+bool SmLinkCreate(HWND hWnd, SM_HUB *s)
+{
+ return SmLinkCreateEx(hWnd, s, false);
+}
+bool SmLinkCreateEx(HWND hWnd, SM_HUB *s, bool connectNow)
+{
+ CM_ACCOUNT a;
+ bool ret = false;;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ Zero(&a, sizeof(a));
+
+ a.Hub = s;
+ a.EditMode = false;
+ a.LinkMode = true;
+ a.ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));
+ a.OnlineFlag = false;
+ a.ClientAuth = ZeroMalloc(sizeof(CLIENT_AUTH));
+ a.ClientAuth->AuthType = CLIENT_AUTHTYPE_PASSWORD;
+ Copy(&a.Policy, GetDefaultPolicy(), sizeof(POLICY));
+ a.ClientOption->Port = 443; // Default port number
+ a.ClientOption->NumRetry = INFINITE;
+ a.ClientOption->RetryInterval = 15;
+ a.ClientOption->MaxConnection = 8;
+ a.ClientOption->UseEncrypt = true;
+ a.ClientOption->HalfConnection = false;
+ a.ClientOption->AdditionalConnectionInterval = 1;
+ a.ClientOption->RequireBridgeRoutingMode = true;
+ a.Link_ConnectNow = connectNow;
+
+ a.PolicyVer = s->p->PolicyVer;
+
+ if (GetCapsBool(s->p->CapsList, "b_support_cascade_client_cert") == false)
+ {
+ a.HideClientCertAuth = true;
+ }
+
+ a.HideSecureAuth = true;
+
+ ret = CmEditAccountDlg(hWnd, &a);
+
+ FreeX(a.ServerCert);
+ Free(a.ClientOption);
+ CiFreeClientAuth(a.ClientAuth);
+
+ return ret;
+}
+
+// Initialize
+void SmLinkDlgInit(HWND hWnd, SM_HUB *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_LINK);
+
+ FormatText(hWnd, 0, s->HubName);
+
+ LvInit(hWnd, L_LINK);
+
+ LvInsertColumn(hWnd, L_LINK, 0, _UU("SM_LINK_COLUMN_1"), 120);
+ LvInsertColumn(hWnd, L_LINK, 1, _UU("SM_LINK_COLUMN_2"), 150);
+ LvInsertColumn(hWnd, L_LINK, 2, _UU("SM_LINK_COLUMN_3"), 180);
+ LvInsertColumn(hWnd, L_LINK, 3, _UU("SM_LINK_COLUMN_4"), 130);
+ LvInsertColumn(hWnd, L_LINK, 4, _UU("SM_LINK_COLUMN_5"), 130);
+
+ LvSetStyle(hWnd, L_LINK, LVS_EX_GRIDLINES);
+
+ SmLinkDlgRefresh(hWnd, s);
+}
+
+// Update the controls
+void SmLinkDlgUpdate(HWND hWnd, SM_HUB *s)
+{
+ bool ok = true;
+ bool online = false;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (LvIsSelected(hWnd, L_LINK) == false || LvIsMultiMasked(hWnd, L_LINK))
+ {
+ ok = false;
+ }
+ else
+ {
+ online = (bool)LvGetParam(hWnd, L_LINK, LvGetSelected(hWnd, L_LINK));
+ }
+
+ SetEnable(hWnd, B_EDIT, ok);
+ SetEnable(hWnd, B_ONLINE, ok && (online == false));
+ SetEnable(hWnd, B_OFFLINE, ok && online);
+ SetEnable(hWnd, IDOK, ok && online);
+ SetEnable(hWnd, B_DELETE, ok);
+ SetEnable(hWnd, B_RENAME, ok);
+}
+
+// Content update
+void SmLinkDlgRefresh(HWND hWnd, SM_HUB *s)
+{
+ LVB *b;
+ RPC_ENUM_LINK t;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ if (CALL(hWnd, ScEnumLink(s->Rpc, &t)) == false)
+ {
+ EndDialog(hWnd, false);
+ return;
+ }
+
+ b = LvInsertStart();
+
+ for (i = 0;i < t.NumLink;i++)
+ {
+ RPC_ENUM_LINK_ITEM *e = &t.Links[i];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp4[MAX_SIZE];
+ UINT icon = ICO_CASCADE;
+
+ GetDateTimeStrEx64(tmp1, sizeof(tmp1), SystemToLocal64(e->ConnectedTime), NULL);
+ StrToUni(tmp2, sizeof(tmp2), e->Hostname);
+ StrToUni(tmp3, sizeof(tmp3), e->HubName);
+
+ if (e->Online == false)
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_LINK_STATUS_OFFLINE"));
+ }
+ else
+ {
+ if (e->Connected)
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_LINK_STATUS_ONLINE"));
+ }
+ else
+ {
+ if (e->LastError != 0)
+ {
+ UniFormat(tmp4, sizeof(tmp4), _UU("SM_LINK_STATUS_ERROR"), e->LastError, _E(e->LastError));
+ }
+ else
+ {
+ UniStrCpy(tmp4, sizeof(tmp4), _UU("SM_LINK_CONNECTING"));
+ }
+ }
+ }
+
+ if (e->Online == false)
+ {
+ icon = ICO_CASCADE_OFFLINE;
+ }
+ else
+ {
+ if (e->Connected == false && e->LastError != 0)
+ {
+ icon = ICO_CASCADE_ERROR;
+ }
+ else
+ {
+ icon = ICO_CASCADE;
+ }
+ }
+
+ LvInsertAdd(b,
+ icon, (void *)e->Online, 5,
+ e->AccountName, tmp4, tmp1, tmp2, tmp3);
+ }
+
+ LvInsertEnd(b, hWnd, L_LINK);
+
+ FreeRpcEnumLink(&t);
+
+ SmLinkDlgUpdate(hWnd, s);
+}
+
+
+// Link List dialog procedure
+UINT SmLinkDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_HUB *s = (SM_HUB *)param;
+ wchar_t *str;
+ NMHDR *n;
+ NMLVDISPINFOW *disp_info;
+ NMLVKEYDOWN *key;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ str = LvGetSelectedStr(hWnd, L_LINK, 0);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmLinkDlgInit(hWnd, s);
+
+ if (link_create_now)
+ {
+ if (SmLinkCreateEx(hWnd, s, true))
+ {
+ SmLinkDlgRefresh(hWnd, s);
+ }
+ }
+
+ SetTimer(hWnd, 1, 1000, NULL);
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ if (IsEnable(hWnd, 0))
+ {
+ KillTimer(hWnd, 1);
+ SmLinkDlgRefresh(hWnd, s);
+ SetTimer(hWnd, 1, 1000, NULL);
+ }
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_CREATE:
+ // Create new
+ if (SmLinkCreate(hWnd, s))
+ {
+ SmLinkDlgRefresh(hWnd, s);
+ }
+ break;
+
+ case B_EDIT:
+ // Edit
+ if (str != NULL)
+ {
+ if (SmLinkEdit(hWnd, s, str))
+ {
+ SmLinkDlgRefresh(hWnd, s);
+ }
+ }
+ break;
+
+ case B_ONLINE:
+ // Online
+ if (str != NULL)
+ {
+ RPC_LINK t;
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), str);
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+ if (CALL(hWnd, ScSetLinkOnline(s->Rpc, &t)))
+ {
+ SmLinkDlgRefresh(hWnd, s);
+ }
+ }
+ break;
+
+ case B_OFFLINE:
+ // Offline
+ if (str != NULL)
+ {
+ RPC_LINK t;
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), str);
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+ if (MsgBoxEx(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2,
+ _UU("SM_LINK_OFFLINE_MSG"), t.AccountName) == IDYES)
+ {
+ if (CALL(hWnd, ScSetLinkOffline(s->Rpc, &t)))
+ {
+ SmLinkDlgRefresh(hWnd, s);
+ }
+ }
+ }
+ break;
+
+ case IDOK:
+ // Status
+ if (str != NULL)
+ {
+ wchar_t tmp[MAX_SIZE];
+ SM_LINK t;
+ Zero(&t, sizeof(t));
+ t.Hub = s;
+ t.AccountName = str;
+ UniFormat(tmp, sizeof(tmp), _UU("SM_LINK_STATUS_CAPTION"), str);
+ SmStatusDlg(hWnd, s->p, &t, true, true, tmp,
+ ICO_CASCADE, NULL, SmRefreshLinkStatus);
+ }
+ break;
+
+ case B_DELETE:
+ // Delete
+ if (str != NULL)
+ {
+ RPC_LINK t;
+ Zero(&t, sizeof(t));
+ UniStrCpy(t.AccountName, sizeof(t.AccountName), str);
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+ if (MsgBoxEx(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2,
+ _UU("SM_LINK_DELETE_MSG"), t.AccountName) == IDYES)
+ {
+ if (CALL(hWnd, ScDeleteLink(s->Rpc, &t)))
+ {
+ SmLinkDlgRefresh(hWnd, s);
+ }
+ }
+ }
+ break;
+
+ case B_REFRESH:
+ // Update
+ SmLinkDlgRefresh(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+
+ case B_RENAME:
+ // Change the name
+ Focus(hWnd, L_LINK);
+ LvRename(hWnd, L_LINK, LvGetSelected(hWnd, L_LINK));
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_LINK:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ // Change the selection state
+ SmLinkDlgUpdate(hWnd, s);
+ break;
+
+ case LVN_ENDLABELEDITW:
+ // Change the name
+ disp_info = (NMLVDISPINFOW *)n;
+ if (disp_info->item.pszText != NULL)
+ {
+ wchar_t *new_name = disp_info->item.pszText;
+ wchar_t *old_name = LvGetStr(hWnd, L_LINK, disp_info->item.iItem, 0);
+
+ if (old_name != NULL)
+ {
+ if (UniStrCmp(new_name, old_name) != 0 && UniIsEmptyStr(new_name) == false)
+ {
+ RPC_RENAME_LINK t;
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ UniStrCpy(t.OldAccountName, sizeof(t.OldAccountName), old_name);
+ UniStrCpy(t.NewAccountName, sizeof(t.NewAccountName), new_name);
+ if (CALL(hWnd, ScRenameLink(s->Rpc, &t)))
+ {
+ SmLinkDlgRefresh(hWnd, s);
+ }
+ }
+
+ Free(old_name);
+ }
+ }
+ break;
+
+ case LVN_KEYDOWN:
+ // Keypress
+ key = (NMLVKEYDOWN *)n;
+ if (key != NULL)
+ {
+ bool ctrl, alt;
+ UINT code = key->wVKey;
+ ctrl = (GetKeyState(VK_CONTROL) & 0x8000) == 0 ? false : true;
+ alt = (GetKeyState(VK_MENU) & 0x8000) == 0 ? false : true;
+
+ if (code == VK_F2)
+ {
+ Command(hWnd, B_RENAME);
+ }
+ }
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ Free(str);
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_LINK);
+
+ return 0;
+}
+
+// Link List dialog
+void SmLinkDlg(HWND hWnd, SM_HUB *s)
+{
+ SmLinkDlgEx(hWnd, s, false);
+}
+void SmLinkDlgEx(HWND hWnd, SM_HUB *s, bool createNow)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ link_create_now = createNow;
+
+ Dialog(hWnd, D_SM_LINK, SmLinkDlgProc, s);
+}
+
+// Initialize
+void SmRadiusDlgInit(HWND hWnd, SM_HUB *s)
+{
+ RPC_RADIUS t;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_TOWER);
+
+ FormatText(hWnd, S_TITLE, s->HubName);
+ FormatText(hWnd, S_RADIUS_7, RADIUS_RETRY_INTERVAL, RADIUS_RETRY_TIMEOUT);
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+ if (CALL(hWnd, ScGetHubRadius(s->Rpc, &t)) == false)
+ {
+ EndDialog(hWnd, false);
+ return;
+ }
+
+ Check(hWnd, R_USE_RADIUS, StrLen(t.RadiusServerName) != 0);
+
+ if (StrLen(t.RadiusServerName) != 0)
+ {
+ SetTextA(hWnd, E_HOSTNAME, t.RadiusServerName);
+ SetIntEx(hWnd, E_PORT, t.RadiusPort);
+ SetTextA(hWnd, E_SECRET1, t.RadiusSecret);
+ SetTextA(hWnd, E_SECRET2, t.RadiusSecret);
+ SetIntEx(hWnd, E_RADIUS_RETRY_INTERVAL, t.RadiusRetryInterval);
+ FocusEx(hWnd, E_HOSTNAME);
+ }
+ else
+ {
+ SetInt(hWnd, E_PORT, RADIUS_DEFAULT_PORT);
+ SetInt(hWnd, E_RADIUS_RETRY_INTERVAL, RADIUS_RETRY_INTERVAL);
+ }
+
+ SmRadiusDlgUpdate(hWnd, s);
+}
+
+// Update the control
+void SmRadiusDlgUpdate(HWND hWnd, SM_HUB *s)
+{
+ bool ok = true;
+ bool b, b1;
+ char tmp1[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ b1 = GetCapsBool(s->p->CapsList, "b_support_radius_retry_interval_and_several_servers");
+ if(b1 == false)
+ {
+ Hide(hWnd, S_RADIUS_7);
+ Hide(hWnd, S_RADIUS_8);
+ Hide(hWnd, S_RADIUS_9);
+ Hide(hWnd, E_RADIUS_RETRY_INTERVAL);
+ }
+
+ b = IsChecked(hWnd, R_USE_RADIUS);
+
+ SetEnable(hWnd, S_RADIUS_1, b);
+ SetEnable(hWnd, S_RADIUS_2, b);
+ SetEnable(hWnd, S_RADIUS_3, b);
+ SetEnable(hWnd, S_RADIUS3, b);
+ SetEnable(hWnd, S_RADIUS_4, b);
+ SetEnable(hWnd, S_RADIUS_5, b);
+ SetEnable(hWnd, S_RADIUS_6, b);
+ SetEnable(hWnd, S_RADIUS_7, b);
+ SetEnable(hWnd, S_RADIUS_8, b);
+ SetEnable(hWnd, S_RADIUS_9, b);
+ SetEnable(hWnd, E_HOSTNAME, b);
+ SetEnable(hWnd, E_PORT, b);
+ SetEnable(hWnd, E_SECRET1, b);
+ SetEnable(hWnd, E_SECRET2, b);
+ SetEnable(hWnd, E_RADIUS_RETRY_INTERVAL, b);
+
+ if (b)
+ {
+ UINT p, m;
+ GetTxtA(hWnd, E_SECRET1, tmp1, sizeof(tmp1));
+ GetTxtA(hWnd, E_SECRET2, tmp2, sizeof(tmp2));
+
+ if (StrCmp(tmp1, tmp2) != 0)
+ {
+ ok = false;
+ }
+
+ if (IsEmpty(hWnd, E_HOSTNAME))
+ {
+ ok = false;
+ }
+
+ p = GetInt(hWnd, E_PORT);
+
+ if (p == 0 || p >= 65536)
+ {
+ ok = false;
+ }
+
+ m = GetInt(hWnd, E_RADIUS_RETRY_INTERVAL);
+ if (m > RADIUS_RETRY_TIMEOUT || m < RADIUS_RETRY_INTERVAL)
+ {
+ ok = false;
+ }
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// [OK] button
+void SmRadiusDlgOnOk(HWND hWnd, SM_HUB *s)
+{
+ RPC_RADIUS t;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+
+ if (IsChecked(hWnd, R_USE_RADIUS))
+ {
+ GetTxtA(hWnd, E_HOSTNAME, t.RadiusServerName, sizeof(t.RadiusServerName));
+ t.RadiusPort = GetInt(hWnd, E_PORT);
+ GetTxtA(hWnd, E_SECRET1,t.RadiusSecret, sizeof(t.RadiusSecret));
+ t.RadiusRetryInterval = GetInt(hWnd, E_RADIUS_RETRY_INTERVAL);
+ }
+
+ if (CALL(hWnd, ScSetHubRadius(s->Rpc, &t)) == false)
+ {
+ return;
+ }
+
+ EndDialog(hWnd, true);
+}
+
+
+// Radius dialog procedure
+UINT SmRadiusDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_HUB *s = (SM_HUB *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmRadiusDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_HOSTNAME:
+ case E_PORT:
+ case E_SECRET1:
+ case E_SECRET2:
+ case E_RADIUS_RETRY_INTERVAL:
+ case R_USE_RADIUS:
+ SmRadiusDlgUpdate(hWnd, s);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ // [OK] button
+ SmRadiusDlgOnOk(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+
+ case R_USE_RADIUS:
+ if (IsChecked(hWnd, R_USE_RADIUS))
+ {
+ FocusEx(hWnd, E_HOSTNAME);
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Radius Setup dialog
+void SmRadiusDlg(HWND hWnd, SM_HUB *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_SM_RADIUS, SmRadiusDlgProc, s);
+}
+
+
+// Initialize
+void SmEditAccessInit(HWND hWnd, SM_EDIT_ACCESS *s)
+{
+ ACCESS *a;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_PASS);
+
+ GetTxt(hWnd, 0, tmp, sizeof(tmp));
+
+ UniStrCat(tmp, sizeof(tmp), s->Access->IsIPv6 ? L" (IPv6)" : L" (IPv4)");
+
+ SetText(hWnd, 0, tmp);
+
+ s->Inited = false;
+ a = s->Access;
+
+ SetText(hWnd, E_NOTE, a->Note);
+
+ Check(hWnd, R_DISCARD, a->Discard);
+ Check(hWnd, R_PASS, a->Discard == false);
+ SetIntEx(hWnd, E_PRIORITY, a->Priority);
+
+ if (a->IsIPv6 == false)
+ {
+ // IPv4
+ if (a->SrcIpAddress == 0 && a->SrcSubnetMask == 0)
+ {
+ Check(hWnd, R_SRC_ALL, true);
+ }
+ else
+ {
+ IpSet(hWnd, E_SRC_IP, a->SrcIpAddress);
+ IpSet(hWnd, E_SRC_MASK, a->SrcSubnetMask);
+ }
+
+ if (a->DestIpAddress == 0 && a->DestSubnetMask == 0)
+ {
+ Check(hWnd, R_DST_ALL, true);
+ }
+ else
+ {
+ IpSet(hWnd, E_DST_IP, a->DestIpAddress);
+ IpSet(hWnd, E_DST_MASK, a->DestSubnetMask);
+ }
+ }
+ else
+ {
+ // IPv6
+ if (IsZeroIP6Addr(&a->SrcIpAddress6) && IsZeroIP6Addr(&a->SrcSubnetMask6))
+ {
+ Check(hWnd, R_SRC_ALL, true);
+ }
+ else
+ {
+ char tmp[MAX_SIZE];
+
+ IP6AddrToStr(tmp, sizeof(tmp), &a->SrcIpAddress6);
+ SetTextA(hWnd, E_SRC_IP_V6, tmp);
+
+ Mask6AddrToStrEx(tmp, sizeof(tmp), &a->SrcSubnetMask6, false);
+
+ if (IsNum(tmp))
+ {
+ StrCatLeft(tmp, sizeof(tmp), "/");
+ }
+
+ SetTextA(hWnd, E_SRC_MASK_V6, tmp);
+ }
+
+ if (IsZeroIP6Addr(&a->DestIpAddress6) && IsZeroIP6Addr(&a->DestSubnetMask6))
+ {
+ Check(hWnd, R_DST_ALL, true);
+ }
+ else
+ {
+ char tmp[MAX_SIZE];
+
+ IP6AddrToStr(tmp, sizeof(tmp), &a->DestIpAddress6);
+ SetTextA(hWnd, E_DST_IP_V6, tmp);
+
+ Mask6AddrToStrEx(tmp, sizeof(tmp), &a->DestSubnetMask6, false);
+
+ if (IsNum(tmp))
+ {
+ StrCatLeft(tmp, sizeof(tmp), "/");
+ }
+
+ SetTextA(hWnd, E_DST_MASK_V6, tmp);
+ }
+ }
+
+ CbSetHeight(hWnd, C_PROTOCOL, 18);
+ CbAddStr(hWnd, C_PROTOCOL, _UU("SM_ACCESS_PROTO_1"), 0);
+ CbAddStr(hWnd, C_PROTOCOL, _UU("SM_ACCESS_PROTO_2"), 0);
+ CbAddStr(hWnd, C_PROTOCOL, _UU("SM_ACCESS_PROTO_3"), 0);
+ CbAddStr(hWnd, C_PROTOCOL, _UU("SM_ACCESS_PROTO_4"), 0);
+ CbAddStr(hWnd, C_PROTOCOL, _UU("SM_ACCESS_PROTO_5"), 0);
+ CbAddStr(hWnd, C_PROTOCOL, _UU("SM_ACCESS_PROTO_6"), 0);
+
+ switch (a->Protocol)
+ {
+ case 0:
+ CbSelectIndex(hWnd, C_PROTOCOL, 0);
+ break;
+ case 6:
+ CbSelectIndex(hWnd, C_PROTOCOL, 1);
+ break;
+ case 17:
+ CbSelectIndex(hWnd, C_PROTOCOL, 2);
+ break;
+ case 1:
+ CbSelectIndex(hWnd, C_PROTOCOL, 3);
+ break;
+ case 58:
+ CbSelectIndex(hWnd, C_PROTOCOL, 4);
+ break;
+ default:
+ CbSelectIndex(hWnd, C_PROTOCOL, 5);
+ break;
+ }
+
+ SetIntEx(hWnd, E_IP_PROTO, a->Protocol);
+
+ SetIntEx(hWnd, E_SRC_PORT_1, a->SrcPortStart);
+ SetIntEx(hWnd, E_SRC_PORT_2, a->SrcPortEnd);
+ SetIntEx(hWnd, E_DST_PORT_1, a->DestPortStart);
+ SetIntEx(hWnd, E_DST_PORT_2, a->DestPortEnd);
+
+ SetTextA(hWnd, E_USERNAME1, a->SrcUsername);
+ SetTextA(hWnd, E_USERNAME2, a->DestUsername);
+
+ if(a->CheckSrcMac != false)
+ {
+ char mac[MAX_SIZE], mask[MAX_SIZE];
+ MacToStr(mac, sizeof(mac), a->SrcMacAddress);
+ MacToStr(mask, sizeof(mask), a->SrcMacMask);
+ SetTextA(hWnd, E_SRC_MAC, mac);
+ SetTextA(hWnd, E_SRC_MAC_MASK, mask);
+ }
+ if(a->CheckDstMac != false)
+ {
+ char mac[MAX_SIZE], mask[MAX_SIZE];
+ MacToStr(mac, sizeof(mac), a->DstMacAddress);
+ MacToStr(mask, sizeof(mask), a->DstMacMask);
+ SetTextA(hWnd, E_DST_MAC, mac);
+ SetTextA(hWnd, E_DST_MAC_MASK, mask);
+ }
+ Check(hWnd, R_CHECK_SRC_MAC, !a->CheckSrcMac);
+ Check(hWnd, R_CHECK_DST_MAC, !a->CheckDstMac);
+
+ Check(hWnd, R_CHECK_TCP_STATE, a->CheckTcpState);
+ if(a->CheckTcpState != false)
+ {
+ Check(hWnd, R_ESTABLISHED, a->Established);
+ Check(hWnd, R_UNESTABLISHED, !a->Established);
+ }
+
+ if (GetCapsBool(s->Hub->p->CapsList, "b_support_acl_group") == false)
+ {
+ SetText(hWnd, S_STATIC11, _UU("D_SM_EDIT_ACCESS@STATIC11_OLD"));
+ SetText(hWnd, S_STATIC12, _UU("D_SM_EDIT_ACCESS@STATIC12_OLD"));
+ SetText(hWnd, S_STATIC15, _UU("D_SM_EDIT_ACCESS@STATIC15_OLD"));
+ }
+
+ SetEnable(hWnd, R_REDIRECT, GetCapsBool(s->Hub->p->CapsList, "b_support_redirect_url_acl"));
+ Check(hWnd, R_REDIRECT, (IsEmptyStr(a->RedirectUrl) ? false : true));
+
+ s->Inited = true;
+
+ SmEditAccessUpdate(hWnd, s);
+}
+
+// HTTP Redirection Settings dialog
+void SmRedirect(HWND hWnd, SM_EDIT_ACCESS *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_SM_REDIRECT, SmRedirectDlg, s);
+}
+UINT SmRedirectDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_EDIT_ACCESS *s = (SM_EDIT_ACCESS *)param;
+ char tmp[MAX_REDIRECT_URL_LEN + 1];
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmRedirectDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_URL:
+ SmRedirectDlgUpdate(hWnd, s);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ GetTxtA(hWnd, E_URL, tmp, sizeof(tmp));
+
+ if (StartWith(tmp, "http://") == false &&
+ StartWith(tmp, "https://") == false)
+ {
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SM_ADVANCED_REDIRECT_URL_MSG"));
+
+ FocusEx(hWnd, E_URL);
+ break;
+ }
+
+ StrCpy(s->Access->RedirectUrl, sizeof(s->Access->RedirectUrl), tmp);
+
+ EndDialog(hWnd, 1);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case B_HINT:
+ OnceMsg(hWnd, _UU("SM_ADVANCED_REDIRECT_URL_HINT_TITLE"),
+ _UU("SM_ADVANCED_REDIRECT_URL_HINT"), false, ICO_INTERNET);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+void SmRedirectDlgInit(HWND hWnd, SM_EDIT_ACCESS *s)
+{
+ ACCESS *a;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ a = s->Access;
+
+ DlgFont(hWnd, S_BOLD, 0, true);
+ DlgFont(hWnd, S_BOLD2, 0, true);
+
+ SetFont(hWnd, E_SAMPLE1, GetFont("Verdana", 0, false, false, false, false));
+ SetFont(hWnd, E_SAMPLE2, GetFont("Verdana", 0, false, false, false, false));
+ SetFont(hWnd, E_URL, GetFont("Verdana", 10, false, false, false, false));
+
+ SetTextA(hWnd, E_SAMPLE1, "http://www.google.com/about/");
+ SetTextA(hWnd, E_SAMPLE2, "http://www.google.com/search?q=<INFO>|secret");
+
+ SetTextA(hWnd, E_URL, s->Access->RedirectUrl);
+
+ if (IsEmpty(hWnd, E_URL))
+ {
+ SetTextA(hWnd, E_URL, "http://");
+
+ SetCursorOnRight(hWnd, E_URL);
+ Focus(hWnd, E_URL);
+ }
+ else
+ {
+ FocusEx(hWnd, E_URL);
+ }
+
+ SmRedirectDlgUpdate(hWnd, s);
+}
+void SmRedirectDlgUpdate(HWND hWnd, SM_EDIT_ACCESS *s)
+{
+ char tmp[MAX_REDIRECT_URL_LEN + 1];
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ GetTxtA(hWnd, E_URL, tmp, sizeof(tmp));
+
+ if (IsEmptyStr(tmp))
+ {
+ ok = false;
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Update the control
+void SmEditAccessUpdate(HWND hWnd, SM_EDIT_ACCESS *s)
+{
+ bool ok = true;
+ bool tcp;
+ bool b;
+ bool check_srcmac, check_dstmac, support_mac;
+ bool check_state, support_check_state;
+ char srcmac[MAX_SIZE], srcmac_mask[MAX_SIZE], dstmac[MAX_SIZE], dstmac_mask[MAX_SIZE];
+ char tmp[MAX_SIZE];
+ wchar_t unitmp[MAX_SIZE];
+ ACCESS *a;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (s->Inited == false)
+ {
+ return;
+ }
+
+ a = s->Access;
+
+ GetTxt(hWnd, E_NOTE, a->Note, sizeof(a->Note));
+
+ a->Discard = IsChecked(hWnd, R_DISCARD);
+
+ a->Priority = GetInt(hWnd, E_PRIORITY);
+ if (a->Priority == 0)
+ {
+ ok = false;
+ }
+
+
+ b = IsChecked(hWnd, R_SRC_ALL) ? false : true;
+ if (b == false)
+ {
+ if (a->IsIPv6 == false)
+ {
+ a->SrcIpAddress = 0;
+ a->SrcSubnetMask = 0;
+ }
+ else
+ {
+ Zero(&a->SrcIpAddress6, sizeof(IPV6_ADDR));
+ Zero(&a->SrcSubnetMask6, sizeof(IPV6_ADDR));
+ }
+ }
+ else
+ {
+ if (a->IsIPv6 == false)
+ {
+ if (IpIsFilled(hWnd, E_SRC_IP) == false || IpIsFilled(hWnd, E_SRC_MASK) == false)
+ {
+ ok = false;
+ }
+ else
+ {
+ a->SrcIpAddress = IpGet(hWnd, E_SRC_IP);
+ a->SrcSubnetMask = IpGet(hWnd, E_SRC_MASK);
+ }
+ }
+ else
+ {
+ char tmp1[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+
+ GetTxtA(hWnd, E_SRC_IP_V6, tmp1, sizeof(tmp1));
+ GetTxtA(hWnd, E_SRC_MASK_V6, tmp2, sizeof(tmp2));
+
+ if (StrToIP6Addr(&a->SrcIpAddress6, tmp1) == false ||
+ StrToMask6Addr(&a->SrcSubnetMask6, tmp2) == false)
+ {
+ ok = false;
+ }
+ }
+ }
+ SetEnable(hWnd, S_SRC_IP_1, b);
+ SetEnable(hWnd, S_SRC_IP_2, b);
+ SetEnable(hWnd, S_SRC_IP_3, b);
+ SetEnable(hWnd, E_SRC_IP, b);
+ SetEnable(hWnd, E_SRC_MASK, b);
+ SetEnable(hWnd, E_SRC_IP_V6, b);
+ SetEnable(hWnd, E_SRC_MASK_V6, b);
+
+ b = IsChecked(hWnd, R_DST_ALL) ? false : true;
+ if (b == false)
+ {
+ if (a->IsIPv6 == false)
+ {
+ a->DestIpAddress = 0;
+ a->DestSubnetMask = 0;
+ }
+ else
+ {
+ Zero(&a->DestIpAddress6, sizeof(IPV6_ADDR));
+ Zero(&a->DestSubnetMask6, sizeof(IPV6_ADDR));
+ }
+ }
+ else
+ {
+ if (a->IsIPv6 == false)
+ {
+ if (IpIsFilled(hWnd, E_DST_IP) == false || IpIsFilled(hWnd, E_DST_MASK) == false)
+ {
+ ok = false;
+ }
+ else
+ {
+ a->DestIpAddress = IpGet(hWnd, E_DST_IP);
+ a->DestSubnetMask = IpGet(hWnd, E_DST_MASK);
+ }
+ }
+ else
+ {
+ char tmp1[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+
+ GetTxtA(hWnd, E_DST_IP_V6, tmp1, sizeof(tmp1));
+ GetTxtA(hWnd, E_DST_MASK_V6, tmp2, sizeof(tmp2));
+
+ if (StrToIP6Addr(&a->DestIpAddress6, tmp1) == false ||
+ StrToMask6Addr(&a->DestSubnetMask6, tmp2) == false)
+ {
+ ok = false;
+ }
+ }
+ }
+ SetEnable(hWnd, S_IP_DST_1, b);
+ SetEnable(hWnd, S_IP_DST_2, b);
+ SetEnable(hWnd, S_IP_DST_3, b);
+ SetEnable(hWnd, E_DST_IP, b);
+ SetEnable(hWnd, E_DST_MASK, b);
+ SetEnable(hWnd, E_DST_IP_V6, b);
+ SetEnable(hWnd, E_DST_MASK_V6, b);
+
+ a->Protocol = GetInt(hWnd, C_PROTOCOL);
+
+ GetTxtA(hWnd, C_PROTOCOL, tmp, sizeof(tmp));
+ GetTxt(hWnd, C_PROTOCOL, unitmp, sizeof(unitmp));
+
+ if (UniStrCmpi(unitmp, _UU("SM_ACCESS_PROTO_6")) == 0 || StrCmpi(tmp, _SS("SM_ACCESS_PROTO_6")) == 0)
+ {
+ a->Protocol = GetInt(hWnd, E_IP_PROTO);
+
+ if (IsEmpty(hWnd, E_IP_PROTO))
+ {
+ ok = false;
+ }
+
+ Enable(hWnd, S_PROTOID);
+ Enable(hWnd, E_IP_PROTO);
+ }
+ else
+ {
+ Disable(hWnd, E_IP_PROTO);
+ Disable(hWnd, S_PROTOID);
+ }
+
+ tcp = false;
+ if (a->Protocol == 17 || a->Protocol == 6)
+ {
+ tcp = true;
+ }
+
+ SetEnable(hWnd, S_TCP_1, tcp);
+ SetEnable(hWnd, S_TCP_2, tcp);
+ SetEnable(hWnd, S_TCP_3, tcp);
+ SetEnable(hWnd, S_TCP_4, tcp);
+ SetEnable(hWnd, S_TCP_5, tcp);
+ SetEnable(hWnd, S_TCP_6, tcp);
+ SetEnable(hWnd, S_TCP_7, tcp);
+ SetEnable(hWnd, E_SRC_PORT_1, tcp);
+ SetEnable(hWnd, E_SRC_PORT_2, tcp);
+ SetEnable(hWnd, E_DST_PORT_1, tcp);
+ SetEnable(hWnd, E_DST_PORT_2, tcp);
+
+ if (tcp == false)
+ {
+ a->SrcPortEnd = a->SrcPortStart = a->DestPortEnd = a->DestPortStart = 0;
+ }
+ else
+ {
+ a->SrcPortStart = GetInt(hWnd, E_SRC_PORT_1);
+ a->SrcPortEnd = GetInt(hWnd, E_SRC_PORT_2);
+ a->DestPortStart = GetInt(hWnd, E_DST_PORT_1);
+ a->DestPortEnd = GetInt(hWnd, E_DST_PORT_2);
+
+ if (a->SrcPortStart != 0)
+ {
+ if (a->SrcPortEnd != 0)
+ {
+ if (a->SrcPortStart > a->SrcPortEnd)
+ {
+ ok = false;
+ }
+ }
+ }
+ else
+ {
+ if (a->SrcPortEnd != 0)
+ {
+ ok = false;
+ }
+ }
+
+ if (a->DestPortStart != 0)
+ {
+ if (a->DestPortEnd != 0)
+ {
+ if (a->DestPortStart > a->DestPortEnd)
+ {
+ ok = false;
+ }
+ }
+ }
+ else
+ {
+ if (a->DestPortEnd != 0)
+ {
+ ok = false;
+ }
+ }
+
+ if (a->DestPortEnd < a->DestPortStart)
+ {
+ a->DestPortEnd = a->DestPortStart;
+ }
+
+ if (a->SrcPortEnd < a->SrcPortStart)
+ {
+ a->SrcPortEnd = a->SrcPortStart;
+ }
+ }
+
+ a->SrcUsernameHash = a->DestUsernameHash = 0;
+ GetTxtA(hWnd, E_USERNAME1, a->SrcUsername, sizeof(a->SrcUsername));
+ GetTxtA(hWnd, E_USERNAME2, a->DestUsername, sizeof(a->DestUsername));
+
+ if (StartWith(a->SrcUsername, ACCESS_LIST_INCLUDED_PREFIX) == false &&
+ StartWith(a->SrcUsername, ACCESS_LIST_EXCLUDED_PREFIX) == false)
+ {
+ MakeSimpleUsernameRemoveNtDomain(a->SrcUsername, sizeof(a->SrcUsername), a->SrcUsername);
+ }
+
+ if (StartWith(a->DestUsername, ACCESS_LIST_INCLUDED_PREFIX) == false &&
+ StartWith(a->DestUsername, ACCESS_LIST_EXCLUDED_PREFIX) == false)
+ {
+ MakeSimpleUsernameRemoveNtDomain(a->DestUsername, sizeof(a->DestUsername), a->DestUsername);
+ }
+
+ Trim(a->SrcUsername);
+ /*
+ if (StrLen(a->SrcUsername) != 0)
+ {
+ if (IsUserName(a->SrcUsername) == false)
+ {
+ ok = false;
+ }
+ }*/
+
+ Trim(a->DestUsername);
+ /*
+ if (StrLen(a->DestUsername) != 0)
+ {
+ if (IsUserName(a->DestUsername) == false)
+ {
+ ok = false;
+ }
+ }*/
+
+ support_mac = GetCapsBool(s->Hub->p->CapsList, "b_support_check_mac");
+
+ // Set the source MAC address
+ check_srcmac = a->CheckSrcMac = support_mac && (IsChecked(hWnd, R_CHECK_SRC_MAC) ? false : true);
+ if(check_srcmac == false)
+ {
+ Zero(a->SrcMacAddress, sizeof(a->SrcMacAddress));
+ Zero(a->SrcMacMask, sizeof(a->SrcMacMask));
+ }
+ else
+ {
+ GetTxtA(hWnd, E_SRC_MAC, srcmac, sizeof(srcmac));
+ GetTxtA(hWnd, E_SRC_MAC_MASK, srcmac_mask, sizeof(srcmac_mask));
+ Trim(srcmac);
+ Trim(srcmac_mask);
+ if(StrLen(srcmac) != 0 && StrLen(srcmac_mask) != 0)
+ {
+ UCHAR mac[6], mask[6];
+ if(StrToMac(mac, srcmac) && StrToMac(mask, srcmac_mask))
+ {
+ Copy(a->SrcMacAddress, mac, 6);
+ Copy(a->SrcMacMask, mask, 6);
+ }
+ else
+ {
+ ok = false;
+ }
+ }
+ else
+ {
+ ok = false;
+ }
+ }
+ SetEnable(hWnd, S_CHECK_SRC_MAC, support_mac);
+ SetEnable(hWnd, R_CHECK_SRC_MAC, support_mac);
+ SetEnable(hWnd, S_SRC_MAC, check_srcmac);
+ SetEnable(hWnd, S_SRC_MAC_MASK, check_srcmac);
+ SetEnable(hWnd, E_SRC_MAC, check_srcmac);
+ SetEnable(hWnd, E_SRC_MAC_MASK, check_srcmac);
+
+ // Set the destination MAC address
+ check_dstmac = a->CheckDstMac = support_mac && (IsChecked(hWnd, R_CHECK_DST_MAC) ? false : true);
+ if(check_dstmac == false)
+ {
+ Zero(a->DstMacAddress, sizeof(a->DstMacAddress));
+ Zero(a->DstMacMask, sizeof(a->DstMacMask));
+ }
+ else
+ {
+ GetTxtA(hWnd, E_DST_MAC, dstmac, sizeof(dstmac));
+ GetTxtA(hWnd, E_DST_MAC_MASK, dstmac_mask, sizeof(dstmac_mask));
+ Trim(dstmac);
+ Trim(dstmac_mask);
+ if(StrLen(dstmac) != 0 && StrLen(dstmac_mask) != 0)
+ {
+ UCHAR mac[6], mask[6];
+ if(StrToMac(mac, dstmac) && StrToMac(mask, dstmac_mask))
+ {
+ Copy(a->DstMacAddress, mac, 6);
+ Copy(a->DstMacMask, mask, 6);
+ }
+ else
+ {
+ ok = false;
+ }
+ }
+ else
+ {
+ ok = false;
+ }
+ }
+ SetEnable(hWnd, S_CHECK_DST_MAC, support_mac);
+ SetEnable(hWnd, R_CHECK_DST_MAC, support_mac);
+ SetEnable(hWnd, S_DST_MAC, check_dstmac);
+ SetEnable(hWnd, S_DST_MAC_MASK, check_dstmac);
+ SetEnable(hWnd, E_DST_MAC, check_dstmac);
+ SetEnable(hWnd, E_DST_MAC_MASK, check_dstmac);
+
+ SetEnable(hWnd, S_MAC_NOTE, check_srcmac || check_dstmac);
+
+ // Status of the TCP connection
+ support_check_state = GetCapsBool(s->Hub->p->CapsList, "b_support_check_tcp_state") && a->Protocol == 6;
+ SetEnable(hWnd, R_CHECK_TCP_STATE, support_check_state);
+ check_state = a->CheckTcpState = support_check_state && IsChecked(hWnd, R_CHECK_TCP_STATE);
+
+ a->Established = IsChecked(hWnd, R_ESTABLISHED) && check_state;
+ SetEnable(hWnd, R_ESTABLISHED, check_state);
+ SetEnable(hWnd, R_UNESTABLISHED, check_state);
+ if(check_state != false && IsChecked(hWnd, R_ESTABLISHED) == false && IsChecked(hWnd, R_UNESTABLISHED) == false)
+ {
+ ok = false;
+ }
+
+ // Settings button such as delay
+ SetEnable(hWnd, B_SIMULATION, a->Discard == false && GetCapsBool(s->Hub->p->CapsList, "b_support_ex_acl"));
+
+ // HTTP redirection settings button
+ SetEnable(hWnd, B_REDIRECT, IsChecked(hWnd, R_REDIRECT) && (a->Discard == false) && GetCapsBool(s->Hub->p->CapsList, "b_support_redirect_url_acl"));
+ SetEnable(hWnd, R_REDIRECT, (a->Discard == false) && GetCapsBool(s->Hub->p->CapsList, "b_support_redirect_url_acl"));
+
+ if (IsChecked(hWnd, R_REDIRECT) && (a->Discard == false) && GetCapsBool(s->Hub->p->CapsList, "b_support_redirect_url_acl"))
+ {
+ if (IsEmptyStr(a->RedirectUrl))
+ {
+ ok = false;
+ }
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// OK Click
+void SmEditAccessOnOk(HWND hWnd, SM_EDIT_ACCESS *s)
+{
+ ACCESS *a;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ a = s->Access;
+
+ SmEditAccessUpdate(hWnd, s);
+
+ if (IsChecked(hWnd, R_REDIRECT) == false || (a->Discard) || GetCapsBool(s->Hub->p->CapsList, "b_support_redirect_url_acl") == false)
+ {
+ // Disable the HTTP redirection
+ ClearStr(a->RedirectUrl, sizeof(a->RedirectUrl));
+ }
+
+ EndDialog(hWnd, true);
+}
+
+
+// Access list editing dialog
+UINT SmEditAccessDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_EDIT_ACCESS *s = (SM_EDIT_ACCESS *)param;
+ UINT ico;
+ ACCESS *a;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmEditAccessInit(hWnd, s);
+
+ goto REFRESH_ICON;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case R_PASS:
+ case R_DISCARD:
+ case E_PRIORITY:
+ case R_SRC_ALL:
+ case E_SRC_IP:
+ case E_SRC_MASK:
+ case R_DST_ALL:
+ case E_DST_MASK:
+ case E_SRC_IP_V6:
+ case E_SRC_MASK_V6:
+ case E_DST_MASK_V6:
+ case E_DST_IP_V6:
+ case C_PROTOCOL:
+ case E_SRC_PORT_1:
+ case E_SRC_PORT_2:
+ case E_DST_PORT_1:
+ case E_DST_PORT_2:
+ case E_USERNAME1:
+ case E_USERNAME2:
+ case E_IP_PROTO:
+ case R_CHECK_SRC_MAC:
+ case E_SRC_MAC:
+ case E_SRC_MAC_MASK:
+ case R_CHECK_DST_MAC:
+ case E_DST_MAC:
+ case E_DST_MAC_MASK:
+ case R_CHECK_TCP_STATE:
+ case R_ESTABLISHED:
+ case R_UNESTABLISHED:
+ case R_REDIRECT:
+ SmEditAccessUpdate(hWnd, s);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case B_USER1:
+ if (GetTxtA(hWnd, E_USERNAME1, tmp, sizeof(tmp)))
+ {
+ char *ret = SmSelectUserDlgEx(hWnd, s->Hub, tmp, GetCapsBool(s->Hub->p->CapsList, "b_support_acl_group"));
+ if (ret == NULL)
+ {
+ SetTextA(hWnd, E_USERNAME1, "");
+ }
+ else
+ {
+ SetTextA(hWnd, E_USERNAME1, ret);
+ Free(ret);
+ }
+ FocusEx(hWnd, E_USERNAME1);
+ }
+ break;
+
+ case B_USER2:
+ if (GetTxtA(hWnd, E_USERNAME2, tmp, sizeof(tmp)))
+ {
+ char *ret = SmSelectUserDlgEx(hWnd, s->Hub, tmp, GetCapsBool(s->Hub->p->CapsList, "b_support_acl_group"));
+ if (ret == NULL)
+ {
+ SetTextA(hWnd, E_USERNAME2, "");
+ }
+ else
+ {
+ SetTextA(hWnd, E_USERNAME2, ret);
+ Free(ret);
+ }
+ FocusEx(hWnd, E_USERNAME2);
+ }
+ break;
+
+ case IDOK:
+ // [OK] button
+ SmEditAccessOnOk(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+
+ case R_SRC_ALL:
+ if (IsChecked(hWnd, R_SRC_ALL) == false)
+ {
+ if (s->Access->IsIPv6)
+ {
+ FocusEx(hWnd, E_SRC_IP_V6);
+ }
+ else
+ {
+ Focus(hWnd, E_SRC_IP);
+ }
+ }
+ break;
+
+ case R_DST_ALL:
+ if (IsChecked(hWnd, R_DST_ALL) == false)
+ {
+ if (s->Access->IsIPv6)
+ {
+ FocusEx(hWnd, E_DST_IP_V6);
+ }
+ else
+ {
+ Focus(hWnd, E_DST_IP);
+ }
+ }
+ break;
+ case R_CHECK_SRC_MAC:
+ if(IsChecked(hWnd, R_CHECK_SRC_MAC) == false)
+ {
+ Focus(hWnd, E_SRC_MAC);
+ }
+ break;
+ case R_CHECK_DST_MAC:
+ if(IsChecked(hWnd, R_CHECK_DST_MAC) == false)
+ {
+ Focus(hWnd, E_DST_MAC);
+ }
+ break;
+
+ case R_PASS:
+ case R_DISCARD:
+REFRESH_ICON:
+ a = s->Access;
+ if (a->Discard == false && a->Active == false)
+ {
+ ico = ICO_PASS_DISABLE;
+ }
+ else if (a->Discard == false && a->Active)
+ {
+ ico = ICO_PASS;
+ }
+ else if (a->Discard && a->Active == false)
+ {
+ ico = ICO_DISCARD_DISABLE;
+ }
+ else
+ {
+ ico = ICO_DISCARD;
+ }
+
+ SetIcon(hWnd, S_ICON, ico);
+ break;
+
+ case B_SIMULATION:
+ // Simulation
+ Dialog(hWnd, D_SM_SIMULATION, SmSimulationDlg, s);
+ break;
+
+ case B_REDIRECT:
+ // Set the URL to redirect to
+ SmRedirect(hWnd, s);
+ SmEditAccessUpdate(hWnd, s);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Delay, jitter, packet-loss dialog
+UINT SmSimulationDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_EDIT_ACCESS *s = (SM_EDIT_ACCESS *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmSimulationInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_DELAY:
+ case E_JITTER:
+ case E_LOSS:
+ SmSimulationUpdate(hWnd, s);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ SmSimulationOnOk(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case C_DELAY:
+ SmSimulationUpdate(hWnd, s);
+ if (IsChecked(hWnd, C_DELAY))
+ {
+ FocusEx(hWnd, E_DELAY);
+ }
+ break;
+
+ case C_JITTER:
+ SmSimulationUpdate(hWnd, s);
+ if (IsChecked(hWnd, C_JITTER))
+ {
+ FocusEx(hWnd, E_JITTER);
+ }
+ break;
+
+ case C_LOSS:
+ SmSimulationUpdate(hWnd, s);
+ if (IsChecked(hWnd, C_LOSS))
+ {
+ FocusEx(hWnd, E_LOSS);
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Update of delay, jitter, packet-loss dialog
+void SmSimulationUpdate(HWND hWnd, SM_EDIT_ACCESS *s)
+{
+ bool b1, b2, b3;
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ b1 = IsChecked(hWnd, C_DELAY);
+ b2 = IsChecked(hWnd, C_JITTER);
+ b3 = IsChecked(hWnd, C_LOSS);
+
+ SetEnable(hWnd, S_DELAY, b1);
+ SetEnable(hWnd, S_DELAY2, b1);
+ SetEnable(hWnd, E_DELAY, b1);
+
+ SetEnable(hWnd, C_JITTER, b1);
+
+ if (b1 == false)
+ {
+ b2 = false;
+ }
+
+ SetEnable(hWnd, S_JITTER, b2);
+ SetEnable(hWnd, S_JITTER2, b2);
+ SetEnable(hWnd, E_JITTER, b2);
+
+ SetEnable(hWnd, S_LOSS, b3);
+ SetEnable(hWnd, S_LOSS2, b3);
+ SetEnable(hWnd, E_LOSS, b3);
+
+ if (b1)
+ {
+ UINT i = GetInt(hWnd, E_DELAY);
+ if (i == 0 || i > HUB_ACCESSLIST_DELAY_MAX)
+ {
+ ok = false;
+ }
+ }
+
+ if (b2)
+ {
+ UINT i = GetInt(hWnd, E_JITTER);
+ if (i == 0 || i > HUB_ACCESSLIST_JITTER_MAX)
+ {
+ ok = false;
+ }
+ }
+
+ if (b3)
+ {
+ UINT i = GetInt(hWnd, E_LOSS);
+ if (i == 0 || i > HUB_ACCESSLIST_LOSS_MAX)
+ {
+ ok = false;
+ }
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Initialization of delay, jitter, packet-loss dialog
+void SmSimulationInit(HWND hWnd, SM_EDIT_ACCESS *s)
+{
+ ACCESS *a;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ a = s->Access;
+
+ Check(hWnd, C_DELAY, a->Delay != 0);
+ Check(hWnd, C_JITTER, a->Jitter != 0);
+ Check(hWnd, C_LOSS, a->Loss != 0);
+
+ SetIntEx(hWnd, E_DELAY, a->Delay);
+ if (a->Delay != 0)
+ {
+ SetIntEx(hWnd, E_JITTER, a->Jitter);
+ }
+ SetIntEx(hWnd, E_LOSS, a->Loss);
+
+ SmSimulationUpdate(hWnd, s);
+
+ if (a->Delay != 0)
+ {
+ FocusEx(hWnd, E_DELAY);
+ }
+ else
+ {
+ Focus(hWnd, C_DELAY);
+ }
+}
+
+// Saving of delay, jitter, packet-loss dialog
+void SmSimulationOnOk(HWND hWnd, SM_EDIT_ACCESS *s)
+{
+ ACCESS *a;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ a = s->Access;
+
+ a->Jitter = a->Loss = a->Delay = 0;
+
+ if (IsChecked(hWnd, C_DELAY))
+ {
+ a->Delay = GetInt(hWnd, E_DELAY);
+ }
+
+ if (IsChecked(hWnd, C_JITTER))
+ {
+ a->Jitter = GetInt(hWnd, E_JITTER);
+ }
+
+ if (IsChecked(hWnd, C_LOSS))
+ {
+ a->Loss = GetInt(hWnd, E_LOSS);
+ }
+
+ EndDialog(hWnd, 1);
+}
+
+// Edit the access list
+bool SmEditAccess(HWND hWnd, SM_ACCESS_LIST *s, ACCESS *a)
+{
+ SM_EDIT_ACCESS edit;
+ bool ret;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ Zero(&edit, sizeof(edit));
+ edit.AccessList = s;
+ edit.EditMode = true;
+ edit.Access = ZeroMalloc(sizeof(ACCESS));
+ edit.Hub = s->Hub;
+ Copy(edit.Access, a, sizeof(ACCESS));
+
+ if (edit.Access->IsIPv6 == false)
+ {
+ ret = Dialog(hWnd, D_SM_EDIT_ACCESS, SmEditAccessDlg, &edit);
+ }
+ else
+ {
+ ret = Dialog(hWnd, D_SM_EDIT_ACCESS_V6, SmEditAccessDlg, &edit);
+ }
+
+ if (ret)
+ {
+ Copy(a, edit.Access, sizeof(ACCESS));
+ Free(edit.Access);
+ Sort(s->AccessList);
+
+ // Reassign the ID
+ for (i = 0;i < LIST_NUM(s->AccessList);i++)
+ {
+ ACCESS *a = LIST_DATA(s->AccessList, i);
+ a->Id = (i + 1);
+ }
+ }
+ else
+ {
+ Free(edit.Access);
+ }
+
+ return ret;
+}
+
+// Clone of the access list
+bool SmCloneAccess(HWND hWnd, SM_ACCESS_LIST *s, ACCESS *t)
+{
+ SM_EDIT_ACCESS edit;
+ bool ret;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL || t == NULL)
+ {
+ return false;
+ }
+
+ Zero(&edit, sizeof(edit));
+ edit.AccessList = s;
+ edit.Access = Clone(t, sizeof(ACCESS));
+ edit.Access->Priority = 0;
+ edit.Hub = s->Hub;
+
+ // Generate a number that does not duplicate with other and is larger than the priority of the cloning original
+ for (edit.Access->Priority = t->Priority;edit.Access->Priority != INFINITE;edit.Access->Priority++)
+ {
+ bool exists = false;
+
+ for (i = 0;i < LIST_NUM(s->AccessList);i++)
+ {
+ ACCESS *a = LIST_DATA(s->AccessList, i);
+
+ if (a->Priority == edit.Access->Priority)
+ {
+ exists = true;
+ break;
+ }
+ }
+
+ if (exists == false)
+ {
+ break;
+ }
+ }
+
+ if (edit.Access->IsIPv6 == false)
+ {
+ ret = Dialog(hWnd, D_SM_EDIT_ACCESS, SmEditAccessDlg, &edit);
+ }
+ else
+ {
+ ret = Dialog(hWnd, D_SM_EDIT_ACCESS_V6, SmEditAccessDlg, &edit);
+ }
+
+ if (ret)
+ {
+ Insert(s->AccessList, edit.Access);
+
+ // Reassign the ID
+ for (i = 0;i < LIST_NUM(s->AccessList);i++)
+ {
+ ACCESS *a = LIST_DATA(s->AccessList, i);
+ a->Id = (i + 1);
+ }
+ }
+ else
+ {
+ Free(edit.Access);
+ }
+
+ return ret;
+}
+
+// Add to Access List
+bool SmAddAccess(HWND hWnd, SM_ACCESS_LIST *s, bool ipv6)
+{
+ SM_EDIT_ACCESS edit;
+ bool ret;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ Zero(&edit, sizeof(edit));
+ edit.AccessList = s;
+ edit.Access = ZeroMalloc(sizeof(ACCESS));
+ edit.Access->Active = true;
+ edit.Access->Priority = 0;
+ edit.Access->IsIPv6 = ipv6;
+ edit.Hub = s->Hub;
+
+ // Get the new priority
+ for (i = 0;i < LIST_NUM(s->AccessList);i++)
+ {
+ ACCESS *a = LIST_DATA(s->AccessList, i);
+ edit.Access->Priority = MAX(edit.Access->Priority, a->Priority);
+ }
+
+ if (edit.Access->Priority == 0)
+ {
+ edit.Access->Priority = 900;
+ }
+
+ edit.Access->Priority += 100;
+
+ if (edit.Access->IsIPv6 == false)
+ {
+ ret = Dialog(hWnd, D_SM_EDIT_ACCESS, SmEditAccessDlg, &edit);
+ }
+ else
+ {
+ ret = Dialog(hWnd, D_SM_EDIT_ACCESS_V6, SmEditAccessDlg, &edit);
+ }
+
+ if (ret)
+ {
+ Insert(s->AccessList, edit.Access);
+
+ // Reassign the ID
+ for (i = 0;i < LIST_NUM(s->AccessList);i++)
+ {
+ ACCESS *a = LIST_DATA(s->AccessList, i);
+ a->Id = (i + 1);
+ }
+ }
+ else
+ {
+ Free(edit.Access);
+ }
+
+ return ret;
+}
+
+// Initialize
+void SmAccessListInit(HWND hWnd, SM_ACCESS_LIST *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_PASS);
+ FormatText(hWnd, S_TITLE, s->Hub->HubName);
+
+ LvInit(hWnd, L_ACCESS_LIST);
+ LvInsertColumn(hWnd, L_ACCESS_LIST, 0, _UU("SM_ACCESS_COLUMN_0"), 60);
+ LvInsertColumn(hWnd, L_ACCESS_LIST, 1, _UU("SM_ACCESS_COLUMN_1"), 60);
+ LvInsertColumn(hWnd, L_ACCESS_LIST, 2, _UU("SM_ACCESS_COLUMN_2"), 60);
+ LvInsertColumn(hWnd, L_ACCESS_LIST, 3, _UU("SM_ACCESS_COLUMN_3"), 70);
+ LvInsertColumn(hWnd, L_ACCESS_LIST, 4, _UU("SM_ACCESS_COLUMN_4"), 150);
+ LvInsertColumn(hWnd, L_ACCESS_LIST, 5, _UU("SM_ACCESS_COLUMN_5"), 600);
+
+ LvSetStyle(hWnd, L_ACCESS_LIST, LVS_EX_GRIDLINES);
+
+ SetEnable(hWnd, B_ADD_V6, GetCapsBool(s->Hub->p->CapsList, "b_support_ipv6_acl"));
+
+ SmAccessListRefresh(hWnd, s);
+}
+
+// Update the control
+void SmAccessListUpdate(HWND hWnd, SM_ACCESS_LIST *s)
+{
+ bool ok = true;
+ UINT max_access_lists = 0;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (LvIsSelected(hWnd, L_ACCESS_LIST) == false || LvIsMultiMasked(hWnd, L_ACCESS_LIST))
+ {
+ ok = false;
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+ SetEnable(hWnd, B_DELETE, ok);
+ SetEnable(hWnd, B_CLONE, ok);
+
+ if (ok == false)
+ {
+ SetEnable(hWnd, B_ENABLE, false);
+ SetEnable(hWnd, B_DISABLE, false);
+ }
+ else
+ {
+ ACCESS *a = LvGetParam(hWnd, L_ACCESS_LIST, LvGetSelected(hWnd, L_ACCESS_LIST));
+
+ if (a != NULL)
+ {
+ SetEnable(hWnd, B_ENABLE, (a->Active == false));
+ SetEnable(hWnd, B_DISABLE, (a->Active == true));
+ }
+ else
+ {
+ SetEnable(hWnd, B_ENABLE, false);
+ SetEnable(hWnd, B_DISABLE, false);
+ }
+ }
+
+ max_access_lists = GetCapsInt(s->Hub->p->CapsList, "i_max_access_lists");
+
+ SetEnable(hWnd, B_CREATE, LIST_NUM(s->AccessList) < max_access_lists);
+}
+
+// Content update
+void SmAccessListRefresh(HWND hWnd, SM_ACCESS_LIST *s)
+{
+ LVB *b;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ b = LvInsertStart();
+
+ Sort(s->AccessList);
+
+ for (i = 0;i < LIST_NUM(s->AccessList);i++)
+ {
+ ACCESS *a = LIST_DATA(s->AccessList, i);
+ char tmp[MAX_SIZE];
+ UINT ico = ICO_PASS;
+ wchar_t tmp3[MAX_SIZE];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ GetAccessListStr(tmp, sizeof(tmp), a);
+ UniToStru(tmp1, a->Priority);
+ StrToUni(tmp2, sizeof(tmp2), tmp);
+
+ if (a->Discard == false && a->Active == false)
+ {
+ ico = ICO_PASS_DISABLE;
+ }
+ else if (a->Discard == false && a->Active)
+ {
+ ico = ICO_PASS;
+ }
+ else if (a->Discard && a->Active == false)
+ {
+ ico = ICO_DISCARD_DISABLE;
+ }
+ else
+ {
+ ico = ICO_DISCARD;
+ }
+
+ UniToStru(tmp3, a->Id);
+
+ LvInsertAdd(b, ico, (void *)a, 6,
+ tmp3,
+ a->Discard ? _UU("SM_ACCESS_DISCARD") : _UU("SM_ACCESS_PASS"),
+ a->Active ? _UU("SM_ACCESS_ENABLE") : _UU("SM_ACCESS_DISABLE"),
+ tmp1,
+ a->Note,
+ tmp2);
+ }
+
+ LvInsertEnd(b, hWnd, L_ACCESS_LIST);
+ LvSortEx(hWnd, L_ACCESS_LIST, 0, false, true);
+
+ SmAccessListUpdate(hWnd, s);
+}
+
+// Access List dialog procedure
+UINT SmAccessListProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_ACCESS_LIST *s = (SM_ACCESS_LIST *)param;
+ NMHDR *n;
+ ACCESS *a;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmAccessListInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_ADD:
+ // Add (IPv4)
+ if (SmAddAccess(hWnd, s, false))
+ {
+ SmAccessListRefresh(hWnd, s);
+ }
+ break;
+
+ case B_ADD_V6:
+ // Add (IPv6)
+ if (SmAddAccess(hWnd, s, true))
+ {
+ SmAccessListRefresh(hWnd, s);
+ }
+ break;
+
+ case IDOK:
+ // Edit
+ a = LvGetParam(hWnd, L_ACCESS_LIST, LvGetSelected(hWnd, L_ACCESS_LIST));
+ if (a != NULL)
+ {
+ if (SmEditAccess(hWnd, s, a))
+ {
+ SmAccessListRefresh(hWnd, s);
+ }
+ }
+ break;
+
+ case B_CLONE:
+ // Create by cloning
+ a = LvGetParam(hWnd, L_ACCESS_LIST, LvGetSelected(hWnd, L_ACCESS_LIST));
+ if (a != NULL)
+ {
+ if (SmCloneAccess(hWnd, s, a))
+ {
+ SmAccessListRefresh(hWnd, s);
+ }
+ }
+ break;
+
+ case B_ENABLE:
+ a = LvGetParam(hWnd, L_ACCESS_LIST, LvGetSelected(hWnd, L_ACCESS_LIST));
+ if (a != NULL)
+ {
+ a->Active = true;
+ SmAccessListRefresh(hWnd, s);
+ }
+ break;
+
+ case B_DISABLE:
+ a = LvGetParam(hWnd, L_ACCESS_LIST, LvGetSelected(hWnd, L_ACCESS_LIST));
+ if (a != NULL)
+ {
+ a->Active = false;
+ SmAccessListRefresh(hWnd, s);
+ }
+ break;
+
+ case B_DELETE:
+ // Delete
+ a = LvGetParam(hWnd, L_ACCESS_LIST, LvGetSelected(hWnd, L_ACCESS_LIST));
+ if (a != NULL)
+ {
+ UINT i;
+ if (IsInList(s->AccessList, a))
+ {
+ Delete(s->AccessList, a);
+ Free(a);
+ // Reassign the ID
+ for (i = 0;i < LIST_NUM(s->AccessList);i++)
+ {
+ ACCESS *a = LIST_DATA(s->AccessList, i);
+ a->Id = (i + 1);
+ }
+ SmAccessListRefresh(hWnd, s);
+ }
+ }
+ break;
+
+ case B_SAVE:
+ // Save
+ {
+ UINT i;
+ bool ok;
+ // Save the access list
+ RPC_ENUM_ACCESS_LIST t;
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->Hub->HubName);
+ t.NumAccess = LIST_NUM(s->AccessList);
+ t.Accesses = ZeroMalloc(sizeof(ACCESS) * t.NumAccess);
+ for (i = 0;i < LIST_NUM(s->AccessList);i++)
+ {
+ ACCESS *access = LIST_DATA(s->AccessList, i);
+ Copy(&t.Accesses[i], access, sizeof(ACCESS));
+ }
+
+ ok = CALL(hWnd, ScSetAccessList(s->Rpc, &t));
+ FreeRpcEnumAccessList(&t);
+ if (ok)
+ {
+ EndDialog(hWnd, true);
+ }
+ }
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_ACCESS_LIST:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ SmAccessListUpdate(hWnd, s);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_ACCESS_LIST);
+
+ return 0;
+}
+
+
+// Access List dialog
+void SmAccessListDlg(HWND hWnd, SM_HUB *s)
+{
+ SM_ACCESS_LIST a;
+ UINT i;
+ RPC_ENUM_ACCESS_LIST t;
+ bool ret;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&a, sizeof(a));
+ a.Hub = s;
+ a.Rpc = s->Rpc;
+
+ // Get the access list
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ if (CALL(hWnd, ScEnumAccess(s->Rpc, &t)) == false)
+ {
+ return;
+ }
+
+ a.AccessList = NewListFast(CmpAccessList);
+ // Add to the list
+ for (i = 0;i < t.NumAccess;i++)
+ {
+ ACCESS *access = ZeroMalloc(sizeof(ACCESS));
+ Copy(access, &t.Accesses[i], sizeof(ACCESS));
+
+ Add(a.AccessList, access);
+ }
+
+ // Sort
+ Sort(a.AccessList);
+ FreeRpcEnumAccessList(&t);
+
+ // Show the dialog
+ ret = Dialog(hWnd, D_SM_ACCESS_LIST, SmAccessListProc, &a);
+
+ for (i = 0;i < LIST_NUM(a.AccessList);i++)
+ {
+ ACCESS *access = LIST_DATA(a.AccessList, i);
+ Free(access);
+ }
+ ReleaseList(a.AccessList);
+}
+
+// Initialize
+void SmEditGroupDlgInit(HWND hWnd, SM_EDIT_GROUP *g)
+{
+ RPC_SET_GROUP *group;
+ LVB *b;
+ // Validate arguments
+ if (hWnd == NULL || g == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_GROUP);
+
+ group = &g->SetGroup;
+
+ if (g->EditMode == false)
+ {
+ SetText(hWnd, 0, _UU("SM_EDIT_GROUP_CAPTION_1"));
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ UniFormat(tmp, sizeof(tmp), _UU("SM_EDIT_GROUP_CAPTION_2"), group->Name);
+ SetText(hWnd, 0, tmp);
+ }
+
+ SetTextA(hWnd, E_GROUPNAME, group->Name);
+ SetText(hWnd, E_REALNAME, group->Realname);
+ SetText(hWnd, E_NOTE, group->Note);
+
+ g->Inited = true;
+
+ if (g->EditMode == false)
+ {
+ Disable(hWnd, L_STATUS);
+ }
+ else
+ {
+ LvInit(hWnd, L_STATUS);
+ LvInsertColumn(hWnd, L_STATUS, 0, _UU("SM_STATUS_COLUMN_1"), 0);
+ LvInsertColumn(hWnd, L_STATUS, 1, _UU("SM_STATUS_COLUMN_2"), 0);
+ LvSetStyle(hWnd, L_STATUS, LVS_EX_GRIDLINES);
+
+ b = LvInsertStart();
+
+ SmInsertTrafficInfo(b, &group->Traffic);
+
+ LvInsertEnd(b, hWnd, L_STATUS);
+
+ LvAutoSize(hWnd, L_STATUS);
+ }
+
+ Check(hWnd, R_POLICY, group->Policy != NULL);
+
+ if (g->EditMode)
+ {
+ Disable(hWnd, E_GROUPNAME);
+ FocusEx(hWnd, E_REALNAME);
+ }
+
+ SmEditGroupDlgUpdate(hWnd, g);
+}
+
+// Update
+void SmEditGroupDlgUpdate(HWND hWnd, SM_EDIT_GROUP *g)
+{
+ bool ok = true;
+ RPC_SET_GROUP *group;
+ // Validate arguments
+ if (hWnd == NULL || g == NULL)
+ {
+ return;
+ }
+
+ if (g->Inited == false)
+ {
+ return;
+ }
+
+ group = &g->SetGroup;
+
+ GetTxtA(hWnd, E_GROUPNAME, group->Name, sizeof(group->Name));
+ Trim(group->Name);
+
+ if (IsUserName(group->Name) == false)
+ {
+ ok = false;
+ }
+
+ GetTxt(hWnd, E_REALNAME, group->Realname, sizeof(group->Realname));
+ UniTrim(group->Realname);
+
+ GetTxt(hWnd, E_NOTE, group->Note, sizeof(group->Note));
+ UniTrim(group->Note);
+
+ SetEnable(hWnd, B_POLICY, IsChecked(hWnd, R_POLICY));
+
+ if (IsChecked(hWnd, R_POLICY))
+ {
+ if (group->Policy == NULL)
+ {
+ ok = false;
+ }
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// OK
+void SmEditGroupDlgOnOk(HWND hWnd, SM_EDIT_GROUP *g)
+{
+ RPC_SET_GROUP *group;
+ RPC_SET_GROUP t;
+ // Validate arguments
+ if (hWnd == NULL || g == NULL)
+ {
+ return;
+ }
+
+ SmEditGroupDlgUpdate(hWnd, g);
+
+ group = &g->SetGroup;
+
+ if (IsChecked(hWnd, R_POLICY) == false)
+ {
+ if (group->Policy != NULL)
+ {
+ Free(group->Policy);
+ group->Policy = NULL;
+ }
+ }
+
+ Zero(&t, sizeof(t));
+ Copy(&t, group, sizeof(RPC_SET_GROUP));
+
+ t.Policy = ClonePolicy(group->Policy);
+
+ if (g->EditMode == false)
+ {
+ if (CALL(hWnd, ScCreateGroup(g->Rpc, &t)) == false)
+ {
+ FocusEx(hWnd, E_GROUPNAME);
+ return;
+ }
+ }
+ else
+ {
+ if (CALL(hWnd, ScSetGroup(g->Rpc, &t)) == false)
+ {
+ return;
+ }
+ }
+
+ FreeRpcSetGroup(&t);
+
+ if (g->EditMode == false)
+ {
+ MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("SM_GROUP_CREATED"), group->Name);
+ }
+
+ EndDialog(hWnd, true);
+}
+
+// Group editing dialog procedure
+UINT SmEditGroupDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_EDIT_GROUP *g = (SM_EDIT_GROUP *)param;
+ wchar_t tmp[MAX_SIZE];
+ NMHDR *n;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmEditGroupDlgInit(hWnd, g);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_GROUPNAME:
+ case E_REALNAME:
+ case E_NOTE:
+ case R_POLICY:
+ SmEditGroupDlgUpdate(hWnd, g);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ // [OK] button
+ SmEditGroupDlgOnOk(hWnd, g);
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+
+ case R_POLICY:
+ if (IsChecked(hWnd, R_POLICY))
+ {
+ Focus(hWnd, B_POLICY);
+ }
+ break;
+
+ case B_POLICY:
+ // Security policy
+ UniFormat(tmp, sizeof(tmp), _UU("SM_GROUP_POLICY_CAPTION"), g->SetGroup.Name);
+ if (g->SetGroup.Policy == NULL)
+ {
+ POLICY *p = ClonePolicy(GetDefaultPolicy());
+ if (SmPolicyDlgEx2(hWnd, p, tmp, false, g->p->PolicyVer))
+ {
+ g->SetGroup.Policy = p;
+ SmEditGroupDlgUpdate(hWnd, g);
+ }
+ else
+ {
+ Free(p);
+ }
+ }
+ else
+ {
+ SmPolicyDlgEx2(hWnd, g->SetGroup.Policy, tmp, false, g->p->PolicyVer);
+ }
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_STATUS:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ SmEditGroupDlgUpdate(hWnd, g);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Group editing dialog
+bool SmEditGroupDlg(HWND hWnd, SM_GROUP *s, char *name)
+{
+ SM_EDIT_GROUP g;
+ RPC_SET_GROUP *group;
+ bool ret;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ Zero(&g, sizeof(g));
+ g.EditMode = true;
+ g.Hub = s->Hub;
+ g.p = s->p;
+ g.Rpc = s->Rpc;
+
+ group = &g.SetGroup;
+
+ StrCpy(group->Name, sizeof(group->Name), name);
+ StrCpy(group->HubName, sizeof(group->HubName), s->Hub->HubName);
+
+ if (CALL(hWnd, ScGetGroup(s->Rpc, group)) == false)
+ {
+ return false;
+ }
+
+ ret = Dialog(hWnd, D_SM_EDIT_GROUP, SmEditGroupDlgProc, &g);
+
+ FreeRpcSetGroup(group);
+
+ return ret;
+}
+
+// Group creation dialog
+bool SmCreateGroupDlg(HWND hWnd, SM_GROUP *s)
+{
+ SM_EDIT_GROUP g;
+ RPC_SET_GROUP *group;
+ bool ret;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ Zero(&g, sizeof(g));
+ g.EditMode = false;
+ g.Hub = s->Hub;
+ g.p = s->p;
+ g.Rpc = s->Rpc;
+
+ group = &g.SetGroup;
+
+ StrCpy(group->HubName, sizeof(group->HubName), s->Hub->HubName);
+
+ ret = Dialog(hWnd, D_SM_EDIT_GROUP, SmEditGroupDlgProc, &g);
+
+ FreeRpcSetGroup(group);
+
+ return ret;
+}
+
+// Initialize
+void SmGroupListDlgInit(HWND hWnd, SM_GROUP *s)
+{
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_GROUP);
+
+ // Initialize the column
+ LvInit(hWnd, L_GROUP);
+ LvInsertColumn(hWnd, L_GROUP, 0, _UU("SM_GROUPLIST_NAME"), 130);
+ LvInsertColumn(hWnd, L_GROUP, 1, _UU("SM_GROUPLIST_REALNAME"), 130);
+ LvInsertColumn(hWnd, L_GROUP, 2, _UU("SM_GROUPLIST_NOTE"), 170);
+ LvInsertColumn(hWnd, L_GROUP, 3, _UU("SM_GROUPLIST_NUMUSERS"), 80);
+ LvSetStyle(hWnd, L_GROUP, LVS_EX_GRIDLINES);
+
+ FormatText(hWnd, S_TITLE, s->Hub->HubName);
+
+ SmGroupListDlgRefresh(hWnd, s);
+
+ if (s->SelectMode)
+ {
+ SetStyle(hWnd, L_GROUP, LVS_SINGLESEL);
+ }
+
+ if (s->SelectMode)
+ {
+ wchar_t tmp[MAX_SIZE];
+ SetText(hWnd, IDOK, _UU("SM_SELECT_GROUP"));
+
+ if (s->SelectedGroupName != NULL)
+ {
+ UINT i;
+ StrToUni(tmp, sizeof(tmp), s->SelectedGroupName);
+ i = LvSearchStr(hWnd, L_GROUP, 0, tmp);
+ if (i != INFINITE)
+ {
+ LvSelect(hWnd, L_GROUP, i);
+ }
+ }
+ }
+}
+
+// Update the controls
+void SmGroupListDlgUpdate(HWND hWnd, SM_GROUP *s)
+{
+ bool ok = true;
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (LvIsSelected(hWnd, L_GROUP) == false || LvIsMultiMasked(hWnd, L_GROUP))
+ {
+ ok = false;
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+ SetEnable(hWnd, B_USER, ok);
+ SetEnable(hWnd, B_STATUS, ok);
+
+ if (s->SelectMode == false)
+ {
+ SetEnable(hWnd, B_DELETE, ok);
+ }
+ else
+ {
+ SetEnable(hWnd, B_DELETE, false);
+ SetEnable(hWnd, B_USER, false);
+ SetText(hWnd, IDCANCEL, _UU("SM_SELECT_NO_GROUP"));
+ }
+}
+
+// Content update
+void SmGroupListDlgRefresh(HWND hWnd, SM_GROUP *s)
+{
+ RPC_ENUM_GROUP t;
+ UINT i;
+ LVB *b;
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->Hub->HubName);
+
+ if (CALL(hWnd, ScEnumGroup(s->Rpc, &t)) == false)
+ {
+ return;
+ }
+
+ b = LvInsertStart();
+
+ for (i = 0;i < t.NumGroup;i++)
+ {
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ RPC_ENUM_GROUP_ITEM *e = &t.Groups[i];
+
+ StrToUni(tmp1, sizeof(tmp1), e->Name);
+ UniToStru(tmp2, e->NumUsers);
+
+ LvInsertAdd(b, e->DenyAccess == false ? ICO_GROUP : ICO_GROUP_DENY,
+ NULL, 4, tmp1, e->Realname, e->Note, tmp2);
+ }
+
+ LvInsertEnd(b, hWnd, L_GROUP);
+
+ SmGroupListDlgUpdate(hWnd, s);
+
+ FreeRpcEnumGroup(&t);
+}
+
+// Group List dialog procedure
+UINT SmGroupListDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_GROUP *s = (SM_GROUP *)param;
+ NMHDR *n;
+ wchar_t *tmp;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmGroupListDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_CREATE:
+ // Create new
+ if (SmCreateGroupDlg(hWnd, s))
+ {
+ SmGroupListDlgRefresh(hWnd, s);
+ }
+ break;
+
+ case IDOK:
+ // Edit
+ tmp = LvGetSelectedStr(hWnd, L_GROUP, 0);
+ if (tmp != NULL)
+ {
+ char name[MAX_SIZE];
+ UniToStr(name, sizeof(name), tmp);
+
+ if (s->SelectMode == false)
+ {
+ if (SmEditGroupDlg(hWnd, s, name))
+ {
+ SmGroupListDlgRefresh(hWnd, s);
+ }
+ }
+ else
+ {
+ s->SelectedGroupName = CopyStr(name);
+ EndDialog(hWnd, true);
+ }
+ Free(tmp);
+ }
+ break;
+
+ case B_DELETE:
+ // Delete
+ tmp = LvGetSelectedStr(hWnd, L_GROUP, 0);
+ if (tmp != NULL)
+ {
+ char name[MAX_SIZE];
+ RPC_DELETE_USER t;
+ UniToStr(name, sizeof(name), tmp);
+
+ if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
+ _UU("SM_GROUP_DELETE_MSG"), name) == IDYES)
+ {
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->Hub->HubName);
+ StrCpy(t.Name, sizeof(t.Name), name);
+
+ if (CALL(hWnd, ScDeleteGroup(s->Rpc, &t)))
+ {
+ SmGroupListDlgRefresh(hWnd, s);
+ }
+ }
+
+ Free(tmp);
+ }
+ break;
+
+ case B_USER:
+ // Member List
+ tmp = LvGetSelectedStr(hWnd, L_GROUP, 0);
+ if (tmp != NULL)
+ {
+ char name[MAX_SIZE];
+ UniToStr(name, sizeof(name), tmp);
+ SmUserListDlgEx(hWnd, s->Hub, name, false);
+ Free(tmp);
+ }
+ break;
+
+ case B_REFRESH:
+ // Update to the latest information
+ SmGroupListDlgRefresh(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_GROUP:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ SmGroupListDlgUpdate(hWnd, s);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_GROUP);
+
+ return 0;
+}
+
+// Group List dialog (selection mode)
+char *SmSelectGroupDlg(HWND hWnd, SM_HUB *s, char *default_name)
+{
+ SM_GROUP g;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&g, sizeof(g));
+ g.Hub = s;
+ g.p = s->p;
+ g.Rpc = s->Rpc;
+ g.SelectMode = true;
+ g.SelectedGroupName = default_name;
+
+ if (Dialog(hWnd, D_SM_GROUP, SmGroupListDlgProc, &g) == false)
+ {
+ return NULL;
+ }
+
+ return g.SelectedGroupName;
+}
+
+// Group List dialog
+void SmGroupListDlg(HWND hWnd, SM_HUB *s)
+{
+ SM_GROUP g;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&g, sizeof(g));
+ g.Hub = s;
+ g.p = s->p;
+ g.Rpc = s->Rpc;
+ g.SelectMode = false;
+
+ Dialog(hWnd, D_SM_GROUP, SmGroupListDlgProc, &g);
+}
+
+// Update the user information
+bool SmRefreshUserInfo(HWND hWnd, SM_SERVER *s, void *param)
+{
+ RPC_SET_USER t;
+ SM_USER_INFO *p = (SM_USER_INFO *)param;
+ LVB *b;
+ wchar_t tmp[MAX_SIZE];
+ char *username;
+
+ // Validate arguments
+ if (hWnd == NULL || s == NULL || param == NULL)
+ {
+ return false;
+ }
+
+ username = p->Username;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), p->Hub->HubName);
+ StrCpy(t.Name, sizeof(t.Name), username);
+
+ if (CALL(hWnd, ScGetUser(s->Rpc, &t)) == false)
+ {
+ return false;
+ }
+
+ b = LvInsertStart();
+
+ StrToUni(tmp, sizeof(tmp), t.Name);
+ LvInsertAdd(b, ICO_USER, NULL, 2, _UU("SM_USERINFO_NAME"), tmp);
+
+ if (StrLen(t.GroupName) != 0)
+ {
+ StrToUni(tmp, sizeof(tmp), t.GroupName);
+ LvInsertAdd(b, ICO_GROUP, NULL, 2, _UU("SM_USERINFO_GROUP"), tmp);
+ }
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.CreatedTime), NULL);
+ LvInsertAdd(b, ICO_USER_ADMIN, NULL, 2, _UU("SM_USERINFO_CREATE"), tmp);
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.UpdatedTime), NULL);
+ LvInsertAdd(b, ICO_USER_ADMIN, NULL, 2, _UU("SM_USERINFO_UPDATE"), tmp);
+
+ if (t.ExpireTime != 0)
+ {
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.ExpireTime), NULL);
+ LvInsertAdd(b, ICO_WARNING, NULL, 2, _UU("SM_USERINFO_EXPIRE"), tmp);
+ }
+
+ SmInsertTrafficInfo(b, &t.Traffic);
+
+ UniToStru(tmp, t.NumLogin);
+ LvInsertAdd(b, ICO_LINK, NULL, 2, _UU("SM_USERINFO_NUMLOGIN"), tmp);
+
+ LvInsertEnd(b, hWnd, L_STATUS);
+
+ FreeRpcSetUser(&t);
+
+ return true;
+}
+
+// Initialize
+void SmPolicyDlgInit(HWND hWnd, SM_POLICY *s)
+{
+ CM_POLICY cp;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_MACHINE);
+ SetText(hWnd, 0, s->Caption);
+ SetText(hWnd, S_TITLE, s->Caption);
+ DlgFont(hWnd, S_BOLD, 10, true);
+ DlgFont(hWnd, S_BOLD2, 10, true);
+
+ DlgFont(hWnd, S_POLICY_TITLE, 11, false);
+ DlgFont(hWnd, E_POLICY_DESCRIPTION, 10, false);
+
+ Zero(&cp, sizeof(cp));
+ cp.Policy = s->Policy;
+ cp.Extension = true;
+
+ LvInit(hWnd, L_POLICY);
+ LvInsertColumn(hWnd, L_POLICY, 0, _UU("POL_TITLE_STR"), 250);
+ LvInsertColumn(hWnd, L_POLICY, 1, _UU("POL_VALUE_STR"), 150);
+ LvSetStyle(hWnd, L_POLICY, LVS_EX_GRIDLINES);
+
+ CmPolicyDlgPrintEx2(hWnd, &cp, s->CascadeMode, s->Ver);
+
+ LvSelect(hWnd, L_POLICY, 0);
+
+ s->Inited = true;
+ SmPolicyDlgUpdate(hWnd, s);
+}
+
+// Update
+void SmPolicyDlgUpdate(HWND hWnd, SM_POLICY *s)
+{
+ bool ok = true;
+ bool value_changed = false;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (s->Inited == false)
+ {
+ return;
+ }
+
+ i = LvGetSelected(hWnd, L_POLICY);
+ if (i != INFINITE)
+ {
+ i = (UINT)LvGetParam(hWnd, L_POLICY, i);
+ }
+ if (i == INFINITE || i >= NUM_POLICY_ITEM)
+ {
+ SetText(hWnd, S_POLICY_TITLE, _UU("SM_POLICY_INIT_TITLE"));
+ SetText(hWnd, E_POLICY_DESCRIPTION, L"");
+ Disable(hWnd, S_POLICY_TITLE);
+ Disable(hWnd, S_BOLD);
+ Hide(hWnd, S_BOLD2);
+ Hide(hWnd, R_ENABLE);
+ Hide(hWnd, R_DISABLE);
+ Hide(hWnd, R_DEFINE);
+ Hide(hWnd, E_VALUE);
+ Hide(hWnd, S_TANI);
+ Hide(hWnd, S_LIMIT);
+ }
+ else
+ {
+ POLICY_ITEM *item = &policy_item[i];
+ bool changed = false;
+ wchar_t *tmp = GetText(hWnd, S_POLICY_TITLE);
+ if (UniStrCmp(tmp, GetPolicyTitle(i)) != 0)
+ {
+ changed = true;
+ }
+ Free(tmp);
+ SetText(hWnd, S_POLICY_TITLE, GetPolicyTitle(i));
+ SetText(hWnd, E_POLICY_DESCRIPTION, GetPolicyDescription(i));
+ Enable(hWnd, S_POLICY_TITLE);
+ Enable(hWnd, S_BOLD);
+ Show(hWnd, S_BOLD2);
+
+ if (item->TypeInt == false)
+ {
+ Show(hWnd, R_ENABLE);
+ Show(hWnd, R_DISABLE);
+ Hide(hWnd, R_DEFINE);
+ Hide(hWnd, E_VALUE);
+ Hide(hWnd, S_TANI);
+ Hide(hWnd, S_LIMIT);
+
+ if (changed)
+ {
+ if (POLICY_BOOL(s->Policy, i))
+ {
+ Check(hWnd, R_ENABLE, true);
+ Check(hWnd, R_DISABLE, false);
+ }
+ else
+ {
+ Check(hWnd, R_ENABLE, false);
+ Check(hWnd, R_DISABLE, true);
+ }
+ }
+
+ if ((!(POLICY_BOOL(s->Policy, i))) != (!(IsChecked(hWnd, R_ENABLE))))
+ {
+ POLICY_BOOL(s->Policy, i) = IsChecked(hWnd, R_ENABLE);
+ value_changed = true;
+ }
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ UINT value;
+ if (item->AllowZero)
+ {
+ if (changed)
+ {
+ Check(hWnd, R_DEFINE, POLICY_INT(s->Policy, i) != 0);
+ Enable(hWnd, R_DEFINE);
+ SetIntEx(hWnd, E_VALUE, POLICY_INT(s->Policy, i));
+ }
+
+ SetEnable(hWnd, E_VALUE, IsChecked(hWnd, R_DEFINE));
+ SetEnable(hWnd, S_TANI, IsChecked(hWnd, R_DEFINE));
+ SetEnable(hWnd, S_LIMIT, IsChecked(hWnd, R_DEFINE));
+ }
+ else
+ {
+ if (changed)
+ {
+ Check(hWnd, R_DEFINE, true);
+ Disable(hWnd, R_DEFINE);
+ SetInt(hWnd, E_VALUE, POLICY_INT(s->Policy, i));
+ }
+
+ SetEnable(hWnd, E_VALUE, IsChecked(hWnd, R_DEFINE));
+ SetEnable(hWnd, S_TANI, IsChecked(hWnd, R_DEFINE));
+ SetEnable(hWnd, S_LIMIT, IsChecked(hWnd, R_DEFINE));
+ }
+
+ UniReplaceStrEx(tmp, sizeof(tmp), _UU(policy_item[i].FormatStr),
+ L"%u ", L"", false);
+ UniReplaceStrEx(tmp, sizeof(tmp), tmp,
+ L"%u", L"", false);
+
+ SetText(hWnd, S_TANI, tmp);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_LIMIT_STR"), policy_item[i].MinValue, policy_item[i].MaxValue);
+ SetText(hWnd, S_LIMIT, tmp);
+
+ Hide(hWnd, R_ENABLE);
+ Hide(hWnd, R_DISABLE);
+ Show(hWnd, E_VALUE);
+ Show(hWnd, R_DEFINE);
+ Show(hWnd, S_TANI);
+ Show(hWnd, S_LIMIT);
+
+ value = GetInt(hWnd, E_VALUE);
+
+ if (item->AllowZero && (IsChecked(hWnd, R_DEFINE) == false))
+ {
+ value = 0;
+ }
+ else
+ {
+ if (value < policy_item[i].MinValue || value > policy_item[i].MaxValue)
+ {
+ ok = false;
+ }
+ }
+
+ if (ok)
+ {
+ if (POLICY_INT(s->Policy, i) != value)
+ {
+ POLICY_INT(s->Policy, i) = value;
+ value_changed = true;
+ }
+ }
+ }
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+ SetEnable(hWnd, L_POLICY, ok);
+
+ if (value_changed)
+ {
+ CM_POLICY cp;
+ Zero(&cp, sizeof(cp));
+ cp.Policy = s->Policy;
+ cp.Extension = true;
+
+ CmPolicyDlgPrintEx(hWnd, &cp, s->CascadeMode);
+ }
+}
+
+// Confirmation
+void SmPolicyDlgOk(HWND hWnd, SM_POLICY *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ EndDialog(hWnd, true);
+}
+
+// Policy dialog box procedure
+UINT SmPolicyDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_POLICY *s = (SM_POLICY *)param;
+ NMHDR *n;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmPolicyDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case R_DEFINE:
+ case R_ENABLE:
+ case R_DISABLE:
+ case E_VALUE:
+ SmPolicyDlgUpdate(hWnd, s);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ // [OK] button
+ SmPolicyDlgOk(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+
+ case R_DEFINE:
+ if (IsChecked(hWnd, R_DEFINE))
+ {
+ FocusEx(hWnd, E_VALUE);
+ }
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_POLICY:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ SmPolicyDlgUpdate(hWnd, s);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Show Policies dialog box
+bool SmPolicyDlg(HWND hWnd, POLICY *p, wchar_t *caption)
+{
+ return SmPolicyDlgEx(hWnd, p, caption, false);
+}
+bool SmPolicyDlgEx(HWND hWnd, POLICY *p, wchar_t *caption, bool cascade_mode)
+{
+ return SmPolicyDlgEx2(hWnd, p, caption, cascade_mode, POLICY_CURRENT_VERSION);
+}
+bool SmPolicyDlgEx2(HWND hWnd, POLICY *p, wchar_t *caption, bool cascade_mode, UINT ver)
+{
+ SM_POLICY s;
+ bool ret;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return false;
+ }
+
+ if (caption == NULL)
+ {
+ caption = _UU("SM_POLICY_DEF_CAPTION");
+ }
+
+ Zero(&s, sizeof(s));
+ s.Caption = caption;
+ s.Policy = ClonePolicy(p);
+ s.CascadeMode = cascade_mode;
+ s.Ver = ver;
+
+ ret = Dialog(hWnd, D_SM_POLICY, SmPolicyDlgProc, &s);
+
+ if (ret)
+ {
+ Copy(p, s.Policy, sizeof(POLICY));
+ }
+
+ Free(s.Policy);
+
+ return ret;
+}
+
+// Edit user confirmed
+void SmEditUserDlgOk(HWND hWnd, SM_EDIT_USER *s)
+{
+ RPC_SET_USER t;
+ RPC_SET_USER *u;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SmEditUserDlgUpdate(hWnd, s);
+
+ Zero(&t, sizeof(t));
+ u = &s->SetUser;
+
+ StrCpy(t.HubName, sizeof(t.HubName), u->HubName);
+ StrCpy(t.Name, sizeof(t.Name), u->Name);
+ StrCpy(t.GroupName, sizeof(t.GroupName), u->GroupName);
+ UniStrCpy(t.Realname, sizeof(t.Realname), u->Realname);
+ UniStrCpy(t.Note, sizeof(t.Note), u->Note);
+ t.ExpireTime = u->ExpireTime;
+ t.AuthType = u->AuthType;
+ t.AuthData = CopyAuthData(u->AuthData, t.AuthType);
+
+ if (IsChecked(hWnd, R_POLICY))
+ {
+ t.Policy = ClonePolicy(u->Policy);
+ }
+ else
+ {
+ t.Policy = NULL;
+ }
+
+ if (s->EditMode == false)
+ {
+ if (CALL(hWnd, ScCreateUser(s->Rpc, &t)) == false)
+ {
+ FocusEx(hWnd, E_USERNAME);
+ return;
+ }
+ FreeRpcSetUser(&t);
+
+ MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("SM_USER_CREEATE_OK"), u->Name);
+ }
+ else
+ {
+ if (CALL(hWnd, ScSetUser(s->Rpc, &t)) == false)
+ {
+ FocusEx(hWnd, E_REALNAME);
+ return;
+ }
+ FreeRpcSetUser(&t);
+ }
+
+ EndDialog(hWnd, true);
+}
+
+// Edit user initialization
+void SmEditUserDlgInit(HWND hWnd, SM_EDIT_USER *s)
+{
+ RPC_SET_USER *u;
+ wchar_t tmp[MAX_SIZE];
+ UINT i;
+ UINT icons[6] = {ICO_PASS, ICO_KEY, ICO_CERT, ICO_SERVER_CERT,
+ ICO_TOWER, ICO_LINK};
+ RECT rect;
+
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_USER);
+
+ u = &s->SetUser;
+
+ // Initialize the column
+ LvInit(hWnd, L_AUTH);
+ LvSetStyle(hWnd, L_AUTH, LVS_EX_GRIDLINES);
+
+ GetClientRect(DlgItem(hWnd, L_AUTH), &rect);
+ LvInsertColumn(hWnd, L_AUTH, 0, L"Name", rect.right - rect.left);
+
+ for (i = 0;i < 6;i++)
+ {
+ LvInsert(hWnd, L_AUTH, icons[i], (void *)i, 1, SmGetAuthTypeStr(i));
+ }
+
+ // User name, etc.
+ SetTextA(hWnd, E_USERNAME, u->Name);
+ SetText(hWnd, E_REALNAME, u->Realname);
+ SetText(hWnd, E_NOTE, u->Note);
+
+
+ // Expiration date
+ if (u->ExpireTime == 0)
+ {
+ SYSTEMTIME st;
+ Check(hWnd, R_EXPIRES, false);
+ GetLocalTime(&st);
+ UINT64ToSystem(&st, SystemToUINT64(&st) + (60 * 60 * 24 * 1000));
+ st.wHour = st.wMinute = st.wSecond = st.wMilliseconds = 0;
+ DateTime_SetSystemtime(DlgItem(hWnd, E_EXPIRES_DATE), GDT_VALID, &st);
+ DateTime_SetSystemtime(DlgItem(hWnd, E_EXPIRES_TIME), GDT_VALID, &st);
+ }
+ else
+ {
+ SYSTEMTIME st;
+ UINT64ToSystem(&st, SystemToLocal64(u->ExpireTime));
+ Check(hWnd, R_EXPIRES, true);
+ DateTime_SetSystemtime(DlgItem(hWnd, E_EXPIRES_DATE), GDT_VALID, &st);
+ DateTime_SetSystemtime(DlgItem(hWnd, E_EXPIRES_TIME), GDT_VALID, &st);
+ }
+
+ if (GetCurrentOsLangId() == SE_LANG_JAPANESE || GetCurrentOsLangId() == SE_LANG_CHINESE_ZH)
+ {
+ SetStyle(hWnd, E_EXPIRES_DATE, DTS_LONGDATEFORMAT);
+ }
+ else
+ {
+ SetStyle(hWnd, E_EXPIRES_DATE, DTS_SHORTDATEFORMAT);
+ }
+
+ SetWindowLong(DlgItem(hWnd, E_EXPIRES_TIME), GWL_STYLE, WS_CHILDWINDOW | WS_VISIBLE | WS_TABSTOP | DTS_RIGHTALIGN | DTS_TIMEFORMAT | DTS_UPDOWN);
+
+ // Group name
+ SetTextA(hWnd, E_GROUP, u->GroupName);
+
+ // Authentication method
+ LvSelect(hWnd, L_AUTH, u->AuthType);
+
+ SetText(hWnd, S_CERT_INFO, _UU("SM_EDIT_USER_CERT_INFO"));
+
+ switch (u->AuthType)
+ {
+ case AUTHTYPE_PASSWORD:
+ if (s->EditMode)
+ {
+ SetTextA(hWnd, E_PASSWORD1, HIDDEN_PASSWORD);
+ SetTextA(hWnd, E_PASSWORD2, HIDDEN_PASSWORD);
+ }
+ break;
+
+ case AUTHTYPE_USERCERT:
+ SmGetCertInfoStr(tmp, sizeof(tmp), ((AUTHUSERCERT *)u->AuthData)->UserX);
+ break;
+
+ case AUTHTYPE_ROOTCERT:
+ if (u->AuthData != NULL)
+ {
+ AUTHROOTCERT *c = (AUTHROOTCERT *)u->AuthData;
+ if (c->CommonName != NULL && UniStrLen(c->CommonName) != 0)
+ {
+ Check(hWnd, R_CN, true);
+ SetText(hWnd, E_CN, c->CommonName);
+ }
+ else
+ {
+ Check(hWnd, R_CN, false);
+ }
+ if (c->Serial != NULL && c->Serial->size != 0)
+ {
+ X_SERIAL *s = c->Serial;
+ char *tmp;
+ UINT tmp_size = s->size * 3 + 1;
+ tmp = ZeroMalloc(tmp_size);
+ BinToStrEx(tmp, tmp_size, s->data, s->size);
+ SetTextA(hWnd, E_SERIAL, tmp);
+ Free(tmp);
+ Check(hWnd, R_SERIAL, true);
+ }
+ else
+ {
+ Check(hWnd, R_SERIAL, false);
+ }
+ }
+ break;
+
+ case AUTHTYPE_RADIUS:
+ if (u->AuthData != NULL)
+ {
+ AUTHRADIUS *r = (AUTHRADIUS *)u->AuthData;
+ if (UniStrLen(r->RadiusUsername) != 0)
+ {
+ Check(hWnd, R_SET_RADIUS_USERNAME, true);
+ SetText(hWnd, E_RADIUS_USERNAME, r->RadiusUsername);
+ }
+ else
+ {
+ Check(hWnd, R_SET_RADIUS_USERNAME, false);
+ }
+ }
+ break;
+
+ case AUTHTYPE_NT:
+ if (u->AuthData != NULL)
+ {
+ AUTHNT *n = (AUTHNT *)u->AuthData;
+ if (UniStrLen(n->NtUsername) != 0)
+ {
+ Check(hWnd, R_SET_RADIUS_USERNAME, true);
+ SetText(hWnd, E_RADIUS_USERNAME, n->NtUsername);
+ }
+ else
+ {
+ Check(hWnd, R_SET_RADIUS_USERNAME, false);
+ }
+ }
+ break;
+ }
+
+ if (u->Policy != NULL)
+ {
+ Check(hWnd, R_POLICY, true);
+ }
+
+ s->Inited = true;
+
+ SmEditUserDlgUpdate(hWnd, s);
+
+ if (s->EditMode == false)
+ {
+ Focus(hWnd, E_USERNAME);
+ SetText(hWnd, 0, _UU("SM_EDIT_USER_CAPTION_1"));
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ UniFormat(tmp, sizeof(tmp), _UU("SM_EDIT_USER_CAPTION_2"), s->SetUser.Name);
+ SetText(hWnd, 0, tmp);
+
+ Disable(hWnd, E_USERNAME);
+ FocusEx(hWnd, E_REALNAME);
+ }
+
+ SetShow(hWnd, S_HINT, (s->EditMode ? false : true));
+}
+
+// User edit control update
+void SmEditUserDlgUpdate(HWND hWnd, SM_EDIT_USER *s)
+{
+ RPC_SET_USER *u;
+ bool ok = true;
+ UINT old_authtype;
+ char tmp1[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ bool authtype_changed = false;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (s->Inited == false)
+ {
+ return;
+ }
+
+ u = &s->SetUser;
+
+ // User name
+ GetTxtA(hWnd, E_USERNAME, u->Name, sizeof(u->Name));
+ Trim(u->Name);
+ if (StrLen(u->Name) == 0 || IsUserName(u->Name) == false)
+ {
+ ok = false;
+ }
+
+ // Real name
+ GetTxt(hWnd, E_REALNAME, u->Realname, sizeof(u->Realname));
+ UniTrim(u->Realname);
+
+ // Note
+ GetTxt(hWnd, E_NOTE, u->Note, sizeof(u->Note));
+ UniTrim(u->Realname);
+
+ // Group
+ GetTxtA(hWnd, E_GROUP, u->GroupName, sizeof(u->GroupName));
+ Trim(u->GroupName);
+
+ // Expiration date
+ if (IsChecked(hWnd, R_EXPIRES) == false)
+ {
+ u->ExpireTime = 0;
+ Disable(hWnd, E_EXPIRES_DATE);
+ Disable(hWnd, E_EXPIRES_TIME);
+ }
+ else
+ {
+ SYSTEMTIME st1, st2;
+ Enable(hWnd, E_EXPIRES_DATE);
+ Enable(hWnd, E_EXPIRES_TIME);
+ DateTime_GetSystemtime(DlgItem(hWnd, E_EXPIRES_DATE), &st1);
+ DateTime_GetSystemtime(DlgItem(hWnd, E_EXPIRES_TIME), &st2);
+ st1.wHour = st2.wHour;
+ st1.wMinute = st2.wMinute;
+ st1.wSecond = st2.wSecond;
+ st1.wMilliseconds = st2.wMilliseconds;
+ u->ExpireTime = LocalToSystem64(SystemToUINT64(&st1));
+ }
+
+ // Authentication method
+ old_authtype = u->AuthType;
+ u->AuthType = LvGetSelected(hWnd, L_AUTH);
+
+ if (StrCmpi(u->Name, "*") == 0)
+ {
+ if (u->AuthType != AUTHTYPE_RADIUS && u->AuthType != AUTHTYPE_NT)
+ {
+ ok = false;
+ }
+ }
+
+ if (u->AuthType == INFINITE)
+ {
+ ok = false;
+ u->AuthType = 0;
+ }
+ if (old_authtype != u->AuthType)
+ {
+ authtype_changed = true;
+ }
+
+ if (authtype_changed)
+ {
+ FreeAuthData(old_authtype, u->AuthData);
+ u->AuthData = NULL;
+ switch (u->AuthType)
+ {
+ case AUTHTYPE_ANONYMOUS:
+ u->AuthData = NULL;
+ break;
+
+ case AUTHTYPE_PASSWORD:
+ u->AuthData = NewPasswordAuthData("", "");
+ GetTxtA(hWnd, E_PASSWORD1, tmp1, sizeof(tmp1));
+ if (StrCmp(tmp1, HIDDEN_PASSWORD) == 0)
+ {
+ SetTextA(hWnd, E_PASSWORD1, "");
+ }
+ GetTxtA(hWnd, E_PASSWORD2, tmp2, sizeof(tmp2));
+ if (StrCmp(tmp2, HIDDEN_PASSWORD) == 0)
+ {
+ SetTextA(hWnd, E_PASSWORD2, "");
+ }
+ break;
+
+ case AUTHTYPE_USERCERT:
+ u->AuthData = NewUserCertAuthData(NULL);
+ SetText(hWnd, S_CERT_INFO, _UU("SM_EDIT_USER_CERT_INFO"));
+ break;
+
+ case AUTHTYPE_ROOTCERT:
+ u->AuthData = NewRootCertAuthData(NULL, NULL);
+ break;
+
+ case AUTHTYPE_NT:
+ u->AuthData = NewNTAuthData(L"");
+ break;
+
+ case AUTHTYPE_RADIUS:
+ u->AuthData = NewRadiusAuthData(L"");
+ break;
+ }
+ }
+
+ SetEnable(hWnd, S_RADIUS_3, (u->AuthType == AUTHTYPE_RADIUS) || (u->AuthType == AUTHTYPE_NT));
+ SetEnable(hWnd, R_SET_RADIUS_USERNAME, (u->AuthType == AUTHTYPE_RADIUS) || (u->AuthType == AUTHTYPE_NT));
+ SetEnable(hWnd, S_RADIUS_1, (u->AuthType == AUTHTYPE_RADIUS) || (u->AuthType == AUTHTYPE_NT));
+
+ if (StrCmp(u->Name, "*") == 0)
+ {
+ Check(hWnd, R_SET_RADIUS_USERNAME, false);
+ Disable(hWnd, R_SET_RADIUS_USERNAME);
+ }
+
+ if ((u->AuthType == AUTHTYPE_RADIUS) || (u->AuthType == AUTHTYPE_NT))
+ {
+ SetEnable(hWnd, E_RADIUS_USERNAME, IsChecked(hWnd, R_SET_RADIUS_USERNAME));
+ SetEnable(hWnd, S_RADIUS_2, IsChecked(hWnd, R_SET_RADIUS_USERNAME));
+ }
+ else
+ {
+ SetEnable(hWnd, E_RADIUS_USERNAME, false);
+ SetEnable(hWnd, S_RADIUS_2, false);
+ }
+
+ SetEnable(hWnd, S_PASSWORD_1, u->AuthType == AUTHTYPE_PASSWORD);
+ SetEnable(hWnd, S_PASSWORD_2, u->AuthType == AUTHTYPE_PASSWORD);
+ SetEnable(hWnd, S_PASSWORD_3, u->AuthType == AUTHTYPE_PASSWORD);
+ SetEnable(hWnd, E_PASSWORD1, u->AuthType == AUTHTYPE_PASSWORD);
+ SetEnable(hWnd, E_PASSWORD2, u->AuthType == AUTHTYPE_PASSWORD);
+
+ SetEnable(hWnd, S_USER_CERT_1, u->AuthType == AUTHTYPE_USERCERT);
+ SetEnable(hWnd, S_CERT_INFO, u->AuthType == AUTHTYPE_USERCERT);
+ SetEnable(hWnd, B_LOAD_CERT, u->AuthType == AUTHTYPE_USERCERT);
+
+ if (u->AuthType == AUTHTYPE_USERCERT)
+ {
+ SetEnable(hWnd, B_VIEW_CERT, ((AUTHUSERCERT *)u->AuthData)->UserX != NULL);
+ }
+ else
+ {
+ SetEnable(hWnd, B_VIEW_CERT, false);
+ }
+
+ SetEnable(hWnd, S_ROOT_CERT_1, u->AuthType == AUTHTYPE_ROOTCERT);
+ SetEnable(hWnd, S_ROOT_CERT_2, u->AuthType == AUTHTYPE_ROOTCERT);
+ SetEnable(hWnd, S_ROOT_CERT_3, u->AuthType == AUTHTYPE_ROOTCERT);
+ SetEnable(hWnd, R_CN, u->AuthType == AUTHTYPE_ROOTCERT);
+ SetEnable(hWnd, R_SERIAL, u->AuthType == AUTHTYPE_ROOTCERT);
+
+ if (u->AuthType == AUTHTYPE_ROOTCERT)
+ {
+ SetEnable(hWnd, E_CN, IsChecked(hWnd, R_CN));
+ SetEnable(hWnd, E_SERIAL, IsChecked(hWnd, R_SERIAL));
+ }
+ else
+ {
+ Disable(hWnd, E_CN);
+ Disable(hWnd, E_SERIAL);
+ }
+
+ switch (u->AuthType)
+ {
+ case AUTHTYPE_PASSWORD:
+ GetTxtA(hWnd, E_PASSWORD1, tmp1, sizeof(tmp1));
+ GetTxtA(hWnd, E_PASSWORD2, tmp2, sizeof(tmp2));
+ if (StrCmp(tmp1, tmp2) != 0)
+ {
+ ok = false;
+ }
+ else
+ {
+ if (StrCmp(tmp1, HIDDEN_PASSWORD) != 0)
+ {
+ HashPassword(((AUTHPASSWORD *)u->AuthData)->HashedKey, u->Name, tmp1);
+ GenerateNtPasswordHash(((AUTHPASSWORD *)u->AuthData)->NtLmSecureHash, tmp1);
+ }
+ }
+ break;
+
+ case AUTHTYPE_USERCERT:
+ if (((AUTHUSERCERT *)u->AuthData)->UserX == NULL)
+ {
+ ok = false;
+ }
+ break;
+
+ case AUTHTYPE_ROOTCERT:
+ Free(((AUTHROOTCERT *)u->AuthData)->CommonName);
+ ((AUTHROOTCERT *)u->AuthData)->CommonName = NULL;
+ if (IsChecked(hWnd, R_CN) && (IsEmpty(hWnd, E_CN) == false))
+ {
+ ((AUTHROOTCERT *)u->AuthData)->CommonName = GetText(hWnd, E_CN);
+ UniTrim(((AUTHROOTCERT *)u->AuthData)->CommonName);
+ }
+ if (IsChecked(hWnd, R_CN) && ((AUTHROOTCERT *)u->AuthData)->CommonName == NULL)
+ {
+ ok = false;
+ }
+ FreeXSerial(((AUTHROOTCERT *)u->AuthData)->Serial);
+ ((AUTHROOTCERT *)u->AuthData)->Serial = NULL;
+ if (IsChecked(hWnd, R_SERIAL))
+ {
+ char *serial_str = GetTextA(hWnd, E_SERIAL);
+ if (serial_str != NULL)
+ {
+ BUF *b = StrToBin(serial_str);
+ if (b->Size >= 1)
+ {
+ ((AUTHROOTCERT *)u->AuthData)->Serial = NewXSerial(b->Buf, b->Size);
+ }
+ FreeBuf(b);
+ Free(serial_str);
+ }
+ }
+ if (IsChecked(hWnd, R_SERIAL) && ((AUTHROOTCERT *)u->AuthData)->Serial == NULL)
+ {
+ ok = false;
+ }
+ break;
+
+ case AUTHTYPE_RADIUS:
+ Free(((AUTHRADIUS *)u->AuthData)->RadiusUsername);
+ ((AUTHRADIUS *)u->AuthData)->RadiusUsername = NULL;
+ if (IsChecked(hWnd, R_SET_RADIUS_USERNAME) && (IsEmpty(hWnd, E_RADIUS_USERNAME) == false))
+ {
+ ((AUTHRADIUS *)u->AuthData)->RadiusUsername = GetText(hWnd, E_RADIUS_USERNAME);
+ }
+ if (IsChecked(hWnd, R_SET_RADIUS_USERNAME) && ((AUTHRADIUS *)u->AuthData)->RadiusUsername == NULL)
+ {
+ ok = false;
+ }
+ break;
+
+ case AUTHTYPE_NT:
+ Free(((AUTHNT *)u->AuthData)->NtUsername);
+ ((AUTHNT *)u->AuthData)->NtUsername = NULL;
+ if (IsChecked(hWnd, R_SET_RADIUS_USERNAME) && (IsEmpty(hWnd, E_RADIUS_USERNAME) == false))
+ {
+ ((AUTHNT *)u->AuthData)->NtUsername = GetText(hWnd, E_RADIUS_USERNAME);
+ }
+ if (IsChecked(hWnd, R_SET_RADIUS_USERNAME) && ((AUTHNT *)u->AuthData)->NtUsername == NULL)
+ {
+ ok = false;
+ }
+ break;
+ }
+
+ SetEnable(hWnd, B_POLICY, IsChecked(hWnd, R_POLICY));
+ if (IsChecked(hWnd, R_POLICY))
+ {
+ if (u->Policy == NULL)
+ {
+ ok = false;
+ }
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Edit User dialog procedure
+UINT SmEditUserDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_EDIT_USER *s = (SM_EDIT_USER *)param;
+ NMHDR *n;
+ POLICY *policy;
+ X *x = NULL;
+ wchar_t tmp[MAX_SIZE];
+ char name[MAX_SIZE];
+ char *ret;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmEditUserDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_USERNAME:
+ case E_REALNAME:
+ case E_NOTE:
+ case R_EXPIRES:
+ case E_EXPIRES_DATE:
+ case E_EXPIRES_TIME:
+ case E_GROUP:
+ case L_AUTH:
+ case R_SET_RADIUS_USERNAME:
+ case E_RADIUS_USERNAME:
+ case R_POLICY:
+ case E_PASSWORD1:
+ case E_PASSWORD2:
+ case R_CN:
+ case E_CN:
+ case R_SERIAL:
+ case E_SERIAL:
+ SmEditUserDlgUpdate(hWnd, s);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ // [OK] button
+ SmEditUserDlgOk(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+
+ case B_POLICY:
+ UniFormat(tmp, sizeof(tmp), _UU("SM_EDIT_USER_POL_DLG"), s->SetUser.Name);
+ // Policy
+ if (s->SetUser.Policy == NULL)
+ {
+ policy = ClonePolicy(GetDefaultPolicy());
+ if (SmPolicyDlgEx2(hWnd, policy, tmp, false, s->p->PolicyVer))
+ {
+ s->SetUser.Policy = policy;
+ SmEditUserDlgUpdate(hWnd, s);
+ }
+ else
+ {
+ Free(policy);
+ }
+ }
+ else
+ {
+ SmPolicyDlgEx2(hWnd, s->SetUser.Policy, tmp, false, s->p->PolicyVer);
+ }
+ break;
+
+ case B_GROUP:
+ // Browse for a Group
+ GetTxtA(hWnd, E_GROUP, name, sizeof(name));
+ Trim(name);
+ ret = SmSelectGroupDlg(hWnd, s->Hub, StrLen(name) == 0 ? NULL : name);
+ if (ret != NULL)
+ {
+ SetTextA(hWnd, E_GROUP, ret);
+ Free(ret);
+ }
+ else
+ {
+ SetTextA(hWnd, E_GROUP, "");
+ }
+ FocusEx(hWnd, E_GROUP);
+ break;
+
+ case B_LOAD_CERT:
+ // Specify the certificate
+ if (CmLoadXFromFileOrSecureCard(hWnd, &x))
+ {
+UPDATE_CERT:
+ if (s->SetUser.AuthType == AUTHTYPE_USERCERT)
+ {
+ wchar_t tmp[MAX_SIZE];
+ FreeX(((AUTHUSERCERT *)s->SetUser.AuthData)->UserX);
+ ((AUTHUSERCERT *)s->SetUser.AuthData)->UserX = x;
+ SmGetCertInfoStr(tmp, sizeof(tmp), x);
+ SetText(hWnd, S_CERT_INFO, tmp);
+ SmEditUserDlgUpdate(hWnd, s);
+ }
+ else
+ {
+ if (x != NULL)
+ {
+ FreeX(x);
+ x = NULL;
+ }
+ }
+ }
+ break;
+
+ case B_VIEW_CERT:
+ // Show the certificate
+ if (s->SetUser.AuthType == AUTHTYPE_USERCERT)
+ {
+ CertDlg(hWnd, ((AUTHUSERCERT *)s->SetUser.AuthData)->UserX, NULL, true);
+ }
+ break;
+
+ case B_CREATE:
+ // Create
+ GetTxtA(hWnd, E_USERNAME, name, sizeof(name));
+ Trim(name);
+ if (SmCreateCert(hWnd, &x, NULL, false, name, false))
+ {
+ if (s->SetUser.AuthType != AUTHTYPE_USERCERT)
+ {
+ LvSelect(hWnd, L_AUTH, 2);
+ }
+ goto UPDATE_CERT;
+ }
+ break;
+
+ case R_SET_RADIUS_USERNAME:
+ if (IsChecked(hWnd, R_SET_RADIUS_USERNAME))
+ {
+ FocusEx(hWnd, E_RADIUS_USERNAME);
+ }
+ break;
+
+ case R_EXPIRES:
+ if (IsChecked(hWnd, R_EXPIRES))
+ {
+ Focus(hWnd, E_EXPIRES_DATE);
+ }
+ break;
+
+ case R_POLICY:
+ if (IsChecked(hWnd, R_POLICY))
+ {
+ Focus(hWnd, B_POLICY);
+ }
+ break;
+
+ case R_CN:
+ if (IsChecked(hWnd, R_CN))
+ {
+ Focus(hWnd, E_CN);
+ }
+ break;
+
+ case R_SERIAL:
+ if (IsChecked(hWnd, R_SERIAL))
+ {
+ Focus(hWnd, E_SERIAL);
+ }
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_AUTH:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ SmEditUserDlgUpdate(hWnd, s);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// User editing dialog
+bool SmEditUserDlg(HWND hWnd, SM_HUB *s, char *username)
+{
+ SM_EDIT_USER e;
+ bool ret;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL || username == NULL)
+ {
+ return false;
+ }
+
+ Zero(&e, sizeof(e));
+ e.p = s->p;
+ e.Rpc = s->Rpc;
+ e.Hub = s;
+
+ // Get the User
+ StrCpy(e.SetUser.HubName, sizeof(e.SetUser.HubName), e.Hub->HubName);
+ StrCpy(e.SetUser.Name, sizeof(e.SetUser.Name), username);
+
+ if (CALL(hWnd, ScGetUser(s->Rpc, &e.SetUser)) == false)
+ {
+ return false;
+ }
+
+ e.EditMode = true;
+
+ ret = Dialog(hWnd, D_SM_EDIT_USER, SmEditUserDlgProc, &e);
+
+ FreeRpcSetUser(&e.SetUser);
+
+ return ret;
+}
+
+// New user creation dialog
+bool SmCreateUserDlg(HWND hWnd, SM_HUB *s)
+{
+ SM_EDIT_USER e;
+ bool ret;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return false;
+ }
+
+ Zero(&e, sizeof(e));
+ e.EditMode = false;
+ e.p = s->p;
+ e.Rpc = s->Rpc;
+ e.Hub = s;
+
+ // Set up a new user
+ StrCpy(e.SetUser.HubName, sizeof(e.SetUser.HubName), e.Hub->HubName);
+ e.SetUser.AuthType = CLIENT_AUTHTYPE_PASSWORD;
+ e.SetUser.AuthData = NewPasswordAuthData("", "");
+
+ ret = Dialog(hWnd, D_SM_EDIT_USER, SmEditUserDlgProc, &e);
+
+ FreeRpcSetUser(&e.SetUser);
+
+ return ret;
+}
+
+// Get a string of user authentication method
+wchar_t *SmGetAuthTypeStr(UINT id)
+{
+ return GetAuthTypeStr(id);
+}
+
+// User list initialization
+void SmUserListInit(HWND hWnd, SM_USER *s)
+{
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_USER);
+
+ // Initialize the column
+ LvInit(hWnd, L_USER);
+ LvSetStyle(hWnd, L_USER, LVS_EX_GRIDLINES);
+ LvInsertColumn(hWnd, L_USER, 0, _UU("SM_USER_COLUMN_1"), 120);
+ LvInsertColumn(hWnd, L_USER, 1, _UU("SM_USER_COLUMN_2"), 100);
+ LvInsertColumn(hWnd, L_USER, 2, _UU("SM_USER_COLUMN_3"), 100);
+ LvInsertColumn(hWnd, L_USER, 3, _UU("SM_USER_COLUMN_4"), 130);
+ LvInsertColumn(hWnd, L_USER, 4, _UU("SM_USER_COLUMN_5"), 100);
+ LvInsertColumn(hWnd, L_USER, 5, _UU("SM_USER_COLUMN_6"), 90);
+ LvInsertColumn(hWnd, L_USER, 6, _UU("SM_USER_COLUMN_7"), 120);
+ LvInsertColumn(hWnd, L_USER, 7, _UU("SM_LICENSE_COLUMN_5"), 120);
+ LvInsertColumn(hWnd, L_USER, 8, _UU("SM_SESS_COLUMN_6"), 100);
+ LvInsertColumn(hWnd, L_USER, 9, _UU("SM_SESS_COLUMN_7"), 100);
+
+ FormatText(hWnd, S_TITLE, s->Hub->HubName);
+
+ if (s->GroupName != NULL)
+ {
+ GetTxt(hWnd, 0, tmp1, sizeof(tmp1));
+ UniFormat(tmp2, sizeof(tmp2), _UU("SM_GROUP_MEMBER_STR"), s->GroupName);
+ UniStrCat(tmp1, sizeof(tmp1), tmp2);
+ SetText(hWnd, S_TITLE, tmp1);
+ Disable(hWnd, B_CREATE);
+ }
+
+ if (s->SelectMode)
+ {
+ SetStyle(hWnd, L_USER, LVS_SINGLESEL);
+ }
+
+ SmUserListRefresh(hWnd, s);
+
+ if (s->SelectMode)
+ {
+ wchar_t tmp[MAX_SIZE];
+ UINT i;
+ StrToUni(tmp, sizeof(tmp), s->SelectedName);
+ i = LvSearchStr(hWnd, L_USER, 0, tmp);
+ if (i != INFINITE)
+ {
+ LvSelect(hWnd, L_USER, i);
+ }
+
+ if (s->AllowGroup)
+ {
+ SetText(hWnd, B_DELETE, _UU("SM_SELECT_ALT_GROUP"));
+ }
+ }
+}
+
+// User list update
+void SmUserListRefresh(HWND hWnd, SM_USER *s)
+{
+ LVB *b;
+ RPC_ENUM_USER t;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+
+ StrCpy(t.HubName, sizeof(t.HubName), s->Hub->HubName);
+ if (CALL(hWnd, ScEnumUser(s->Rpc, &t)) == false)
+ {
+ EndDialog(hWnd, false);
+ return;
+ }
+
+ b = LvInsertStart();
+
+ for (i = 0;i < t.NumUser;i++)
+ {
+ RPC_ENUM_USER_ITEM *e = &t.Users[i];
+ wchar_t name[MAX_SIZE];
+ wchar_t group[MAX_SIZE];
+ wchar_t num[MAX_SIZE];
+ wchar_t time[MAX_SIZE];
+ wchar_t exp[MAX_SIZE];
+ wchar_t num1[64], num2[64];
+
+ if (s->GroupName != NULL)
+ {
+ if (StrCmpi(s->GroupName, e->GroupName) != 0)
+ {
+ continue;
+ }
+ }
+
+ StrToUni(name, sizeof(name), e->Name);
+
+ if (StrLen(e->GroupName) != 0)
+ {
+ StrToUni(group, sizeof(group), e->GroupName);
+ }
+ else
+ {
+ UniStrCpy(group, sizeof(group), _UU("SM_NO_GROUP"));
+ }
+
+ UniToStru(num, e->NumLogin);
+
+ GetDateTimeStrEx64(time, sizeof(time), SystemToLocal64(e->LastLoginTime), NULL);
+
+ if (e->IsExpiresFilled == false)
+ {
+ UniStrCpy(exp, sizeof(exp), _UU("CM_ST_NONE"));
+ }
+ else
+ {
+ if (e->Expires == 0)
+ {
+ UniStrCpy(exp, sizeof(exp), _UU("SM_LICENSE_NO_EXPIRES"));
+ }
+ else
+ {
+ GetDateTimeStrEx64(exp, sizeof(exp), SystemToLocal64(e->Expires), NULL);
+ }
+ }
+
+ if (e->IsTrafficFilled == false)
+ {
+ UniStrCpy(num1, sizeof(num1), _UU("CM_ST_NONE"));
+ UniStrCpy(num2, sizeof(num2), _UU("CM_ST_NONE"));
+ }
+ else
+ {
+ UniToStr3(num1, sizeof(num1),
+ e->Traffic.Recv.BroadcastBytes + e->Traffic.Recv.UnicastBytes +
+ e->Traffic.Send.BroadcastBytes + e->Traffic.Send.UnicastBytes);
+
+ UniToStr3(num2, sizeof(num2),
+ e->Traffic.Recv.BroadcastCount + e->Traffic.Recv.UnicastCount +
+ e->Traffic.Send.BroadcastBytes + e->Traffic.Send.UnicastCount);
+ }
+
+ LvInsertAdd(b, e->DenyAccess ? ICO_USER_DENY : ICO_USER, NULL, 10,
+ name, e->Realname, group, e->Note, SmGetAuthTypeStr(e->AuthType),
+ num, time, exp, num1, num2);
+ }
+
+ LvInsertEnd(b, hWnd, L_USER);
+
+ FreeRpcEnumUser(&t);
+
+ SmUserListUpdate(hWnd, s);
+}
+
+// User list control update
+void SmUserListUpdate(HWND hWnd, SM_USER *s)
+{
+ bool b = true;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (LvIsSelected(hWnd, L_USER) == false || LvIsMultiMasked(hWnd, L_USER))
+ {
+ b = false;
+ }
+
+ if (s->SelectMode)
+ {
+ SetText(hWnd, IDOK, _UU("SM_SELECT_USER"));
+ SetText(hWnd, IDCANCEL, _UU("SM_SELECT_NO"));
+ SetText(hWnd, S_TITLE, _UU("SM_PLEASE_SELECT"));
+ }
+
+ SetEnable(hWnd, IDOK, b);
+
+ SetEnable(hWnd, B_STATUS, b);
+ SetEnable(hWnd, B_DELETE, (b && s->SelectedName == false) || s->AllowGroup);
+ SetEnable(hWnd, B_CREATE, s->SelectedName == false);
+}
+
+// User List dialog procedure
+UINT SmUserListProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_USER *s = (SM_USER *)param;
+ NMHDR *n;
+ wchar_t *str;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmUserListInit(hWnd, s);
+
+ if (s->CreateNow)
+ {
+ // Create instantly
+ if (IsEnable(hWnd, B_CREATE))
+ {
+ Command(hWnd, B_CREATE);
+ }
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ if (s->SelectMode == false)
+ {
+ // Property
+ str = LvGetSelectedStr(hWnd, L_USER, 0);
+ if (str != NULL)
+ {
+ char name[MAX_SIZE];
+ UniToStr(name, sizeof(name), str);
+
+ if (SmEditUserDlg(hWnd, s->Hub, name))
+ {
+ SmUserListRefresh(hWnd, s);
+ }
+
+ Free(str);
+ }
+ }
+ else
+ {
+ // The user has been chosen
+ str = LvGetSelectedStr(hWnd, L_USER, 0);
+ if (str != NULL)
+ {
+ char name[MAX_SIZE];
+ UniToStr(name, sizeof(name), str);
+
+ s->SelectedName = CopyStr(name);
+
+ EndDialog(hWnd, true);
+
+ Free(str);
+ }
+ }
+ break;
+
+ case B_CREATE:
+ // Create new
+ if (SmCreateUserDlg(hWnd, s->Hub))
+ {
+ SmUserListRefresh(hWnd, s);
+ }
+ break;
+
+ case B_DELETE:
+ if (s->AllowGroup)
+ {
+ // Group selection
+ EndDialog(hWnd, INFINITE);
+ }
+ else
+ {
+ // Delete
+ str = LvGetSelectedStr(hWnd, L_USER, 0);
+ if (str != NULL)
+ {
+ RPC_DELETE_USER t;
+ char name[MAX_SIZE];
+ UniToStr(name, sizeof(name), str);
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), s->Hub->HubName);
+ StrCpy(t.Name, sizeof(t.Name), name);
+
+ if (MsgBoxEx(hWnd, MB_YESNO | MB_DEFBUTTON2 | MB_ICONQUESTION,
+ _UU("SM_USER_DELETE_MSG"), str) == IDYES)
+ {
+ if (CALL(hWnd, ScDeleteUser(s->Rpc, &t)))
+ {
+ SmUserListRefresh(hWnd, s);
+ }
+ }
+
+ Free(str);
+ }
+ }
+ break;
+
+ case B_STATUS:
+ // Display the User Information
+ str = LvGetSelectedStr(hWnd, L_USER, 0);
+ if (str != NULL)
+ {
+ char name[MAX_SIZE];
+ wchar_t tmp[MAX_SIZE];
+ SM_USER_INFO info;
+ UniToStr(name, sizeof(name), str);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_USERINFO_CAPTION"), name);
+
+ Zero(&info, sizeof(info));
+ info.p = s->p;
+ info.Rpc = s->Rpc;
+ info.Hub = s->Hub;
+ info.Username = name;
+
+ SmStatusDlg(hWnd, s->p, &info, false, true, tmp, ICO_USER, NULL, SmRefreshUserInfo);
+
+ Free(str);
+ }
+ break;
+ break;
+
+ case B_REFRESH:
+ // Update
+ SmUserListRefresh(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_USER:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ // Update the control
+ SmUserListUpdate(hWnd, s);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_USER);
+
+ return 0;
+}
+
+// User List dialog (selection)
+char *SmSelectUserDlg(HWND hWnd, SM_HUB *s, char *default_name)
+{
+ return SmSelectUserDlgEx(hWnd, s, default_name, false);
+}
+char *SmSelectUserDlgEx(HWND hWnd, SM_HUB *s, char *default_name, bool allow_group)
+{
+ UINT ret;
+ SM_USER user;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&user, sizeof(user));
+ user.Hub = s;
+ user.p = s->p;
+ user.Rpc = s->Rpc;
+ user.GroupName = NULL;
+ user.SelectedName = default_name;
+ user.SelectMode = true;
+ user.AllowGroup = allow_group;
+
+ ret = Dialog(hWnd, D_SM_USER, SmUserListProc, &user);
+
+ if (ret == 0)
+ {
+ return NULL;
+ }
+ else if (ret == INFINITE)
+ {
+ // Select a Group
+ return SmSelectGroupDlg(hWnd, s, default_name);
+ }
+ else
+ {
+ return user.SelectedName;
+ }
+}
+
+// User List dialog (filtered by group name)
+void SmUserListDlgEx(HWND hWnd, SM_HUB *s, char *groupname, bool create)
+{
+ SM_USER user;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&user, sizeof(user));
+ user.Hub = s;
+ user.p = s->p;
+ user.Rpc = s->Rpc;
+ user.GroupName = groupname;
+ user.CreateNow = create;
+
+ Dialog(hWnd, D_SM_USER, SmUserListProc, &user);
+}
+
+// User List dialog
+void SmUserListDlg(HWND hWnd, SM_HUB *s)
+{
+ SmUserListDlgEx(hWnd, s, NULL, false);
+}
+
+// Initialize
+void SmHubDlgInit(HWND hWnd, SM_HUB *s)
+{
+ CAPSLIST *caps;
+ bool support_user, support_group, support_accesslist, support_cascade,
+ support_log, support_config_hub, support_secure_nat, support_config_radius;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ FormatText(hWnd, 0, s->HubName);
+ FormatText(hWnd, S_TITLE, s->HubName);
+ SetIcon(hWnd, 0, ICO_HUB);
+ DlgFont(hWnd, S_TITLE, 15, true);
+
+ LvInit(hWnd, L_STATUS);
+ LvSetStyle(hWnd, L_STATUS, LVS_EX_GRIDLINES);
+ LvInsertColumn(hWnd, L_STATUS, 0, _UU("SM_STATUS_COLUMN_1"), 0);
+ LvInsertColumn(hWnd, L_STATUS, 1, _UU("SM_STATUS_COLUMN_2"), 0);
+
+ caps = s->p->CapsList;
+
+ support_user = GetCapsInt(caps, "i_max_users_per_hub") == 0 ? false : true;
+ support_group = GetCapsInt(caps, "i_max_groups_per_hub") == 0 ? false : true;
+ support_accesslist = GetCapsInt(caps, "i_max_access_lists") == 0 ? false : true;
+ support_cascade = GetCapsBool(caps, "b_support_cascade");
+ support_log = GetCapsBool(caps, "b_support_config_log");
+ support_config_hub = GetCapsBool(caps, "b_support_config_hub");
+ support_secure_nat = GetCapsBool(caps, "b_support_securenat");
+ support_config_radius = GetCapsBool(caps, "b_support_radius");
+
+ SetEnable(hWnd, B_USER, support_user);
+ SetEnable(hWnd, S_USER, support_user);
+
+ SetEnable(hWnd, B_GROUP, support_group);
+ SetEnable(hWnd, S_GROUP, support_group);
+
+ SetEnable(hWnd, B_ACCESS, support_accesslist);
+ SetEnable(hWnd, S_ACCESS, support_accesslist);
+
+ SetEnable(hWnd, B_PROPERTY, s->p->ServerType != SERVER_TYPE_FARM_MEMBER);
+ SetEnable(hWnd, S_PROPERTY, s->p->ServerType != SERVER_TYPE_FARM_MEMBER);
+
+ SetEnable(hWnd, B_RADIUS, support_config_radius);
+ SetEnable(hWnd, S_RADIUS, support_config_radius);
+
+ SetEnable(hWnd, B_LINK, support_cascade);
+ SetEnable(hWnd, S_LINK, support_cascade);
+
+ SetEnable(hWnd, B_LOG, support_log);
+ SetEnable(hWnd, S_LOG, support_log);
+
+ SetEnable(hWnd, B_CA, support_config_hub);
+ SetEnable(hWnd, S_CA, support_config_hub);
+
+ SetEnable(hWnd, B_SNAT, support_secure_nat);
+ SetEnable(hWnd, S_SNAT, support_secure_nat);
+
+ SetEnable(hWnd, B_CRL, GetCapsBool(caps, "b_support_crl"));
+
+ SetEnable(hWnd, B_LOG_FILE, GetCapsBool(caps, "b_support_read_log"));
+
+ SmHubDlgRefresh(hWnd, s);
+}
+
+// Update the control
+void SmHubDlgUpdate(HWND hWnd, SM_HUB *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+}
+
+// Content update
+void SmHubDlgRefresh(HWND hWnd, SM_HUB *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SmRefreshHubStatus(hWnd, s->p, (void *)s->HubName);
+ LvAutoSize(hWnd, L_STATUS);
+
+ SmHubDlgUpdate(hWnd, s);
+}
+
+// HUB management dialog
+UINT SmHubDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_HUB *s = (SM_HUB *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmHubDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_USER:
+ // User
+ SmUserListDlg(hWnd, s);
+ SmHubDlgRefresh(hWnd, s);
+ break;
+
+ case B_GROUP:
+ // Group
+ SmGroupListDlg(hWnd, s);
+ SmHubDlgRefresh(hWnd, s);
+ break;
+
+ case B_ACCESS:
+ // Access list
+ SmAccessListDlg(hWnd, s);
+ SmHubDlgRefresh(hWnd, s);
+ break;
+
+ case B_PROPERTY:
+ // Property
+ if (SmEditHubDlg(hWnd, s->p, s->HubName))
+ {
+ SmHubDlgRefresh(hWnd, s);
+ }
+ break;
+
+ case B_RADIUS:
+ // Radius
+ SmRadiusDlg(hWnd, s);
+ SmHubDlgRefresh(hWnd, s);
+ break;
+
+ case B_LINK:
+ // Cascade
+ SmLinkDlg(hWnd, s);
+ SmHubDlgRefresh(hWnd, s);
+ break;
+
+ case B_SESSION:
+ // Session
+ SmSessionDlg(hWnd, s);
+ SmHubDlgRefresh(hWnd, s);
+ break;
+
+ case B_LOG:
+ // Log
+ Dialog(hWnd, D_SM_LOG, SmLogDlg, s);
+ SmHubDlgRefresh(hWnd, s);
+ break;
+
+ case B_CA:
+ // CA
+ SmCaDlg(hWnd, s);
+ SmHubDlgRefresh(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+
+ case B_REFRESH:
+ // Update
+ SmHubDlgRefresh(hWnd, s);
+ break;
+
+ case B_SNAT:
+ // SecureNAT
+ Dialog(hWnd, D_SM_SNAT, SmSNATDlgProc, s);
+ SmHubDlgRefresh(hWnd, s);
+ break;
+
+ case B_CRL:
+ // Certificate revocation list
+ Dialog(hWnd, D_SM_CRL, SmCrlDlgProc, s);
+ break;
+
+ case B_LOG_FILE:
+ // Log file
+ Dialog(hWnd, D_SM_LOG_FILE, SmLogFileDlgProc, s->p);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Management of HUB
+void SmHubDlg(HWND hWnd, SM_HUB *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_SM_HUB, SmHubDlgProc, s);
+}
+
+// Change the server password
+UINT SmChangeServerPasswordDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_SERVER *p = (SM_SERVER *)param;
+ char tmp1[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ UCHAR hash[SHA1_SIZE];
+ RPC_SET_PASSWORD t;
+ SETTING *setting;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SetIcon(hWnd, 0, ICO_USER_ADMIN);
+ FormatText(hWnd, 0, p->ServerName);
+ FormatText(hWnd, S_TITLE, p->ServerName);
+ Focus(hWnd, E_PASSWORD1);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_PASSWORD1:
+ case E_PASSWORD2:
+ GetTxtA(hWnd, E_PASSWORD1, tmp1, sizeof(tmp1));
+ GetTxtA(hWnd, E_PASSWORD2, tmp2, sizeof(tmp2));
+
+ if (StrLen(tmp1) == 0 || StrLen(tmp2) == 0)
+ {
+ Disable(hWnd, IDOK);
+ }
+ else
+ {
+ Enable(hWnd, IDOK);
+ }
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ // [OK] button
+ GetTxtA(hWnd, E_PASSWORD1, tmp1, sizeof(tmp1));
+ GetTxtA(hWnd, E_PASSWORD2, tmp2, sizeof(tmp2));
+ if (StrCmp(tmp1, tmp2) != 0)
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("SM_CHANGE_PASSWORD_1"));
+ FocusEx(hWnd, E_PASSWORD2);
+ break;
+ }
+ if (StrLen(tmp1) == 0)
+ {
+ if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, _UU("SM_CHANGE_PASSWORD_2")) == IDNO)
+ {
+ Focus(hWnd, E_PASSWORD1);
+ break;
+ }
+ }
+ Zero(&t, sizeof(t));
+ Hash(t.HashedPassword, tmp1, StrLen(tmp1), true);
+ Copy(hash, t.HashedPassword, sizeof(hash));
+ if (CALL(hWnd, ScSetServerPassword(p->Rpc, &t)) == false)
+ {
+ break;
+ }
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SM_CHANGE_PASSWORD_3"));
+
+ // Change the password for the connection setting
+ setting = SmGetSetting(p->CurrentSetting->Title);
+ if (setting != NULL && sm->TempSetting == NULL)
+ {
+ if (IsZero(setting->HashedPassword, SHA1_SIZE) == false)
+ {
+ Copy(setting->HashedPassword, hash, SHA1_SIZE);
+ SmWriteSettingList();
+ }
+ }
+
+ EndDialog(hWnd, true);
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Update the status of the connection to the server farm controller
+bool SmRefreshFarmConnectionInfo(HWND hWnd, SM_SERVER *p, void *param)
+{
+ RPC_FARM_CONNECTION_STATUS t;
+ LVB *b;
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+ if (CALL(hWnd, ScGetFarmConnectionStatus(p->Rpc, &t)) == false)
+ {
+ return false;
+ }
+
+ b = LvInsertStart();
+
+ if (t.Online == false)
+ {
+ LvInsertAdd(b, ICO_FARM, NULL, 2, _UU("SM_FC_IP"), _UU("SM_FC_NOT_CONNECTED"));
+
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_FC_PORT"), _UU("SM_FC_NOT_CONNECTED"));
+ }
+ else
+ {
+ IPToStr32(str, sizeof(str), t.Ip);
+ StrToUni(tmp, sizeof(tmp), str);
+ LvInsertAdd(b, ICO_FARM, NULL, 2, _UU("SM_FC_IP"), tmp);
+
+ UniToStru(tmp, t.Port);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_FC_PORT"), tmp);
+ }
+
+ LvInsertAdd(b,
+ t.Online ? ICO_SERVER_ONLINE_EX : ICO_PROTOCOL_X, NULL, 2,
+ _UU("SM_FC_STATUS"),
+ t.Online ? _UU("SM_FC_ONLINE") : _UU("SM_FC_OFFLINE"));
+
+ if (t.Online == false)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SM_FC_ERROR_TAG"), _E(t.LastError), t.LastError);
+ LvInsertAdd(b, ICO_STOP, NULL, 2,
+ _UU("SM_FC_LAST_ERROR"), tmp);
+ }
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.StartedTime), NULL);
+ LvInsertAdd(b, ICO_INFORMATION, NULL, 2, _UU("SM_FC_START_TIME"), tmp);
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.FirstConnectedTime), NULL);
+ LvInsertAdd(b, ICO_INFORMATION, NULL, 2, _UU("SM_FC_FIRST_TIME"), tmp);
+
+ //if (t.Online == false)
+ {
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.CurrentConnectedTime), NULL);
+ LvInsertAdd(b, ICO_INFORMATION, NULL, 2, _UU("SM_FC_CURRENT_TIME"), tmp);
+ }
+
+ UniToStru(tmp, t.NumTry);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_FC_NUM_TRY"), tmp);
+
+ UniToStru(tmp, t.NumConnected);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_FC_NUM_CONNECTED"), tmp);
+
+ UniToStru(tmp, t.NumFailed);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_FC_NUM_FAILED"), tmp);
+
+ LvInsertEnd(b, hWnd, L_STATUS);
+
+ return true;
+}
+
+// Initialize
+void SmFarmMemberDlgInit(HWND hWnd, SM_SERVER *p)
+{
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_FARM);
+
+ FormatText(hWnd, S_TITLE, p->ServerName);
+
+ // Initialize the column
+ LvInit(hWnd, L_FARM_MEMBER);
+ LvSetStyle(hWnd, L_FARM_MEMBER, LVS_EX_GRIDLINES);
+ LvInsertColumn(hWnd, L_FARM_MEMBER, 0, _UU("SM_FM_COLUMN_1"), 90);
+ LvInsertColumn(hWnd, L_FARM_MEMBER, 1, _UU("SM_FM_COLUMN_2"), 150);
+ LvInsertColumn(hWnd, L_FARM_MEMBER, 2, _UU("SM_FM_COLUMN_3"), 140);
+ LvInsertColumn(hWnd, L_FARM_MEMBER, 3, _UU("SM_FM_COLUMN_4"), 60);
+ LvInsertColumn(hWnd, L_FARM_MEMBER, 4, _UU("SM_FM_COLUMN_5"), 80);
+ LvInsertColumn(hWnd, L_FARM_MEMBER, 5, _UU("SM_FM_COLUMN_6"), 80);
+ LvInsertColumn(hWnd, L_FARM_MEMBER, 6, _UU("SM_FM_COLUMN_7"), 80);
+ LvInsertColumn(hWnd, L_FARM_MEMBER, 7, _UU("SM_FM_COLUMN_8"), 160);
+ LvInsertColumn(hWnd, L_FARM_MEMBER, 8, _UU("SM_FM_COLUMN_9"), 160);
+
+ SmFarmMemberDlgRefresh(hWnd, p);
+}
+
+// Update
+void SmFarmMemberDlgUpdate(HWND hWnd, SM_SERVER *p)
+{
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ SetEnable(hWnd, IDOK, LvIsSelected(hWnd, L_FARM_MEMBER) && (LvIsMultiMasked(hWnd, L_FARM_MEMBER) == false));
+ SetEnable(hWnd, B_CERT, LvIsSelected(hWnd, L_FARM_MEMBER) && (LvIsMultiMasked(hWnd, L_FARM_MEMBER) == false));
+}
+
+// Content update
+void SmFarmMemberDlgRefresh(HWND hWnd, SM_SERVER *p)
+{
+ RPC_ENUM_FARM t;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ if (CALL(hWnd, ScEnumFarmMember(p->Rpc, &t)) == false)
+ {
+ EndDialog(hWnd, false);
+ return;
+ }
+
+ LvReset(hWnd, L_FARM_MEMBER);
+
+ for (i = 0;i < t.NumFarm;i++)
+ {
+ RPC_ENUM_FARM_ITEM *e = &t.Farms[i];
+ wchar_t tmp1[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ wchar_t tmp3[64];
+ wchar_t tmp4[64];
+ wchar_t tmp5[64];
+ wchar_t tmp6[64];
+ wchar_t tmp7[64];
+ wchar_t tmp8[64];
+
+ GetDateTimeStrEx64(tmp1, sizeof(tmp1), SystemToLocal64(e->ConnectedTime), NULL);
+ StrToUni(tmp2, sizeof(tmp2), e->Hostname);
+ UniToStru(tmp3, e->Point);
+ UniToStru(tmp4, e->NumSessions);
+ UniToStru(tmp5, e->NumTcpConnections);
+ UniToStru(tmp6, e->NumHubs);
+ UniToStru(tmp7, e->AssignedClientLicense);
+ UniToStru(tmp8, e->AssignedBridgeLicense);
+
+ LvInsert(hWnd, L_FARM_MEMBER, e->Controller ? ICO_FARM : ICO_TOWER, (void *)e->Id, 9,
+ e->Controller ? _UU("SM_FM_CONTROLLER") : _UU("SM_FM_MEMBER"),
+ tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8);
+ }
+
+ FreeRpcEnumFarm(&t);
+
+ SmFarmMemberDlgUpdate(hWnd, p);
+}
+
+// [OK] button
+void SmFarmMemberDlgOnOk(HWND hWnd, SM_SERVER *p)
+{
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+}
+
+// Display the farm member certificate
+void SmFarmMemberCert(HWND hWnd, SM_SERVER *p, UINT id)
+{
+ RPC_FARM_INFO t;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL || id == 0)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ t.Id = id;
+
+ if (CALL(hWnd, ScGetFarmInfo(p->Rpc, &t)) == false)
+ {
+ return;
+ }
+
+ CertDlg(hWnd, t.ServerCert, NULL, true);
+
+ FreeRpcFarmInfo(&t);
+}
+
+// Update the farm member information
+bool SmRefreshFarmMemberInfo(HWND hWnd, SM_SERVER *p, void *param)
+{
+ RPC_FARM_INFO t;
+ UINT id = (UINT)param;
+ LVB *b;
+ UINT i;
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || p == NULL || id == 0)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+ t.Id = id;
+
+ if (CALL(hWnd, ScGetFarmInfo(p->Rpc, &t)) == false)
+ {
+ return false;
+ }
+
+ b = LvInsertStart();
+
+ LvInsertAdd(b, ICO_FARM, NULL, 2, _UU("SM_FMINFO_TYPE"),
+ t.Controller ? _UU("SM_FARM_CONTROLLER") : _UU("SM_FARM_MEMBER"));
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.ConnectedTime), NULL);
+ LvInsertAdd(b, ICO_INFORMATION, NULL, 2, _UU("SM_FMINFO_CONNECT_TIME"), tmp);
+
+ IPToStr32(str, sizeof(str), t.Ip);
+ StrToUni(tmp, sizeof(tmp), str);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_FMINFO_IP"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.Hostname);
+ LvInsertAdd(b, ICO_TOWER, NULL, 2, _UU("SM_FMINFO_HOSTNAME"), tmp);
+
+ UniToStru(tmp, t.Point);
+ LvInsertAdd(b, ICO_TEST, NULL, 2, _UU("SM_FMINFO_POINT"), tmp);
+
+ UniToStru(tmp, t.Weight);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_FMINFO_WEIGHT"), tmp);
+
+ UniToStru(tmp, t.NumPort);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_FMINFO_NUM_PORT"), tmp);
+
+ for (i = 0;i < t.NumPort;i++)
+ {
+ wchar_t tmp2[MAX_SIZE];
+ UniFormat(tmp, sizeof(tmp), _UU("SM_FMINFO_PORT"), i + 1);
+ UniToStru(tmp2, t.Ports[i]);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, tmp, tmp2);
+ }
+
+ UniToStru(tmp, t.NumFarmHub);
+ LvInsertAdd(b, ICO_HUB_OFFLINE, NULL, 2, _UU("SM_FMINFO_NUM_HUB"), tmp);
+
+ for (i = 0;i < t.NumFarmHub;i++)
+ {
+ wchar_t tmp2[MAX_SIZE];
+ UniFormat(tmp, sizeof(tmp), _UU("SM_FMINFO_HUB"), i + 1);
+ UniFormat(tmp2, sizeof(tmp2),
+ t.FarmHubs[i].DynamicHub ? _UU("SM_FMINFO_HUB_TAG_2") : _UU("SM_FMINFO_HUB_TAG_1"),
+ t.FarmHubs[i].HubName);
+ LvInsertAdd(b, ICO_HUB, NULL, 2, tmp, tmp2);
+ }
+
+ UniToStru(tmp, t.NumSessions);
+ LvInsertAdd(b, ICO_VPN, NULL, 2, _UU("SM_FMINFO_NUM_SESSION"), tmp);
+
+ UniToStru(tmp, t.NumTcpConnections);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_FMINFO_NUN_CONNECTION"), tmp);
+
+ LvInsertEnd(b, hWnd, L_STATUS);
+
+ FreeRpcFarmInfo(&t);
+
+ return true;
+}
+
+// Farm Member List dialog
+UINT SmFarmMemberDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_SERVER *p = (SM_SERVER *)param;
+ NMHDR *n;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmFarmMemberDlgInit(hWnd, p);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ // Display the information of farm members
+ i = LvGetSelected(hWnd, L_FARM_MEMBER);
+ if (i != INFINITE)
+ {
+ SmStatusDlg(hWnd, p, LvGetParam(hWnd, L_FARM_MEMBER, i), false, true,
+ _UU("SM_FMINFO_CAPTION"), ICO_FARM, NULL, SmRefreshFarmMemberInfo);
+ }
+ break;
+
+ case B_CERT:
+ // Show the Server Certificate
+ i = LvGetSelected(hWnd, L_FARM_MEMBER);
+ if (i != INFINITE)
+ {
+ SmFarmMemberCert(hWnd, p, (UINT)LvGetParam(hWnd, L_FARM_MEMBER, i));
+ }
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+
+ case B_REFRESH:
+ // Update
+ SmFarmMemberDlgRefresh(hWnd, p);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ switch (n->idFrom)
+ {
+ case L_FARM_MEMBER:
+ SmFarmMemberDlgUpdate(hWnd, p);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_FARM_MEMBER);
+
+ return 0;
+}
+
+// Convert the string to port list
+LIST *SmStrToPortList(char *str)
+{
+ return StrToPortList(str);
+}
+
+// Initialize the dialog
+void SmFarmDlgInit(HWND hWnd, SM_SERVER *p)
+{
+ RPC_FARM t;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_FARM);
+
+ // Get the current settings
+ Zero(&t, sizeof(t));
+ if (CALL(hWnd, ScGetFarmSetting(p->Rpc, &t)) == false)
+ {
+ EndDialog(hWnd, false);
+ return;
+ }
+
+ if (t.Weight == 0)
+ {
+ t.Weight = FARM_DEFAULT_WEIGHT;
+ }
+
+ FormatText(hWnd, S_TITLE, p->ServerName);
+ DlgFont(hWnd, S_CURRENT, 11, true);
+
+ SetText(hWnd, S_CURRENT, GetServerTypeStr(t.ServerType));
+
+ switch (t.ServerType)
+ {
+ case SERVER_TYPE_FARM_CONTROLLER:
+ Check(hWnd, R_CONTROLLER, true);
+ break;
+
+ case SERVER_TYPE_FARM_MEMBER:
+ Check(hWnd, R_MEMBER, true);
+ break;
+
+ default:
+ Check(hWnd, R_STANDALONE, true);
+ break;
+ }
+
+ SetInt(hWnd, E_WEIGHT, t.Weight);
+
+ if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ Check(hWnd, R_CONTROLLER_ONLY, t.ControllerOnly);
+ }
+
+ if (t.ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ char tmp[MAX_PUBLIC_PORT_NUM * 8];
+ UINT i;
+ if (t.PublicIp != 0)
+ {
+ IpSet(hWnd, E_IP, t.PublicIp);
+ }
+ StrCpy(tmp, sizeof(tmp), "");
+ if (t.NumPort != 0)
+ {
+ for (i = 0;i < t.NumPort;i++)
+ {
+ Format(tmp, sizeof(tmp), "%s%u", tmp, t.Ports[i]);
+ if (i != (t.NumPort - 1))
+ {
+ StrCat(tmp, sizeof(tmp), ", ");
+ }
+ }
+ SetTextA(hWnd, E_PORT, tmp);
+ }
+ SetTextA(hWnd, E_CONTROLLER, t.ControllerName);
+ SetIntEx(hWnd, E_CONTROLLER_PORT, t.ControllerPort);
+ SetTextA(hWnd, E_PASSWORD, HIDDEN_PASSWORD);
+ }
+ else
+ {
+ // Write the port list
+ RPC_LISTENER_LIST t;
+ char tmp[MAX_PUBLIC_PORT_NUM * 8];
+ Zero(&t, sizeof(t));
+ StrCpy(tmp, sizeof(tmp), "");
+ if (CALL(hWnd, ScEnumListener(p->Rpc, &t)))
+ {
+ UINT i;
+ if (t.NumPort != 0)
+ {
+ for (i = 0;i < t.NumPort;i++)
+ {
+ Format(tmp, sizeof(tmp), "%s%u", tmp, t.Ports[i]);
+ if (i != (t.NumPort - 1))
+ {
+ StrCat(tmp, sizeof(tmp), ", ");
+ }
+ }
+ SetTextA(hWnd, E_PORT, tmp);
+ }
+ FreeRpcListenerList(&t);
+ }
+ }
+
+ SmFarmDlgUpdate(hWnd, p);
+
+ FreeRpcFarm(&t);
+
+ Focus(hWnd, IDOK);
+}
+
+// Dialog update
+void SmFarmDlgUpdate(HWND hWnd, SM_SERVER *p)
+{
+ bool ok = true;
+ bool farm_member_control = false;
+ char *s;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (IsChecked(hWnd, R_MEMBER))
+ {
+ LIST *o;
+ UINT i = IpGetFilledNum(hWnd, E_IP);
+ if (i != 0 && i != 4)
+ {
+ ok = false;
+ }
+
+ s = GetTextA(hWnd, E_PORT);
+ o = SmStrToPortList(s);
+ if (o == NULL)
+ {
+ ok = false;
+ }
+ else
+ {
+ ReleaseList(o);
+ }
+ Free(s);
+
+ if (IsEmpty(hWnd, E_CONTROLLER))
+ {
+ ok = false;
+ }
+
+ i = GetInt(hWnd, E_CONTROLLER_PORT);
+ if (i == 0 || i >= 65536)
+ {
+ ok = false;
+ }
+
+ farm_member_control = true;
+ }
+
+ if (IsChecked(hWnd, R_STANDALONE))
+ {
+ Disable(hWnd, S_1);
+ Disable(hWnd, S_2);
+ Disable(hWnd, E_WEIGHT);
+ }
+ else
+ {
+ Enable(hWnd, S_1);
+ Enable(hWnd, S_2);
+ Enable(hWnd, E_WEIGHT);
+ }
+
+ if (IsChecked(hWnd, R_CONTROLLER))
+ {
+ Enable(hWnd, R_CONTROLLER_ONLY);
+ }
+ else
+ {
+ Disable(hWnd, R_CONTROLLER_ONLY);
+ }
+
+ if (IsChecked(hWnd, R_CONTROLLER) || IsChecked(hWnd, R_MEMBER))
+ {
+ if (GetInt(hWnd, E_WEIGHT) == 0)
+ {
+ ok = false;
+ }
+ }
+
+ SetEnable(hWnd, S_IP_1, farm_member_control);
+ SetEnable(hWnd, E_IP, farm_member_control);
+ SetEnable(hWnd, S_IP_2, farm_member_control);
+ SetEnable(hWnd, S_PORT_1, farm_member_control);
+ SetEnable(hWnd, E_PORT, farm_member_control);
+ SetEnable(hWnd, S_PORT_2, farm_member_control);
+ SetEnable(hWnd, S_PORT_3, farm_member_control);
+ SetEnable(hWnd, E_CONTROLLER, farm_member_control);
+ SetEnable(hWnd, S_CONTROLLER, farm_member_control);
+ SetEnable(hWnd, E_CONTROLLER_PORT, farm_member_control);
+ SetEnable(hWnd, S_CONTROLLER_PORT, farm_member_control);
+ SetEnable(hWnd, S_PASSWORD, farm_member_control);
+ SetEnable(hWnd, E_PASSWORD, farm_member_control);
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// [OK] button
+void SmFarmDlgOnOk(HWND hWnd, SM_SERVER *p)
+{
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ // Display the message
+ if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_OKCANCEL | MB_DEFBUTTON2,
+ _UU("SM_FARM_REBOOT_MSG")) == IDOK)
+ {
+ RPC_FARM t;
+ Zero(&t, sizeof(t));
+ t.ServerType = SERVER_TYPE_STANDALONE;
+ if (IsChecked(hWnd, R_CONTROLLER))
+ {
+ t.ServerType = SERVER_TYPE_FARM_CONTROLLER;
+ }
+ if (IsChecked(hWnd, R_MEMBER))
+ {
+ t.ServerType = SERVER_TYPE_FARM_MEMBER;
+ }
+
+ t.ControllerOnly = IsChecked(hWnd, R_CONTROLLER_ONLY);
+ t.Weight = GetInt(hWnd, E_WEIGHT);
+
+ if (t.ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ char *s;
+ char pass[MAX_SIZE];
+ t.PublicIp = IpGet(hWnd, E_IP);
+ s = GetTextA(hWnd, E_PORT);
+ if (s != NULL)
+ {
+ LIST *o = SmStrToPortList(s);
+ if (o != NULL)
+ {
+ UINT i;
+ t.NumPort = LIST_NUM(o);
+ t.Ports = ZeroMalloc(sizeof(UINT) * t.NumPort);
+ for (i = 0;i < t.NumPort;i++)
+ {
+ t.Ports[i] = (UINT)LIST_DATA(o, i);
+ }
+ ReleaseList(o);
+ }
+ Free(s);
+ }
+ GetTxtA(hWnd, E_CONTROLLER, t.ControllerName, sizeof(t.ControllerName));
+ t.ControllerPort = GetInt(hWnd, E_CONTROLLER_PORT);
+ GetTxtA(hWnd, E_PASSWORD, pass, sizeof(pass));
+ if (StrCmp(pass, HIDDEN_PASSWORD) != 0)
+ {
+ Hash(t.MemberPassword, pass, StrLen(pass), true);
+ }
+ }
+
+ // Configuration update
+ if (CALL(hWnd, ScSetFarmSetting(p->Rpc, &t)) == false)
+ {
+ return;
+ }
+
+ FreeRpcFarm(&t);
+
+ EndDialog(hWnd, true);
+ }
+}
+
+// Server farm dialog procedure
+UINT SmFarmDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_SERVER *p = (SM_SERVER *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmFarmDlgInit(hWnd, p);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case R_STANDALONE:
+ case R_CONTROLLER:
+ case R_MEMBER:
+ case E_IP:
+ case E_PORT:
+ case E_CONTROLLER:
+ case E_CONTROLLER_PORT:
+ case E_PASSWORD:
+ case R_CONTROLLER_ONLY:
+ case E_WEIGHT:
+ SmFarmDlgUpdate(hWnd, p);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ // [OK] button
+ SmFarmDlgOnOk(hWnd, p);
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+
+ case R_MEMBER:
+ if (IsChecked(hWnd, R_MEMBER))
+ {
+ Focus(hWnd, E_IP);
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Server farm configuration
+bool SmFarmDlg(HWND hWnd, SM_SERVER *p)
+{
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return false;
+ }
+
+ return Dialog(hWnd, D_SM_FARM, SmFarmDlgProc, p);
+}
+
+// Update the connection information
+bool SmRefreshConnectionStatus(HWND hWnd, SM_SERVER *p, void *param)
+{
+ RPC_CONNECTION_INFO t;
+ SM_CONNECTION_INFO *info = (SM_CONNECTION_INFO *)param;
+ LVB *b;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || p == NULL || param == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), info->ConnectionName);
+ if (CALL(hWnd, ScGetConnectionInfo(p->Rpc, &t)) == false)
+ {
+ return false;
+ }
+
+ b = LvInsertStart();
+
+ StrToUni(tmp, sizeof(tmp), t.Name);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_CONNINFO_NAME"), tmp);
+
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_CONNINFO_TYPE"), SmGetConnectionTypeStr(t.Type));
+
+ StrToUni(tmp, sizeof(tmp), t.Hostname);
+ LvInsertAdd(b, ICO_FARM, NULL, 2, _UU("SM_CONNINFO_HOSTNAME"), tmp);
+
+ UniToStru(tmp, t.Port);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_CONNINFO_PORT"), tmp);
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.ConnectedTime), NULL);
+ LvInsertAdd(b, ICO_INFORMATION, NULL, 2, _UU("SM_CONNINFO_TIME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.ServerStr);
+ LvInsertAdd(b, ICO_VPNSERVER, NULL, 2, _UU("SM_CONNINFO_SERVER_STR"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), L"%u.%02u", t.ServerVer / 100, t.ServerVer % 100);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_CONNINFO_SERVER_VER"), tmp);
+
+ UniToStru(tmp, t.ServerBuild);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_CONNINFO_SERVER_BUILD"), tmp);
+
+ if (StrLen(t.ClientStr) != 0)
+ {
+ StrToUni(tmp, sizeof(tmp), t.ClientStr);
+ LvInsertAdd(b, ICO_VPN, NULL, 2, _UU("SM_CONNINFO_CLIENT_STR"), tmp);
+
+ UniFormat(tmp, sizeof(tmp), L"%u.%02u", t.ClientVer / 100, t.ClientVer % 100);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_CONNINFO_CLIENT_VER"), tmp);
+
+ UniToStru(tmp, t.ClientBuild);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_CONNINFO_CLIENT_BUILD"), tmp);
+ }
+
+ LvInsertEnd(b, hWnd, L_STATUS);
+
+ return true;
+}
+
+// Initialize
+void SmConnectionDlgInit(HWND hWnd, SM_SERVER *p)
+{
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_PROTOCOL);
+ FormatText(hWnd, S_TITLE, p->ServerName);
+
+ // Initialize the column
+ LvInit(hWnd, L_LIST);
+ LvSetStyle(hWnd, L_LIST, LVS_EX_GRIDLINES);
+ LvInsertColumn(hWnd, L_LIST, 0, _UU("SM_CONN_COLUMN_1"), 90);
+ LvInsertColumn(hWnd, L_LIST, 1, _UU("SM_CONN_COLUMN_2"), 150);
+ LvInsertColumn(hWnd, L_LIST, 2, _UU("SM_CONN_COLUMN_3"), 200);
+ LvInsertColumn(hWnd, L_LIST, 3, _UU("SM_CONN_COLUMN_4"), 80);
+
+ SmConnectionDlgRefresh(hWnd, p);
+ SmConnectionDlgUpdate(hWnd, p);
+}
+
+// Update
+void SmConnectionDlgRefresh(HWND hWnd, SM_SERVER *p)
+{
+ LVB *b;
+ UINT i;
+ RPC_ENUM_CONNECTION t;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ if (CALL(hWnd, ScEnumConnection(p->Rpc, &t)) == false)
+ {
+ EndDialog(hWnd, false);
+ return;
+ }
+
+ b = LvInsertStart();
+
+ for (i = 0;i < t.NumConnection;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ wchar_t name[MAX_SIZE];
+ wchar_t datetime[MAX_SIZE];
+ RPC_ENUM_CONNECTION_ITEM *e = &t.Connections[i];
+
+ StrToUni(name, sizeof(name), e->Name);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_HOSTNAME_AND_PORT"), e->Hostname, e->Port);
+ GetDateTimeStrEx64(datetime, sizeof(datetime), SystemToLocal64(e->ConnectedTime), NULL);
+
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 4, name, tmp, datetime,
+ SmGetConnectionTypeStr(e->Type));
+ }
+
+ LvInsertEnd(b, hWnd, L_LIST);
+
+ FreeRpcEnumConnetion(&t);
+}
+
+// Update the control
+void SmConnectionDlgUpdate(HWND hWnd, SM_SERVER *p)
+{
+ bool b = false;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (LvIsSelected(hWnd, L_LIST) && (LvIsMultiMasked(hWnd, L_LIST) == false))
+ {
+ b = true;
+ }
+
+ SetEnable(hWnd, IDOK, b);
+ SetEnable(hWnd, B_DISCONNECT, b && p->ServerAdminMode);
+}
+
+// Connection List procedure
+UINT SmConnectionDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_SERVER *p = (SM_SERVER *)param;
+ NMHDR *n;
+ wchar_t *s;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmConnectionDlgInit(hWnd, p);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ // Show the connection information
+ s = LvGetSelectedStr(hWnd, L_LIST, 0);
+ if (s != NULL)
+ {
+ wchar_t caption[MAX_SIZE];
+ SM_CONNECTION_INFO info;
+ UniFormat(caption, sizeof(caption), _UU("SM_CONNINFO_CAPTION"),
+ s);
+ Zero(&info, sizeof(info));
+ info.ConnectionName = CopyUniToStr(s);
+ info.p = p;
+ SmStatusDlg(hWnd, p, &info, false, false, caption, ICO_PROTOCOL,
+ NULL, SmRefreshConnectionStatus);
+ Free(info.ConnectionName);
+ Free(s);
+ }
+ break;
+
+ case B_DISCONNECT:
+ // Disconnect
+ s = LvGetSelectedStr(hWnd, L_LIST, 0);
+ if (s != NULL)
+ {
+ if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
+ _UU("SM_CONN_DISCONNECT_MSG"), s) == IDYES)
+ {
+ char tmp[MAX_SIZE];
+ RPC_DISCONNECT_CONNECTION t;
+
+ UniToStr(tmp, sizeof(tmp), s);
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), tmp);
+
+ if (CALL(hWnd, ScDisconnectConnection(p->Rpc, &t)))
+ {
+ SmConnectionDlgRefresh(hWnd, p);
+ }
+ }
+ Free(s);
+ }
+ break;
+
+ case B_REFRESH:
+ // Update to the latest state
+ SmConnectionDlgRefresh(hWnd, p);
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ SmConnectionDlgUpdate(hWnd, p);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_LIST);
+
+ return 0;
+}
+
+// Display the connection list
+void SmConnectionDlg(HWND hWnd, SM_SERVER *p)
+{
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_SM_CONNECTION, SmConnectionDlgProc, p);
+}
+
+// Get the connection type string
+wchar_t *SmGetConnectionTypeStr(UINT type)
+{
+ return GetConnectionTypeStr(type);
+}
+
+// Update the server information
+bool SmRefreshServerInfo(HWND hWnd, SM_SERVER *p, void *param)
+{
+ RPC_SERVER_INFO t;
+ LVB *b;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+ if (CALL(hWnd, ScGetServerInfo(p->Rpc, &t)) == false)
+ {
+ return false;
+ }
+
+ b = LvInsertStart();
+
+ // Product name
+ StrToUni(tmp, sizeof(tmp), t.ServerProductName);
+ LvInsertAdd(b, ICO_VPNSERVER, NULL, 2, _UU("SM_INFO_PRODUCT_NAME"), tmp);
+
+ // Version
+ StrToUni(tmp, sizeof(tmp), t.ServerVersionString);
+ LvInsertAdd(b, ICO_INFORMATION, NULL, 2, _UU("SM_INFO_VERSION"), tmp);
+
+ // Build
+ StrToUni(tmp, sizeof(tmp), t.ServerBuildInfoString);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_INFO_BUILD"), tmp);
+
+ // Host name
+ StrToUni(tmp, sizeof(tmp), t.ServerHostName);
+ LvInsertAdd(b, ICO_TOWER, NULL, 2, _UU("SM_INFO_HOSTNAME"), tmp);
+
+ // Type
+ LvInsertAdd(b, t.ServerType == SERVER_TYPE_STANDALONE ? ICO_SERVER_ONLINE : ICO_FARM, 0,
+ 2, _UU("SM_ST_SERVER_TYPE"),
+ GetServerTypeStr(t.ServerType));
+
+ // OS
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsSystemName);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_SYSTEM_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsProductName);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_PRODUCT_NAME"), tmp);
+
+ if (t.OsInfo.OsServicePack != 0)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SM_OS_SP_TAG"), t.OsInfo.OsServicePack);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_SERVICE_PACK"), tmp);
+ }
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsVendorName);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_VENDER_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.OsVersion);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_VERSION"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.KernelName);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_KERNEL_NAME"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), t.OsInfo.KernelVersion);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_OS_KERNEL_VERSION"), tmp);
+
+ SmAddServerCaps(b, p->CapsList);
+
+ LvInsertEnd(b, hWnd, L_STATUS);
+
+ FreeRpcServerInfo(&t);
+
+ return true;
+}
+
+// Display the Caps of the server on the screen
+void SmAddServerCaps(LVB *b, CAPSLIST *t)
+{
+ UINT i;
+ // Validate arguments
+ if (b == NULL || t == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(t->CapsList);i++)
+ {
+ CAPS *c = LIST_DATA(t->CapsList, i);
+ wchar_t title[MAX_SIZE];
+ char name[256];
+
+ Format(name, sizeof(name), "CT_%s", c->Name);
+
+ UniStrCpy(title, sizeof(title), _UU(name));
+
+ if (UniIsEmptyStr(title))
+ {
+ UniFormat(title, sizeof(title), L"%S", (StrLen(c->Name) >= 2) ? c->Name + 2 : c->Name);
+ }
+
+ if (StartWith(c->Name, "b_"))
+ {
+ bool icon_pass = c->Value == 0 ? false : true;
+ if (StrCmpi(c->Name, "b_must_install_pcap") == 0)
+ {
+ // Invert only the item of WinPcap
+ icon_pass = !icon_pass;
+ }
+ LvInsertAdd(b, icon_pass == false ? ICO_DISCARD : ICO_PASS,
+ NULL, 2, title, c->Value == 0 ? _UU("CAPS_NO") : _UU("CAPS_YES"));
+ }
+ else
+ {
+ wchar_t str[64];
+ UniToStru(str, c->Value);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, title, str);
+ }
+ }
+}
+
+// Update the server state
+bool SmRefreshServerStatus(HWND hWnd, SM_SERVER *p, void *param)
+{
+ RPC_SERVER_STATUS t;
+ LVB *b;
+ wchar_t tmp[MAX_SIZE];
+ char str[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(t));
+ if (CALL(hWnd, ScGetServerStatus(p->Rpc, &t)) == false)
+ {
+ return false;
+ }
+
+ b = LvInsertStart();
+
+ // Type of server
+ LvInsertAdd(b, t.ServerType == SERVER_TYPE_STANDALONE ? ICO_SERVER_ONLINE : ICO_FARM, 0,
+ 2, _UU("SM_ST_SERVER_TYPE"),
+ GetServerTypeStr(t.ServerType));
+
+ // Number of TCP connections
+ UniToStru(tmp, t.NumTcpConnections);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_ST_NUM_TCP"), tmp);
+
+ if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ // Number of Local TCP connections
+ UniToStru(tmp, t.NumTcpConnectionsLocal);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_ST_NUM_TCP_LOCAL"), tmp);
+
+ // Number of remote TCP connections
+ UniToStru(tmp, t.NumTcpConnectionsRemote);
+ LvInsertAdd(b, ICO_PROTOCOL, NULL, 2, _UU("SM_ST_NUM_TCP_REMOTE"), tmp);
+ }
+
+ // Number of Virtual HUBs
+ UniToStru(tmp, t.NumHubTotal);
+ LvInsertAdd(b, ICO_HUB, NULL, 2, _UU("SM_ST_NUM_HUB_TOTAL"), tmp);
+
+ if (t.ServerType != SERVER_TYPE_STANDALONE)
+ {
+ // Number of static HUBs
+ UniToStru(tmp, t.NumHubStatic);
+ LvInsertAdd(b, ICO_HUB, NULL, 2, _UU("SM_ST_NUM_HUB_STATIC"), tmp);
+
+ // Number of Dynamic HUBs
+ UniToStru(tmp, t.NumHubDynamic);
+ LvInsertAdd(b, ICO_HUB, NULL, 2, _UU("SM_ST_NUM_HUB_DYNAMIC"), tmp);
+ }
+
+ // Number of sessions
+ UniToStru(tmp, t.NumSessionsTotal);
+ LvInsertAdd(b, ICO_VPN, NULL, 2, _UU("SM_ST_NUM_SESSION_TOTAL"), tmp);
+
+ if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ // Number of local sessions
+ UniToStru(tmp, t.NumSessionsLocal);
+ LvInsertAdd(b, ICO_VPN, NULL, 2, _UU("SM_ST_NUM_SESSION_LOCAL"), tmp);
+
+ // Number of local sessions
+ UniToStru(tmp, t.NumSessionsRemote);
+ LvInsertAdd(b, ICO_VPN, NULL, 2, _UU("SM_ST_NUM_SESSION_REMOTE"), tmp);
+ }
+
+ // Number of MAC table entries
+ UniToStru(tmp, t.NumMacTables);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_ST_NUM_MAC_TABLE"), tmp);
+
+ // Number of IP table entries
+ UniToStru(tmp, t.NumIpTables);
+ LvInsertAdd(b, ICO_MACHINE, NULL, 2, _UU("SM_ST_NUM_IP_TABLE"), tmp);
+
+ // Number of users
+ UniToStru(tmp, t.NumUsers);
+ LvInsertAdd(b, ICO_USER, NULL, 2, _UU("SM_ST_NUM_USERS"), tmp);
+
+ // Number of groups
+ UniToStru(tmp, t.NumGroups);
+ LvInsertAdd(b, ICO_GROUP, NULL, 2, _UU("SM_ST_NUM_GROUPS"), tmp);
+
+ // Number of assigned licenses
+ UniToStru(tmp, t.AssignedClientLicenses);
+ LvInsertAdd(b, ICO_CERT, NULL, 2, _UU("SM_ST_CLIENT_LICENSE"), tmp);
+ UniToStru(tmp, t.AssignedBridgeLicenses);
+ LvInsertAdd(b, ICO_CERT, NULL, 2, _UU("SM_ST_BRIDGE_LICENSE"), tmp);
+
+ if (t.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ UniToStru(tmp, t.AssignedClientLicensesTotal);
+ LvInsertAdd(b, ICO_CERT, NULL, 2, _UU("SM_ST_CLIENT_LICENSE_EX"), tmp);
+ UniToStru(tmp, t.AssignedBridgeLicensesTotal);
+ LvInsertAdd(b, ICO_CERT, NULL, 2, _UU("SM_ST_BRIDGE_LICENSE_EX"), tmp);
+ }
+
+ // Traffic
+ SmInsertTrafficInfo(b, &t.Traffic);
+
+ // Server start-up time
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(t.StartTime), NULL);
+ LvInsertAdd(b, ICO_NULL, NULL, 2, _UU("SM_ST_START_TIME"), tmp);
+
+ // Current time
+ GetDateTimeStrMilli64(str, sizeof(str), SystemToLocal64(t.CurrentTime));
+ StrToUni(tmp, sizeof(tmp), str);
+ LvInsertAdd(b, ICO_NULL, NULL, 2, _UU("SM_ST_CURRENT_TIME"), tmp);
+
+ // Tick value
+ UniFormat(tmp, sizeof(tmp), L"%I64u", t.CurrentTick);
+ LvInsertAdd(b, ICO_NULL, NULL, 2, _UU("SM_ST_CURRENT_TICK"), tmp);
+
+ // Memory information
+ if (t.MemInfo.TotalMemory != 0)
+ {
+ char vv[128];
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.TotalMemory);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_TOTAL_MEMORY"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.UsedMemory);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_USED_MEMORY"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.FreeMemory);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_FREE_MEMORY"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.TotalPhys);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_TOTAL_PHYS"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.UsedPhys);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_USED_PHYS"), tmp);
+
+ ToStr3(vv, sizeof(vv), t.MemInfo.FreePhys);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_RAM_SIZE_KB"), vv);
+ LvInsertAdd(b, ICO_MEMORY, NULL, 2, _UU("SM_ST_FREE_PHYS"), tmp);
+ }
+
+ LvInsertEnd(b, hWnd, L_STATUS);
+
+ return true;
+}
+
+// Initialize
+void SmSaveKeyPairDlgInit(HWND hWnd, SM_SAVE_KEY_PAIR *s)
+{
+ UINT current;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ current = MsRegReadInt(REG_CURRENT_USER, SM_REG_KEY, "SavePkcs12");
+
+ if (current == 1)
+ {
+ Check(hWnd, R_PKCS12, true);
+ }
+ else if (current == 2)
+ {
+ Check(hWnd, R_SECURE, true);
+ }
+ else
+ {
+ Check(hWnd, R_X509_AND_KEY, true);
+ }
+
+ SmSaveKeyPairDlgUpdate(hWnd, s);
+}
+
+// Update
+void SmSaveKeyPairDlgUpdate(HWND hWnd, SM_SAVE_KEY_PAIR *s)
+{
+ SECURE_DEVICE *dev;
+ bool ok = true;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ dev = GetSecureDevice(SmGetCurrentSecureIdFromReg());
+ if (dev == NULL)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SEC_CURRENT_NO_DEVICE"));
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SEC_CURRENT_DEVICE"), dev->DeviceName);
+ }
+
+ SetText(hWnd, S_INFO, tmp);
+
+ if (IsChecked(hWnd, R_USE_PASS))
+ {
+ char *s1, *s2;
+ s1 = GetTextA(hWnd, E_PASS1);
+ s2 = GetTextA(hWnd, E_PASS2);
+ if (StrCmp(s1, s2) != 0)
+ {
+ ok = false;
+ }
+ Free(s1);
+ Free(s2);
+ }
+
+ if (IsChecked(hWnd, R_SECURE))
+ {
+ if (dev == NULL)
+ {
+ ok = false;
+ }
+ }
+
+ SetEnable(hWnd, B_SELECT, IsChecked(hWnd, R_SECURE));
+ SetEnable(hWnd, B_SECURE_MANAGER, IsChecked(hWnd, R_SECURE));
+ SetEnable(hWnd, S_INFO, IsChecked(hWnd, R_SECURE));
+
+ SetEnable(hWnd, E_PASS1, IsChecked(hWnd, R_USE_PASS) && (IsChecked(hWnd, R_SECURE) == false));
+ SetEnable(hWnd, E_PASS2, IsChecked(hWnd, R_USE_PASS) && (IsChecked(hWnd, R_SECURE) == false));
+ SetEnable(hWnd, S_PASS1, IsChecked(hWnd, R_USE_PASS) && (IsChecked(hWnd, R_SECURE) == false));
+ SetEnable(hWnd, S_PASS2, IsChecked(hWnd, R_USE_PASS) && (IsChecked(hWnd, R_SECURE) == false));
+ SetEnable(hWnd, R_USE_PASS, (IsChecked(hWnd, R_SECURE) == false));
+ SetEnable(hWnd, S_PASS3, (IsChecked(hWnd, R_SECURE) == false));
+ SetEnable(hWnd, S_PASS4, (IsChecked(hWnd, R_SECURE) == false));
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// [OK] button
+void SmSaveKeyPairDlgOnOk(HWND hWnd, SM_SAVE_KEY_PAIR *s)
+{
+ UINT pkcs12;
+ char pass[MAX_SIZE];
+ char *password;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ pkcs12 = 0;
+
+ if (IsChecked(hWnd, R_PKCS12))
+ {
+ pkcs12 = 1;
+ }
+ else if (IsChecked(hWnd, R_SECURE))
+ {
+ pkcs12 = 2;
+ }
+ MsRegWriteInt(REG_CURRENT_USER, SM_REG_KEY, "SavePkcs12", pkcs12);
+
+ if (pkcs12 != 2)
+ {
+ GetTxtA(hWnd, E_PASS1, pass, sizeof(pass));
+
+ if (StrLen(pass) != 0)
+ {
+ password = pass;
+ }
+ else
+ {
+ password = NULL;
+ }
+
+ if (pkcs12 == false)
+ {
+ // Write to the X509 and KEY
+ wchar_t *x509_name, *key_name;
+ x509_name = SaveDlg(hWnd, _UU("DLG_CERT_FILES"), _UU("DLG_SAVE_CERT"), NULL, L".cer");
+ if (x509_name == NULL)
+ {
+ // Cancel
+ return;
+ }
+ else
+ {
+ wchar_t default_key_name[MAX_SIZE];
+ UniReplaceStrEx(default_key_name, sizeof(default_key_name), x509_name,
+ L".cer", L"", false);
+ UniReplaceStrEx(default_key_name, sizeof(default_key_name), default_key_name,
+ L".crt", L"", false);
+ UniStrCat(default_key_name, sizeof(default_key_name), L".key");
+ key_name = SaveDlg(hWnd, _UU("DLG_KEY_FILTER"), _UU("DLG_SAVE_KEY"),
+ default_key_name, L".key");
+ if (key_name == NULL)
+ {
+ // Cancel
+ Free(x509_name);
+ return;
+ }
+ else
+ {
+ bool ok = true;
+ wchar_t filename1[MAX_SIZE];
+ wchar_t filename2[MAX_SIZE];
+
+ UniStrCpy(filename1, sizeof(filename1), x509_name);
+ UniStrCpy(filename2, sizeof(filename2), key_name);
+
+ // Save the certificate
+ if (XToFileW(s->Cert, filename1, true) == false)
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("DLG_CERT_SAVE_ERROR"));
+ ok = false;
+ }
+ else
+ {
+ if (KToFileW(s->Key, filename2, true, password) == false)
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("DLG_KEY_SAVE_ERROR"));
+ ok = false;
+ }
+ }
+
+ if (ok)
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("DLG_KEY_PAIR_SAVE_OK"));
+ EndDialog(hWnd, true);
+ }
+
+ Free(key_name);
+ }
+ Free(x509_name);
+ }
+ }
+ else
+ {
+ // Write to the PKCS#12
+ wchar_t *name = SaveDlg(hWnd, _UU("DLG_PKCS12_FILTER"), _UU("DLG_SAVE_P12"), NULL, L".p12");
+ if (name == NULL)
+ {
+ // Cancel
+ return;
+ }
+ else
+ {
+ P12 *p12;
+ wchar_t filename[MAX_SIZE];
+ UniStrCpy(filename, sizeof(filename), name);
+
+ // Convert to PKCS#12
+ p12 = NewP12(s->Cert, s->Key, pass);
+ if (p12 == NULL)
+ {
+ // Failure
+ MsgBox(hWnd, MB_ICONSTOP, _UU("DLG_KEY_PAIR_SAVE_ERROR"));
+ }
+ else
+ {
+ // Save
+ if (P12ToFileW(p12, filename) == false)
+ {
+ // Failure
+ MsgBox(hWnd, MB_ICONSTOP, _UU("DLG_KEY_PAIR_SAVE_ERROR"));
+ }
+ else
+ {
+ // Success
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("DLG_KEY_PAIR_SAVE_OK"));
+ EndDialog(hWnd, true);
+ }
+ FreeP12(p12);
+ }
+
+ Free(name);
+ }
+ }
+ }
+ else
+ {
+ char default_name[MAX_SIZE];
+ char *object_name;
+ bool ok = false;
+ X *x;
+ K *k;
+ WINUI_SECURE_BATCH batch[] =
+ {
+ {WINUI_SECURE_WRITE_CERT, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL},
+ {WINUI_SECURE_WRITE_KEY, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL},
+ };
+
+ x = s->Cert;
+ k = s->Key;
+
+ // Generate the default name
+ GetPrintNameFromXA(default_name, sizeof(default_name), x);
+ ConvertSafeFileName(default_name, sizeof(default_name), default_name);
+
+ object_name = StringDlgA(hWnd, _UU("SEC_OBJECT_NAME_TITLE"),
+ _UU("SEC_OBJECT_NAME_INFO"), default_name, ICO_CERT, false, false);
+
+ if (object_name != NULL)
+ {
+ // Write and enumerate
+ batch[0].InputX = x;
+ batch[0].Name = object_name;
+ batch[1].InputK = k;
+ batch[1].Name = object_name;
+
+ if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), SmGetCurrentSecureIdFromReg(), 0) == false)
+ {
+ // Failure
+ }
+ else
+ {
+ ok = true;
+ }
+
+ Free(object_name);
+ }
+
+ if (ok)
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SEC_NEW_CERT_IMPORT_OK"));
+
+ EndDialog(hWnd, true);
+ }
+ }
+}
+
+// Saving dialog box of the certificate and private key
+UINT SmSaveKeyPairDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_SAVE_KEY_PAIR *s = (SM_SAVE_KEY_PAIR *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmSaveKeyPairDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_PASS1:
+ case E_PASS2:
+ case R_USE_PASS:
+ case R_SECURE:
+ case R_X509_AND_KEY:
+ case R_PKCS12:
+ SmSaveKeyPairDlgUpdate(hWnd, s);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ // [OK] button
+ SmSaveKeyPairDlgOnOk(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+
+ case R_USE_PASS:
+ if (IsChecked(hWnd, R_USE_PASS))
+ {
+ FocusEx(hWnd, E_PASS1);
+ }
+ break;
+
+ case B_SELECT:
+ SmSelectSecureId(hWnd);
+ SmSaveKeyPairDlgUpdate(hWnd, s);
+ break;
+
+ case B_SECURE_MANAGER:
+ CmSecureManagerEx(hWnd, SmGetCurrentSecureId(hWnd), true);
+ SmSaveKeyPairDlgUpdate(hWnd, s);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Save the certificate and private key
+bool SmSaveKeyPairDlg(HWND hWnd, X *x, K *k)
+{
+ SM_SAVE_KEY_PAIR s;
+ // Validate arguments
+ if (hWnd == NULL || x == NULL || k == NULL)
+ {
+ return false;
+ }
+
+ Zero(&s, sizeof(s));
+ s.Cert = x;
+ s.Key = k;
+
+ return Dialog(hWnd, D_SM_SAVE_KEY_PAIR, SmSaveKeyPairDlgProc, &s);
+}
+
+// OK is clicked on the SSL related dialog
+void SmSslDlgOnOk(HWND hWnd, SM_SSL *s)
+{
+ char *name;
+ RPC_KEEP t;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (s->p->ServerAdminMode == false)
+ {
+ EndDialog(hWnd, false);
+ return;
+ }
+
+ name = GetTextA(hWnd, C_CIPHER);
+ if (name == NULL)
+ {
+ return;
+ }
+ else
+ {
+ RPC_STR t;
+ Zero(&t, sizeof(t));
+ t.String = name;
+
+ // Set the encryption algorithm
+ if (CALL(hWnd, ScSetServerCipher(s->p->Rpc, &t)) == false)
+ {
+ Focus(hWnd, C_CIPHER);
+ return;
+ }
+ FreeRpcStr(&t);
+ }
+
+ if (s->SetCertAndKey)
+ {
+ // Set the certificate
+ RPC_KEY_PAIR t;
+ Zero(&t, sizeof(t));
+
+ t.Cert = CloneX(s->Cert);
+ t.Key = CloneK(s->Key);
+
+ if (CALL(hWnd, ScSetServerCert(s->p->Rpc, &t)) == false)
+ {
+ return;
+ }
+ FreeRpcKeyPair(&t);
+
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("CM_CERT_SET_MSG"));
+ }
+
+ Zero(&t, sizeof(t));
+ t.UseKeepConnect = IsChecked(hWnd, R_USE_KEEP_CONNECT);
+ GetTxtA(hWnd, E_HOSTNAME, t.KeepConnectHost, sizeof(t.KeepConnectHost));
+ t.KeepConnectPort = GetInt(hWnd, E_PORT);
+ t.KeepConnectInterval = GetInt(hWnd, E_INTERVAL);
+ t.KeepConnectProtocol = IsChecked(hWnd, R_UDP) ? 1 : 0;
+
+ CALL(hWnd, ScSetKeep(s->p->Rpc, &t));
+
+ if (GetCapsBool(s->p->CapsList, "b_support_syslog"))
+ {
+ if (s->p->ServerAdminMode)
+ {
+ SYSLOG_SETTING set;
+
+ Zero(&set, sizeof(set));
+ GetTxtA(hWnd, E_SYSLOG_HOSTNAME, set.Hostname, sizeof(set.Hostname));
+ set.Port = GetInt(hWnd, E_SYSLOG_PORT);
+ set.SaveType = CbGetSelect(hWnd, C_SYSLOG);
+
+ if (CALL(hWnd, ScSetSysLog(s->p->Rpc, &set)) == false)
+ {
+ return;
+ }
+ }
+ }
+
+ EndDialog(hWnd, true);
+}
+
+// SSL related dialog initialization
+void SmSslDlgInit(HWND hWnd, SM_SSL *s)
+{
+ UINT i;
+ TOKEN_LIST *cipher_list;
+ RPC_KEEP t;
+ bool private_key_exportable = false;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ // Set the encryption algorithm list
+ cipher_list = GetCipherList();
+ CbSetHeight(hWnd, C_CIPHER, 18);
+ for (i = 0;i < cipher_list->NumTokens;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ char *name = cipher_list->Token[i];
+ StrToUni(tmp, sizeof(tmp), name);
+ CbAddStr(hWnd, C_CIPHER, tmp, 0);
+ }
+
+ if (s->p != NULL)
+ {
+ // Get the encryption algorithm name from the server
+ RPC_STR t;
+ Zero(&t, sizeof(t));
+ if (CALL(hWnd, ScGetServerCipher(s->p->Rpc, &t)))
+ {
+ wchar_t tmp[MAX_SIZE];
+ StrToUni(tmp, sizeof(tmp), t.String);
+ SetText(hWnd, C_CIPHER, tmp);
+ FreeRpcStr(&t);
+ }
+ else
+ {
+ EndDialog(hWnd, 0);
+ return;
+ }
+ }
+
+ if (s->p != NULL)
+ {
+ wchar_t tmp[MAX_SIZE];
+ // Get the SSL certificate and private key from the server
+ RPC_KEY_PAIR t;
+ s->SetCertAndKey = false;
+ Zero(&t, sizeof(t));
+ if (CALL(hWnd, ScGetServerCert(s->p->Rpc, &t)))
+ {
+ // Copy the certificate and key
+ s->Cert = CloneX(t.Cert);
+ s->Key = CloneK(t.Key);
+
+ if (t.Key != NULL)
+ {
+ private_key_exportable = true;
+ }
+
+ FreeRpcKeyPair(&t);
+ }
+ else
+ {
+ EndDialog(hWnd, 0);
+ return;
+ }
+
+ // Show the Certificate Information
+ SmGetCertInfoStr(tmp, sizeof(tmp), s->Cert);
+ SetText(hWnd, S_CERT_INFO, tmp);
+ }
+
+ // Password change
+ SetEnable(hWnd, B_PASSWORD, s->p->ServerAdminMode);
+ SetEnable(hWnd, S_INFO4, s->p->ServerAdminMode);
+
+ // Enable / disable the button
+ SetEnable(hWnd, B_IMPORT, s->p->ServerAdminMode);
+ SetEnable(hWnd, B_EXPORT, s->p->ServerAdminMode && private_key_exportable);
+ SetEnable(hWnd, B_REGENERATE, s->p->ServerAdminMode);
+ SetEnable(hWnd, R_USE_KEEP_CONNECT, s->p->ServerAdminMode);
+ SetEnable(hWnd, B_UPDATE_CONFIG, s->p->Update != NULL);
+
+ if (s->p->ServerAdminMode && GetCapsBool(s->p->CapsList, "b_support_special_listener"))
+ {
+ SetEnable(hWnd, B_SPECIALLISTENER, true);
+ SetEnable(hWnd, S_INFO5, true);
+ }
+ else
+ {
+ SetEnable(hWnd, B_SPECIALLISTENER, false);
+ SetEnable(hWnd, S_INFO5, false);
+ }
+
+ if (s->p->ServerAdminMode == false)
+ {
+ Disable(hWnd, C_CIPHER);
+ }
+
+ if (CALL(hWnd, ScGetKeep(s->p->Rpc, &t)))
+ {
+ Check(hWnd, R_USE_KEEP_CONNECT, t.UseKeepConnect);
+ SetTextA(hWnd, E_HOSTNAME, t.KeepConnectHost);
+ SetIntEx(hWnd, E_PORT, t.KeepConnectPort);
+ SetInt(hWnd, E_INTERVAL, t.KeepConnectInterval);
+ Check(hWnd, R_TCP, t.KeepConnectProtocol == 0);
+ Check(hWnd, R_UDP, t.KeepConnectProtocol != 0);
+ }
+
+ CbSetHeight(hWnd, C_SYSLOG, 18);
+ CbReset(hWnd, C_SYSLOG);
+ CbAddStr(hWnd, C_SYSLOG, _UU("SM_SYSLOG_0"), SYSLOG_NONE);
+ CbAddStr(hWnd, C_SYSLOG, _UU("SM_SYSLOG_1"), SYSLOG_SERVER_LOG);
+ CbAddStr(hWnd, C_SYSLOG, _UU("SM_SYSLOG_2"), SYSLOG_SERVER_AND_HUB_SECURITY_LOG);
+ CbAddStr(hWnd, C_SYSLOG, _UU("SM_SYSLOG_3"), SYSLOG_SERVER_AND_HUB_ALL_LOG);
+
+ if (GetCapsBool(s->p->CapsList, "b_support_syslog"))
+ {
+ SYSLOG_SETTING set;
+
+ SetEnable(hWnd, C_SYSLOG, s->p->ServerAdminMode);
+ SetEnable(hWnd, E_SYSLOG_HOSTNAME, s->p->ServerAdminMode);
+ SetEnable(hWnd, E_SYSLOG_PORT, s->p->ServerAdminMode);
+ SetEnable(hWnd, S_01, s->p->ServerAdminMode);
+ SetEnable(hWnd, S_02, s->p->ServerAdminMode);
+
+ Zero(&set, sizeof(set));
+
+ if (CALL(hWnd, ScGetSysLog(s->p->Rpc, &set)))
+ {
+ SetTextA(hWnd, E_SYSLOG_HOSTNAME, set.Hostname);
+ SetInt(hWnd, E_SYSLOG_PORT, set.Port == 0 ? SYSLOG_PORT : set.Port);
+ CbSelect(hWnd, C_SYSLOG, set.SaveType);
+ }
+ }
+ else
+ {
+ Disable(hWnd, C_SYSLOG);
+ Disable(hWnd, E_SYSLOG_HOSTNAME);
+ Disable(hWnd, E_SYSLOG_PORT);
+ Disable(hWnd, S_01);
+ Disable(hWnd, S_02);
+ }
+
+ SmSslDlgUpdate(hWnd, s);
+}
+
+// SSL related dialog control update
+void SmSslDlgUpdate(HWND hWnd, SM_SSL *s)
+{
+ bool ok = true;
+ bool b;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ if (IsChecked(hWnd, R_USE_KEEP_CONNECT))
+ {
+ UINT i;
+ b = true;
+ if (IsEmpty(hWnd, E_HOSTNAME))
+ {
+ ok = false;
+ }
+ i = GetInt(hWnd, E_PORT);
+ if (i == 0 || i >= 65536)
+ {
+ ok = false;
+ }
+ i = GetInt(hWnd, E_INTERVAL);
+ if (i < 5 || i > 600)
+ {
+ ok = false;
+ }
+ }
+ else
+ {
+ b = false;
+ }
+
+ if (IsEnable(hWnd, C_SYSLOG))
+ {
+ UINT i = CbGetSelect(hWnd, C_SYSLOG);
+
+ SetEnable(hWnd, E_SYSLOG_HOSTNAME, i != SYSLOG_NONE);
+ SetEnable(hWnd, E_SYSLOG_PORT, i != SYSLOG_NONE);
+ SetEnable(hWnd, S_01, i != SYSLOG_NONE);
+ SetEnable(hWnd, S_02, i != SYSLOG_NONE);
+ }
+
+ SetEnable(hWnd, S_HOSTNAME, b);
+ SetEnable(hWnd, E_HOSTNAME, b);
+ SetEnable(hWnd, S_PORT, b);
+ SetEnable(hWnd, E_PORT, b);
+ SetEnable(hWnd, S_INTERVAL, b);
+ SetEnable(hWnd, E_INTERVAL, b);
+ SetEnable(hWnd, S_INTERVAL2, b);
+ SetEnable(hWnd, S_PROTOCOL, b);
+ SetEnable(hWnd, R_TCP, b);
+ SetEnable(hWnd, R_UDP, b);
+ SetEnable(hWnd, S_INFO, b);
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Get the certificate information string
+void SmGetCertInfoStr(wchar_t *str, UINT size, X *x)
+{
+ wchar_t subject[MAX_SIZE];
+ wchar_t issuer[MAX_SIZE];
+ wchar_t date[MAX_SIZE];
+ // Validate arguments
+ if (x == NULL || str == NULL)
+ {
+ if (str != NULL)
+ {
+ str[0] = 0;
+ }
+ return;
+ }
+
+ GetPrintNameFromName(subject, sizeof(subject), x->subject_name);
+ GetPrintNameFromName(issuer, sizeof(issuer), x->issuer_name);
+ GetDateStrEx64(date, sizeof(date), x->notAfter, NULL);
+
+ UniFormat(str, size, _UU("CM_CERT_INFO"), subject, issuer, date);
+}
+
+// Regenerate the server certificate
+bool SmRegenerateServerCert(HWND hWnd, SM_SERVER *server, char *default_cn, X **x, K **k, bool root_only)
+{
+ char defcn[MAX_SIZE];
+ // Validate arguments
+ if (server == NULL || x == NULL || k == NULL)
+ {
+ return false;
+ }
+
+ Zero(defcn, sizeof(defcn));
+ if (IsEmptyStr(default_cn) == false)
+ {
+ StrCpy(defcn, sizeof(defcn), default_cn);
+ }
+
+ if (IsEmptyStr(defcn))
+ {
+ // If default CN is not specified, copy from the setting of the DDNS server
+ DDNS_CLIENT_STATUS t;
+
+ Zero(&t, sizeof(t));
+
+ if (ScGetDDnsClientStatus(server->Rpc, &t) == ERR_NO_ERROR)
+ {
+ if (IsEmptyStr(t.CurrentFqdn) == false)
+ {
+ StrCpy(defcn, sizeof(defcn), t.CurrentFqdn);
+ }
+ }
+ }
+
+ if (IsEmptyStr(defcn))
+ {
+ // Copy from the certificate information of the current server
+ RPC_KEY_PAIR t;
+
+ Zero(&t, sizeof(t));
+
+ if (ScGetServerCert(server->Rpc, &t) == ERR_NO_ERROR)
+ {
+ if (t.Cert != NULL)
+ {
+ if (t.Cert->subject_name != NULL)
+ {
+ UniToStr(defcn, sizeof(defcn), t.Cert->subject_name->CommonName);
+ }
+ }
+
+ FreeRpcKeyPair(&t);
+ }
+ }
+
+ if (IsEmptyStr(defcn))
+ {
+ // Copy from the destination server name of the current connection settings
+ StrCpy(defcn, sizeof(defcn), server->ServerName);
+ }
+
+ // Create a new certificate in the Certificate Creation Tool
+ if (SmCreateCert(hWnd, x, k, true, defcn, root_only) == false)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// SSL related dialog procedure
+UINT SmSslDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_SSL *s = (SM_SSL *)param;
+ X *x;
+ K *k;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SmSslDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case R_USE_KEEP_CONNECT:
+ case E_HOSTNAME:
+ case E_PORT:
+ case E_INTERVAL:
+ case R_TCP:
+ case R_UDP:
+ case C_SYSLOG:
+ case E_SYSLOG_HOSTNAME:
+ case E_SYSLOG_PORT:
+ SmSslDlgUpdate(hWnd, s);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ // [OK] button
+ SmSslDlgOnOk(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+
+ case B_UPDATE_CONFIG:
+ // Update notification setting
+ ConfigUpdateUi(s->p->Update, hWnd);
+ break;
+
+ case B_IMPORT:
+ // Import
+ if (CmLoadXAndK(hWnd, &x, &k))
+ {
+ wchar_t tmp[MAX_SIZE];
+
+LABEL_APPLY_NEW_CERT:
+ FreeX(s->Cert);
+ FreeK(s->Key);
+ s->Cert = x;
+ s->Key = k;
+ s->SetCertAndKey = true;
+ // Show the Certificate Information
+ SmGetCertInfoStr(tmp, sizeof(tmp), s->Cert);
+ SetText(hWnd, S_CERT_INFO, tmp);
+ }
+ break;
+
+ case B_EXPORT:
+ // Export
+ SmSaveKeyPairDlg(hWnd, s->Cert, s->Key);
+ break;
+
+ case B_VIEW:
+ // Show the certificate
+ CertDlg(hWnd, s->Cert, NULL, true);
+ break;
+
+ case B_SPECIALLISTENER:
+ // Special listener configuration
+ SmSpecialListener(hWnd, s->p);
+ break;
+
+ case B_REGENERATE:
+ // Regenerating the certificate
+ if (SmRegenerateServerCert(hWnd, s->p, NULL, &x, &k, false))
+ {
+ // Confirmation message
+ if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_YESNO, _UU("SM_REGENERATE_CERT_MSG")) == IDYES)
+ {
+ goto LABEL_APPLY_NEW_CERT;
+ }
+ else
+ {
+ FreeX(x);
+ FreeK(k);
+ }
+ }
+ break;
+
+ case B_PASSWORD:
+ // Password change
+ Dialog(hWnd, D_SM_CHANGE_PASSWORD, SmChangeServerPasswordDlg, s->p);
+ break;
+
+ case R_USE_KEEP_CONNECT:
+ if (IsChecked(hWnd, R_USE_KEEP_CONNECT))
+ {
+ FocusEx(hWnd, E_HOSTNAME);
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Display the SSL related dialog
+void SmSslDlg(HWND hWnd, SM_SERVER *p)
+{
+ SM_SSL s;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Zero(&s, sizeof(s));
+ s.p = p;
+
+ Dialog(hWnd, D_SM_SSL, SmSslDlgProc, &s);
+
+ // Cleanup
+ FreeX(s.Cert);
+ FreeK(s.Key);
+}
+
+// Listener creation dialog procedure
+UINT SmCreateListenerDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ UINT port;
+ RPC_LISTENER t;
+ SM_SERVER *p = (SM_SERVER *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ Focus(hWnd, E_PORT);
+ Disable(hWnd, IDOK);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_PORT:
+ port = GetInt(hWnd, E_PORT);
+ if (port == 0 || port >= 65536)
+ {
+ Disable(hWnd, IDOK);
+ }
+ else
+ {
+ Enable(hWnd, IDOK);
+ }
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ port = GetInt(hWnd, E_PORT);
+ Zero(&t, sizeof(t));
+ t.Enable = true;
+ t.Port = port;
+ if (CALL(hWnd, ScCreateListener(p->Rpc, &t)))
+ {
+ EndDialog(hWnd, true);
+ }
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Listener creation dialog
+bool SmCreateListenerDlg(HWND hWnd, SM_SERVER *p)
+{
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return false;
+ }
+
+ return Dialog(hWnd, D_SM_CREATE_LISTENER, SmCreateListenerDlgProc, p);
+}
+
+// HUB edit OK button
+void SmEditHubOnOk(HWND hWnd, SM_EDIT_HUB *s)
+{
+ RPC_CREATE_HUB t;
+ char pass1[MAX_SIZE];
+ char pass2[MAX_SIZE];
+ char hubname[MAX_HUBNAME_LEN + 1];
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ if (s->EditMode)
+ {
+ StrCpy(hubname, sizeof(hubname), s->HubName);
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ }
+ else
+ {
+ GetTxtA(hWnd, E_HUBNAME, t.HubName, sizeof(t.HubName));
+ StrCpy(hubname, sizeof(hubname), t.HubName);
+ }
+
+ GetTxtA(hWnd, E_PASSWORD1, pass1, sizeof(pass1));
+ GetTxtA(hWnd, E_PASSWORD2, pass2, sizeof(pass2));
+
+ if (s->EditMode == false || StrCmp(pass1, HIDDEN_PASSWORD) != 0)
+ {
+ Hash(t.HashedPassword, pass1, StrLen(pass1), true);
+ HashPassword(t.SecurePassword, ADMINISTRATOR_USERNAME, pass1);
+ }
+
+ if (IsChecked(hWnd, R_LIMIT_MAX_SESSION))
+ {
+ t.HubOption.MaxSession = GetInt(hWnd, E_MAX_SESSION);
+ }
+
+ t.Online = IsChecked(hWnd, R_ONLINE);
+
+ if (s->p->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ t.HubType = HUB_TYPE_FARM_STATIC;
+ if (IsChecked(hWnd, R_DYNAMIC))
+ {
+ t.HubType = HUB_TYPE_FARM_DYNAMIC;
+ }
+ }
+
+ t.HubOption.NoEnum = IsChecked(hWnd, R_NO_ENUM);
+
+ if (s->EditMode == false)
+ {
+ if (CALL(hWnd, ScCreateHub(s->p->Rpc, &t)))
+ {
+ MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("CM_EDIT_HUB_CREATER"), hubname);
+ EndDialog(hWnd, true);
+ }
+ }
+ else
+ {
+ if (CALL(hWnd, ScSetHub(s->p->Rpc, &t)))
+ {
+ EndDialog(hWnd, true);
+ }
+ }
+}
+
+// HUB editing update
+void SmEditHubUpdate(HWND hWnd, SM_EDIT_HUB *s)
+{
+ bool ok = true;
+ char *s1, *s2;
+ char hubname[MAX_HUBNAME_LEN + 1];
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ s1 = GetTextA(hWnd, E_PASSWORD1);
+ s2 = GetTextA(hWnd, E_PASSWORD2);
+ if (StrCmp(s1, s2) != 0)
+ {
+ ok = false;
+ }
+ Free(s1);
+ Free(s2);
+
+ GetTxtA(hWnd, E_HUBNAME, hubname, sizeof(hubname));
+ Trim(hubname);
+ if (StrLen(hubname) == 0 ||
+ IsSafeStr(hubname) == false)
+ {
+ ok = false;
+ }
+
+ if (IsChecked(hWnd, R_LIMIT_MAX_SESSION))
+ {
+ Enable(hWnd, E_MAX_SESSION);
+ Enable(hWnd, S_MAX_SESSION_1);
+ Enable(hWnd, S_MAX_SESSION_2);
+ if (GetInt(hWnd, E_MAX_SESSION) == 0)
+ {
+ ok = false;
+ }
+ }
+ else
+ {
+ Disable(hWnd, E_MAX_SESSION);
+ Disable(hWnd, S_MAX_SESSION_1);
+ Disable(hWnd, S_MAX_SESSION_2);
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// HUB editing initialization
+void SmEditHubInit(HWND hWnd, SM_EDIT_HUB *s)
+{
+ RPC_CREATE_HUB t;
+ bool b = false;
+ bool support_extoption = false;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_HUB);
+
+ Zero(&t, sizeof(t));
+
+ if (s->EditMode == false)
+ {
+ // Create new
+ SetText(hWnd, 0, _UU("CM_EDIT_HUB_1"));
+ FocusEx(hWnd, E_HUBNAME);
+
+ if (s->p->ServerType == SERVER_TYPE_STANDALONE)
+ {
+ // Stand-alone mode
+ Disable(hWnd, R_STATIC);
+ Disable(hWnd, R_DYNAMIC);
+ SetText(hWnd, S_FARM_INFO, _UU("CM_EDIT_HUB_STANDALONE"));
+ }
+ else
+ {
+ Check(hWnd, R_STATIC, true);
+ }
+
+ Check(hWnd, R_ONLINE, true);
+
+ Hide(hWnd, B_ACL);
+ Hide(hWnd, S_ACL);
+ Hide(hWnd, S_ACL_2);
+ Hide(hWnd, S_ACL_3);
+ Hide(hWnd, S_MSG_1);
+ Hide(hWnd, S_MSG_4);
+ Hide(hWnd, S_MSG_2);
+ Hide(hWnd, B_MSG);
+ }
+ else
+ {
+ // Edit
+ wchar_t tmp[MAX_SIZE];
+ UniFormat(tmp, sizeof(tmp), _UU("CM_EDIT_HUB_2"), s->HubName);
+ SetText(hWnd, 0, tmp);
+ SetTextA(hWnd, E_HUBNAME, s->HubName);
+ Disable(hWnd, E_HUBNAME);
+
+ if (s->p->ServerType == SERVER_TYPE_STANDALONE)
+ {
+ // Stand-alone mode
+ Disable(hWnd, R_STATIC);
+ Disable(hWnd, R_DYNAMIC);
+ SetText(hWnd, S_FARM_INFO, _UU("CM_EDIT_HUB_STANDALONE"));
+ }
+
+ if (s->p->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ // Controller
+ if (GetCapsBool(s->p->CapsList, "b_cluster_hub_type_fixed"))
+ {
+ Disable(hWnd, R_STATIC);
+ Disable(hWnd, R_DYNAMIC);
+ SetText(hWnd, S_FARM_INFO, _UU("CM_EDIT_HUB_TYPE_FIXED"));
+ }
+ }
+
+ // Get the HUB information
+ StrCpy(t.HubName, sizeof(t.HubName), s->HubName);
+ if (CALL(hWnd, ScGetHub(s->p->Rpc, &t)) == false)
+ {
+ EndDialog(hWnd, false);
+ return;
+ }
+
+ SetTextA(hWnd, E_PASSWORD1, HIDDEN_PASSWORD);
+ SetTextA(hWnd, E_PASSWORD2, HIDDEN_PASSWORD);
+
+ if (t.HubOption.MaxSession == 0)
+ {
+ Check(hWnd, R_LIMIT_MAX_SESSION, false);
+ }
+ else
+ {
+ Check(hWnd, R_LIMIT_MAX_SESSION, true);
+ }
+
+ Check(hWnd, R_NO_ENUM, t.HubOption.NoEnum);
+
+ SetIntEx(hWnd, E_MAX_SESSION, t.HubOption.MaxSession);
+
+ Check(hWnd, R_ONLINE, t.Online);
+ Check(hWnd, R_OFFLINE, t.Online ? false : true);
+
+ Check(hWnd, R_STATIC, t.HubType == HUB_TYPE_FARM_STATIC);
+ Check(hWnd, R_DYNAMIC, t.HubType == HUB_TYPE_FARM_DYNAMIC);
+
+ SetShow(hWnd, B_ACL, GetCapsBool(s->p->CapsList, "b_support_ac"));
+ SetShow(hWnd, S_ACL, GetCapsBool(s->p->CapsList, "b_support_ac"));
+ SetShow(hWnd, S_ACL_2, GetCapsBool(s->p->CapsList, "b_support_ac"));
+ SetShow(hWnd, S_ACL_3, GetCapsBool(s->p->CapsList, "b_support_ac"));
+
+ SetShow(hWnd, S_MSG_1, GetCapsBool(s->p->CapsList, "b_support_msg"));
+ SetShow(hWnd, S_MSG_4, GetCapsBool(s->p->CapsList, "b_support_msg"));
+ SetShow(hWnd, S_MSG_2, GetCapsBool(s->p->CapsList, "b_support_msg"));
+ SetShow(hWnd, B_MSG, GetCapsBool(s->p->CapsList, "b_support_msg"));
+ }
+
+ // Advanced options
+ if (s->EditMode)
+ {
+ support_extoption = GetCapsBool(s->p->CapsList, "b_support_hub_ext_options");
+ }
+
+ SetEnable(hWnd, S_STATIC, support_extoption);
+ SetEnable(hWnd, B_EXTOPTION, support_extoption);
+
+ SetEnable(hWnd, R_NO_ENUM, GetCapsBool(s->p->CapsList, "b_support_hide_hub"));
+
+ SmEditHubUpdate(hWnd, s);
+
+ if (s->EditMode)
+ {
+ Focus(hWnd, IDOK);
+ }
+
+ if (s->EditMode)
+ {
+ if (GetCapsBool(s->p->CapsList, "b_support_hub_admin_option"))
+ {
+ b = true;
+ }
+ }
+
+ SetShow(hWnd, S_AO_1, b);
+ SetShow(hWnd, S_AO_2, b);
+ SetShow(hWnd, S_AO_3, b);
+ SetShow(hWnd, B_ADMINOPTION, b);
+}
+
+// HUB edit procedure
+UINT SmEditHubProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_EDIT_HUB *s = (SM_EDIT_HUB *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmEditHubInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_PASSWORD1:
+ case E_PASSWORD2:
+ case E_HUBNAME:
+ case R_LIMIT_MAX_SESSION:
+ case E_MAX_SESSION:
+ SmEditHubUpdate(hWnd, s);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ SmEditHubOnOk(hWnd, s);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case R_LIMIT_MAX_SESSION:
+ if (IsChecked(hWnd, R_LIMIT_MAX_SESSION))
+ {
+ FocusEx(hWnd, E_MAX_SESSION);
+ }
+ break;
+
+ case B_ADMINOPTION:
+ SmHubAdminOption(hWnd, s);
+ break;
+
+ case B_EXTOPTION:
+ SmHubExtOption(hWnd, s);
+ break;
+
+ case B_ACL:
+ SmHubAc(hWnd, s);
+ break;
+
+ case B_MSG:
+ SmHubMsg(hWnd, s);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// HUB edit dialog
+bool SmEditHubDlg(HWND hWnd, SM_SERVER *p, char *hubname)
+{
+ SM_EDIT_HUB s;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return false;
+ }
+
+ Zero(&s, sizeof(s));
+ s.p = p;
+ s.EditMode = true;
+ StrCpy(s.HubName, sizeof(s.HubName), hubname);
+
+ if (p->Bridge == false)
+ {
+ return Dialog(hWnd, D_SM_EDIT_HUB, SmEditHubProc, &s);
+ }
+ else
+ {
+ SmHubExtOption(hWnd, &s);
+ return false;
+ }
+}
+
+// HUB creation dialog
+bool SmCreateHubDlg(HWND hWnd, SM_SERVER *p)
+{
+ SM_EDIT_HUB s;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return false;
+ }
+
+ Zero(&s, sizeof(s));
+ s.p = p;
+ s.EditMode = false;
+
+ return Dialog(hWnd, D_SM_EDIT_HUB, SmEditHubProc, &s);
+}
+
+// Display the status of the virtual HUB
+bool SmRefreshHubStatus(HWND hWnd, SM_SERVER *p, void *param)
+{
+ RPC_HUB_STATUS t;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL || param == NULL)
+ {
+ return false;
+ }
+
+ Zero(&t, sizeof(RPC_HUB_STATUS));
+ StrCpy(t.HubName, sizeof(t.HubName), (char *)param);
+ if (CALL(hWnd, ScGetHubStatus(p->Rpc, &t)))
+ {
+ wchar_t *s;
+ wchar_t tmp[MAX_SIZE];
+ LVB *b = LvInsertStart();
+
+ // HUB name
+ s = CopyStrToUni((char *)param);
+ LvInsertAdd(b, ICO_HUB, 0, 2, _UU("SM_HUB_STATUS_HUBNAME"), s);
+ Free(s);
+
+ // Online
+ LvInsertAdd(b, t.Online ? ICO_PROTOCOL : ICO_PROTOCOL_X, 0, 2, _UU("SM_HUB_STATUS_ONLINE"),
+ t.Online ? _UU("SM_HUB_ONLINE") : _UU("SM_HUB_OFFLINE"));
+
+ // Type of HUB
+ LvInsertAdd(b, t.HubType == HUB_TYPE_STANDALONE ? ICO_TOWER : ICO_FARM, 0, 2, _UU("SM_HUB_TYPE"),
+ GetHubTypeStr(t.HubType));
+
+ if (t.HubType == HUB_TYPE_STANDALONE)
+ {
+ // Enable / Disable the SecureNAT
+ LvInsertAdd(b, ICO_ROUTER, NULL, 2, _UU("SM_HUB_SECURE_NAT"),
+ t.SecureNATEnabled ? _UU("SM_HUB_SECURE_NAT_YES") : _UU("SM_HUB_SECURE_NAT_NO"));
+ }
+
+ // Other values
+ UniToStru(tmp, t.NumSessions);
+ LvInsertAdd(b, ICO_PROTOCOL, 0, 2, _UU("SM_HUB_NUM_SESSIONS"), tmp);
+ if (t.NumSessionsClient != 0 || t.NumSessionsBridge != 0)
+ {
+ UniToStru(tmp, t.NumSessionsClient);
+ LvInsertAdd(b, ICO_PROTOCOL, 0, 2, _UU("SM_HUB_NUM_SESSIONS_CLIENT"), tmp);
+ UniToStru(tmp, t.NumSessionsBridge);
+ LvInsertAdd(b, ICO_PROTOCOL, 0, 2, _UU("SM_HUB_NUM_SESSIONS_BRIDGE"), tmp);
+ }
+
+ UniToStru(tmp, t.NumAccessLists);
+ LvInsertAdd(b, ICO_DISCARD, 0, 2, _UU("SM_HUB_NUM_ACCESSES"), tmp);
+
+ if (p->ServerType != SERVER_TYPE_FARM_MEMBER)
+ {
+ UniToStru(tmp, t.NumUsers);
+ LvInsertAdd(b, ICO_USER, 0, 2, _UU("SM_HUB_NUM_USERS"), tmp);
+ UniToStru(tmp, t.NumGroups);
+ LvInsertAdd(b, ICO_GROUP, 0, 2, _UU("SM_HUB_NUM_GROUPS"), tmp);
+ }
+
+ UniToStru(tmp, t.NumMacTables);
+ LvInsertAdd(b, ICO_MACHINE, 0, 2, _UU("SM_HUB_NUM_MAC_TABLES"), tmp);
+ UniToStru(tmp, t.NumIpTables);
+ LvInsertAdd(b, ICO_MACHINE, 0, 2, _UU("SM_HUB_NUM_IP_TABLES"), tmp);
+
+ // Usage status
+ UniToStru(tmp, t.NumLogin);
+ LvInsertAdd(b, ICO_KEY, NULL, 2, _UU("SM_HUB_NUM_LOGIN"), tmp);
+
+ if (t.LastLoginTime != 0)
+ {
+ GetDateTimeStr64Uni(tmp, sizeof(tmp), SystemToLocal64(t.LastLoginTime));
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("COMMON_UNKNOWN"));
+ }
+ LvInsertAdd(b, ICO_DATETIME, NULL, 2, _UU("SM_HUB_LAST_LOGIN_TIME"), tmp);
+
+ if (t.LastCommTime != 0)
+ {
+ GetDateTimeStr64Uni(tmp, sizeof(tmp), SystemToLocal64(t.LastCommTime));
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("COMMON_UNKNOWN"));
+ }
+ LvInsertAdd(b, ICO_DATETIME, NULL, 2, _UU("SM_HUB_LAST_COMM_TIME"), tmp);
+
+ if (t.CreatedTime != 0)
+ {
+ GetDateTimeStr64Uni(tmp, sizeof(tmp), SystemToLocal64(t.CreatedTime));
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("COMMON_UNKNOWN"));
+ }
+ LvInsertAdd(b, ICO_DATETIME, NULL, 2, _UU("SM_HUB_CREATED_TIME"), tmp);
+
+ // Traffic information
+ SmInsertTrafficInfo(b, &t.Traffic);
+
+ LvInsertEnd(b, hWnd, L_STATUS);
+ }
+ else
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Add a traffic information to LVB
+void SmInsertTrafficInfo(LVB *b, TRAFFIC *t)
+{
+ wchar_t tmp[MAX_SIZE];
+ char vv[128];
+ // Validate arguments
+ if (b == NULL || t == NULL)
+ {
+ return;
+ }
+
+ // Transmission information
+ ToStr3(vv, sizeof(vv), t->Send.UnicastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+ LvInsertAdd(b, ICO_INFORMATION, 0, 2, _UU("SM_ST_SEND_UCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), t->Send.UnicastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+ LvInsertAdd(b, ICO_INFORMATION, 0, 2, _UU("SM_ST_SEND_UCAST_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), t->Send.BroadcastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+ LvInsertAdd(b, ICO_INFORMATION, 0, 2, _UU("SM_ST_SEND_BCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), t->Send.BroadcastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+ LvInsertAdd(b, ICO_INFORMATION, 0, 2, _UU("SM_ST_SEND_BCAST_SIZE"), tmp);
+
+ // Reception information
+ ToStr3(vv, sizeof(vv), t->Recv.UnicastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+ LvInsertAdd(b, ICO_INFORMATION, 0, 2, _UU("SM_ST_RECV_UCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), t->Recv.UnicastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+ LvInsertAdd(b, ICO_INFORMATION, 0, 2, _UU("SM_ST_RECV_UCAST_SIZE"), tmp);
+
+ ToStr3(vv, sizeof(vv), t->Recv.BroadcastCount);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_NUM_PACKET_STR"), vv);
+ LvInsertAdd(b, ICO_INFORMATION, 0, 2, _UU("SM_ST_RECV_BCAST_NUM"), tmp);
+
+ ToStr3(vv, sizeof(vv), t->Recv.BroadcastBytes);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_ST_SIZE_BYTE_STR"), vv);
+ LvInsertAdd(b, ICO_INFORMATION, 0, 2, _UU("SM_ST_RECV_BCAST_SIZE"), tmp);
+}
+
+// Status display dialog procedure
+UINT SmStatusDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_STATUS *s = (SM_STATUS *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ LvInitEx(hWnd, L_STATUS, s->NoImage);
+ LvSetStyle(hWnd, L_STATUS, LVS_EX_GRIDLINES);
+ SetIcon(hWnd, 0, s->Icon);
+ SetIcon(hWnd, S_ICON, s->Icon);
+ SetText(hWnd, 0, s->Caption);
+ SetText(hWnd, S_TITLE, s->Caption);
+ DlgFont(hWnd, S_TITLE, 15, true);
+ if (s->InitProc != NULL)
+ {
+ s->InitProc(hWnd, s->p, s->Param);
+ }
+ else
+ {
+ // Initialize the column
+ LvInsertColumn(hWnd, L_STATUS, 0, _UU("SM_STATUS_COLUMN_1"), 0);
+ LvInsertColumn(hWnd, L_STATUS, 1, _UU("SM_STATUS_COLUMN_2"), 0);
+ }
+ if (s->RefreshProc(hWnd, s->p, s->Param) == false)
+ {
+ Close(hWnd);
+ }
+ LvAutoSize(hWnd, L_STATUS);
+ Focus(hWnd, L_STATUS);
+
+ if (s->show_refresh_button == false)
+ {
+ Hide(hWnd, IDOK);
+ }
+
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ // Update
+ if (s->RefreshProc(hWnd, s->p, s->Param) == false)
+ {
+ Close(hWnd);
+ }
+ LvAutoSize(hWnd, L_STATUS);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_STATUS);
+
+ return 0;
+}
+
+// Status display dialog
+void SmStatusDlg(HWND hWnd, SM_SERVER *p, void *param, bool no_image, bool show_refresh_button, wchar_t *caption, UINT icon,
+ SM_STATUS_INIT_PROC *init, SM_STATUS_REFRESH_PROC *refresh)
+{
+ SM_STATUS s;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL || refresh == NULL)
+ {
+ return;
+ }
+
+ if (icon == 0)
+ {
+ icon = ICO_INFORMATION;
+ }
+ if (caption == NULL)
+ {
+ caption = _UU("SM_INFORMATION");
+ }
+
+ Zero(&s, sizeof(s));
+ s.show_refresh_button = show_refresh_button;
+ s.p = p;
+ s.NoImage = no_image;
+ s.Param = param;
+ s.Icon = icon;
+ s.Caption = caption;
+ s.InitProc = init;
+ s.RefreshProc = refresh;
+
+ Dialog(hWnd, D_SM_STATUS, SmStatusDlgProc, &s);
+}
+
+// Server management dialog update
+void SmServerDlgUpdate(HWND hWnd, SM_SERVER *p)
+{
+ bool hub_selected = false;
+ bool hub_selected_online = false;
+ bool hub_selected_offline = false;
+ bool hub_have_admin_right = false;
+ bool listener_selected = false;
+ bool listener_selected_enabled = false;
+ bool listener_selected_disabled = false;
+ bool two_or_more_listener = false;
+ bool bridge;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ bridge = GetCapsBool(p->CapsList, "b_bridge");
+
+ hub_selected = LvIsSelected(hWnd, L_HUB);
+
+ if (hub_selected)
+ {
+ if (p->ServerAdminMode)
+ {
+ hub_have_admin_right = true;
+ }
+ i = LvGetSelected(hWnd, L_HUB);
+ if (i != INFINITE)
+ {
+ wchar_t *s = LvGetStr(hWnd, L_HUB, i, 1);
+ if (p->ServerAdminMode == false)
+ {
+ char *hubname = LvGetStrA(hWnd, L_HUB, i, 0);
+ if (hubname != NULL)
+ {
+ if (StrCmpi(hubname, p->HubName) == 0)
+ {
+ hub_have_admin_right = true;
+ }
+ Free(hubname);
+ }
+ }
+ hub_selected_online = (UniStrCmpi(s, _UU("SM_HUB_ONLINE")) == 0);
+ hub_selected_offline = hub_selected_online ? false : true;
+ Free(s);
+ }
+ }
+
+ listener_selected = LvIsSelected(hWnd, L_LISTENER);
+ if (listener_selected)
+ {
+ wchar_t *s = LvGetSelectedStr(hWnd, L_LISTENER, 1);
+ if (UniStrCmpi(s, _UU("CM_LISTENER_OFFLINE")) == 0)
+ {
+ listener_selected_disabled = true;
+ }
+ else
+ {
+ listener_selected_enabled = true;
+ }
+ Free(s);
+ }
+
+ if (LvNum(hWnd, L_LISTENER) >= 2)
+ {
+ two_or_more_listener = true;
+ }
+
+ SetEnable(hWnd, IDOK, bridge || (hub_selected && hub_have_admin_right));
+ SetEnable(hWnd, B_ONLINE, bridge == false && hub_selected_offline && hub_have_admin_right && p->ServerType != SERVER_TYPE_FARM_MEMBER);
+ SetEnable(hWnd, B_OFFLINE, bridge == false && hub_selected_online && hub_have_admin_right && p->ServerType != SERVER_TYPE_FARM_MEMBER);
+ SetEnable(hWnd, B_HUB_STATUS, hub_selected && hub_have_admin_right);
+ SetEnable(hWnd, B_DELETE, bridge == false && hub_selected && p->ServerAdminMode && p->ServerType != SERVER_TYPE_FARM_MEMBER);
+ SetEnable(hWnd, B_EDIT, hub_selected && hub_have_admin_right && p->ServerType != SERVER_TYPE_FARM_MEMBER);
+ SetEnable(hWnd, B_CREATE, bridge == false && p->ServerAdminMode && p->ServerType != SERVER_TYPE_FARM_MEMBER);
+
+ SetEnable(hWnd, B_CREATE_LISTENER, p->ServerAdminMode);
+ SetEnable(hWnd, B_DELETE_LISTENER, p->ServerAdminMode && listener_selected && two_or_more_listener);
+ SetEnable(hWnd, B_START, p->ServerAdminMode && listener_selected_disabled);
+ SetEnable(hWnd, B_STOP, p->ServerAdminMode && listener_selected_enabled);
+ SetEnable(hWnd, B_FARM, GetCapsBool(p->CapsList, "b_support_cluster") && p->ServerAdminMode && GetCapsBool(p->CapsList, "b_support_vgs_in_client") == false);
+ SetEnable(hWnd, B_FARM_STATUS, GetCapsBool(p->CapsList, "b_support_cluster") && p->ServerType != SERVER_TYPE_STANDALONE);
+}
+
+// Server management dialog initialization
+void SmServerDlgInit(HWND hWnd, SM_SERVER *p)
+{
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ // Initialize the column
+ LvInit(hWnd, L_HUB);
+ LvSetStyle(hWnd, L_HUB, LVS_EX_GRIDLINES);
+ LvInsertColumn(hWnd, L_HUB, 0, _UU("SM_HUB_COLUMN_1"), 150);
+ LvInsertColumn(hWnd, L_HUB, 1, _UU("SM_HUB_COLUMN_2"), 80);
+ LvInsertColumn(hWnd, L_HUB, 2, _UU("SM_HUB_COLUMN_3"), 80);
+ LvInsertColumn(hWnd, L_HUB, 3, _UU("SM_HUB_COLUMN_4"), 80);
+ LvInsertColumn(hWnd, L_HUB, 4, _UU("SM_HUB_COLUMN_5"), 80);
+ LvInsertColumn(hWnd, L_HUB, 5, _UU("SM_HUB_COLUMN_6"), 80);
+ LvInsertColumn(hWnd, L_HUB, 6, _UU("SM_HUB_COLUMN_7"), 80);
+ LvInsertColumn(hWnd, L_HUB, 7, _UU("SM_HUB_COLUMN_8"), 80);
+ LvInsertColumn(hWnd, L_HUB, 8, _UU("SM_HUB_COLUMN_9"), 80);
+ LvInsertColumn(hWnd, L_HUB, 9, _UU("SM_HUB_COLUMN_10"), 120);
+ LvInsertColumn(hWnd, L_HUB, 10, _UU("SM_HUB_COLUMN_11"), 120);
+ LvInsertColumn(hWnd, L_HUB, 11, _UU("SM_SESS_COLUMN_6"), 100);
+ LvInsertColumn(hWnd, L_HUB, 12, _UU("SM_SESS_COLUMN_7"), 100);
+
+ LvInit(hWnd, L_LISTENER);
+ LvSetStyle(hWnd, L_LISTENER, LVS_EX_GRIDLINES);
+ LvInsertColumn(hWnd, L_LISTENER, 0, _UU("CM_LISTENER_COLUMN_1"), 90);
+ LvInsertColumn(hWnd, L_LISTENER, 1, _UU("CM_LISTENER_COLUMN_2"), 80);
+
+ SmServerDlgRefresh(hWnd, p);
+
+ if (p->ServerAdminMode == false)
+ {
+ // Select the target HUB in the case of the Virtual HUB management mode
+ wchar_t *s = CopyStrToUni(p->HubName);
+ LvSelect(hWnd, L_HUB, LvSearchStr(hWnd, L_HUB, 0, s));
+ Free(s);
+ }
+ else
+ {
+ // In the case of whole server management mode
+ UINT num_hubs = LvNum(hWnd, L_HUB);
+
+ if (num_hubs == 1)
+ {
+ // Select the Virtual HUB if Virtual HUB exists only one
+ LvSelect(hWnd, L_HUB, 0);
+ }
+ else
+ {
+ // Select the Virtual HUB the last selected if there are some virtual HUBs
+ char tmp[MAX_SIZE];
+ char *hubname;
+
+ Format(tmp, sizeof(tmp), "%s:%u:%s", p->CurrentSetting->ClientOption.Hostname,
+ p->CurrentSetting->ClientOption.Port,
+ p->CurrentSetting->ServerAdminMode ? "" : p->CurrentSetting->HubName);
+
+ hubname = MsRegReadStr(REG_CURRENT_USER, SM_LASTHUB_REG_KEY, tmp);
+
+ if (IsEmptyStr(hubname) == false)
+ {
+ LvSelect(hWnd, L_HUB, LvSearchStrA(hWnd, L_HUB, 0, hubname));
+ }
+
+ Free(hubname);
+ }
+ }
+
+ Focus(hWnd, L_HUB);
+
+ SmServerDlgUpdate(hWnd, p);
+
+ if (GetCapsBool(p->CapsList, "b_bridge"))
+ {
+ Disable(hWnd, L_HUB);
+ }
+
+ // Enable Local bridge button, etc. in the case of the Admin of the Server
+ SetEnable(hWnd, B_BRIDGE, GetCapsBool(p->CapsList, "b_local_bridge") && p->ServerAdminMode && GetCapsBool(p->CapsList, "b_support_vgs_in_client") == false);
+ SetEnable(hWnd, B_CONNECTION, p->ServerAdminMode);
+
+ // Config R/W button
+ SetEnable(hWnd, B_CONFIG, GetCapsBool(p->CapsList, "b_support_config_rw") && p->ServerAdminMode && GetCapsBool(p->CapsList, "b_support_vgs_in_client") == false);
+
+ // Layer 3 button
+ SetEnable(hWnd, B_L3, GetCapsBool(p->CapsList, "b_support_layer3") && p->ServerAdminMode && GetCapsBool(p->CapsList, "b_support_vgs_in_client") == false);
+
+ // License button
+ SetShow(hWnd, B_LICENSE, GetCapsBool(p->CapsList, "b_support_license") && p->ServerAdminMode);
+ SetShow(hWnd, S_LICENSE, GetCapsBool(p->CapsList, "b_support_license") && p->ServerAdminMode);
+ SetShow(hWnd, S_BETA, GetCapsBool(p->CapsList, "b_beta_version") && (IsShow(hWnd, B_LICENSE) == false));
+
+ // IPsec button
+ SetEnable(hWnd, B_IPSEC, GetCapsBool(p->CapsList, "b_support_ipsec") && p->ServerAdminMode);
+
+ // OpenVPN, SSTP button
+ SetEnable(hWnd, B_OPENVPN, GetCapsBool(p->CapsList, "b_support_openvpn") && p->ServerAdminMode);
+
+ // DDNS button
+ SetEnable(hWnd, B_DDNS, GetCapsBool(p->CapsList, "b_support_ddns") && p->ServerAdminMode);
+
+ // VPN Azure button
+ SetEnable(hWnd, B_AZURE, GetCapsBool(p->CapsList, "b_support_azure") && p->ServerAdminMode);
+
+ DlgFont(hWnd, S_BETA, 12, false);
+ SetFont(hWnd, E_DDNS_HOST, GetFont("Verdana", 10, false, false, false, false));
+ SetFont(hWnd, E_AZURE_HOST, GetFont("Verdana", 10, false, false, false, false));
+
+ SetShow(hWnd, B_VPNGATE, false);
+ SetShow(hWnd, S_ICO_VPNGATE, false);
+
+ DlgFont(hWnd, IDOK, 0, true);
+}
+
+// Server management dialog update
+void SmServerDlgRefresh(HWND hWnd, SM_SERVER *p)
+{
+ RPC_ENUM_HUB t;
+ DDNS_CLIENT_STATUS st;
+ RPC_AZURE_STATUS sta;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ // Virtual HUB list update
+ Zero(&t, sizeof(t));
+ if (CALL(hWnd, ScEnumHub(p->Rpc, &t)))
+ {
+ LVB *b = LvInsertStart();
+ for (i = 0;i < t.NumHub;i++)
+ {
+ RPC_ENUM_HUB_ITEM *e = &t.Hubs[i];
+ wchar_t name[MAX_HUBNAME_LEN + 1];
+ wchar_t s1[64], s2[64], s3[64], s4[64], s5[64];
+ wchar_t s6[64], s7[128], s8[128];
+ wchar_t s9[64], s10[64];
+ UINT icon;
+
+ UniToStru(s1, e->NumUsers);
+ UniToStru(s2, e->NumGroups);
+ UniToStru(s3, e->NumSessions);
+ UniToStru(s4, e->NumMacTables);
+ UniToStru(s5, e->NumIpTables);
+
+ UniToStru(s6, e->NumLogin);
+
+ if (e->LastLoginTime != 0)
+ {
+ GetDateTimeStr64Uni(s7, sizeof(s7), SystemToLocal64(e->LastLoginTime));
+ }
+ else
+ {
+ UniStrCpy(s7, sizeof(s7), _UU("COMMON_UNKNOWN"));
+ }
+
+ if (e->LastCommTime != 0)
+ {
+ GetDateTimeStr64Uni(s8, sizeof(s8), SystemToLocal64(e->LastCommTime));
+ }
+ else
+ {
+ UniStrCpy(s8, sizeof(s8), _UU("COMMON_UNKNOWN"));
+ }
+
+ StrToUni(name, sizeof(name), e->HubName);
+
+ icon = ICO_HUB;
+ if (e->Online == false)
+ {
+ icon = ICO_HUB_OFFLINE;
+ }
+
+ if (e->IsTrafficFilled == false)
+ {
+ UniStrCpy(s9, sizeof(s9), _UU("CM_ST_NONE"));
+ UniStrCpy(s10, sizeof(s10), _UU("CM_ST_NONE"));
+ }
+ else
+ {
+ UniToStr3(s9, sizeof(s9),
+ e->Traffic.Recv.BroadcastBytes + e->Traffic.Recv.UnicastBytes +
+ e->Traffic.Send.BroadcastBytes + e->Traffic.Send.UnicastBytes);
+
+ UniToStr3(s10, sizeof(s10),
+ e->Traffic.Recv.BroadcastCount + e->Traffic.Recv.UnicastCount +
+ e->Traffic.Send.BroadcastCount + e->Traffic.Send.UnicastCount);
+ }
+
+ LvInsertAdd(b,
+ icon,
+ NULL,
+ 13,
+ name,
+ e->Online ? _UU("SM_HUB_ONLINE") : _UU("SM_HUB_OFFLINE"),
+ GetHubTypeStr(e->HubType),
+ s1, s2, s3, s4, s5, s6, s7, s8, s9, s10);
+ }
+ LvInsertEnd(b, hWnd, L_HUB);
+ FreeRpcEnumHub(&t);
+ }
+
+ // Listener list update
+ if (p != NULL)
+ {
+ RPC_LISTENER_LIST t;
+ Zero(&t, sizeof(RPC_LISTENER_LIST));
+ if (CALL(hWnd, ScEnumListener(p->Rpc, &t)))
+ {
+ LVB *b = LvInsertStart();
+ for (i = 0;i < t.NumPort;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ wchar_t *status;
+ UINT icon;
+ UniFormat(tmp, sizeof(tmp), _UU("CM_LISTENER_TCP_PORT"), t.Ports[i]);
+
+ status = _UU("CM_LISTENER_ONLINE");
+ icon = ICO_PROTOCOL;
+ if (t.Errors[i])
+ {
+ status = _UU("CM_LISTENER_ERROR");
+ icon = ICO_PROTOCOL_X;
+ }
+ else if (t.Enables[i] == false)
+ {
+ status = _UU("CM_LISTENER_OFFLINE");
+ icon = ICO_PROTOCOL_OFFLINE;
+ }
+
+ LvInsertAdd(b, icon, (void *)t.Ports[i], 2, tmp, status);
+ }
+ LvInsertEnd(b, hWnd, L_LISTENER);
+ FreeRpcListenerList(&t);
+ }
+ }
+
+ // Get the DDNS client state
+ Zero(&st, sizeof(st));
+ if (ScGetDDnsClientStatus(p->Rpc, &st) == ERR_NO_ERROR && IsEmptyStr(st.CurrentFqdn) == false)
+ {
+ SetTextA(hWnd, E_DDNS_HOST, st.CurrentFqdn);
+
+ Show(hWnd, S_DDNS);
+ Show(hWnd, E_DDNS_HOST);
+ }
+ else
+ {
+ Hide(hWnd, S_DDNS);
+ Hide(hWnd, E_DDNS_HOST);
+ }
+
+ // VPN Azure client state acquisition
+ Zero(&sta, sizeof(sta));
+ if (ScGetAzureStatus(p->Rpc, &sta) == ERR_NO_ERROR && sta.IsEnabled && IsEmptyStr(st.CurrentFqdn) == false)
+ {
+ char tmp[MAX_SIZE];
+
+ StrCpy(tmp, sizeof(tmp), st.CurrentHostName);
+ StrCat(tmp, sizeof(tmp), AZURE_DOMAIN_SUFFIX);
+
+ SetTextA(hWnd, E_AZURE_HOST, tmp);
+
+ Show(hWnd, S_AZURE);
+ Show(hWnd, E_AZURE_HOST);
+ }
+ else
+ {
+ Hide(hWnd, S_AZURE);
+ Hide(hWnd, E_AZURE_HOST);
+ }
+
+ SmServerDlgUpdate(hWnd, p);
+}
+
+// Server management dialog procedure
+UINT SmServerDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_SERVER *p = (SM_SERVER *)param;
+ wchar_t *s;
+ wchar_t tmp[MAX_SIZE];
+ NMHDR *n;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ FormatText(hWnd, 0, p->Title);
+
+ if (p->Bridge == false)
+ {
+ FormatText(hWnd, S_TITLE, p->ServerName);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SERVER_BRIDGE_TITLE"), p->ServerName);
+ SetText(hWnd, S_TITLE, tmp);
+ }
+
+ DlgFont(hWnd, S_TITLE, 16, 1);
+
+ SetIcon(hWnd, 0, p->Bridge == false ? ICO_VPNSERVER : ICO_BRIDGE);
+
+ SmServerDlgInit(hWnd, p);
+
+ SetTimer(hWnd, 1, 50, NULL);
+
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ // Management
+ if (IsEnable(hWnd, IDOK))
+ {
+ if (p->Bridge == false)
+ {
+ s = LvGetSelectedStr(hWnd, L_HUB, 0);
+ }
+ else
+ {
+ s = CopyUniStr(L"BRIDGE");
+ }
+ if (s != NULL)
+ {
+ char hubname[MAX_HUBNAME_LEN + 1];
+ SM_HUB hub;
+ Zero(&hub, sizeof(hub));
+ UniToStr(hubname, sizeof(hubname), s);
+ hub.p = p;
+ hub.Rpc = p->Rpc;
+ hub.HubName = hubname;
+ SmHubDlg(hWnd, &hub);
+ //SmServerDlgRefresh(hWnd, p);
+ Free(s);
+ }
+ }
+ break;
+
+ case B_ONLINE:
+ // Online
+ s = LvGetSelectedStr(hWnd, L_HUB, 0);
+ if (s != NULL)
+ {
+ RPC_SET_HUB_ONLINE t;
+ Zero(&t, sizeof(t));
+ UniToStr(t.HubName, sizeof(t.HubName), s);
+ t.Online = true;
+ if (CALL(hWnd, ScSetHubOnline(p->Rpc, &t)))
+ {
+ SmServerDlgRefresh(hWnd, p);
+ }
+ Free(s);
+ }
+ break;
+
+ case B_OFFLINE:
+ // Offline
+ s = LvGetSelectedStr(hWnd, L_HUB, 0);
+ if (s != NULL)
+ {
+ RPC_SET_HUB_ONLINE t;
+ Zero(&t, sizeof(t));
+ // Confirmation message
+ if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
+ _UU("CM_OFFLINE_MSG"), s) == IDYES)
+ {
+ UniToStr(t.HubName, sizeof(t.HubName), s);
+ t.Online = false;
+ if (CALL(hWnd, ScSetHubOnline(p->Rpc, &t)))
+ {
+ SmServerDlgRefresh(hWnd, p);
+ }
+ }
+ Free(s);
+ }
+ break;
+
+ case B_HUB_STATUS:
+ // Status of HUB
+ s = LvGetSelectedStr(hWnd, L_HUB, 0);
+ if (s != NULL)
+ {
+ wchar_t tmp[MAX_SIZE];
+ char *hubname = CopyUniToStr(s);
+ UniFormat(tmp, sizeof(tmp), _UU("SM_HUB_STATUS_CAPTION"), s);
+ SmStatusDlg(hWnd, p, hubname, false, true, tmp, ICO_HUB,
+ NULL, SmRefreshHubStatus);
+ Free(hubname);
+ Free(s);
+ }
+ break;
+
+ case B_CREATE:
+ // Create a HUB
+ if (SmCreateHubDlg(hWnd, p))
+ {
+ SmServerDlgRefresh(hWnd, p);
+ }
+ break;
+
+ case B_EDIT:
+ // Edit the HUB
+ s = LvGetSelectedStr(hWnd, L_HUB, 0);
+ if (s != NULL)
+ {
+ char *name = CopyUniToStr(s);
+ if (SmEditHubDlg(hWnd, p, name))
+ {
+ SmServerDlgRefresh(hWnd, p);
+ }
+ Free(name);
+ Free(s);
+ }
+ break;
+
+ case B_DELETE:
+ // Delete the HUB
+ s = LvGetSelectedStr(hWnd, L_HUB, 0);
+ if (s != NULL)
+ {
+ char *name = CopyUniToStr(s);
+ RPC_DELETE_HUB t;
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), name);
+ if (MsgBoxEx(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_DELETE_HUB_MSG"), name) == IDYES)
+ {
+ if (CALL(hWnd, ScDeleteHub(p->Rpc, &t)))
+ {
+ SmServerDlgRefresh(hWnd, p);
+ MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("CM_HUB_DELETED_MSG"), name);
+ }
+ }
+ Free(name);
+ Free(s);
+ }
+ break;
+
+ case B_CREATE_LISTENER:
+ // Create a listener
+ if (SmCreateListenerDlg(hWnd, p))
+ {
+ SmServerDlgRefresh(hWnd, p);
+ }
+ break;
+
+ case B_DELETE_LISTENER:
+ // Remove the listener
+ i = LvGetSelected(hWnd, L_LISTENER);
+ if (i != INFINITE)
+ {
+ UINT port = (UINT)LvGetParam(hWnd, L_LISTENER, i);
+ if (MsgBoxEx(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_DELETE_LISTENER_MSG"), port) == IDYES)
+ {
+ RPC_LISTENER t;
+ Zero(&t, sizeof(t));
+ t.Enable = false;
+ t.Port = port;
+
+ if (CALL(hWnd, ScDeleteListener(p->Rpc, &t)))
+ {
+ SmServerDlgRefresh(hWnd, p);
+ }
+ }
+ }
+ break;
+
+ case B_START:
+ // Start
+ i = LvGetSelected(hWnd, L_LISTENER);
+ if (i != INFINITE)
+ {
+ UINT port = (UINT)LvGetParam(hWnd, L_LISTENER, i);
+ RPC_LISTENER t;
+ Zero(&t, sizeof(t));
+ t.Enable = true;
+ t.Port = port;
+
+ if (CALL(hWnd, ScEnableListener(p->Rpc, &t)))
+ {
+ SmServerDlgRefresh(hWnd, p);
+ }
+ }
+ break;
+
+ case B_STOP:
+ // Stop
+ i = LvGetSelected(hWnd, L_LISTENER);
+ if (i != INFINITE)
+ {
+ UINT port = (UINT)LvGetParam(hWnd, L_LISTENER, i);
+ if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("CM_STOP_LISTENER_MSG"), port) == IDYES)
+ {
+ RPC_LISTENER t;
+ Zero(&t, sizeof(t));
+ t.Enable = false;
+ t.Port = port;
+
+ if (CALL(hWnd, ScEnableListener(p->Rpc, &t)))
+ {
+ SmServerDlgRefresh(hWnd, p);
+ }
+ }
+ }
+ break;
+
+ case B_SSL:
+ // SSL related
+ SmSslDlg(hWnd, p);
+ break;
+
+ case B_STATUS:
+ // Server status
+ SmStatusDlg(hWnd, p, p, false, true, _UU("SM_SERVER_STATUS"), ICO_VPNSERVER,
+ NULL, SmRefreshServerStatus);
+ break;
+
+ case B_INFO:
+ // Server Information
+ SmStatusDlg(hWnd, p, p, false, false, _UU("SM_INFO_TITLE"), ICO_VPNSERVER,
+ NULL, SmRefreshServerInfo);
+ break;
+
+ case B_BRIDGE:
+ // Local bridge configuration
+ SmBridgeDlg(hWnd, p);
+ SmServerDlgRefresh(hWnd, p);
+ break;
+
+ case B_FARM:
+ // Server farm
+ if (SmFarmDlg(hWnd, p))
+ {
+ // Close the dialog if the server farm configuration has changed
+ Close(hWnd);
+ }
+ break;
+
+ case B_FARM_STATUS:
+ // Server farm status
+ if (p->ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ Dialog(hWnd, D_SM_FARM_MEMBER, SmFarmMemberDlgProc, p);
+ }
+ else if (p->ServerType == SERVER_TYPE_FARM_MEMBER)
+ {
+ SmStatusDlg(hWnd, p, NULL, false, true, _UU("SM_FC_STATUS_CAPTION"),
+ ICO_FARM, NULL, SmRefreshFarmConnectionInfo);
+ }
+ break;
+
+ case B_CONNECTION:
+ // TCP connection list
+ SmConnectionDlg(hWnd, p);
+ break;
+
+ case B_REFRESH:
+ // Update to the latest state
+ SmServerDlgRefresh(hWnd, p);
+ break;
+
+ case B_CONFIG:
+ // Config edit
+ SmConfig(hWnd, p);
+ break;
+
+ case B_L3:
+ // L3 switch
+ SmL3(hWnd, p);
+ break;
+
+ case B_LICENSE:
+ // Add or Remove license
+ SmLicense(hWnd, p);
+ SmServerDlgUpdate(hWnd, p);
+ break;
+
+ case B_IPSEC:
+ // IPsec Settings
+ SmIPsec(hWnd, p);
+ break;
+
+ case B_OPENVPN:
+ // OpenVPN, SSTP setting
+ SmOpenVpn(hWnd, p);
+ break;
+
+ case B_DDNS:
+ // DDNS setting
+ if (SmDDns(hWnd, p, false, false))
+ {
+ SmServerDlgRefresh(hWnd, p);
+ }
+ break;
+
+ case B_AZURE:
+ // VPN Azure setting
+ SmAzure(hWnd, p, false);
+
+ SmServerDlgRefresh(hWnd, p);
+ break;
+
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ {
+ // Save the HUB that was selected last
+ char *hubname = NULL;
+ char tmp[MAX_SIZE];
+
+
+ Format(tmp, sizeof(tmp), "%s:%u:%s", p->CurrentSetting->ClientOption.Hostname,
+ p->CurrentSetting->ClientOption.Port,
+ p->CurrentSetting->ServerAdminMode ? "" : p->CurrentSetting->HubName);
+
+ if (LvIsSingleSelected(hWnd, L_HUB))
+ {
+ hubname = LvGetSelectedStrA(hWnd, L_HUB, 0);
+ }
+
+ if (IsEmptyStr(hubname) == false)
+ {
+ MsRegWriteStr(REG_CURRENT_USER, SM_LASTHUB_REG_KEY, tmp, hubname);
+ }
+ else
+ {
+ MsRegDeleteValue(REG_CURRENT_USER, SM_LASTHUB_REG_KEY, tmp);
+ }
+
+ Free(hubname);
+
+ EndDialog(hWnd, false);
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_HUB:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ SmServerDlgUpdate(hWnd, p);
+ break;
+ }
+ break;
+ case L_LISTENER:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ SmServerDlgUpdate(hWnd, p);
+ break;
+ }
+ break;
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+
+ if (p->ServerAdminMode)
+ {
+ // Prompt the registration if the license key is not registered
+ RPC_LICENSE_STATUS t;
+
+ Zero(&t, sizeof(t));
+ if (p->Bridge == false && GetCapsBool(p->CapsList, "b_support_license"))
+ {
+ if (ScGetLicenseStatus(p->Rpc, &t) == ERR_NO_ERROR)
+ {
+ if (t.EditionId == LICENSE_EDITION_VPN3_NO_LICENSE || (t.NeedSubscription && t.SubscriptionExpires == 0))
+ {
+ // Valid license key is not registered
+
+ if (MsgBox(hWnd, MB_YESNO | MB_ICONINFORMATION,
+ _UU("SM_SETUP_NO_LICENSE_KEY")) == IDYES)
+ {
+ SmLicense(hWnd, p);
+ }
+ }
+ }
+ }
+ }
+
+ SetTimer(hWnd, 2, 150, NULL);
+ break;
+
+ case 2:
+ // Setup
+ KillTimer(hWnd, 2);
+
+ if (SmSetupIsNew(p))
+ {
+ if (SmSetup(hWnd, p))
+ {
+ SmServerDlgRefresh(hWnd, p);
+ }
+ }
+
+ SmShowIPSecMessageIfNecessary(hWnd, p);
+
+ SetTimer(hWnd, 3, 150, NULL);
+ break;
+
+ case 3:
+ // Message for Administrators
+ KillTimer(hWnd, 3);
+
+ if (UniIsEmptyStr(p->AdminMsg) == false)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), _UU("SM_SERVER_ADMIN_MSG"), p->ServerName);
+ OnceMsg(hWnd, tmp, p->AdminMsg, true, ICO_VPNSERVER);
+ }
+ break;
+ }
+ break;
+ }
+
+ LvStandardHandler(hWnd, msg, wParam, lParam, L_HUB);
+
+ return 0;
+}
+
+// Display messages about IPsec, and prompt for the setting
+void SmShowIPSecMessageIfNecessary(HWND hWnd, SM_SERVER *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ if (GetCapsBool(p->CapsList, "b_support_vgs_in_client") == false)
+ {
+ if (GetCapsBool(p->CapsList, "b_support_ipsec") && p->IPsecMessageDisplayed == false)
+ {
+ // Display a message about IPsec
+ RPC_TEST flag;
+
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("SM_IPSEC_SETUP_QUESTION")) == IDYES)
+ {
+ // Display the IPsec dialog
+ SmIPsec(hWnd, p);
+ }
+
+ Zero(&flag, sizeof(flag));
+ flag.IntValue = 9;
+ ToStr(flag.StrValue, 1);
+
+ ScDebug(p->Rpc, &flag);
+
+ p->IPsecMessageDisplayed = true;
+ }
+
+ }
+}
+
+// Connection
+void SmConnect(HWND hWnd, SETTING *s)
+{
+ SmConnectEx(hWnd, s, false);
+}
+void SmConnectEx(HWND hWnd, SETTING *s, bool is_in_client)
+{
+ bool ok;
+ RPC *rpc;
+ char *pass;
+ bool empty_password = false;
+ bool first_bad_password = false;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ // Updater terminate
+ if (sm->Update != NULL)
+ {
+ FreeUpdateUi(sm->Update);
+ sm->Update = NULL;
+ }
+
+ // Disable the control
+ Disable(hWnd, L_SETTING);
+ Disable(hWnd, B_NEW_SETTING);
+ Disable(hWnd, B_EDIT_SETTING);
+ Disable(hWnd, B_DELETE);
+ Disable(hWnd, IDOK);
+ Disable(hWnd, B_ABOUT);
+ Disable(hWnd, IDCANCEL);
+ Disable(hWnd, B_SECURE_MANAGER);
+ Disable(hWnd, B_SELECT_SECURE);
+ Disable(hWnd, B_CERT_TOOL);
+
+ ok = true;
+
+ if (IsZero(s->HashedPassword, SHA1_SIZE))
+ {
+ // Password input screen
+ENTER_PASSWORD:
+ pass = SmPassword(hWnd, s->ClientOption.Hostname);
+ if (pass != NULL)
+ {
+ Hash(s->HashedPassword, pass, StrLen(pass), true);
+ Free(pass);
+ ok = true;
+ }
+ else
+ {
+ ok = false;
+ }
+ }
+
+ if (ok)
+ {
+ UINT err = ERR_INTERNAL_ERROR;
+ // Connection
+ rpc = AdminConnectEx2(sm->Cedar, &s->ClientOption, s->ServerAdminMode ? "" : s->HubName, s->HashedPassword, &err, NULL,
+ hWnd);
+ if (rpc == NULL)
+ {
+ // An error has occured
+ if (err != ERR_ACCESS_DENIED || first_bad_password)
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _E(err));
+ }
+ if (err == ERR_ACCESS_DENIED)
+ {
+ // Password incorrect
+ first_bad_password = true;
+ goto ENTER_PASSWORD;
+ }
+ else
+ {
+ // Other errors
+ }
+ }
+ else
+ {
+ UCHAR test[SHA1_SIZE];
+ SM_SERVER p;
+ RPC_SERVER_STATUS status;
+ RPC_SERVER_INFO info;
+ SETTING *setting;
+ RPC_MSG msg;
+ RPC_TEST flag;
+ bool cancel = false;
+
+ Hash(test, "", 0, true);
+
+ if (Cmp(test, s->HashedPassword, SHA1_SIZE) == 0 || Cmp(test, rpc->VpnServerHashedPassword, SHA1_SIZE) == 0)
+ {
+ empty_password = true;
+ }
+
+ if (sm->TempSetting == NULL)
+ {
+ setting = SmGetSetting(s->Title);
+ if (setting != NULL)
+ {
+ if (IsZero(setting->HashedPassword, SHA1_SIZE) == false)
+ {
+ Copy(setting->HashedPassword, s->HashedPassword, SHA1_SIZE);
+ SmWriteSettingList();
+ }
+ }
+ }
+
+ rpc->ServerAdminMode = s->ServerAdminMode;
+ if (s->ServerAdminMode == false)
+ {
+ StrCpy(rpc->HubName, sizeof(rpc->HubName), s->HubName);
+ }
+
+ Zero(&p, sizeof(p));
+ p.IsInClient = is_in_client;
+ p.CurrentSetting = s;
+ p.Rpc = rpc;
+ p.ServerAdminMode = rpc->ServerAdminMode;
+ StrCpy(p.ServerName, sizeof(p.ServerName), s->ClientOption.Hostname);
+ if (p.ServerAdminMode == false)
+ {
+ StrCpy(p.HubName, sizeof(p.HubName), rpc->HubName);
+ }
+ UniStrCpy(p.Title, sizeof(p.Title), s->Title);
+
+ // Get the type of server
+ Zero(&status, sizeof(status));
+ ScGetServerStatus(rpc, &status);
+
+ p.ServerType = status.ServerType;
+
+ Zero(&info, sizeof(info));
+ ScGetServerInfo(rpc, &info);
+
+ Copy(&p.ServerInfo, &info, sizeof(RPC_SERVER_INFO));
+ Copy(&p.ServerStatus, &status, sizeof(RPC_SERVER_STATUS));
+
+ // Get the Admin Msg
+ Zero(&msg, sizeof(msg));
+ if (ScGetAdminMsg(rpc, &msg) == ERR_NO_ERROR)
+ {
+ p.AdminMsg = UniCopyStr(msg.Msg);
+ FreeRpcMsg(&msg);
+ }
+
+ // IPsec related
+ Zero(&flag, sizeof(flag));
+ flag.IntValue = 8;
+ if (ScDebug(rpc, &flag) == ERR_NO_ERROR)
+ {
+ p.IPsecMessageDisplayed = ToInt(flag.StrValue);
+ }
+ else
+ {
+ p.IPsecMessageDisplayed = true;
+ }
+
+ // VGS related
+ Zero(&flag, sizeof(flag));
+ flag.IntValue = 10;
+ if (ScDebug(rpc, &flag) == ERR_NO_ERROR)
+ {
+ p.VgsMessageDisplayed = ToInt(flag.StrValue);
+ }
+ else
+ {
+ p.VgsMessageDisplayed = true;
+ }
+
+ // Get the Caps
+ p.CapsList = ScGetCapsEx(p.Rpc);
+
+ p.Bridge = GetCapsBool(p.CapsList, "b_bridge");
+
+ if (GetCapsBool(p.CapsList, "b_support_policy_ver_3"))
+ {
+ p.PolicyVer = 3;
+ }
+ else
+ {
+ p.PolicyVer = 2;
+ }
+
+ if (empty_password && s->ServerAdminMode)
+ {
+ // Make the user set a password when a password empty (In the case of server management mode)
+ if (Dialog(hWnd, D_SM_CHANGE_PASSWORD, SmChangeServerPasswordDlg, &p) == 0)
+ {
+ cancel = true;
+ }
+ }
+
+ // Server management screen
+ if (cancel == false)
+ {
+ // Update notification initialization
+ WINUI_UPDATE *update = NULL;
+
+ if (p.ServerAdminMode && is_in_client == false)
+ {
+ wchar_t update_software_title[MAX_SIZE];
+ char update_software_name[MAX_SIZE];
+ char server_name_safe[MAX_HOST_NAME_LEN + 1];
+ char family_name[128];
+
+ MakeSafeFileName(server_name_safe, sizeof(server_name_safe), p.ServerName);
+ Format(update_software_name, sizeof(update_software_name), (p.Bridge ? NAME_OF_VPN_BRIDGE_TARGET : NAME_OF_VPN_SERVER_TARGET), server_name_safe);
+ StrLower(update_software_name);
+ Trim(update_software_name);
+
+ Zero(family_name, sizeof(family_name));
+ StrCpy(family_name, sizeof(family_name), p.ServerInfo.ServerFamilyName);
+
+ if (IsEmptyStr(family_name))
+ {
+ if (InStr(p.ServerInfo.ServerProductName, "PacketiX"))
+ {
+ StrCpy(family_name, sizeof(family_name), "PacketiX");
+ }
+ else if (InStr(p.ServerInfo.ServerProductName, "UT-VPN") ||
+ InStr(p.ServerInfo.ServerProductName, "SoftEther"))
+ {
+ StrCpy(family_name, sizeof(family_name), "softether");
+ }
+ }
+
+ if (IsEmptyStr(family_name) == false)
+ {
+ UniFormat(update_software_title, sizeof(update_software_title), _UU(p.Bridge ? "SM_UPDATE_CHECK_TITLE_VPNBRIDGE" : "SM_UPDATE_CHECK_TITLE_VPNSERVER"),
+ family_name, p.ServerName);
+
+ update = InitUpdateUi(update_software_title, update_software_name, family_name, p.ServerInfo.ServerBuildDate,
+ p.ServerInfo.ServerBuildInt, p.ServerInfo.ServerVerInt, NULL);
+ }
+ }
+
+ p.Update = update;
+
+ // Main screen
+ Dialog(hWnd, D_SM_SERVER, SmServerDlgProc, &p);
+
+ if (p.Update != NULL)
+ {
+ FreeUpdateUi(p.Update);
+ p.Update = NULL;
+ }
+ }
+
+ // Disconnect
+ AdminDisconnect(rpc);
+
+ // Release the Caps
+ FreeCapsList(p.CapsList);
+
+ Free(p.AdminMsg);
+ p.AdminMsg = NULL;
+
+ FreeRpcServerInfo(&info);
+ }
+ }
+
+ // Enable the control
+ Enable(hWnd, L_SETTING);
+ Enable(hWnd, B_NEW_SETTING);
+ Enable(hWnd, B_EDIT_SETTING);
+ Enable(hWnd, B_DELETE);
+ Enable(hWnd, IDOK);
+ Enable(hWnd, B_ABOUT);
+ Enable(hWnd, IDCANCEL);
+ Enable(hWnd, B_SECURE_MANAGER);
+ Enable(hWnd, B_SELECT_SECURE);
+ Enable(hWnd, B_CERT_TOOL);
+}
+
+// Password input dialog
+char *SmPassword(HWND hWnd, char *server_name)
+{
+ char *ret;
+ UI_PASSWORD_DLG p;
+ // Validate arguments
+ if (server_name == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&p, sizeof(p));
+ p.AdminMode = true;
+ StrCpy(p.ServerName, sizeof(p.ServerName), server_name);
+
+ if (PasswordDlg(hWnd, &p) == false)
+ {
+ return NULL;
+ }
+
+ ret = CopyStr(p.Password);
+
+ return ret;
+}
+
+// Configuration editing dialog initialization
+void SmEditSettingDlgInit(HWND hWnd, SM_EDIT_SETTING *p)
+{
+ SETTING *s;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ p->Inited = false;
+
+ s = p->Setting;
+
+ // Title
+ if (p->EditMode == false)
+ {
+ SetText(hWnd, 0, _UU("SM_EDIT_CAPTION_1"));
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ UniFormat(tmp, sizeof(tmp), _UU("SM_EDIT_CAPTION_2"), s->Title);
+ SetText(hWnd, 0, tmp);
+ }
+
+ // Connection setting name
+ SetText(hWnd, E_ACCOUNT_NAME, s->Title);
+
+ // Host name
+ SetTextA(hWnd, E_HOSTNAME, s->ClientOption.Hostname);
+
+ // Port number
+ CbSetHeight(hWnd, C_PORT, 18);
+ CbAddStr(hWnd, C_PORT, _UU("CM_PORT_1"), 0);
+ CbAddStr(hWnd, C_PORT, _UU("CM_PORT_2"), 0);
+ CbAddStr(hWnd, C_PORT, _UU("CM_PORT_3"), 0);
+ CbAddStr(hWnd, C_PORT, _UU("CM_PORT_4"), 0);
+ SetIntEx(hWnd, C_PORT, s->ClientOption.Port);
+
+ // Proxy Settings
+ Check(hWnd, R_DIRECT_TCP, s->ClientOption.ProxyType == PROXY_DIRECT);
+ Check(hWnd, R_HTTPS, s->ClientOption.ProxyType == PROXY_HTTP);
+ Check(hWnd, R_SOCKS, s->ClientOption.ProxyType == PROXY_SOCKS);
+
+ // Management mode setting
+ Check(hWnd, R_SERVER_ADMIN, s->ServerAdminMode);
+ Check(hWnd, R_HUB_ADMIN, s->ServerAdminMode == false ? true : false);
+ CbSetHeight(hWnd, C_HUBNAME, 18);
+ SetTextA(hWnd, C_HUBNAME, s->HubName);
+
+ // Password
+ if (IsZero(s->HashedPassword, SHA1_SIZE))
+ {
+ Check(hWnd, R_NO_SAVE, true);
+ }
+ else
+ {
+ UCHAR test[SHA1_SIZE];
+
+ Hash(test, "", 0, true);
+ if (Cmp(test, s->HashedPassword, SHA1_SIZE) != 0)
+ {
+ SetTextA(hWnd, E_PASSWORD, HIDDEN_PASSWORD);
+ }
+ }
+
+ if (p->EditMode == false)
+ {
+ FocusEx(hWnd, E_ACCOUNT_NAME);
+ }
+ else
+ {
+ FocusEx(hWnd, E_HOSTNAME);
+ }
+
+ p->Inited = true;
+
+ // Start enumerating the Virtual HUBs
+ CmEnumHubStart(hWnd, &s->ClientOption);
+
+ SmEditSettingDlgUpdate(hWnd, p);
+}
+
+// Configuration editing dialog update
+void SmEditSettingDlgUpdate(HWND hWnd, SM_EDIT_SETTING *p)
+{
+ bool ok = true;
+ UINT delete_hub_list = 0;
+ SETTING *s;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || p == NULL || p->Inited == false)
+ {
+ return;
+ }
+
+ s = p->Setting;
+
+ GetTxt(hWnd, E_ACCOUNT_NAME, s->Title, sizeof(s->Title));
+ UniTrim(s->Title);
+
+ if (UniStrLen(s->Title) == 0)
+ {
+ ok = false;
+ }
+
+ if (IsChecked(hWnd, R_LOCALHOST))
+ {
+ SetTextA(hWnd, E_HOSTNAME, "localhost");
+ Disable(hWnd, E_HOSTNAME);
+ }
+ else
+ {
+ Enable(hWnd, E_HOSTNAME);
+ }
+
+ GetTxtA(hWnd, E_HOSTNAME, tmp, sizeof(tmp));
+ Trim(tmp);
+
+ if (StrCmpi(tmp, s->ClientOption.Hostname) != 0)
+ {
+ delete_hub_list++;
+ }
+
+ StrCpy(s->ClientOption.Hostname, sizeof(s->ClientOption.Hostname), tmp);
+
+ if (StrLen(s->ClientOption.Hostname) == 0)
+ {
+ ok = false;
+ }
+
+ s->ClientOption.Port = GetInt(hWnd, C_PORT);
+ if (s->ClientOption.Port == 0)
+ {
+ ok = false;
+ }
+
+ if (IsChecked(hWnd, R_DIRECT_TCP))
+ {
+ s->ClientOption.ProxyType = PROXY_DIRECT;
+ }
+ else if (IsChecked(hWnd, R_HTTPS))
+ {
+ s->ClientOption.ProxyType = PROXY_HTTP;
+ }
+ else
+ {
+ s->ClientOption.ProxyType = PROXY_SOCKS;
+ }
+
+ SetEnable(hWnd, B_PROXY_CONFIG, s->ClientOption.ProxyType != PROXY_DIRECT);
+
+ if (s->ClientOption.ProxyType != PROXY_DIRECT)
+ {
+ if (StrLen(s->ClientOption.ProxyName) == 0)
+ {
+ ok = false;
+ }
+ if (s->ClientOption.ProxyPort == 0)
+ {
+ ok = false;
+ }
+ }
+
+ s->ServerAdminMode = IsChecked(hWnd, R_SERVER_ADMIN);
+
+ SetEnable(hWnd, C_HUBNAME, s->ServerAdminMode == false ? true : false);
+ SetEnable(hWnd, S_HUBNAME, s->ServerAdminMode == false ? true : false);
+
+ GetTxtA(hWnd, C_HUBNAME, s->HubName, sizeof(s->HubName));
+ Trim(s->HubName);
+ if (StrLen(s->HubName) == 0)
+ {
+ if (s->ServerAdminMode == false)
+ {
+ ok = false;
+ }
+ }
+
+ if (IsChecked(hWnd, R_NO_SAVE))
+ {
+ Zero(s->HashedPassword, SHA1_SIZE);
+ SetTextA(hWnd, E_PASSWORD, "");
+ Disable(hWnd, E_PASSWORD);
+ Disable(hWnd, S_PASSWORD);
+ }
+ else
+ {
+ char tmp[MAX_PASSWORD_LEN + 1];
+ Enable(hWnd, E_PASSWORD);
+ Enable(hWnd, S_PASSWORD);
+ GetTxtA(hWnd, E_PASSWORD, tmp, sizeof(tmp));
+ if (StrCmp(tmp, HIDDEN_PASSWORD) != 0)
+ {
+ Hash(s->HashedPassword, tmp, StrLen(tmp), true);
+ }
+ }
+
+ if (delete_hub_list)
+ {
+ CbReset(hWnd, C_HUBNAME);
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Configuration Edit dialog OK button
+void SmEditSettingDlgOnOk(HWND hWnd, SM_EDIT_SETTING *p)
+{
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (p->EditMode == false)
+ {
+ // Register new
+ SETTING *s = ZeroMalloc(sizeof(SETTING));
+ Copy(s, p->Setting, sizeof(SETTING));
+ if (SmAddSetting(s) == false)
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SM_SETTING_EXISTS"), s->Title);
+ Free(s);
+ FocusEx(hWnd, E_ACCOUNT_NAME);
+ return;
+ }
+ EndDialog(hWnd, true);
+ }
+ else
+ {
+ // Update registration
+ SETTING *t = SmGetSetting(p->Setting->Title);
+ if (t != NULL && t != p->OldSetting)
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SM_SETTING_EXISTS"), p->Setting->Title);
+ FocusEx(hWnd, E_ACCOUNT_NAME);
+ return;
+ }
+
+ Copy(p->OldSetting, p->Setting, sizeof(SETTING));
+ Sort(sm->SettingList);
+ SmWriteSettingList();
+
+ EndDialog(hWnd, true);
+ }
+}
+
+// Settings add / edit dialog
+UINT SmEditSettingDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SM_EDIT_SETTING *p = (SM_EDIT_SETTING *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmEditSettingDlgInit(hWnd, p);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case R_LOCALHOST:
+ case E_ACCOUNT_NAME:
+ case E_HOSTNAME:
+ case C_PORT:
+ case R_DIRECT_TCP:
+ case R_HTTPS:
+ case R_SOCKS:
+ case R_SERVER_ADMIN:
+ case R_HUB_ADMIN:
+ case C_HUBNAME:
+ case E_PASSWORD:
+ case R_NO_SAVE:
+ SmEditSettingDlgUpdate(hWnd, p);
+ break;
+ }
+
+ if (LOWORD(wParam) == R_LOCALHOST)
+ {
+ FocusEx(hWnd, E_HOSTNAME);
+ }
+
+ switch (LOWORD(wParam))
+ {
+ case E_HOSTNAME:
+ if (HIWORD(wParam) == EN_KILLFOCUS)
+ {
+ CmEnumHubStart(hWnd, &p->Setting->ClientOption);
+ }
+ break;
+ case C_PORT:
+ if (HIWORD(wParam) == CBN_KILLFOCUS)
+ {
+ CmEnumHubStart(hWnd, &p->Setting->ClientOption);
+ }
+ break;
+ case R_DIRECT_TCP:
+ case R_HTTPS:
+ case R_SOCKS:
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ CmEnumHubStart(hWnd, &p->Setting->ClientOption);
+ }
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ SmEditSettingDlgOnOk(hWnd, p);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case B_PROXY_CONFIG:
+ // Proxy Settings
+ if (CmProxyDlg(hWnd, &p->Setting->ClientOption))
+ {
+ UINT n = GetInt(hWnd, C_PORT);
+ if (p->Setting->ClientOption.ProxyType == PROXY_HTTP &&
+ n != 443)
+ {
+ // Show a warning message if the destination port is
+ // other than 443 in when HTTP proxy is used
+ if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO, _UU("CM_HTTP_PROXY_WARNING"), n) == IDYES)
+ {
+ // Change the port number to 443
+ SetText(hWnd, C_PORT, _UU("CM_PORT_2"));
+ }
+ }
+ SmEditSettingDlgUpdate(hWnd, p);
+ CmEnumHubStart(hWnd, &p->Setting->ClientOption);
+ }
+ break;
+
+ case R_NO_SAVE:
+ if (IsChecked(hWnd, R_NO_SAVE) == false)
+ {
+ FocusEx(hWnd, E_PASSWORD);
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Show the Settings Adding dialog
+bool SmAddSettingDlg(HWND hWnd, wchar_t *new_name, UINT new_name_size)
+{
+ SM_EDIT_SETTING p;
+ SETTING s;
+ UINT i;
+ bool ret;
+ // Validate arguments
+ if (hWnd == NULL || new_name == NULL)
+ {
+ return false;
+ }
+
+ Zero(&p, sizeof(p));
+ Zero(&s, sizeof(s));
+
+ s.ClientOption.Port = 443;
+
+ p.EditMode = false;
+ p.Setting = &s;
+
+ for (i = 1;;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ if (i == 1)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_NEW_ACCOUNT_NAME_1"));
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CM_NEW_ACCOUNT_NAME_2"), i);
+ }
+
+ if (SmGetSetting(tmp) == NULL)
+ {
+ UniStrCpy(s.Title, sizeof(s.Title), tmp);
+ Hash(s.HashedPassword, "", 0, true);
+ s.ServerAdminMode = true;
+ break;
+ }
+ }
+
+ ret = Dialog(hWnd, D_SM_EDIT_SETTING, SmEditSettingDlgProc, &p);
+
+ if (ret)
+ {
+ UniStrCpy(new_name, new_name_size, s.Title);
+ }
+
+ return ret;
+}
+
+// Show the settings edit dialog
+bool SmEditSettingDlg(HWND hWnd)
+{
+ SM_EDIT_SETTING p;
+ SETTING s, *setting;
+ UINT i;
+ wchar_t *name;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return false;
+ }
+
+ i = LvGetSelected(hWnd, L_SETTING);
+ if (i == INFINITE)
+ {
+ return false;
+ }
+
+ name = LvGetStr(hWnd, L_SETTING, i, 0);
+
+ setting = SmGetSetting(name);
+ if (setting == NULL)
+ {
+ Free(name);
+ return false;
+ }
+
+ Free(name);
+
+ Copy(&s, setting, sizeof(SETTING));
+
+ Zero(&p, sizeof(p));
+
+ p.EditMode = true;
+ p.OldSetting = setting;
+ p.Setting = &s;
+
+ return Dialog(hWnd, D_SM_EDIT_SETTING, SmEditSettingDlgProc, &p);
+}
+
+// Update the configuration
+bool SmCheckNewName(SETTING *s, wchar_t *new_title)
+{
+ UINT i;
+ // Validate arguments
+ if (new_title == NULL)
+ {
+ return false;
+ }
+ if (s != NULL)
+ {
+ if (IsInList(sm->SettingList, s) == false)
+ {
+ return false;
+ }
+ }
+
+ // Check whether there is the same name in other
+ for (i = 0;i < LIST_NUM(sm->SettingList);i++)
+ {
+ SETTING *t = LIST_DATA(sm->SettingList, i);
+
+ if (s != t)
+ {
+ if (UniStrCmpi(t->Title, new_title) == 0)
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+// Delete the configuration
+void SmDeleteSetting(wchar_t *title)
+{
+ SETTING *s;
+ // Validate arguments
+ if (title == NULL)
+ {
+ return;
+ }
+
+ s = SmGetSetting(title);
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Delete(sm->SettingList, s);
+ Free(s);
+ Sort(sm->SettingList);
+
+ SmWriteSettingList();
+}
+
+// Add the settings
+bool SmAddSetting(SETTING *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ if (SmGetSetting(s->Title) != NULL)
+ {
+ return false;
+ }
+
+ Insert(sm->SettingList, s);
+
+ SmWriteSettingList();
+
+ return true;
+}
+
+// Get the configuration
+SETTING *SmGetSetting(wchar_t *title)
+{
+ SETTING s;
+ // Validate arguments
+ if (title == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&s, sizeof(SETTING));
+ UniStrCpy(s.Title, sizeof(s.Title), title);
+
+ return (SETTING *)Search(sm->SettingList, &s);
+}
+
+// Comparison of connection settings
+int SmCompareSetting(void *p1, void *p2)
+{
+ SETTING *s1, *s2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ s1 = *(SETTING **)p1;
+ s2 = *(SETTING **)p2;
+ if (s1 == NULL || s2 == NULL)
+ {
+ return 0;
+ }
+
+ return UniStrCmpi(s1->Title, s2->Title);
+}
+
+// Initialize the configuration list
+void SmInitSettingList()
+{
+ sm->SettingList = NewList(SmCompareSetting);
+
+ SmLoadSettingList();
+
+ SmInitDefaultSettingList();
+}
+
+// Release the configuration list
+void SmFreeSettingList()
+{
+ UINT i;
+
+ // Write
+ SmWriteSettingList();
+
+ for (i = 0;i < LIST_NUM(sm->SettingList);i++)
+ {
+ SETTING *s = LIST_DATA(sm->SettingList, i);
+ Free(s);
+ }
+ ReleaseList(sm->SettingList);
+
+ sm->SettingList = NULL;
+}
+
+// Write the configuration list
+void SmWriteSettingList()
+{
+ TOKEN_LIST *t;
+ UINT i;
+
+ t = MsRegEnumValue(REG_CURRENT_USER, SM_SETTING_REG_KEY);
+ if (t != NULL)
+ {
+ // Remove all existing values
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ char *name = t->Token[i];
+ MsRegDeleteValue(REG_CURRENT_USER, SM_SETTING_REG_KEY, name);
+ }
+
+ FreeToken(t);
+ }
+
+ for (i = 0;i < LIST_NUM(sm->SettingList);i++)
+ {
+ char name[MAX_SIZE];
+ SETTING *s = LIST_DATA(sm->SettingList, i);
+
+ // Write
+ Format(name, sizeof(name), "Setting%u", i + 1);
+ MsRegWriteBin(REG_CURRENT_USER, SM_SETTING_REG_KEY, name, s, sizeof(SETTING));
+ }
+}
+
+// Load the connection list
+void SmLoadSettingList()
+{
+ TOKEN_LIST *t;
+ UINT i;
+ char *key_name = SM_SETTING_REG_KEY;
+
+ t = MsRegEnumValue(REG_CURRENT_USER, key_name);
+ if (t == NULL)
+ {
+ key_name = SM_SETTING_REG_KEY_OLD;
+ t = MsRegEnumValue(REG_CURRENT_USER, key_name);
+ if (t == NULL)
+ {
+ return;
+ }
+ }
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ char *name = t->Token[i];
+ BUF *b = MsRegReadBin(REG_CURRENT_USER, key_name, name);
+ if (b != NULL)
+ {
+ if (b->Size == sizeof(SETTING))
+ {
+ SETTING *s = ZeroMalloc(sizeof(SETTING));
+ Copy(s, b->Buf, sizeof(SETTING));
+
+ Add(sm->SettingList, s);
+ }
+ FreeBuf(b);
+ }
+ }
+
+ FreeToken(t);
+
+ Sort(sm->SettingList);
+}
+
+// Initialize the default setting list
+void SmInitDefaultSettingList()
+{
+ if (LIST_NUM(sm->SettingList) == 0)
+ {
+ bool b = false;
+ LIST *pl = MsGetProcessList();
+
+ if (pl != NULL)
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(pl);i++)
+ {
+ MS_PROCESS *p = LIST_DATA(pl, i);
+
+ if (UniInStr(p->ExeFilenameW, L"vpnserver.exe") || UniInStr(p->ExeFilenameW, L"vpnserver_x64.exe") ||
+ UniInStr(p->ExeFilenameW, L"vpnserver_ia64.exe") ||
+ UniInStr(p->ExeFilenameW, L"vpnbridge.exe") || UniInStr(p->ExeFilenameW, L"vpnbridge_x64.exe") ||
+ UniInStr(p->ExeFilenameW, L"vpnbridge_ia64.exe"))
+ {
+ b = true;
+ }
+
+ if (UniInStr(p->ExeFilenameW, L"sevpnserver.exe") || UniInStr(p->ExeFilenameW, L"sevpnserver_x64.exe") ||
+ UniInStr(p->ExeFilenameW, L"sevpnserver_ia64.exe") ||
+ UniInStr(p->ExeFilenameW, L"sevpnbridge.exe") || UniInStr(p->ExeFilenameW, L"sevpnbridge_x64.exe") ||
+ UniInStr(p->ExeFilenameW, L"sevpnbridge_ia64.exe"))
+ {
+ b = true;
+ }
+
+ if (UniInStr(p->ExeFilenameW, L"utvpnserver.exe") || UniInStr(p->ExeFilenameW, L"utvpnserver_x64.exe") ||
+ UniInStr(p->ExeFilenameW, L"utvpnserver_ia64.exe") ||
+ UniInStr(p->ExeFilenameW, L"utvpnbridge.exe") || UniInStr(p->ExeFilenameW, L"utvpnbridge_x64.exe") ||
+ UniInStr(p->ExeFilenameW, L"utvpnbridge_ia64.exe"))
+ {
+ b = true;
+ }
+ }
+ }
+
+ MsFreeProcessList(pl);
+
+ if (b == false)
+ {
+ if (MsIsServiceRunning(GC_SVC_NAME_VPNSERVER) || MsIsServiceRunning(GC_SVC_NAME_VPNBRIDGE))
+ {
+ b = true;
+ }
+ }
+
+ if (b)
+ {
+ SETTING *s = ZeroMalloc(sizeof(SETTING));
+
+ UniStrCpy(s->Title, sizeof(s->Title), _UU("SM_LOCALHOST"));
+ s->ServerAdminMode = true;
+ Hash(s->HashedPassword, "", 0, true);
+ UniStrCpy(s->ClientOption.AccountName, sizeof(s->ClientOption.AccountName), s->Title);
+ StrCpy(s->ClientOption.Hostname, sizeof(s->ClientOption.Hostname), "localhost");
+ s->ClientOption.Port = GC_DEFAULT_PORT;
+
+ Add(sm->SettingList, s);
+ }
+ }
+}
+
+// Main dialog initialization
+void SmMainDlgInit(HWND hWnd)
+{
+ wchar_t *last_select;
+ UINT i = INFINITE;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_VPNSERVER);
+
+ LvInit(hWnd, L_SETTING);
+ LvSetStyle(hWnd, L_SETTING, LVS_EX_GRIDLINES);
+ LvInsertColumn(hWnd, L_SETTING, 0, _UU("SM_MAIN_COLUMN_1"), 145);
+ LvInsertColumn(hWnd, L_SETTING, 1, _UU("SM_MAIN_COLUMN_2"), 129);
+ LvInsertColumn(hWnd, L_SETTING, 2, _UU("SM_MAIN_COLUMN_3"), 125);
+
+ SmRefreshSetting(hWnd);
+
+ last_select = MsRegReadStrW(REG_CURRENT_USER, SM_REG_KEY, "Last Select");
+ if (UniIsEmptyStr(last_select) == false)
+ {
+ i = LvSearchStr(hWnd, L_SETTING, 0, last_select);
+ }
+ Free(last_select);
+
+ if (i == INFINITE)
+ {
+ LvSelect(hWnd, L_SETTING, 0);
+ }
+ else
+ {
+ LvSelect(hWnd, L_SETTING, i);
+ }
+
+ DlgFont(hWnd, IDOK, 10, true);
+
+ Focus(hWnd, L_SETTING);
+
+ SmMainDlgUpdate(hWnd);
+}
+
+// Update the configuration list
+void SmRefreshSetting(HWND hWnd)
+{
+ SmRefreshSettingEx(hWnd, NULL);
+}
+void SmRefreshSettingEx(HWND hWnd, wchar_t *select_name)
+{
+ LVB *b;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ b = LvInsertStart();
+
+ for (i = 0;i < LIST_NUM(sm->SettingList);i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ SETTING *s = LIST_DATA(sm->SettingList, i);
+
+ if (s->ServerAdminMode)
+ {
+ UniStrCpy(tmp, sizeof(tmp), _UU("SM_MODE_SERVER"));
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SM_MODE_HUB"), s->HubName);
+ }
+
+ StrToUni(tmp2, sizeof(tmp2), s->ClientOption.Hostname);
+
+ LvInsertAdd(b,
+ (s->ServerAdminMode ? ICO_SERVER_ONLINE : ICO_HUB),
+ NULL,
+ 3,
+ s->Title,
+ tmp2,
+ tmp);
+ }
+
+ LvInsertEnd(b, hWnd, L_SETTING);
+
+ if (UniIsEmptyStr(select_name) == false)
+ {
+ LvSelect(hWnd, L_SETTING, INFINITE);
+ LvSelect(hWnd, L_SETTING, LvSearchStr(hWnd, L_SETTING, 0, select_name));
+ }
+}
+
+// Main dialog update
+void SmMainDlgUpdate(HWND hWnd)
+{
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (LvIsSelected(hWnd, L_SETTING) == false)
+ {
+ ok = false;
+ }
+ if (LvIsMultiMasked(hWnd, L_SETTING))
+ {
+ ok = false;
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+ SetEnable(hWnd, B_EDIT_SETTING, ok);
+ SetEnable(hWnd, B_DELETE, ok);
+}
+
+// Main window procedure
+UINT SmMainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ NMHDR *n;
+ NMLVDISPINFOW *info;
+ NMLVKEYDOWN *key;
+ wchar_t *tmp;
+ UINT i;
+ wchar_t new_name[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SmMainDlgInit(hWnd);
+ SetTimer(hWnd, 4, 100, NULL);
+
+ // Updater start
+ sm->Update = InitUpdateUi(_UU("PRODUCT_NAME_VPN_SMGR"), NAME_OF_VPN_SERVER_MANAGER, NULL, GetCurrentBuildDate(),
+ CEDAR_BUILD, CEDAR_VER, NULL);
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 4:
+ KillTimer(hWnd, 4);
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ // Connection
+ i = LvGetSelected(hWnd, L_SETTING);
+ if (i != INFINITE)
+ {
+ tmp = LvGetStr(hWnd, L_SETTING, i, 0);
+ if (tmp != NULL)
+ {
+ SETTING *setting = SmGetSetting(tmp);
+ if (setting != NULL)
+ {
+ SETTING s;
+
+ // Record in the registry as the last choice
+ MsRegWriteStrW(REG_CURRENT_USER, SM_REG_KEY, "Last Select", tmp);
+
+ // Copy the configuration
+ Copy(&s, setting, sizeof(SETTING));
+ SmConnect(hWnd, &s);
+ }
+ Free(tmp);
+ }
+ }
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case B_NEW_SETTING:
+ // Add
+ if (SmAddSettingDlg(hWnd, new_name, sizeof(new_name)))
+ {
+ SmRefreshSettingEx(hWnd, new_name);
+ }
+ break;
+
+ case B_EDIT_SETTING:
+ // Edit
+ if (SmEditSettingDlg(hWnd))
+ {
+ SmWriteSettingList();
+ SmRefreshSetting(hWnd);
+ }
+
+ break;
+
+ case B_DELETE:
+ // Delete
+ i = LvGetSelected(hWnd, L_SETTING);
+ if (i != INFINITE)
+ {
+ tmp = LvGetStr(hWnd, L_SETTING, i, 0);
+ if (tmp != NULL)
+ {
+ if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
+ _UU("SM_SETTING_DELETE_MSG"), tmp) == IDYES)
+ {
+ SmDeleteSetting(tmp);
+ SmWriteSettingList();
+ SmRefreshSetting(hWnd);
+ }
+ Free(tmp);
+ }
+ }
+ break;
+
+ case B_ABOUT:
+ // Version information
+ AboutEx(hWnd, sm->Cedar, _UU("PRODUCT_NAME_VPN_SMGR"), sm->Update);
+ break;
+
+ case B_SECURE_MANAGER:
+ // Smart Card Manager
+ SmSecureManager(hWnd);
+ break;
+
+ case B_SELECT_SECURE:
+ // Smart card selection
+ SmSelectSecureId(hWnd);
+ break;
+
+ case B_CERT_TOOL:
+ // Certificate Creation Tool
+ SmCreateCert(hWnd, NULL, NULL, false, NULL, false);
+ break;
+ }
+
+ break;
+
+ case WM_CLOSE:
+ // Updater terminate
+ if (sm->Update != NULL)
+ {
+ FreeUpdateUi(sm->Update);
+ sm->Update = NULL;
+ }
+
+ EndDialog(hWnd, 0);
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_SETTING:
+ switch (n->code)
+ {
+ case NM_DBLCLK:
+ Command(hWnd, IDOK);
+ break;
+
+ case LVN_KEYDOWN:
+ key = (NMLVKEYDOWN *)n;
+ if (key != NULL)
+ {
+ UINT code = key->wVKey;
+ switch (code)
+ {
+ case VK_F2:
+ if (LvIsSelected(hWnd, L_SETTING))
+ {
+ LvRename(hWnd, L_SETTING, LvGetSelected(hWnd, L_SETTING));
+ }
+ break;
+
+ case VK_DELETE:
+ Command(hWnd, B_DELETE);
+ break;
+
+ case VK_RETURN:
+ Command(hWnd, IDOK);
+ break;
+ }
+ }
+ break;
+
+ case LVN_ENDLABELEDITW:
+ // Change the name
+ info = (NMLVDISPINFOW *)n;
+ if (info->item.pszText != NULL)
+ {
+ wchar_t *new_name = info->item.pszText;
+ wchar_t *old_name = LvGetStr(hWnd, L_SETTING, info->item.iItem, 0);
+
+ if (old_name != NULL)
+ {
+ if (UniStrCmp(new_name, old_name) != 0 && UniStrLen(new_name) != 0)
+ {
+ // Change the name
+ SETTING *s = SmGetSetting(old_name);
+ if (s != NULL)
+ {
+ if (SmGetSetting(new_name) != NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SM_SETTING_EXISTS"),
+ new_name);
+ }
+ else
+ {
+ UniStrCpy(s->Title, sizeof(s->Title), new_name);
+ Sort(sm->SettingList);
+ SmWriteSettingList();
+ LvSetItem(hWnd, L_SETTING, info->item.iItem, 0, new_name);
+ }
+ }
+ }
+
+ Free(old_name);
+ }
+ }
+ break;
+
+ case LVN_ITEMCHANGED:
+ SmMainDlgUpdate(hWnd);
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ LvSortHander(hWnd, msg, wParam, lParam, L_SETTING);
+
+ return 0;
+}
+
+// Main window
+void SmMainDlg()
+{
+ Dialog(NULL, D_SM_MAIN, SmMainDlgProc, NULL);
+}
+
+// Server Manager main process
+void MainSM()
+{
+ if (sm->TempSetting == NULL)
+ {
+ // Open the main window
+ SmMainDlg();
+ }
+ else
+ {
+ SmConnect(sm->hParentWnd, sm->TempSetting);
+ }
+}
+
+// Initialize
+void InitSM()
+{
+ InitSMEx(false);
+}
+void InitSMEx(bool from_cm)
+{
+ if (sm != NULL)
+ {
+ // Already initialized
+ return;
+ }
+
+ sm = ZeroMalloc(sizeof(SM));
+
+ if (from_cm == false)
+ {
+ InitWinUi(_UU("SM_TITLE"), _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+ }
+
+ sm->Cedar = NewCedar(NULL, NULL);
+
+ if (from_cm == false)
+ {
+ SmInitSettingList();
+ InitCM(false);
+
+ // Interpret the command line
+ SmParseCommandLine();
+ }
+}
+
+// Interpret the command line
+void SmParseCommandLine()
+{
+ LIST *o;
+ CONSOLE *c = NewLocalConsole(NULL, NULL);
+ wchar_t *cmdline;
+ PARAM args[] =
+ {
+ {"[vpnserver]", NULL, NULL, NULL, NULL,},
+ {"HUB", NULL, NULL, NULL, NULL,},
+ {"PASSWORD", NULL, NULL, NULL, NULL,},
+ {"TITLE", NULL, NULL, NULL, NULL,},
+ {"HWND", NULL, NULL, NULL, NULL,},
+ };
+ if (c == NULL)
+ {
+ return;
+ }
+
+ cmdline = GetCommandLineUniStr();
+
+ if (UniIsEmptyStr(cmdline) == false)
+ {
+ o = ParseCommandList(c, "vpnsmgr", cmdline, args, sizeof(args) / sizeof(args[0]));
+ if (o != NULL)
+ {
+ char *host;
+ UINT port;
+
+ if (ParseHostPort(GetParamStr(o, "[vpnserver]"), &host, &port, 443))
+ {
+ char *hub = GetParamStr(o, "HUB");
+ char *password = GetParamStr(o, "PASSWORD");
+ char *title = GetParamStr(o, "TITLE");
+ char *hwndstr = GetParamStr(o, "HWND");
+
+ if (hub == NULL || StrCmpi(hub, "\"") == 0)
+ {
+ hub = CopyStr("");
+ }
+ if (password == NULL)
+ {
+ password = CopyStr("");
+ }
+ if (title == NULL)
+ {
+ title = CopyStr(host);
+ }
+
+ if (IsEmptyStr(host) == false)
+ {
+ SETTING *s = ZeroMalloc(sizeof(SETTING));
+ BUF *b;
+ CLIENT_OPTION *o;
+
+ StrToUni(s->Title, sizeof(s->Title), title);
+
+ if (IsEmptyStr(hub))
+ {
+ s->ServerAdminMode = true;
+ }
+ else
+ {
+ s->ServerAdminMode = false;
+ StrCpy(s->HubName, sizeof(s->HubName), hub);
+ }
+
+ b = StrToBin(password);
+ if (b == NULL || b->Size != SHA1_SIZE)
+ {
+ Hash(s->HashedPassword, password, StrLen(password), true);
+ }
+ else
+ {
+ Copy(s->HashedPassword, b->Buf, SHA1_SIZE);
+ }
+ FreeBuf(b);
+
+ o = &s->ClientOption;
+
+ UniStrCpy(o->AccountName, sizeof(o->AccountName), s->Title);
+ StrCpy(o->Hostname, sizeof(o->Hostname), host);
+ o->Port = port;
+ o->ProxyType = PROXY_DIRECT;
+ StrCpy(o->DeviceName, sizeof(o->DeviceName), "DUMMY");
+
+ sm->TempSetting = s;
+
+ if (IsEmptyStr(hwndstr) == false)
+ {
+ sm->hParentWnd = (HWND)ToInt64(hwndstr);
+ }
+ }
+
+ Free(hwndstr);
+ Free(title);
+ Free(hub);
+ Free(password);
+ Free(host);
+ }
+ }
+ }
+
+ Free(cmdline);
+
+ c->Free(c);
+}
+
+// Release
+void FreeSM()
+{
+ FreeSMEx(false);
+}
+void FreeSMEx(bool from_cm)
+{
+ if (sm == NULL)
+ {
+ // Uninitialized
+ return;
+ }
+
+ if (from_cm == false)
+ {
+ FreeCM();
+
+ SmFreeSettingList();
+ }
+
+ ReleaseCedar(sm->Cedar);
+
+ if (from_cm == false)
+ {
+ FreeWinUi();
+ }
+
+ if (sm->TempSetting != NULL)
+ {
+ Free(sm->TempSetting);
+ }
+
+ Free(sm);
+ sm = NULL;
+}
+
+// Running the Server Manager
+void SMExec()
+{
+ InitSM();
+ MainSM();
+ FreeSM();
+}
+
+#endif // WIN32
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/SM.h b/src/Cedar/SM.h
new file mode 100644
index 00000000..10d1dab8
--- /dev/null
+++ b/src/Cedar/SM.h
@@ -0,0 +1,95 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// SM.h
+// Header of SM.c
+
+#ifndef SM_H
+#define SM_H
+
+void SMExec();
+
+#endif // SM_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/SMInner.h b/src/Cedar/SMInner.h
new file mode 100644
index 00000000..2bf8cdc8
--- /dev/null
+++ b/src/Cedar/SMInner.h
@@ -0,0 +1,801 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// SMInner.h
+// The internal header of SM.c
+
+// Constants
+#define SM_REG_KEY "Software\\SoftEther Corporation\\PacketiX VPN\\Server Manager"
+#define SM_CERT_REG_KEY "Software\\SoftEther Corporation\\PacketiX VPN\\Server Manager\\Cert Tool"
+#define SM_SETTING_REG_KEY "Software\\SoftEther Corporation\\PacketiX VPN\\Server Manager\\Settings"
+#define SM_LASTHUB_REG_KEY "Software\\SoftEther Corporation\\PacketiX VPN\\Server Manager\\Last HUB Name"
+
+#define NAME_OF_VPN_SERVER_MANAGER "vpnsmgr"
+#define NAME_OF_VPN_SERVER_TARGET "vpnserver@%s"
+#define NAME_OF_VPN_BRIDGE_TARGET "vpnbridge@%s"
+
+// Constants (Old value)
+#define SM_SETTING_REG_KEY_OLD "Software\\SoftEther Corporation\\SoftEther VPN 2.0\\Server Manager\\Settings"
+
+// Connection setting
+typedef struct SETTING
+{
+ wchar_t Title[MAX_SIZE]; // Setting Name
+ bool ServerAdminMode; // Server management mode
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB name
+ UCHAR HashedPassword[SHA1_SIZE]; // Password
+ CLIENT_OPTION ClientOption; // Client Option
+ UCHAR Reserved[10240 - sizeof(bool) * 8 - SHA1_SIZE]; // Reserved area
+} SETTING;
+
+// Structure declaration
+typedef struct SM
+{
+ CEDAR *Cedar; // Cedar
+ LIST *SettingList; // Setting List
+ SETTING *TempSetting; // Temporaly setting
+ HWND hParentWnd; // Parent window handle
+ WINUI_UPDATE *Update; // Updater
+} SM;
+
+// Edit connection settings
+typedef struct SM_EDIT_SETTING
+{
+ bool EditMode; // Edit mode
+ SETTING *OldSetting; // Pointer to the previous settings
+ SETTING *Setting; // Pointer to the configuration
+ bool Inited; // Initialized flag
+} SM_EDIT_SETTING;
+
+// Server management dialog
+typedef struct SM_SERVER
+{
+ RPC *Rpc; // RPC
+ char ServerName[MAX_HOST_NAME_LEN + 1]; // Server name
+ wchar_t Title[MAX_SIZE]; // Title
+ bool ServerAdminMode; // Server management mode
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB name
+ UINT ServerType; // Type of server
+ bool Bridge; // VPN Bridge product
+ UINT PolicyVer; // Policy version
+ RPC_SERVER_STATUS ServerStatus; // Server status
+ RPC_SERVER_INFO ServerInfo; // Server Information
+ CAPSLIST *CapsList; // Caps list
+ SETTING *CurrentSetting; // The current connection settings
+ wchar_t *AdminMsg; // Message for Administrators
+ bool IPsecMessageDisplayed; // Whether to have already displayed a message about IPsec
+ bool VgsMessageDisplayed; // Whether to have already displayed a message about VGS
+ WINUI_UPDATE *Update; // Update notification
+ bool IsInClient; // Within VPN Client mode
+} SM_SERVER;
+
+typedef void (SM_STATUS_INIT_PROC)(HWND hWnd, SM_SERVER *p, void *param);
+typedef bool (SM_STATUS_REFRESH_PROC)(HWND hWnd, SM_SERVER *p, void *param);
+
+// Information display dialog
+typedef struct SM_STATUS
+{
+ SM_SERVER *p; // Pointer to the P
+ void *Param; // Parameter
+ UINT Icon; // Icon
+ wchar_t *Caption; // Title
+ bool show_refresh_button; // Show Updates button
+ bool NoImage; // No image
+ SM_STATUS_INIT_PROC *InitProc;
+ SM_STATUS_REFRESH_PROC *RefreshProc;
+} SM_STATUS;
+
+// Virtual HUB edit dialog
+typedef struct SM_EDIT_HUB
+{
+ SM_SERVER *p; // P
+ bool EditMode; // Edit mode
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB name
+} SM_EDIT_HUB;
+
+// SSL related
+typedef struct SM_SSL
+{
+ SM_SERVER *p; // P
+ X *Cert; // Certificate
+ K *Key; // Secret key
+ bool SetCertAndKey; // Set the key
+} SM_SSL;
+
+// Save the certificate
+typedef struct SM_SAVE_KEY_PAIR
+{
+ X *Cert; // Certificate
+ K *Key; // Secret key
+ char *Pass; // Passphrase
+} SM_SAVE_KEY_PAIR;
+
+// Connection information
+typedef struct SM_CONNECTION_INFO
+{
+ SM_SERVER *p; // P
+ char *ConnectionName; // Connection name
+} SM_CONNECTION_INFO;
+
+// Management of HUB
+typedef struct SM_HUB
+{
+ SM_SERVER *p; // P
+ RPC *Rpc; // RPC
+ char *HubName; // HUB name
+} SM_HUB;
+
+// Show the User list
+typedef struct SM_USER
+{
+ SM_SERVER *p; // P
+ RPC *Rpc; // RPC
+ SM_HUB *Hub; // HUB
+ char *GroupName; // Filter by group name
+ bool SelectMode; // Selection mode
+ char *SelectedName; // User name of the selected
+ bool AllowGroup; // Allow selection of group
+ bool CreateNow; // Create a user immediately
+} SM_USER;
+
+// Edit the User
+typedef struct SM_EDIT_USER
+{
+ bool Inited; // Initialized flag
+ bool EditMode; // Edit mode
+ SM_SERVER *p; // P
+ RPC *Rpc; // RPC
+ SM_HUB *Hub; // HUB
+ RPC_SET_USER SetUser; // Configure the User
+} SM_EDIT_USER;
+
+// User information
+typedef struct SM_USER_INFO
+{
+ SM_SERVER *p; // P
+ RPC *Rpc; // RPC
+ SM_HUB *Hub; // HUB
+ char *Username; // Username
+} SM_USER_INFO;
+
+// Policy
+typedef struct SM_POLICY
+{
+ bool Inited; // Initialize
+ POLICY *Policy; // Policy
+ wchar_t *Caption; // Title
+ bool CascadeMode; // Cascade mode
+ UINT Ver; // Version
+} SM_POLICY;
+
+// Show the Group list
+typedef struct SM_GROUP
+{
+ SM_SERVER *p; // P
+ RPC *Rpc; // RPC
+ SM_HUB *Hub; // HUB
+ bool SelectMode; // Selection mode
+ char *SelectedGroupName; // Group name of the selected
+} SM_GROUP;
+
+// Edit the Group
+typedef struct SM_EDIT_GROUP
+{
+ bool Inited; // Initialization flag
+ bool EditMode; // Edit mode
+ SM_SERVER *p; // P
+ RPC *Rpc; // RPC
+ SM_HUB *Hub; // HUB
+ RPC_SET_GROUP SetGroup; // Group Settings
+} SM_EDIT_GROUP;
+
+// Access list
+typedef struct SM_ACCESS_LIST
+{
+ RPC *Rpc; // RPC
+ SM_HUB *Hub; // HUB
+ LIST *AccessList; // Access list
+} SM_ACCESS_LIST;
+
+// Edit the access list
+typedef struct SM_EDIT_ACCESS
+{
+ SM_HUB *Hub; // HUB
+ bool Inited; // Initialization flag
+ bool EditMode; // Edit mode
+ SM_ACCESS_LIST *AccessList; // Access list
+ ACCESS *Access; // Access list item
+} SM_EDIT_ACCESS;
+
+// Display status of the access list
+typedef struct SM_LINK
+{
+ SM_HUB *Hub; // HUB
+ wchar_t *AccountName; // Account name
+} SM_LINK;
+
+// Session status
+typedef struct SM_SESSION_STATUS
+{
+ SM_HUB *Hub; // HUB
+ char *SessionName; // Session name
+} SM_SESSION_STATUS;
+
+// Address table
+typedef struct SM_TABLE
+{
+ SM_HUB *Hub; // HUB
+ RPC *Rpc; // RPC
+ char *SessionName; // Session name
+} SM_TABLE;
+
+// Certificate tool
+typedef struct SM_CERT
+{
+ X *x; // Generated certificate
+ K *k; // Generated secret key
+ X *root_x; // Root certificate
+ K *root_k; // Private key of the root certificate
+ bool do_not_save; // Do not save to the file
+ char *default_cn; // Default CN
+ bool root_only; // Only the root certificate
+} SM_CERT;
+
+// Config edit
+typedef struct SM_CONFIG
+{
+ SM_SERVER *s; // SM_SERVER
+ RPC_CONFIG Config; // Config body
+} SM_CONFIG;
+
+// Hub_admin_option edit
+typedef struct SM_EDIT_AO
+{
+ SM_EDIT_HUB *e;
+ bool CanChange;
+ RPC_ADMIN_OPTION CurrentOptions;
+ RPC_ADMIN_OPTION DefaultOptions;
+ bool NewMode;
+ char Name[MAX_ADMIN_OPTION_NAME_LEN + 1];
+ UINT Value;
+ bool ExtOption;
+} SM_EDIT_AO;
+
+// Editing the switch
+typedef struct SM_L3SW
+{
+ SM_SERVER *s;
+ char *SwitchName;
+ bool Enable;
+} SM_L3SW;
+
+// Specify the certificate and private key in the smart card
+typedef struct SM_SECURE_KEYPAIR
+{
+ UINT Id;
+ bool UseCert;
+ bool UseKey;
+ char CertName[MAX_SIZE];
+ char KeyName[MAX_SIZE];
+ bool Flag;
+ UINT BitmapId;
+} SM_SECURE_KEYPAIR;
+
+// CRL edit
+typedef struct SM_EDIT_CRL
+{
+ SM_HUB *s;
+ bool NewCrl;
+ UINT Key;
+} SM_EDIT_CRL;
+
+// AC list edit
+typedef struct SM_EDIT_AC_LIST
+{
+ SM_EDIT_HUB *s;
+ LIST *AcList;
+} SM_EDIT_AC_LIST;
+
+// AC edit
+typedef struct SM_EDIT_AC
+{
+ SM_EDIT_AC_LIST *e;
+ UINT id;
+} SM_EDIT_AC;
+
+// Download the log File
+typedef struct SM_READ_LOG_FILE
+{
+ HWND hWnd;
+ SM_SERVER *s;
+ char *server_name;
+ char *filepath;
+ UINT totalsize;
+ bool cancel_flag;
+ BUF *Buffer;
+} SM_READ_LOG_FILE;
+
+// Setup dialog
+typedef struct SM_SETUP
+{
+ SM_SERVER *s;
+ RPC *Rpc;
+ bool IsBridge;
+ bool UseRemote; // Remote Access VPN
+ bool UseSite; // LAN-to-LAN VPN
+ bool UseSiteEdge; // VPN Server / Bridge to be installed in each site
+ char HubName[MAX_HUBNAME_LEN + 1]; // Virtual HUB name
+ bool Flag1;
+ bool Flag2;
+} SM_SETUP;
+
+// EtherIP ID edit dialog
+typedef struct SM_ETHERIP_ID
+{
+ SM_SERVER *s;
+ bool EditMode;
+ char EditId[MAX_SIZE];
+ bool InitCompleted;
+ ETHERIP_ID Data;
+} SM_ETHERIP_ID;
+
+// DDNS dialog
+typedef struct SM_DDNS
+{
+ SM_SERVER *s;
+ DDNS_CLIENT_STATUS Status;
+ bool Flag;
+ bool HostnameSetFlag;
+ bool Changed;
+ bool Silent;
+ bool NoChangeCert;
+ bool DoNotPoll;
+} SM_DDNS;
+
+// VPN Azure dialog
+typedef struct SM_AZURE
+{
+ SM_SERVER *s;
+ bool OnSetup;
+} SM_AZURE;
+
+
+
+// Function prototype
+void InitSM();
+void InitSMEx(bool from_cm);
+void SmParseCommandLine();
+void MainSM();
+void FreeSM();
+void FreeSMEx(bool from_cm);
+void SmMainDlg();
+UINT SmMainDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmMainDlgInit(HWND hWnd);
+void SmMainDlgUpdate(HWND hWnd);
+void SmInitSettingList();
+void SmFreeSettingList();
+void SmWriteSettingList();
+void SmLoadSettingList();
+void SmInitDefaultSettingList();
+int SmCompareSetting(void *p1, void *p2);
+SETTING *SmGetSetting(wchar_t *title);
+bool SmAddSetting(SETTING *s);
+void SmDeleteSetting(wchar_t *title);
+bool SmCheckNewName(SETTING *s, wchar_t *new_title);
+void SmRefreshSetting(HWND hWnd);
+void SmRefreshSettingEx(HWND hWnd, wchar_t *select_name);
+bool SmAddSettingDlg(HWND hWnd, wchar_t *new_name, UINT new_name_size);
+bool SmEditSettingDlg(HWND hWnd);
+UINT SmEditSettingDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmEditSettingDlgInit(HWND hWnd, SM_EDIT_SETTING *p);
+void SmEditSettingDlgUpdate(HWND hWnd, SM_EDIT_SETTING *p);
+void SmEditSettingDlgOnOk(HWND hWnd, SM_EDIT_SETTING *p);
+void SmConnect(HWND hWnd, SETTING *s);
+void SmConnectEx(HWND hWnd, SETTING *s, bool is_in_client);
+char *SmPassword(HWND hWnd, char *server_name);
+UINT SmServerDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmServerDlgInit(HWND hWnd, SM_SERVER *p);
+void SmServerDlgUpdate(HWND hWnd, SM_SERVER *p);
+void SmServerDlgRefresh(HWND hWnd, SM_SERVER *p);
+void SmStatusDlg(HWND hWnd, SM_SERVER *p, void *param, bool no_image, bool show_refresh_button, wchar_t *caption, UINT icon,
+ SM_STATUS_INIT_PROC *init, SM_STATUS_REFRESH_PROC *refresh);
+UINT SmStatusDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+bool SmRefreshHubStatus(HWND hWnd, SM_SERVER *p, void *param);
+void SmInsertTrafficInfo(LVB *b, TRAFFIC *t);
+bool SmCreateHubDlg(HWND hWnd, SM_SERVER *p);
+bool SmEditHubDlg(HWND hWnd, SM_SERVER *p, char *hubname);
+UINT SmEditHubProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmEditHubInit(HWND hWnd, SM_EDIT_HUB *s);
+void SmEditHubUpdate(HWND hWnd, SM_EDIT_HUB *s);
+void SmEditHubOnOk(HWND hWnd, SM_EDIT_HUB *s);
+bool SmCreateListenerDlg(HWND hWnd, SM_SERVER *p);
+UINT SmCreateListenerDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSslDlg(HWND hWnd, SM_SERVER *p);
+UINT SmSslDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSslDlgInit(HWND hWnd, SM_SSL *s);
+void SmSslDlgOnOk(HWND hWnd, SM_SSL *s);
+void SmSslDlgUpdate(HWND hWnd, SM_SSL *s);
+void SmGetCertInfoStr(wchar_t *str, UINT size, X *x);
+bool SmRegenerateServerCert(HWND hWnd, SM_SERVER *server, char *default_cn, X **x, K **k, bool root_only);
+bool SmSaveKeyPairDlg(HWND hWnd, X *x, K *k);
+UINT SmSaveKeyPairDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSaveKeyPairDlgInit(HWND hWnd, SM_SAVE_KEY_PAIR *s);
+void SmSaveKeyPairDlgUpdate(HWND hWnd, SM_SAVE_KEY_PAIR *s);
+void SmSaveKeyPairDlgOnOk(HWND hWnd, SM_SAVE_KEY_PAIR *s);
+bool SmRefreshServerStatus(HWND hWnd, SM_SERVER *p, void *param);
+bool SmRefreshServerInfo(HWND hWnd, SM_SERVER *p, void *param);
+void SmPrintNodeInfo(LVB *b, NODE_INFO *info);
+wchar_t *SmGetConnectionTypeStr(UINT type);
+void SmConnectionDlg(HWND hWnd, SM_SERVER *p);
+UINT SmConnectionDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmConnectionDlgInit(HWND hWnd, SM_SERVER *p);
+void SmConnectionDlgRefresh(HWND hWnd, SM_SERVER *p);
+void SmConnectionDlgUpdate(HWND hWnd, SM_SERVER *p);
+bool SmRefreshConnectionStatus(HWND hWnd, SM_SERVER *p, void *param);
+bool SmFarmDlg(HWND hWnd, SM_SERVER *p);
+UINT SmFarmDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmFarmDlgInit(HWND hWnd, SM_SERVER *p);
+void SmFarmDlgUpdate(HWND hWnd, SM_SERVER *p);
+void SmFarmDlgOnOk(HWND hWnd, SM_SERVER *p);
+LIST *SmStrToPortList(char *str);
+UINT SmFarmMemberDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmFarmMemberDlgInit(HWND hWnd, SM_SERVER *p);
+void SmFarmMemberDlgUpdate(HWND hWnd, SM_SERVER *p);
+void SmFarmMemberDlgRefresh(HWND hWnd, SM_SERVER *p);
+void SmFarmMemberDlgOnOk(HWND hWnd, SM_SERVER *p);
+void SmFarmMemberCert(HWND hWnd, SM_SERVER *p, UINT id);
+bool SmRefreshFarmMemberInfo(HWND hWnd, SM_SERVER *p, void *param);
+bool SmRefreshFarmConnectionInfo(HWND hWnd, SM_SERVER *p, void *param);
+UINT SmChangeServerPasswordDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmHubDlg(HWND hWnd, SM_HUB *s);
+UINT SmHubDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmHubDlgInit(HWND hWnd, SM_HUB *s);
+void SmHubDlgUpdate(HWND hWnd, SM_HUB *s);
+void SmHubDlgRefresh(HWND hWnd, SM_HUB *s);
+void SmUserListDlg(HWND hWnd, SM_HUB *s);
+UINT SmUserListProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmUserListInit(HWND hWnd, SM_USER *s);
+void SmUserListRefresh(HWND hWnd, SM_USER *s);
+void SmUserListUpdate(HWND hWnd, SM_USER *s);
+wchar_t *SmGetAuthTypeStr(UINT id);
+bool SmCreateUserDlg(HWND hWnd, SM_HUB *s);
+UINT SmEditUserDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmEditUserDlgInit(HWND hWnd, SM_EDIT_USER *s);
+void SmEditUserDlgUpdate(HWND hWnd, SM_EDIT_USER *s);
+void SmEditUserDlgOk(HWND hWnd, SM_EDIT_USER *s);
+bool SmPolicyDlg(HWND hWnd, POLICY *p, wchar_t *caption);
+bool SmPolicyDlgEx(HWND hWnd, POLICY *p, wchar_t *caption, bool cascade_mode);
+bool SmPolicyDlgEx2(HWND hWnd, POLICY *p, wchar_t *caption, bool cascade_mode, UINT ver);
+UINT SmPolicyDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmPolicyDlgInit(HWND hWnd, SM_POLICY *s);
+void SmPolicyDlgUpdate(HWND hWnd, SM_POLICY *s);
+void SmPolicyDlgOk(HWND hWnd, SM_POLICY *s);
+bool SmEditUserDlg(HWND hWnd, SM_HUB *s, char *username);
+bool SmRefreshUserInfo(HWND hWnd, SM_SERVER *s, void *param);
+void SmGroupListDlg(HWND hWnd, SM_HUB *s);
+char *SmSelectGroupDlg(HWND hWnd, SM_HUB *s, char *default_name);
+UINT SmGroupListDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmGroupListDlgInit(HWND hWnd, SM_GROUP *s);
+void SmGroupListDlgUpdate(HWND hWnd, SM_GROUP *s);
+void SmGroupListDlgRefresh(HWND hWnd, SM_GROUP *s);
+bool SmCreateGroupDlg(HWND hWnd, SM_GROUP *s);
+bool SmEditGroupDlg(HWND hWnd, SM_GROUP *s, char *name);
+UINT SmEditGroupDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmEditGroupDlgInit(HWND hWnd, SM_EDIT_GROUP *g);
+void SmEditGroupDlgUpdate(HWND hWnd, SM_EDIT_GROUP *g);
+void SmEditGroupDlgOnOk(HWND hWnd, SM_EDIT_GROUP *g);
+void SmUserListDlgEx(HWND hWnd, SM_HUB *s, char *groupname, bool create);
+void SmAccessListDlg(HWND hWnd, SM_HUB *s);
+UINT SmAccessListProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmAccessListInit(HWND hWnd, SM_ACCESS_LIST *s);
+void SmAccessListUpdate(HWND hWnd, SM_ACCESS_LIST *s);
+void SmAccessListRefresh(HWND hWnd, SM_ACCESS_LIST *s);
+bool SmAddAccess(HWND hWnd, SM_ACCESS_LIST *s, bool ipv6);
+bool SmCloneAccess(HWND hWnd, SM_ACCESS_LIST *s, ACCESS *t);
+bool SmEditAccess(HWND hWnd, SM_ACCESS_LIST *s, ACCESS *a);
+UINT SmEditAccessDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmEditAccessInit(HWND hWnd, SM_EDIT_ACCESS *s);
+void SmEditAccessUpdate(HWND hWnd, SM_EDIT_ACCESS *s);
+void SmEditAccessOnOk(HWND hWnd, SM_EDIT_ACCESS *s);
+void SmRedirect(HWND hWnd, SM_EDIT_ACCESS *s);
+UINT SmRedirectDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmRedirectDlgInit(HWND hWnd, SM_EDIT_ACCESS *s);
+void SmRedirectDlgUpdate(HWND hWnd, SM_EDIT_ACCESS *s);
+UINT SmSimulationDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSimulationUpdate(HWND hWnd, SM_EDIT_ACCESS *s);
+void SmSimulationInit(HWND hWnd, SM_EDIT_ACCESS *s);
+void SmSimulationOnOk(HWND hWnd, SM_EDIT_ACCESS *s);
+char *SmSelectUserDlg(HWND hWnd, SM_HUB *s, char *default_name);
+char *SmSelectUserDlgEx(HWND hWnd, SM_HUB *s, char *default_name, bool allow_group);
+void SmRadiusDlg(HWND hWnd, SM_HUB *s);
+UINT SmRadiusDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmRadiusDlgInit(HWND hWnd, SM_HUB *s);
+void SmRadiusDlgUpdate(HWND hWnd, SM_HUB *s);
+void SmRadiusDlgOnOk(HWND hWnd, SM_HUB *s);
+void SmLinkDlg(HWND hWnd, SM_HUB *s);
+void SmLinkDlgEx(HWND hWnd, SM_HUB *s, bool createNow);
+UINT SmLinkDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmLinkDlgInit(HWND hWnd, SM_HUB *s);
+void SmLinkDlgUpdate(HWND hWnd, SM_HUB *s);
+void SmLinkDlgRefresh(HWND hWnd, SM_HUB *s);
+bool SmLinkCreate(HWND hWnd, SM_HUB *s);
+bool SmLinkCreateEx(HWND hWnd, SM_HUB *s, bool connectNow);
+bool SmLinkEdit(HWND hWnd, SM_HUB *s, wchar_t *name);
+bool SmRefreshLinkStatus(HWND hWnd, SM_SERVER *s, void *param);
+UINT SmLogDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmLogDlgInit(HWND hWnd, SM_HUB *s);
+void SmLogDlgUpdate(HWND hWnd, SM_HUB *s);
+void SmLogDlgOnOk(HWND hWnd, SM_HUB *s);
+void SmCaDlg(HWND hWnd, SM_HUB *s);
+UINT SmCaDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmCaDlgInit(HWND hWnd, SM_HUB *s);
+void SmCaDlgRefresh(HWND hWnd, SM_HUB *s);
+void SmCaDlgUpdate(HWND hWnd, SM_HUB *s);
+void SmCaDlgOnOk(HWND hWnd, SM_HUB *s);
+bool SmCaDlgAdd(HWND hWnd, SM_HUB *s);
+void SmSessionDlg(HWND hWnd, SM_HUB *s);
+UINT SmSessionDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSessionDlgInit(HWND hWnd, SM_HUB *s);
+void SmSessionDlgUpdate(HWND hWnd, SM_HUB *s);
+void SmSessionDlgRefresh(HWND hWnd, SM_HUB *s);
+bool SmRefreshSessionStatus(HWND hWnd, SM_SERVER *s, void *param);
+void SmMacTableDlg(HWND hWnd, SM_HUB *s, char *session_name);
+UINT SmMacTableDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmMacTableDlgInit(HWND hWnd, SM_TABLE *s);
+void SmMacTableDlgUpdate(HWND hWnd, SM_TABLE *s);
+void SmMacTableDlgRefresh(HWND hWnd, SM_TABLE *s);
+void SmIpTableDlg(HWND hWnd, SM_HUB *s, char *session_name);
+UINT SmIpTableDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmIpTableDlgInit(HWND hWnd, SM_TABLE *s);
+void SmIpTableDlgUpdate(HWND hWnd, SM_TABLE *s);
+void SmIpTableDlgRefresh(HWND hWnd, SM_TABLE *s);
+bool SmCreateCert(HWND hWnd, X **x, K **k, bool do_not_save, char *default_cn, bool root_only);
+UINT SmCreateCertDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmCreateCertDlgInit(HWND hWnd, SM_CERT *s);
+void SmCreateCertDlgUpdate(HWND hWnd, SM_CERT *s);
+void SmCreateCertDlgOnOk(HWND hWnd, SM_CERT *s);
+UINT SmSNATDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSNATDlgUpdate(HWND hWnd, SM_HUB *s);
+void SmBridgeDlg(HWND hWnd, SM_SERVER *s);
+void SmInstallWinPcap(HWND hWnd, SM_SERVER *s);
+UINT SmBridgeDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+UINT SmBridgeDlgInit(HWND hWnd, SM_SERVER *s);
+void SmBridgeDlgUpdate(HWND hWnd, SM_SERVER *s);
+void SmBridgeDlgRefresh(HWND hWnd, SM_SERVER *s);
+void SmBridgeDlgOnOk(HWND hWnd, SM_SERVER *s);
+void SmAddServerCaps(LVB *b, CAPSLIST *t);
+void SmConfig(HWND hWnd, SM_SERVER *s);
+UINT SmConfigDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmConfigDlgInit(HWND hWnd, SM_CONFIG *c);
+void SmHubAdminOption(HWND hWnd, SM_EDIT_HUB *e);
+void SmHubExtOption(HWND hWnd, SM_EDIT_HUB *e);
+UINT SmHubAdminOptionDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmHubAdminOptionDlgUpdate(HWND hWnd, SM_EDIT_AO *a);
+void SmHubAdminOptionDlgInit(HWND hWnd, SM_EDIT_AO *a);
+void SmHubAdminOptionDlgOk(HWND hWnd, SM_EDIT_AO *a);
+UINT SmHubAdminOptionValueDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmHubAdminOptionValueDlgUpdate(HWND hWnd, SM_EDIT_AO *a);
+void SmL3(HWND hWnd, SM_SERVER *s);
+UINT SmL3Dlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmL3DlgInit(HWND hWnd, SM_SERVER *s);
+void SmL3DlgUpdate(HWND hWnd, SM_SERVER *s);
+void SmL3DlgRefresh(HWND hWnd, SM_SERVER *s);
+UINT SmL3AddDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmL3AddDlgUpdate(HWND hWnd, SM_SERVER *s);
+UINT SmL3SwDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmL3SwDlgInit(HWND hWnd, SM_L3SW *w);
+void SmL3SwDlgUpdate(HWND hWnd, SM_L3SW *w);
+void SmL3SwDlgRefresh(HWND hWnd, SM_L3SW *w);
+UINT SmL3SwIfDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmL3SwIfDlgInit(HWND hWnd, SM_L3SW *w);
+void SmL3SwIfDlgUpdate(HWND hWnd, SM_L3SW *w);
+UINT SmL3SwTableDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmL3SwTableDlgInit(HWND hWnd, SM_L3SW *w);
+void SmL3SwTableDlgUpdate(HWND hWnd, SM_L3SW *w);
+bool SmL3IsSwActive(SM_SERVER *s, char *name);
+UINT SmGetCurrentSecureId(HWND hWnd);
+UINT SmGetCurrentSecureIdFromReg();
+UINT SmSelectSecureId(HWND hWnd);
+void SmWriteSelectSecureIdReg(UINT id);
+bool SmSelectKeyPair(HWND hWnd, char *cert_name, UINT cert_name_size, char *key_name, UINT key_name_size);
+bool SmSelectKeyPairEx(HWND hWnd, char *cert_name, UINT cert_name_size, char *key_name, UINT key_name_size, UINT bitmap_id);
+UINT SmSelectKeyPairDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSelectKeyPairDlgInit(HWND hWnd, SM_SECURE_KEYPAIR *k);
+void SmSelectKeyPairDlgUpdate(HWND hWnd, SM_SECURE_KEYPAIR *k);
+void SmSelectKeyPairDlgRefresh(HWND hWnd, SM_SECURE_KEYPAIR *k);
+void SmSecureManager(HWND hWnd);
+UINT SmCrlDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmCrlDlgInit(HWND hWnd, SM_HUB *s);
+void SmCrlDlgUpdate(HWND hWnd, SM_HUB *s);
+void SmCrlDlgRefresh(HWND hWnd, SM_HUB *s);
+UINT SmEditCrlDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmEditCrlDlgInit(HWND hWnd, SM_EDIT_CRL *c);
+void SmEditCrlDlgUpdate(HWND hWnd, SM_EDIT_CRL *c);
+void SmEditCrlDlgOnOk(HWND hWnd, SM_EDIT_CRL *c);
+void SmEditCrlDlgOnLoad(HWND hWnd, SM_EDIT_CRL *c);
+void SmEditCrlDlgSetName(HWND hWnd, NAME *name);
+void SmEditCrlDlgSetSerial(HWND hWnd, X_SERIAL *serial);
+void SmEditCrlDlgSetHash(HWND hWnd, UCHAR *hash_md5, UCHAR *hash_sha1);
+void SmHubAc(HWND hWnd, SM_EDIT_HUB *s);
+UINT SmHubAcDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmHubAcDlgInit(HWND hWnd, SM_EDIT_AC_LIST *p);
+void SmHubAcDlgUpdate(HWND hWnd, SM_EDIT_AC_LIST *p);
+void SmHubAcDlgRefresh(HWND hWnd, SM_EDIT_AC_LIST *p);
+UINT SmHubEditAcDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmHubEditAcDlgInit(HWND hWnd, SM_EDIT_AC *p);
+void SmHubEditAcDlgUpdate(HWND hWnd, SM_EDIT_AC *p);
+void SmHubEditAcDlgOnOk(HWND hWnd, SM_EDIT_AC *p);
+UINT SmLogFileDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmLogFileDlgInit(HWND hWnd, SM_SERVER *p);
+void SmLogFileDlgRefresh(HWND hWnd, SM_SERVER *p);
+void SmLogFileDlgUpdate(HWND hWnd, SM_SERVER *p);
+void SmLogFileStartDownload(HWND hWnd, SM_SERVER *s, char *server_name, char *filepath, UINT totalsize);
+UINT SmReadLogFile(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+bool SmReadLogFileProc(DOWNLOAD_PROGRESS *g);
+UINT SmSaveLogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmLicense(HWND hWnd, SM_SERVER *s);
+UINT SmLicenseDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmLicenseDlgInit(HWND hWnd, SM_SERVER *s);
+void SmLicenseDlgRefresh(HWND hWnd, SM_SERVER *s);
+void SmLicenseDlgUpdate(HWND hWnd, SM_SERVER *s);
+bool SmLicenseAdd(HWND hWnd, SM_SERVER *s);
+UINT SmLicenseAddDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmLicenseAddDlgInit(HWND hWnd, SM_SERVER *s);
+void SmLicenseAddDlgUpdate(HWND hWnd, SM_SERVER *s);
+void SmLicenseAddDlgShiftTextItem(HWND hWnd, UINT id1, UINT id2, UINT *next_focus);
+void SmLicenseAddDlgGetText(HWND hWnd, char *str, UINT size);
+void SmLicenseAddDlgOnOk(HWND hWnd, SM_SERVER *s);
+bool SmSetup(HWND hWnd, SM_SERVER *s);
+UINT SmSetupDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSetupDlgInit(HWND hWnd, SM_SETUP *s);
+void SmSetupDlgUpdate(HWND hWnd, SM_SETUP *s);
+void SmSetupDlgOnOk(HWND hWnd, SM_SETUP *s);
+UINT SmSetupHubDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSetupHubDlgUpdate(HWND hWnd, SM_SETUP *s);
+bool SmSetupInit(HWND hWnd, SM_SETUP *s);
+bool SmSetupDeleteAllHub(HWND hWnd, SM_SETUP *s);
+bool SmSetupDeleteAllLocalBridge(HWND hWnd, SM_SETUP *s);
+bool SmSetupDeleteAllLayer3(HWND hWnd, SM_SETUP *s);
+bool SmSetupDeleteAllObjectInBridgeHub(HWND hWnd, SM_SETUP *s);
+void SmSetupStep(HWND hWnd, SM_SETUP *s);
+UINT SmSetupStepDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSetupStepDlgInit(HWND hWnd, SM_SETUP *s);
+void SmSetupOnClose(HWND hWnd, SM_SETUP *s);
+bool SmSetupIsNew(SM_SERVER *s);
+void SmVLan(HWND hWnd, SM_SERVER *s);
+UINT SmVLanDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmVLanDlgInit(HWND hWnd, SM_SERVER *s);
+void SmVLanDlgRefresh(HWND hWnd, SM_SERVER *s);
+void SmVLanDlgUpdate(HWND hWnd, SM_SERVER *s);
+void SmHubMsg(HWND hWnd, SM_EDIT_HUB *s);
+UINT SmHubMsgDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmHubMsgDlgInit(HWND hWnd, SM_EDIT_HUB *s);
+void SmHubMsgDlgUpdate(HWND hWnd, SM_EDIT_HUB *s);
+void SmHubMsgDlgOnOk(HWND hWnd, SM_EDIT_HUB *s);
+void SmIPsec(HWND hWnd, SM_SERVER *s);
+UINT SmIPsecDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmIPsecDlgInit(HWND hWnd, SM_SERVER *s);
+void SmIPsecDlgOnOk(HWND hWnd, SM_SERVER *s);
+void SmIPsecDlgUpdate(HWND hWnd, SM_SERVER *s);
+void SmIPsecDlgGetSetting(HWND hWnd, IPSEC_SERVICES *sl);
+void SmEtherIp(HWND hWnd, SM_SERVER *s);
+UINT SmEtherIpDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmEtherIpDlgInit(HWND hWnd, SM_SERVER *s);
+void SmEtherIpDlgRefresh(HWND hWnd, SM_SERVER *s);
+void SmEtherIpDlgUpdate(HWND hWnd, SM_SERVER *s);
+bool SmEtherIpId(HWND hWnd, SM_ETHERIP_ID *t);
+UINT SmEtherIpIdDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmEtherIpIdDlgInit(HWND hWnd, SM_ETHERIP_ID *t);
+void SmEtherIpIdDlgOnOk(HWND hWnd, SM_ETHERIP_ID *t);
+void SmEtherIpIdDlgUpdate(HWND hWnd, SM_ETHERIP_ID *t);
+void SmEtherIpIdDlgGetSetting(HWND hWnd, SM_ETHERIP_ID *t);
+bool SmDDns(HWND hWnd, SM_SERVER *s, bool silent, bool no_change_cert);
+UINT SmDDnsDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmDDnsDlgInit(HWND hWnd, SM_DDNS *d);
+void SmDDnsRefresh(HWND hWnd, SM_DDNS *d);
+void SmDDnsDlgOnOk(HWND hWnd, SM_DDNS *d);
+void SmDDnsDlgUpdate(HWND hWnd, SM_DDNS *d);
+void SmOpenVpn(HWND hWnd, SM_SERVER *s);
+UINT SmOpenVpnDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmOpenVpnDlgInit(HWND hWnd, SM_SERVER *s);
+void SmOpenVpnDlgOnOk(HWND hWnd, SM_SERVER *s, bool no_close);
+void SmOpenVpnDlgUpdate(HWND hWnd, SM_SERVER *s);
+void SmOpenVpn(HWND hWnd, SM_SERVER *s);
+void SmSpecialListener(HWND hWnd, SM_SERVER *s);
+UINT SmSpecialListenerDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmSpecialListenerDlgInit(HWND hWnd, SM_SERVER *s);
+void SmSpecialListenerDlgOnOk(HWND hWnd, SM_SERVER *s);
+void SmShowIPSecMessageIfNecessary(HWND hWnd, SM_SERVER *p);
+UINT SmVmBridgeDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmAzure(HWND hWnd, SM_SERVER *s, bool on_setup);
+UINT SmAzureDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmAzureDlgOnInit(HWND hWnd, SM_AZURE *a);
+void SmAzureDlgRefresh(HWND hWnd, SM_AZURE *a);
+void SmAzureSetStatus(HWND hWnd, SM_AZURE *a);
+bool SmProxy(HWND hWnd, INTERNET_SETTING *t);
+UINT SmProxyDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void SmProxyDlgInit(HWND hWnd, INTERNET_SETTING *t);
+void SmProxyDlgUpdate(HWND hWnd, INTERNET_SETTING *t);
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/SW.c b/src/Cedar/SW.c
new file mode 100644
index 00000000..19ed156c
--- /dev/null
+++ b/src/Cedar/SW.c
@@ -0,0 +1,6569 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// SW.c
+// Setup Wizard for Win32
+
+#include <GlobalConst.h>
+
+#ifdef WIN32
+
+#define SM_C
+#define CM_C
+#define NM_C
+#define SW_C
+
+#define _WIN32_WINNT 0x0502
+#define WINVER 0x0502
+#include <winsock2.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <wininet.h>
+#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+#include "CMInner.h"
+#include "SMInner.h"
+#include "NMInner.h"
+#include "EMInner.h"
+#include "SWInner.h"
+#include "../PenCore/resource.h"
+
+//// Old MSI product information
+// VPN Server
+static SW_OLD_MSI old_msi_vpnserver[] =
+{
+ {"{B5B58F8A-D56C-4f3e-B400-235A6E007101}", "{1BDA6B01-2DB3-478c-AA5B-E973A7DC49A4}"},
+ {"{124DDAE2-B9AF-4541-B3EF-B169D9007101}", "{BCDE5CF2-7413-47d0-92E1-F6F2189D8E60}"},
+};
+static SW_OLD_MSI old_msi_vpnclient[] =
+{
+ {"{54864EDD-4FC6-4269-AA17-3E7C13607101}", "{13ED64E0-532D-4ff0-A3A0-5D700C73259E}"},
+ {"{8A215EB7-C5F2-4193-9D7D-1017F1007101}", "{AD593FE5-759E-46c6-9355-29031A8C7D44}"},
+};
+static SW_OLD_MSI old_msi_vpnbridge[] =
+{
+ {"{58CE8E96-1234-499D-CAFE-3E62261DF211}", "{211FA6A7-1234-4985-CAFE-3DD3E3151E7E}"},
+};
+
+// List of file names needed to SFX
+static char *sfx_vpn_server_bridge_files[] =
+{
+ "vpnsetup.exe",
+ "vpnserver.exe",
+ "vpnserver_x64.exe",
+ "vpnbridge.exe",
+ "vpnbridge_x64.exe",
+ "vpnsmgr.exe",
+ "vpnsmgr_x64.exe",
+ "vpncmd.exe",
+ "vpncmd_x64.exe",
+ "hamcore.se2",
+};
+static char *sfx_vpn_client_files[] =
+{
+ "vpnsetup.exe",
+ "vpnclient.exe",
+ "vpnclient_x64.exe",
+ "vpncmgr.exe",
+ "vpncmgr_x64.exe",
+ "vpncmd.exe",
+ "vpncmd_x64.exe",
+ "vpninstall.exe",
+ "vpnweb.cab",
+ "hamcore.se2",
+};
+
+// Global variables to be used out of necessity
+static bool g_stop_flag = false;
+static HANDLE g_wait_process_handle = NULL;
+
+
+// SFX generation main
+bool SwGenSfxModeMain(char *mode, wchar_t *dst)
+{
+ LIST *o;
+ bool ret = false;
+ // Validate arguments
+ if (mode == NULL || dst == NULL)
+ {
+ return false;
+ }
+
+ o = SwNewSfxFileList();
+
+ if (SwAddBasicFilesToList(o, mode))
+ {
+ if (SwCompileSfx(o, dst))
+ {
+ ret = true;
+ }
+ }
+
+ SwFreeSfxFileList(o);
+
+ return ret;
+}
+
+// Compile the SFX files
+bool SwCompileSfx(LIST *o, wchar_t *dst_filename)
+{
+ bool ret = false;
+ wchar_t exe_filename[MAX_PATH];
+ HINSTANCE hKernel32 = LoadLibraryA("kernel32.dll");
+ HANDLE (WINAPI *_BeginUpdateResourceW)(LPCWSTR, BOOL) = NULL;
+ BOOL (WINAPI *_UpdateResourceA)(HANDLE, LPCSTR, LPCSTR, WORD, LPVOID, DWORD) = NULL;
+ BOOL (WINAPI *_EndUpdateResourceW)(HANDLE, BOOL) = NULL;
+ // Validate arguments
+ if (o == NULL || dst_filename == NULL || hKernel32 == NULL)
+ {
+ return false;
+ }
+
+ // Get the API related to the resource editing
+ _BeginUpdateResourceW = (HANDLE (__stdcall *)(LPCWSTR,UINT))GetProcAddress(hKernel32, "BeginUpdateResourceW");
+ _UpdateResourceA = (UINT (__stdcall *)(HANDLE,LPCSTR,LPCSTR,WORD,LPVOID,DWORD))GetProcAddress(hKernel32, "UpdateResourceA");
+ _EndUpdateResourceW = (UINT (__stdcall *)(HANDLE,UINT))GetProcAddress(hKernel32, "EndUpdateResourceW");
+
+ if (_BeginUpdateResourceW != NULL && _UpdateResourceA != NULL && _EndUpdateResourceW != NULL)
+ {
+ // Generate the setup.exe file in the Temp directory
+ ConbinePathW(exe_filename, sizeof(exe_filename), MsGetMyTempDirW(), L"setup.exe");
+ if (FileCopyW(L"|vpnsetup_nosign.exe", exe_filename))
+ {
+ // Resource updating start
+ HANDLE h = _BeginUpdateResourceW(exe_filename, false);
+
+ if (h != NULL)
+ {
+ UINT i;
+ bool ok = true;
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ SW_SFX_FILE *f = LIST_DATA(o, i);
+ BUF *b;
+
+ // Read the original file
+ b = ReadDumpW(f->DiskFileName);
+ if (b != NULL)
+ {
+ // Add resources
+ char inner_name[MAX_PATH];
+ BUF *b2;
+ StrCpy(inner_name, sizeof(inner_name), f->InnerFileName);
+ StrUpper(inner_name);
+
+ if (StrCmpi(inner_name, "hamcore.se2") == 0)
+ {
+ // Not to re-compress the hamcore.se2 because they are already compressed
+ // Prepend "raw_" to file name
+ Format(inner_name, sizeof(inner_name), "raw_%s", f->InnerFileName);
+ StrUpper(inner_name);
+ }
+ else
+ {
+ // Compress
+ b2 = CompressBuf(b);
+ FreeBuf(b);
+ b = b2;
+ }
+
+
+ if (_UpdateResourceA(h, SW_SFX_RESOURCE_TYPE, inner_name, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
+ b->Buf, b->Size) == false)
+ {
+ ok = false;
+ }
+
+ FreeBuf(b);
+ }
+
+ if (ok == false)
+ {
+ break;
+ }
+ }
+
+ if (ok)
+ {
+ // Success to add all resources
+ if (_EndUpdateResourceW(h, false))
+ {
+ h = NULL;
+
+ // File Copy
+ if (FileCopyW(exe_filename, dst_filename))
+ {
+ // All succeed
+ ret = true;
+ }
+ }
+ }
+
+ if (ret == false)
+ {
+ // Failed to add resource
+ if (h != NULL)
+ {
+ _EndUpdateResourceW(h, true);
+ h = NULL;
+ }
+ }
+
+ FileDeleteW(exe_filename);
+ }
+ }
+ }
+
+ FreeLibrary(hKernel32);
+
+ return ret;
+}
+
+// Create new item in the SFX compression list
+SW_SFX_FILE *SwNewSfxFile(char *inner_file_name, wchar_t *disk_file_name)
+{
+ SW_SFX_FILE *f = ZeroMalloc(sizeof(SW_SFX_FILE));
+
+ StrCpy(f->InnerFileName, sizeof(f->InnerFileName), inner_file_name);
+ UniStrCpy(f->DiskFileName, sizeof(f->DiskFileName), disk_file_name);
+
+ return f;
+}
+
+// Add the basically required files for the components to SFX compressed files list
+bool SwAddBasicFilesToList(LIST *o, char *component_name)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL || component_name == NULL)
+ {
+ return false;
+ }
+
+ if (StrCmpi(component_name, "vpnserver_vpnbridge") == 0)
+ {
+ // VPN Server & VPN Bridge
+ for (i = 0; i < (sizeof(sfx_vpn_server_bridge_files) / sizeof(char *)); i++)
+ {
+ char *name = sfx_vpn_server_bridge_files[i];
+ wchar_t name_w[MAX_PATH];
+ wchar_t src_file_name[MAX_PATH];
+
+ StrToUni(name_w, sizeof(name_w), name);
+ ConbinePathW(src_file_name, sizeof(src_file_name), MsGetExeFileDirW(), name_w);
+
+ Add(o, SwNewSfxFile(name, src_file_name));
+ }
+ }
+ else if (StrCmpi(component_name, "vpnclient") == 0)
+ {
+ // VPN Client
+ for (i = 0; i < (sizeof(sfx_vpn_client_files) / sizeof(char *)); i++)
+ {
+ char *name = sfx_vpn_client_files[i];
+ wchar_t name_w[MAX_PATH];
+ wchar_t src_file_name[MAX_PATH];
+
+ StrToUni(name_w, sizeof(name_w), name);
+ ConbinePathW(src_file_name, sizeof(src_file_name), MsGetExeFileDirW(), name_w);
+
+ Add(o, SwNewSfxFile(name, src_file_name));
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ Add(o, SwNewSfxFile("install_src.dat", L"|install_src.dat"));
+
+ return true;
+}
+
+// Release the SFX file list
+void SwFreeSfxFileList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ SW_SFX_FILE *f = LIST_DATA(o, i);
+
+ Free(f);
+ }
+
+ ReleaseList(o);
+}
+
+// Generate the SFX file list
+LIST *SwNewSfxFileList()
+{
+ LIST *o = NewListFast(NULL);
+
+ return o;
+}
+
+// Extract from the SFX files
+bool SwSfxExtractFile(HWND hWnd, void *data, UINT size, wchar_t *dst, bool compressed)
+{
+ IO *io;
+ bool ret = false;
+ // Validate arguments
+ if (data == NULL || size == 0 || dst == NULL)
+ {
+ return false;
+ }
+
+ io = FileCreateW(dst);
+
+ if (compressed == false)
+ {
+ // Write uncompressed files as is
+ ret = FileWrite(io, data, size);
+ }
+ else
+ {
+ // Unzip when the files are compressed
+ BUF *src = NewBuf();
+ BUF *dst;
+
+ WriteBuf(src, data, size);
+
+ dst = UncompressBuf(src);
+
+ FreeBuf(src);
+
+ ret = FileWrite(io, dst->Buf, dst->Size);
+
+ FreeBuf(dst);
+ }
+
+ FileClose(io);
+
+ if (ret == false)
+ {
+ FileDeleteW(dst);
+ }
+
+ return ret;
+}
+
+// SFX extraction process
+bool SwSfxExtractProcess(HWND hWnd, bool *hide_error_msg)
+{
+ TOKEN_LIST *t;
+ UINT i;
+ bool ret = true;
+ wchar_t exec_filename[MAX_SIZE];
+ bool is_easy_installer = false;
+ bool dummy_bool = false;
+
+ if (hide_error_msg == NULL)
+ {
+ hide_error_msg = &dummy_bool;
+ }
+
+ *hide_error_msg = false;
+
+ Zero(exec_filename, sizeof(exec_filename));
+
+ // Enumerate the DATAFILE resources
+ t = MsEnumResources(NULL, SW_SFX_RESOURCE_TYPE);
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ char *resource_name = t->Token[i];
+ char filename[MAX_PATH];
+ wchar_t filename_w[MAX_PATH];
+ wchar_t tmp_filename[MAX_PATH];
+ HRSRC hr;
+ bool ok = false;
+ bool is_compressed = true;
+
+ DoEvents(hWnd);
+
+ if (g_stop_flag)
+ {
+ // User cancel
+ ret = false;
+ break;
+ }
+
+ StrCpy(filename, sizeof(filename), resource_name);
+
+ StrLower(filename);
+
+ if (EndWith(filename, ".vpn"))
+ {
+ is_easy_installer = true;
+ }
+
+ if (StartWith(filename, "raw_"))
+ {
+ StrToUni(filename_w, sizeof(filename_w), filename + 4);
+ is_compressed = false;
+ }
+ else
+ {
+ StrToUni(filename_w, sizeof(filename_w), filename);
+ }
+
+ ConbinePathW(tmp_filename, sizeof(tmp_filename), MsGetMyTempDirW(), filename_w);
+
+ if (EndWith(filename, "vpnsetup.exe"))
+ {
+ UniStrCpy(exec_filename, sizeof(exec_filename), tmp_filename);
+ }
+
+ // Find the resources
+ hr = FindResourceA(MsGetCurrentModuleHandle(), resource_name, SW_SFX_RESOURCE_TYPE);
+ if (hr != NULL)
+ {
+ HGLOBAL hg = LoadResource(MsGetCurrentModuleHandle(), hr);
+
+ if (hg != NULL)
+ {
+ UINT size = SizeofResource(MsGetCurrentModuleHandle(), hr);
+ void *ptr = LockResource(hg);
+
+ if (size != 0 && ptr != NULL)
+ {
+ if (SwSfxExtractFile(hWnd, ptr, size, tmp_filename, is_compressed))
+ {
+ ok = true;
+ }
+ }
+ }
+ }
+
+ DoEvents(hWnd);
+
+ if (ok == false)
+ {
+ // Failure
+ ret = false;
+ break;
+ }
+ }
+
+ FreeToken(t);
+
+ if (ret)
+ {
+ wchar_t exe_name[MAX_PATH];
+ wchar_t *exe_dir = MsGetExeFileDirW();
+
+ GetFileNameFromFilePathW(exe_name, sizeof(exe_name), MsGetExeFileNameW());
+
+ }
+
+ if (ret)
+ {
+ // Start the vpnsetup.exe
+ if (UniIsEmptyStr(exec_filename))
+ {
+ ret = false;
+ }
+ else
+ {
+ void *handle = NULL;
+ wchar_t params[MAX_SIZE];
+ wchar_t *current_params = GetCommandLineUniStr();
+ wchar_t tmp[MAX_SIZE];
+ char *last_lang;
+ wchar_t copy_of_me[MAX_PATH];
+
+ UniStrCpy(params, sizeof(params), current_params);
+
+ // Copy itself to the Temp directory
+ CombinePathW(copy_of_me, sizeof(copy_of_me), MsGetMyTempDirW(), L"installer.cache");
+ if (FileCopyW(MsGetExeFileNameW(), copy_of_me) == false)
+ {
+ Zero(copy_of_me, sizeof(copy_of_me));
+ }
+
+ // Add a path of this own
+ UniFormat(tmp, sizeof(tmp), L" /CALLERSFXPATH:\"%s\"", copy_of_me);
+ UniStrCat(params, sizeof(params), tmp);
+
+ // Add information of whether it's a simple installer
+ UniFormat(tmp, sizeof(tmp), L" /ISEASYINSTALLER:%u", is_easy_installer);
+ UniStrCat(params, sizeof(params), tmp);
+
+ UniTrim(params);
+
+ // Specify a language by the lang.config
+ last_lang = MsRegReadStrEx2(REG_CURRENT_USER, SW_REG_KEY, "Last User Language", false, true);
+ if (IsEmptyStr(last_lang) == false)
+ {
+ wchar_t lang_filename[MAX_PATH];
+ BUF *buf;
+
+ CombinePathW(lang_filename, sizeof(lang_filename), MsGetMyTempDirW(), L"lang.config");
+
+ buf = NewBuf();
+ WriteBufLine(buf, "");
+ WriteBufLine(buf, last_lang);
+ WriteBufLine(buf, "");
+ DumpBufW(buf, lang_filename);
+ FreeBuf(buf);
+ }
+ Free(last_lang);
+
+ if (MsExecuteEx2W(exec_filename, params, &handle, false) == false)
+ {
+ ret = false;
+ }
+ else
+ {
+ g_wait_process_handle = handle;
+ }
+ }
+ }
+
+ return ret;
+}
+
+// Copy the files of VPN Gate
+bool SwSfxCopyVgFiles(HWND hWnd, wchar_t *src, wchar_t *dst)
+{
+ wchar_t *msg;
+ wchar_t srcfilename[MAX_PATH];
+ wchar_t exefilename[MAX_PATH];
+
+ GetFileNameFromFilePathW(srcfilename, sizeof(srcfilename), src);
+ GetFileNameFromFilePathW(exefilename, sizeof(exefilename), MsGetExeFileNameW());
+
+ if (FileCopyW(src, dst))
+ {
+ return true;
+ }
+
+ msg = L"The file \"%s\" was not found on the directory which the installer \"%s\" is located on.\r\n\r\n"
+ L"To continue the installation, the file \"%s\" is required on the same direcotry.\r\n"
+ L"If you have extracted the installer from a ZIP archive, you have to also extract the file \"%s\" from the ZIP archive together.";
+
+ MsgBoxEx(hWnd, MB_ICONINFORMATION, msg, srcfilename, exefilename, srcfilename, srcfilename);
+
+ return false;
+}
+
+// SFX extraction dialog procedure
+bool CALLBACK SfxModeMainDialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ UINT ret;
+ bool hide_msg = false;
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetTimer(hWnd, 1, 500, NULL);
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+
+ ret = SW_EXIT_CODE_USER_CANCEL;
+ if (SwSfxExtractProcess(hWnd, &hide_msg))
+ {
+ ret = 0;
+ }
+ else
+ {
+ if (g_stop_flag == false)
+ {
+ if (hide_msg == false)
+ {
+ MsgBoxEx(hWnd, MB_ICONSTOP, L"Fatal Error: Self extracting files to the temporary directory was failed.\r\n\r\n"
+ L"Please try again after reboot Windows.");
+ }
+ }
+ }
+
+ EndDialog(hWnd, ret);
+
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ case IDCANCEL:
+ g_stop_flag = true;
+ Disable(hWnd, IDCANCEL);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ break;
+ }
+
+ return false;
+}
+
+// Main process as SFX mode
+UINT SwSfxModeMain()
+{
+ UINT ret;
+ // Select either English or Japanese
+ UINT dialog_id = (MsIsCurrentUserLocaleIdJapanese() ? 10001 : 10002);
+
+ g_wait_process_handle = NULL;
+ g_stop_flag = false;
+
+ // Show the screen
+ ret = (UINT)DialogBoxParamA(MsGetCurrentModuleHandle(), MAKEINTRESOURCEA(dialog_id), NULL, (DLGPROC)SfxModeMainDialogProc, 0);
+
+ if (g_wait_process_handle != NULL)
+ {
+ // If this have started the vpnsetup.exe, wait for termination of the child process
+ ret = MsWaitProcessExit(g_wait_process_handle);
+ }
+
+ return ret;
+}
+
+// Resource name enumeration procedure
+bool CALLBACK SwEnumResourceNamesProc(HMODULE hModule, const char *type, char *name, LONG_PTR lParam)
+{
+ bool *b = (bool *)lParam;
+ // Validate arguments
+ if (type == NULL || name == NULL || lParam == 0)
+ {
+ return false;
+ }
+
+ *b = true;
+
+ return true;
+}
+
+// Main process of vpnsetup.exe
+UINT SWExec()
+{
+ UINT ret = 0;
+ bool is_datafile_exists = false;
+
+ // Examine whether DATAFILE resources are stored in setup.exe that is currently running
+ EnumResourceNamesA(NULL, SW_SFX_RESOURCE_TYPE, SwEnumResourceNamesProc, (LONG_PTR)(&is_datafile_exists));
+
+ if (is_datafile_exists)
+ {
+ // If DATAFILE resources are stored, extract it as SFX
+ MayaquaMinimalMode();
+ }
+
+ InitMayaqua(false, false, 0, NULL);
+ InitCedar();
+
+ if (is_datafile_exists == false)
+ {
+ // Start the Setup Wizard
+ ret = SWExecMain();
+ }
+ else
+ {
+ // SFX mode
+ ret = SwSfxModeMain();
+ }
+
+ FreeCedar();
+ FreeMayaqua();
+
+ return ret;
+}
+
+// Dialog procedure (for copy and paste)
+UINT SwDefaultDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param)
+{
+ SW *sw = (SW *)param;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ break;
+
+ case WM_WIZ_SHOW:
+ SetWizardButton(wizard_page, true, true, true, false);
+ break;
+
+ case WM_WIZ_HIDE:
+ break;
+
+ case WM_CLOSE:
+ break;
+
+ case WM_WIZ_NEXT:
+ break;
+
+ case WM_WIZ_BACK:
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Update the file specification dialog
+void SwWeb2Update(HWND hWnd, SW *sw, WIZARD *wizard, WIZARD_PAGE *wizard_page)
+{
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL || wizard_page == NULL || wizard == NULL)
+ {
+ return;
+ }
+
+ if (IsEmptyUniStr(sw->Web_OutFile) || IsEmptyUniStr(sw->Web_SettingFile))
+ {
+ ok = false;
+ }
+
+ SetText(hWnd, E_SETTING, sw->Web_SettingFile);
+ SetText(hWnd, E_OUT, sw->Web_OutFile);
+
+ SetWizardButton(wizard_page, ok, true, true, false);
+}
+
+// Update the file specification dialog
+void SwEasy2Update(HWND hWnd, SW *sw, WIZARD *wizard, WIZARD_PAGE *wizard_page)
+{
+ bool ok = true;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL || wizard_page == NULL || wizard == NULL)
+ {
+ return;
+ }
+
+ if (IsEmptyUniStr(sw->Easy_OutFile) || IsEmptyUniStr(sw->Easy_SettingFile))
+ {
+ ok = false;
+ }
+
+ SetText(hWnd, E_SETTING, sw->Easy_SettingFile);
+ SetText(hWnd, E_OUT, sw->Easy_OutFile);
+
+ SetWizardButton(wizard_page, ok, true, true, false);
+}
+
+// Generate a SFX file name of the default
+void SwGenerateDefaultSfxFileName(wchar_t *name, UINT size)
+{
+ // Validate arguments
+ if (name == NULL)
+ {
+ return;
+ }
+
+ UniFormat(name, size, L"easy-" GC_SW_SOFTETHER_PREFIX_W L"vpnclient-v%u.%02u-%u-%04u-%02u-%02u-windows.exe",
+ CEDAR_VER / 100,
+ CEDAR_VER % 100,
+ CEDAR_BUILD,
+ BUILD_DATE_Y, BUILD_DATE_M, BUILD_DATE_D);
+}
+
+// Generate a ZIP file name of the default
+void SwGenerateDefaultZipFileName(wchar_t *name, UINT size)
+{
+ // Validate arguments
+ if (name == NULL)
+ {
+ return;
+ }
+
+ UniFormat(name, size, L"web-" GC_SW_SOFTETHER_PREFIX_W L"vpnclient-v%u.%02u-%u-%04u-%02u-%02u-windows.zip",
+ CEDAR_VER / 100,
+ CEDAR_VER % 100,
+ CEDAR_BUILD,
+ BUILD_DATE_Y, BUILD_DATE_M, BUILD_DATE_D);
+}
+
+// Specify a file
+UINT SwEasy2(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param)
+{
+ SW *sw = (SW *)param;
+ wchar_t *fn;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ DlgFont(hWnd, S_BOLD1, 10, true);
+ DlgFont(hWnd, S_BOLD2, 10, true);
+
+ Check(hWnd, B_DELETE_SENSITIVE, sw->Easy_EraseSensitive);
+ Check(hWnd, B_EASYMODE, sw->Easy_EasyMode);
+
+ break;
+
+ case WM_WIZ_SHOW:
+ SwEasy2Update(hWnd, sw, wizard, wizard_page);
+ break;
+
+ case WM_WIZ_HIDE:
+ break;
+
+ case WM_CLOSE:
+ break;
+
+ case WM_WIZ_NEXT:
+ // Save the Settings
+ MsRegWriteInt(REG_CURRENT_USER, SW_REG_KEY, "Easy_EraseSensitive", sw->Easy_EraseSensitive);
+ MsRegWriteInt(REG_CURRENT_USER, SW_REG_KEY, "Easy_EasyMode", sw->Easy_EasyMode);
+ return D_SW_PERFORM;
+
+ case WM_WIZ_BACK:
+ return D_SW_EASY1;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_DELETE_SENSITIVE:
+ sw->Easy_EraseSensitive = IsChecked(hWnd, B_DELETE_SENSITIVE);
+ sw->Easy_EasyMode = IsChecked(hWnd, B_EASYMODE);
+ break;
+
+ case B_BROWSE_SETTING:
+ fn = OpenDlg(hWnd, _UU("CM_ACCOUNT_SETTING_FILE"), _UU("CM_ACCOUNT_OPEN_TITLE"));
+
+ if (fn != NULL)
+ {
+ // Parse
+ if (CiTryToParseAccountFile(fn) == false)
+ {
+ // Failure
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("CM_ACCOUNT_PARSE_FAILED"));
+ }
+ else
+ {
+ // Success
+ UniStrCpy(sw->Easy_SettingFile, sizeof(sw->Easy_SettingFile), fn);
+
+ SwEasy2Update(hWnd, sw, wizard, wizard_page);
+
+ FocusEx(hWnd, E_SETTING);
+ }
+
+ Free(fn);
+ }
+ break;
+
+ case B_BROWSE_OUT:
+ SwGenerateDefaultSfxFileName(tmp, sizeof(tmp));
+
+ fn = SaveDlg(hWnd, _UU("SW_EXE_FILTER"), _UU("DLG_SAVE_FILE"), tmp, L".exe");
+
+ if (fn != NULL)
+ {
+ UniStrCpy(sw->Easy_OutFile, sizeof(sw->Easy_OutFile), fn);
+
+ SwEasy2Update(hWnd, sw, wizard, wizard_page);
+ }
+ break;
+
+ case B_HINT:
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Specify a file
+UINT SwWeb2(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param)
+{
+ SW *sw = (SW *)param;
+ wchar_t *fn;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ DlgFont(hWnd, S_BOLD1, 10, true);
+ DlgFont(hWnd, S_BOLD2, 10, true);
+
+ Check(hWnd, B_DELETE_SENSITIVE, sw->Web_EraseSensitive);
+ Check(hWnd, B_EASYMODE, sw->Web_EasyMode);
+
+ break;
+
+ case WM_WIZ_SHOW:
+ SwWeb2Update(hWnd, sw, wizard, wizard_page);
+ break;
+
+ case WM_WIZ_HIDE:
+ break;
+
+ case WM_CLOSE:
+ break;
+
+ case WM_WIZ_NEXT:
+ // Save the settings
+ MsRegWriteInt(REG_CURRENT_USER, SW_REG_KEY, "Web_EraseSensitive", sw->Web_EraseSensitive);
+ MsRegWriteInt(REG_CURRENT_USER, SW_REG_KEY, "Web_EasyMode", sw->Web_EasyMode);
+ return D_SW_PERFORM;
+
+ case WM_WIZ_BACK:
+ return D_SW_WEB1;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_DELETE_SENSITIVE:
+ sw->Web_EraseSensitive = IsChecked(hWnd, B_DELETE_SENSITIVE);
+ sw->Web_EasyMode = IsChecked(hWnd, B_EASYMODE);
+ break;
+
+ case B_BROWSE_SETTING:
+ fn = OpenDlg(hWnd, _UU("CM_ACCOUNT_SETTING_FILE"), _UU("CM_ACCOUNT_OPEN_TITLE"));
+
+ if (fn != NULL)
+ {
+ // Parse
+ if (CiTryToParseAccountFile(fn) == false)
+ {
+ // Failure
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("CM_ACCOUNT_PARSE_FAILED"));
+ }
+ else
+ {
+ // Success
+ UniStrCpy(sw->Web_SettingFile, sizeof(sw->Web_SettingFile), fn);
+
+ SwWeb2Update(hWnd, sw, wizard, wizard_page);
+
+ FocusEx(hWnd, E_SETTING);
+ }
+
+ Free(fn);
+ }
+ break;
+
+ case B_BROWSE_OUT:
+ SwGenerateDefaultZipFileName(tmp, sizeof(tmp));
+
+ fn = SaveDlg(hWnd, _UU("DLG_ZIP_FILER"), _UU("DLG_SAVE_FILE"), tmp, L".zip");
+
+ if (fn != NULL)
+ {
+ UniStrCpy(sw->Web_OutFile, sizeof(sw->Web_OutFile), fn);
+
+ SwWeb2Update(hWnd, sw, wizard, wizard_page);
+ }
+ break;
+
+ case B_HINT:
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Start screen of the Web Installer Creation Wizard
+UINT SwWeb1(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param)
+{
+ SW *sw = (SW *)param;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ wizard->CloseConfirmMsg = NULL;
+ DlgFont(hWnd, S_TITLE, 11, true);
+ break;
+
+ case WM_WIZ_SHOW:
+ SetWizardButton(wizard_page, true, false, true, false);
+ break;
+
+ case WM_WIZ_HIDE:
+ break;
+
+ case WM_CLOSE:
+ break;
+
+ case WM_WIZ_NEXT:
+ return D_SW_WEB2;
+
+ case WM_WIZ_BACK:
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Start screen of the Simple installer creation wizard
+UINT SwEasy1(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param)
+{
+ SW *sw = (SW *)param;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ wizard->CloseConfirmMsg = NULL;
+ DlgFont(hWnd, S_TITLE, 11, true);
+ break;
+
+ case WM_WIZ_SHOW:
+ SetWizardButton(wizard_page, true, false, true, false);
+ break;
+
+ case WM_WIZ_HIDE:
+ break;
+
+ case WM_CLOSE:
+ break;
+
+ case WM_WIZ_NEXT:
+ return D_SW_EASY2;
+
+ case WM_WIZ_BACK:
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Get the icon for the language
+UINT SwGetLangIcon(char *name)
+{
+ UINT ret = ICO_NULL;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return ICO_NULL;
+ }
+
+ if (StrCmpi(name, "ja") == 0)
+ {
+ ret = ICO_LANG_JAPANESE;
+ }
+ else if (StrCmpi(name, "en") == 0)
+ {
+ ret = ICO_LANG_ENGLISH;
+ }
+ else if (StrCmpi(name, "cn") == 0)
+ {
+ ret = ICO_LANG_CHINESE;
+ }
+
+ return ret;
+}
+
+// Initialize the language list
+void SwLang1Init(HWND hWnd, SW *sw)
+{
+ LVB *b;
+ UINT i;
+ SW_COMPONENT *default_select = NULL;
+ LIST *o;
+ UINT current_lang = GetCurrentLangId();
+ UINT select_index = INFINITE;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return;
+ }
+
+ o = LoadLangList();
+
+ LvReset(hWnd, L_LIST);
+
+ b = LvInsertStart();
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ LANGLIST *t = LIST_DATA(o, i);
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), L"(%s)", t->TitleLocal);
+ UniFormat(tmp2, sizeof(tmp2), L" %s", t->TitleEnglish);
+
+ LvInsertAdd(b, SwGetLangIcon(t->Name), (void *)(t->Id + 1), 2, tmp2, tmp);
+
+ if (t->Id == current_lang)
+ {
+ select_index = i;
+ }
+ }
+
+ LvInsertEnd(b, hWnd, L_LIST);
+
+ if (sw->CurrentComponent == NULL)
+ {
+ LvSelectByParam(hWnd, L_LIST, default_select);
+ }
+ else
+ {
+ LvSelectByParam(hWnd, L_LIST, sw->CurrentComponent);
+ }
+
+ LvAutoSize(hWnd, L_LIST);
+
+ FreeLangList(o);
+
+ if (select_index != INFINITE)
+ {
+ LvSelect(hWnd, L_LIST, select_index);
+ }
+
+ LvSort(hWnd, L_LIST, 0, false);
+
+ Focus(hWnd, L_LIST);
+
+ // Show the current language
+ if (true)
+ {
+ LANGLIST t;
+ wchar_t tmp[MAX_SIZE];
+
+ Zero(&t, sizeof(t));
+ GetCurrentLang(&t);
+
+ UniFormat(tmp, sizeof(tmp), L"%s (%s)", t.TitleEnglish, t.TitleLocal);
+
+ SetText(hWnd, E_CURRENT, tmp);
+
+ if (MsIsVista())
+ {
+ SetFont(hWnd, E_CURRENT, GetMeiryoFontEx(11));
+ }
+ else
+ {
+ DlgFont(hWnd, E_CURRENT, 11, false);
+ }
+ }
+}
+
+// Update of control
+void SwLang1Update(HWND hWnd, SW *sw, WIZARD *wizard, WIZARD_PAGE *wizard_page)
+{
+ UINT id;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL || wizard == NULL || wizard_page == NULL)
+ {
+ return;
+ }
+
+ id = (UINT)LvGetSelectedParam(hWnd, L_LIST);
+
+ if (id == 0)
+ {
+ SetWizardButtonEx(wizard_page, false, false, true, false, (MsIsAdmin() == false && sw->IsSystemMode));
+ }
+ else
+ {
+ SetWizardButtonEx(wizard_page, true, false, true, false, (MsIsAdmin() == false && sw->IsSystemMode));
+ }
+}
+
+// Language setting screen
+UINT SwLang1(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param)
+{
+ SW *sw = (SW *)param;
+ NMHDR *n;
+ UINT id;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ LvInitEx2(hWnd, L_LIST, false, true);
+
+ if (MsIsVista())
+ {
+ SetFont(hWnd, L_LIST, GetMeiryoFontEx(12));
+ }
+ else
+ {
+ DlgFont(hWnd, L_LIST, 12, false);
+ }
+
+ LvInsertColumn(hWnd, L_LIST, 0, L"English Name", 250);
+ LvInsertColumn(hWnd, L_LIST, 1, L"Local Name", 250);
+
+ SwLang1Update(hWnd, sw, wizard, wizard_page);
+ break;
+
+ case WM_WIZ_SHOW:
+ SetWizardButtonEx(wizard_page, true, false, true, false, (MsIsAdmin() == false && sw->IsSystemMode));
+
+ SwLang1Init(hWnd, sw);
+
+ SwLang1Update(hWnd, sw, wizard, wizard_page);
+ break;
+
+ case WM_WIZ_HIDE:
+ break;
+
+ case WM_CLOSE:
+ break;
+
+ case WM_WIZ_NEXT:
+ if (SwEnterSingle(sw) == false)
+ {
+ // Multiple-starts prevention
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SW_OTHER_INSTANCE_EXISTS"));
+ break;
+ }
+
+ if (MsIsNt() == false)
+ {
+ // Win9x
+ MsgBox(hWnd, MB_ICONSTOP,
+ L"Windows 9x / Me doesn't support multi-language switcing.\r\n\r\nIf you want to switch to another language, please use Windows NT 4.0, 2000 or greater.");
+ break;
+ }
+
+ // Get the current selection
+ id = (UINT)LvGetSelectedParam(hWnd, L_LIST);
+ if (id != 0)
+ {
+ id--;
+
+ if (id == GetCurrentLangId())
+ {
+ // No change
+ sw->LangNotChanged = true;
+
+ sw->ExitCode = 0;
+
+ return D_SW_ERROR;
+ }
+ else
+ {
+ wchar_t add_param[MAX_SIZE];
+ LIST *o;
+ LANGLIST *new_lang;
+ LANGLIST old_lang;
+ char new_lang_name[MAX_SIZE];
+ char old_lang_name[MAX_SIZE];
+
+ GetCurrentLang(&old_lang);
+
+ o = LoadLangList();
+
+ if (o == NULL)
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("SW_LANG_LIST_LOAD_FAILED"));
+ break;
+ }
+
+ new_lang = GetLangById(o, id);
+
+ if (new_lang == NULL)
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("SW_LANG_LIST_LOAD_FAILED"));
+ FreeLangList(o);
+ break;
+ }
+
+ StrCpy(new_lang_name, sizeof(new_lang_name), new_lang->Name);
+ StrCpy(old_lang_name, sizeof(old_lang_name), old_lang.Name);
+
+ FreeLangList(o);
+
+ UniFormat(add_param, sizeof(add_param), L"/LANGID:%u", id);
+
+ if (sw->DoubleClickBlocker)
+ {
+ break;
+ }
+
+ sw->DoubleClickBlocker = true;
+
+ sw->LangId = id;
+
+ if (sw->IsSystemMode == false)
+ {
+LABEL_RUN_CHILD_PROCESS:
+ // Start the process immediately in the case of user mode
+ if (SaveLangConfigCurrentDir(new_lang_name) == false)
+ {
+ sw->DoubleClickBlocker = false;
+ MsgBox(hWnd, MB_ICONSTOP, _UU("SW_LANG_SET_FAILED"));
+ break;
+ }
+
+ UniStrCat(add_param, sizeof(add_param), L" /LANGNOW:yes");
+ if (SwReExecMyself(sw, add_param, false))
+ {
+ // Terminate itself if it succeeds to start the child process
+ CloseWizard(wizard_page);
+ break;
+ }
+ else
+ {
+ // Child process startup failure
+ sw->DoubleClickBlocker = false;
+
+ // Undo the language setting
+ SaveLangConfigCurrentDir(old_lang_name);
+ break;
+ }
+ }
+
+ // In the case of system mode
+ if (MsIsAdmin() == false)
+ {
+ if (MsIsVista())
+ {
+ if (sw->IsReExecForUac == false)
+ {
+ // If there is no Admin privileges in Vista or later, attempt to acquire Admin rights by UAC first during the first run
+ UniStrCat(add_param, sizeof(add_param), L" /SETLANGANDREBOOT:true");
+
+ if (SwReExecMyself(sw, add_param, true))
+ {
+ // Terminate itself if it succeeds to start the child process
+ CloseWizard(wizard_page);
+ break;
+ }
+ else
+ {
+ // Do nothing if it fails to start in the UAC
+ sw->DoubleClickBlocker = false;
+ break;
+ }
+ }
+ else
+ {
+ // If no Admin privileges after being started by the UAC, jump to the guidance screen indicating it is not Admin
+ return D_SW_NOT_ADMIN;
+ }
+ }
+ else
+ {
+ // Jump to guide screen indicating that it is not the Admin in the case of XP or earlier
+ return D_SW_NOT_ADMIN;
+ }
+ }
+ else
+ {
+ // Start the process if there is a Admin privileges
+ goto LABEL_RUN_CHILD_PROCESS;
+ }
+ }
+ }
+ break;
+
+ case WM_WIZ_BACK:
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ SwLang1Update(hWnd, sw, wizard, wizard_page);
+ break;
+ }
+ break;
+ }
+
+ break;
+ }
+
+ return 0;
+}
+
+// Start the uninstallation
+UINT SwUninst1(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param)
+{
+ SW *sw = (SW *)param;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ FormatText(hWnd, S_TITLE, sw->CurrentComponent->Title);
+ FormatText(hWnd, S_WELCOME, sw->CurrentComponent->Title);
+ break;
+
+ case WM_WIZ_SHOW:
+ DlgFont(hWnd, S_TITLE, 11, true);
+ SetWizardButtonEx(wizard_page, true, false, true, false, sw->IsSystemMode);
+
+ sw->DoubleClickBlocker = false;
+
+ break;
+
+ case WM_WIZ_HIDE:
+ break;
+
+ case WM_CLOSE:
+ break;
+
+ case WM_WIZ_NEXT:
+ if (MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, _UU("SW_UNINSTALL_CONFIRM"),
+ sw->CurrentComponent->Title) == IDNO)
+ {
+ break;
+ }
+
+ if (SwEnterSingle(sw) == false)
+ {
+ // Multiple-starts prevention
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SW_OTHER_INSTANCE_EXISTS"));
+ break;
+ }
+
+ if (sw->DoubleClickBlocker)
+ {
+ break;
+ }
+
+ sw->DoubleClickBlocker = true;
+
+ if (sw->IsSystemMode == false)
+ {
+ // Start uninstallation immediately in the case of user mode
+ return D_SW_PERFORM;
+ }
+
+ // In the case of system mode
+ if (MsIsAdmin() == false)
+ {
+ if (MsIsVista())
+ {
+ if (sw->IsReExecForUac == false)
+ {
+ // If there is no Admin privileges in Vista or later, attempt to acquire Admin rights by UAC first during the first run
+ if (SwReExecMyself(sw, NULL, true))
+ {
+ // Terminate itself if it succeeds to start the child process
+ CloseWizard(wizard_page);
+ break;
+ }
+ else
+ {
+ // If fail to run in UAC, jump to guide screen indicating that it is not Admin
+ return D_SW_NOT_ADMIN;
+ }
+ }
+ else
+ {
+ // If no Admin privileges after being started by the UAC, jump to the guidance screen indicating it is not Admin
+ return D_SW_NOT_ADMIN;
+ }
+ }
+ else
+ {
+ // Jump to guide screen indicating that it is not the Admin in the case of XP or earlier
+ return D_SW_NOT_ADMIN;
+ }
+ }
+ else
+ {
+ // Start the uninstallation if it has Admin privileges
+ return D_SW_PERFORM;
+ }
+ break;
+
+ case WM_WIZ_BACK:
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Completion screen
+UINT SwFinish(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param)
+{
+ SW *sw = (SW *)param;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ if (sw->EasyMode)
+ {
+ SetIcon(hWnd, S_ICON, ICO_SETUP);
+ }
+ else if (sw->WebMode)
+ {
+ SetIcon(hWnd, S_ICON, ICO_INTERNET);
+ }
+ else
+ {
+ FormatText(hWnd, S_INFO, sw->CurrentComponent->Title);
+ SetIcon(hWnd, S_ICON, sw->CurrentComponent->Icon);
+ }
+
+ wizard->CloseConfirmMsg = NULL;
+
+ sw->ExitCode = 0;
+ break;
+
+ case WM_WIZ_SHOW:
+ if (UniIsEmptyStr(sw->FinishMsg) == false)
+ {
+ SetText(hWnd, S_INFO, sw->FinishMsg);
+ }
+
+ SetWizardButton(wizard_page, true, false, false, true);
+
+ if (sw->HideStartCommand || sw->UninstallMode || sw->LanguageMode || sw->EasyMode || sw->WebMode || UniIsEmptyStr(sw->CurrentComponent->StartExeName))
+ {
+ Hide(hWnd, B_RUN);
+ sw->Run = false;
+ }
+ else
+ {
+ SetText(hWnd, B_RUN, sw->CurrentComponent->StartDescription);
+ Show(hWnd, B_RUN);
+ Format(tmp, sizeof(tmp), "UI_NoCheck_%s_%u", sw->CurrentComponent->Name, sw->IsSystemMode);
+ Check(hWnd, B_RUN, !MsRegReadInt(REG_CURRENT_USER, SW_REG_KEY, tmp));
+ sw->Run = IsChecked(hWnd, B_RUN);
+ }
+ break;
+
+ case WM_WIZ_HIDE:
+ break;
+
+ case WM_CLOSE:
+ break;
+
+ case WM_WIZ_NEXT:
+ break;
+
+ case WM_WIZ_BACK:
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_RUN:
+ if (sw->HideStartCommand || sw->UninstallMode || sw->LanguageMode || sw->EasyMode || sw->WebMode || UniIsEmptyStr(sw->CurrentComponent->StartExeName))
+ {
+ }
+ else
+ {
+ Format(tmp, sizeof(tmp), "UI_NoCheck_%s_%u", sw->CurrentComponent->Name, sw->IsSystemMode);
+ sw->Run = IsChecked(hWnd, B_RUN);
+ MsRegWriteInt(REG_CURRENT_USER, SW_REG_KEY, tmp, !sw->Run);
+ }
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Error occuring screen
+UINT SwError(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param)
+{
+ SW *sw = (SW *)param;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ wizard->CloseConfirmMsg = NULL;
+
+ if (sw->EasyMode)
+ {
+ SetText(hWnd, S_INFO, _UU("SW_EASY_ERROR_MSG"));
+ }
+ else if (sw->WebMode)
+ {
+ SetText(hWnd, S_INFO, _UU("SW_WEB_ERROR_MSG"));
+ }
+ else
+ {
+ FormatText(hWnd, S_INFO, sw->CurrentComponent->Title);
+ }
+
+ if (sw->MsiRebootRequired)
+ {
+ // MSI requires a reboot
+ wchar_t tmp[MAX_SIZE];
+
+ SetIcon(hWnd, S_ICON, ICO_INFORMATION);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SW_MSI_UNINSTALL_REBOOT_REQUIRED"), sw->CurrentComponent->Title);
+
+ SetText(hWnd, S_INFO, tmp);
+ }
+
+ if (sw->LangNotChanged)
+ {
+ // Language has not changed
+ wchar_t tmp[MAX_SIZE];
+
+ SetIcon(hWnd, S_ICON, ICO_INFORMATION);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SW_LANG_NOT_CHANGED"), sw->CurrentComponent->Title);
+
+ SetText(hWnd, S_INFO, tmp);
+ }
+
+ break;
+
+ case WM_WIZ_SHOW:
+ SetWizardButton(wizard_page, true, false, false, true);
+ break;
+
+ case WM_WIZ_HIDE:
+ break;
+
+ case WM_CLOSE:
+ break;
+
+ case WM_WIZ_NEXT:
+ break;
+
+ case WM_WIZ_BACK:
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Execution thread of the setup process
+void SwPerformThread(THREAD *thread, void *param)
+{
+ WIZARD_PAGE *wp = (WIZARD_PAGE *)param;
+ SW *sw;
+ SW_COMPONENT *c;
+ bool ret;
+ SW_UI ui;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ sw = (SW *)wp->Wizard->Param;
+
+ sw->ExitCode = SW_EXIT_CODE_INTERNAL_ERROR;
+
+ // Components to be installed
+ c = sw->CurrentComponent;
+
+ if (sw->EasyMode)
+ {
+ // Create a simple installer
+ ret = SwEasyMain(sw, wp);
+ }
+ else if (sw->WebMode)
+ {
+ // Create a Web installer
+ ret = SwWebMain(sw, wp);
+ }
+ else if (sw->UninstallMode == false)
+ {
+ // Installation
+ ret = SwInstallMain(sw, wp, c);
+ }
+ else
+ {
+ // Uninstallation
+ ret = SwUninstallMain(sw, wp, c);
+ }
+
+ // Notify the results to the window
+ Zero(&ui, sizeof(ui));
+ ui.Type = (ret ? SW_UI_TYPE_FINISH : SW_UI_TYPE_ERROR);
+ SwInteractUi(wp, &ui);
+}
+
+// Create a file copy task
+SW_TASK_COPY *SwNewCopyTask(wchar_t *srcfilename, wchar_t *dstfilename, wchar_t *srcdir, wchar_t *dstdir, bool overwrite, bool setup_file)
+{
+ SW_TASK_COPY *ct;
+ // Validate arguments
+ if (srcfilename == NULL || srcdir == NULL || dstdir == NULL)
+ {
+ return NULL;
+ }
+
+ ct = ZeroMalloc(sizeof(SW_TASK_COPY));
+
+ UniStrCpy(ct->SrcFileName, sizeof(ct->SrcFileName), srcfilename);
+
+ if (UniIsEmptyStr(dstfilename))
+ {
+ UniStrCpy(ct->DstFileName, sizeof(ct->DstFileName), srcfilename);
+ }
+ else
+ {
+ UniStrCpy(ct->DstFileName, sizeof(ct->DstFileName), dstfilename);
+ }
+
+ UniStrCpy(ct->SrcDir, sizeof(ct->SrcDir), srcdir);
+ UniStrCpy(ct->DstDir, sizeof(ct->DstDir), dstdir);
+
+ ct->Overwrite = overwrite;
+ ct->SetupFile = setup_file;
+
+ return ct;
+}
+
+// Release the file copy task
+void SwFreeCopyTask(SW_TASK_COPY *ct)
+{
+ // Validate arguments
+ if (ct == NULL)
+ {
+ return;
+ }
+
+ Free(ct);
+}
+
+// Create a link creation task
+SW_TASK_LINK *SwNewLinkTask(wchar_t *target_dir, wchar_t *target_exe, wchar_t *target_arg,
+ wchar_t *icon_exe, UINT icon_index,
+ wchar_t *dest_dir, wchar_t *dest_name, wchar_t *dest_desc,
+ bool no_delete_dir)
+{
+ SW_TASK_LINK *lt;
+ // Validate arguments
+ if (target_dir == NULL || target_exe == NULL || dest_dir == NULL || dest_name == NULL)
+ {
+ return NULL;
+ }
+
+ lt = ZeroMalloc(sizeof(SW_TASK_LINK));
+
+ UniStrCpy(lt->TargetDir, sizeof(lt->TargetDir), target_dir);
+ UniStrCpy(lt->TargetExe, sizeof(lt->TargetExe), target_exe);
+ UniStrCpy(lt->TargetArg, sizeof(lt->TargetArg), target_arg);
+
+ if (UniIsEmptyStr(icon_exe) == false)
+ {
+ UniStrCpy(lt->IconExe, sizeof(lt->IconExe), icon_exe);
+ }
+ else
+ {
+ UniStrCpy(lt->IconExe, sizeof(lt->IconExe), target_exe);
+ }
+
+ lt->IconIndex = icon_index;
+
+ UniStrCpy(lt->DestDir, sizeof(lt->DestDir), dest_dir);
+ UniStrCpy(lt->DestName, sizeof(lt->DestName), dest_name);
+ UniStrCpy(lt->DestDescription, sizeof(lt->DestDescription), dest_desc);
+
+ lt->NoDeleteDir = no_delete_dir;
+
+ return lt;
+}
+
+// Release the link creation task
+void SwFreeLinkTask(SW_TASK_LINK *lt)
+{
+ // Validate arguments
+ if (lt == NULL)
+ {
+ return;
+ }
+
+ Free(lt);
+}
+
+// Create a Setup task
+SW_TASK *SwNewTask()
+{
+ SW_TASK *t = ZeroMalloc(sizeof(SW_TASK));
+
+ t->CopyTasks = NewListFast(NULL);
+
+ t->SetSecurityPaths = NewListFast(NULL);
+
+ t->LinkTasks = NewListFast(NULL);
+
+ return t;
+}
+
+// Release the Setup Tasks
+void SwFreeTask(SW_TASK *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(t->CopyTasks);i++)
+ {
+ SW_TASK_COPY *ct = LIST_DATA(t->CopyTasks, i);
+
+ SwFreeCopyTask(ct);
+ }
+
+ ReleaseList(t->CopyTasks);
+
+ FreeStrList(t->SetSecurityPaths);
+
+ for (i = 0;i < LIST_NUM(t->LinkTasks);i++)
+ {
+ SW_TASK_LINK *lt = LIST_DATA(t->LinkTasks, i);
+
+ SwFreeLinkTask(lt);
+ }
+
+ ReleaseList(t->LinkTasks);
+
+ Free(t);
+}
+
+// Delete the shortcut file
+void SwDeleteShortcuts(SW_LOGFILE *logfile)
+{
+ UINT i;
+ LIST *o;
+ // Validate arguments
+ if (logfile == NULL)
+ {
+ return;
+ }
+
+ o = NewListFast(NULL);
+
+ for (i = 0;i < LIST_NUM(logfile->LogList);i++)
+ {
+ SW_LOG *g = LIST_DATA(logfile->LogList, LIST_NUM(logfile->LogList) - i - 1);
+
+ switch (g->Type)
+ {
+ case SW_LOG_TYPE_LNK:
+ FileDeleteW(g->Path);
+ Add(o, g);
+ break;
+
+ case SW_LOG_TYPE_LNK_DIR:
+ SleepThread(100);
+ DeleteDirW(g->Path);
+ Add(o, g);
+ break;
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ SW_LOG *g = LIST_DATA(o, i);
+
+ Delete(logfile->LogList, g);
+
+ Free(g);
+ }
+
+ ReleaseList(o);
+}
+
+// Uninstall main
+bool SwUninstallMain(SW *sw, WIZARD_PAGE *wp, SW_COMPONENT *c)
+{
+ bool x64 = MsIs64BitWindows();
+ bool ok;
+ wchar_t tmp[MAX_SIZE];
+ UINT i;
+ // Validate arguments
+ if (sw == NULL || wp == NULL || c == NULL)
+ {
+ return false;
+ }
+
+ SwPerformPrint(wp, _UU("SW_PERFORM_MSG_INIT_UNINST"));
+
+ // Stop the Service
+ ok = true;
+
+ if (c->InstallService)
+ {
+ char svc_title_name[MAX_SIZE];
+ wchar_t *svc_title;
+
+ Format(svc_title_name, sizeof(svc_title_name), "SVC_%s_TITLE", c->SvcName);
+
+ svc_title = _UU(svc_title_name);
+
+ if (UniIsEmptyStr(svc_title) == false)
+ {
+ if (sw->IsSystemMode && MsIsNt())
+ {
+ // WinNT and system mode
+ if (MsIsServiceRunning(c->SvcName))
+ {
+ wchar_t svc_exe[MAX_SIZE];
+ UINT64 giveup_tick;
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_STOP_SVC"), svc_title);
+ SwPerformPrint(wp, tmp);
+
+LABEL_RETRY_3:
+ if (MsStopService(c->SvcName) == false)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_STOP_SVC_ERROR"), svc_title, c->SvcName);
+ if (SwPerformMsgBox(wp, MB_ICONEXCLAMATION | MB_RETRYCANCEL, tmp) != IDRETRY)
+ {
+ // Cancel
+ ok = false;
+ }
+ else
+ {
+ if (MsIsServiceRunning(c->SvcName))
+ {
+ goto LABEL_RETRY_3;
+ }
+ }
+ }
+
+ // Wait 5 seconds if stop the service
+ SleepThread(5000);
+
+ // Wait until the EXE file for the service become ready to write
+ ConbinePathW(svc_exe, sizeof(svc_exe), sw->InstallDir, c->SvcFileName);
+
+ giveup_tick = Tick64() + (UINT64)10000;
+ while (IsFileWriteLockedW(svc_exe))
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_WAIT_FOR_FILE_UNLOCK"), svc_exe);
+ SwPerformPrint(wp, tmp);
+
+ SleepThread(100);
+
+ if (Tick64() >= giveup_tick)
+ {
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Win9x or user mode
+ wchar_t svc_exe[MAX_SIZE];
+ UINT64 giveup_tick;
+
+ // Stop the Service
+ MsStopUserModeSvc(c->SvcName);
+ SleepThread(3000);
+
+ // Wait until the EXE file for the service become ready to write
+ ConbinePathW(svc_exe, sizeof(svc_exe), sw->InstallDir, c->SvcFileName);
+
+ giveup_tick = Tick64() + (UINT64)10000;
+ while (IsFileWriteLockedW(svc_exe))
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_WAIT_FOR_FILE_UNLOCK"), svc_exe);
+ SwPerformPrint(wp, tmp);
+
+ SleepThread(100);
+
+ if (Tick64() >= giveup_tick)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (ok == false)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ // Examine preliminary whether the files to be deleted can be written successfully
+ ok = true;
+
+ SwPerformPrint(wp, _UU("SW_PERFORM_MSG_DELETE_PREPARE"));
+
+ for (i = 0;i < LIST_NUM(sw->LogFile->LogList);i++)
+ {
+ SW_LOG *g = LIST_DATA(sw->LogFile->LogList, i);
+
+ if (g->Type == SW_LOG_TYPE_FILE)
+ {
+ wchar_t fullpath[MAX_SIZE];
+ IO *io;
+ bool write_ok;
+ bool new_file;
+
+LABEL_RETRY_1:
+ write_ok = new_file = false;
+
+ UniStrCpy(fullpath, sizeof(fullpath), g->Path);
+
+ // If the process with the same name is running, kill it
+ if (MsKillProcessByExeName(fullpath) != 0)
+ {
+ // Wait for 1 second if kill the process
+ SleepThread(1000);
+ }
+
+ // Writing check
+ io = FileOpenExW(fullpath, true, true);
+ if (io == NULL)
+ {
+ io = FileCreateW(fullpath);
+ new_file = true;
+ }
+ if (io != NULL)
+ {
+ // Writing OK
+ write_ok = true;
+
+ FileCloseEx(io, true);
+
+ if (new_file)
+ {
+ FileDeleteW(fullpath);
+ }
+ }
+
+ if (write_ok == false)
+ {
+ // Show an error message if it fails
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_DELETE_ERROR"), fullpath, c->Title);
+ if (SwPerformMsgBox(wp, MB_ICONEXCLAMATION | MB_RETRYCANCEL, tmp) != IDRETRY)
+ {
+ // Cancel
+ ok = false;
+ break;
+ }
+ else
+ {
+ // Retry
+ goto LABEL_RETRY_1;
+ }
+ }
+ }
+ }
+
+ if (ok == false)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ // Delete the service
+ if (c->InstallService)
+ {
+ char svc_title_name[MAX_SIZE];
+ char svc_description_name[MAX_SIZE];
+ wchar_t *svc_title;
+
+ Format(svc_title_name, sizeof(svc_title_name), "SVC_%s_TITLE", c->SvcName);
+ Format(svc_description_name, sizeof(svc_description_name), "SVC_%s_DESCRIPT", c->SvcName);
+
+ svc_title = _UU(svc_title_name);
+
+ if (UniIsEmptyStr(svc_title) == false)
+ {
+ if (sw->IsSystemMode == false || MsIsNt() == false)
+ {
+ // Win9x or user mode
+ if (MsIsNt() == false)
+ {
+ // Remove the Run key from the registry for Win9x
+ MsRegDeleteValue(REG_LOCAL_MACHINE, WIN9X_SVC_REGKEY_1, c->SvcName);
+ MsRegDeleteValue(REG_LOCAL_MACHINE, WIN9X_SVC_REGKEY_2, c->SvcName);
+ }
+ }
+ else
+ {
+ // System mode
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_UNINSTALL_SVC"), svc_title);
+ SwPerformPrint(wp, tmp);
+
+LABEL_RETRY_4:
+
+ if (MsIsServiceInstalled(c->SvcName))
+ {
+ // Stop the service if it is running by any chance
+ MsStopService(c->SvcName);
+ }
+
+ if (MsIsServiceInstalled(c->SvcName))
+ {
+ // Uninstall the service
+ if (MsUninstallService(c->SvcName) == false)
+ {
+ // Show an error message if it fails
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_SVC_UNINSTALL_FAILED"), svc_title, c->SvcName);
+ if (SwPerformMsgBox(wp, MB_ICONEXCLAMATION | MB_RETRYCANCEL, tmp) != IDRETRY)
+ {
+ // Cancel
+ ok = false;
+ }
+ else
+ {
+ // Retry
+ goto LABEL_RETRY_4;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Delete the shortcut
+ SwPerformPrint(wp, _UU("SW_PERFORM_MSG_DELETE_LINKS"));
+ SwDeleteShortcuts(sw->LogFile);
+
+ // Delete the registry, files, and directories
+ for (i = 0;i < LIST_NUM(sw->LogFile->LogList);i++)
+ {
+ SW_LOG *g = LIST_DATA(sw->LogFile->LogList, LIST_NUM(sw->LogFile->LogList) - i - 1);
+ char tmpa[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_DELETE"), g->Path);
+
+ switch (g->Type)
+ {
+ case SW_LOG_TYPE_FILE: // File
+ SwPerformPrint(wp, tmp);
+ FileDeleteW(g->Path);
+ break;
+
+ case SW_LOG_TYPE_DIR: // Directory
+ SwPerformPrint(wp, tmp);
+ SleepThread(100);
+ DeleteDirW(g->Path);
+ break;
+
+ case SW_LOG_TYPE_REGISTRY: // Registry
+ SwPerformPrint(wp, tmp);
+ UniToStr(tmpa, sizeof(tmpa), g->Path);
+ MsRegDeleteKeyEx2(REG_LOCAL_MACHINE, tmpa, false, true);
+ break;
+ }
+ }
+
+ // Remove the installed build number from the registry
+ if (true)
+ {
+ char keyname[MAX_SIZE];
+ Format(keyname, sizeof(keyname), "%s\\%s", SW_REG_KEY, sw->CurrentComponent->Name);
+ MsRegDeleteValueEx2(sw->IsSystemMode ? REG_LOCAL_MACHINE : REG_CURRENT_USER,
+ keyname, "InstalledBuild", false, true);
+ }
+
+ // Remove the EULA agreement record
+ MsRegDeleteValueEx2(REG_CURRENT_USER, SW_REG_KEY_EULA, sw->CurrentComponent->Name, false, true);
+
+ SwPerformPrint(wp, _UU("SW_PERFORM_MSG_DELETE_SETUP_INFO"));
+
+ if (c->Id == SW_CMP_VPN_CLIENT)
+ {
+ // Remove the UI Helper
+ MsRegDeleteValueEx2(REG_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
+ SW_VPN_CLIENT_UIHELPER_REGVALUE, false, true);
+ }
+
+ // Remove the installation directory from the registry
+ if (true)
+ {
+ // Remove the installed directory from the registry
+ char keyname[MAX_SIZE];
+ Format(keyname, sizeof(keyname), "%s\\%s", SW_REG_KEY, sw->CurrentComponent->Name);
+ MsRegDeleteKeyEx2(sw->IsSystemMode ? REG_LOCAL_MACHINE : REG_CURRENT_USER, keyname, false, true);
+ }
+
+ // Delete the setuplog.dat
+ if (true)
+ {
+ wchar_t setuplog[MAX_PATH];
+
+ ConbinePathW(setuplog, sizeof(setuplog), MsGetExeDirNameW(), L"setuplog.dat");
+
+ FileDeleteW(setuplog);
+ }
+
+ SwPerformPrint(wp, _UU("SW_PERFORM_MSG_UPDATING"));
+
+ // Notify the update to the system
+ MsUpdateSystem();
+
+ // Completion message
+ SwPerformPrint(wp, _UU("SW_PERFORM_MSG_FINISHED"));
+
+ if (ok == false)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+LABEL_CLEANUP:
+
+ return ok;
+}
+
+// Create a Task List
+void SwDefineTasks(SW *sw, SW_TASK *t, SW_COMPONENT *c)
+{
+ wchar_t tmp[MAX_SIZE];
+ bool x64 = MsIs64BitWindows();
+ wchar_t src_setup_exe_fullpath[MAX_PATH];
+ wchar_t src_setup_exe_dir[MAX_PATH];
+ wchar_t src_setup_exe_filename[MAX_PATH];
+ wchar_t dir_desktop[MAX_PATH];
+ wchar_t dir_startmenu[MAX_PATH];
+ wchar_t dir_program[MAX_PATH];
+ wchar_t dir_app_program[MAX_PATH];
+ wchar_t dir_config_program[MAX_PATH];
+ wchar_t dir_admin_tools[MAX_PATH];
+ wchar_t dir_config_language[MAX_PATH];
+ wchar_t dir_startup[MAX_PATH];
+ wchar_t tmp1[MAX_SIZE], tmp2[MAX_SIZE];
+ SW_TASK_COPY *setup_exe;
+ // Validate arguments
+ if (sw == NULL || t == NULL || c == NULL)
+ {
+ return;
+ }
+
+ //// Organize directory name for creating shortcut
+ // Desktop
+ UniStrCpy(dir_desktop, sizeof(dir_desktop), (sw->IsSystemMode ? MsGetCommonDesktopDirW() : MsGetPersonalDesktopDirW()));
+ // Start menu
+ UniStrCpy(dir_startmenu, sizeof(dir_startmenu), (sw->IsSystemMode ? MsGetCommonStartMenuDirW() : MsGetPersonalStartMenuDirW()));
+ // Program
+ UniStrCpy(dir_program, sizeof(dir_program), (sw->IsSystemMode ? MsGetCommonProgramsDirW() : MsGetPersonalProgramsDirW()));
+ // Program directory for this application
+ ConbinePathW(dir_app_program, sizeof(dir_app_program), dir_program, c->LongName);
+ if (sw->IsSystemMode == false)
+ {
+ // User mode
+ UniStrCat(dir_app_program, sizeof(dir_app_program), _UU("SW_TAG_USERNAME"));
+ }
+ // Configuration tool directory
+ ConbinePathW(dir_config_program, sizeof(dir_config_program), dir_app_program, _UU("SW_DIRNAME_CONFIG_TOOLS"));
+ // Language configuration directory
+ ConbinePathW(dir_config_language, sizeof(dir_config_language), dir_app_program, _UU("SW_DIRNAME_LANGUAGE_TOOLS"));
+ // Directory for System administrator tool
+ ConbinePathW(dir_admin_tools, sizeof(dir_admin_tools), dir_app_program, _UU("SW_DIRNAME_ADMIN_TOOLS"));
+ // Startup
+ UniStrCpy(dir_startup, sizeof(dir_startup), (sw->IsSystemMode ? MsGetCommonStartupDirW() : MsGetPersonalStartupDirW()));
+
+ // Get the path information related to vpnsetup.exe
+ UniStrCpy(src_setup_exe_fullpath, sizeof(src_setup_exe_fullpath), MsGetExeFileNameW());
+ GetDirNameFromFilePathW(src_setup_exe_dir, sizeof(src_setup_exe_dir), src_setup_exe_fullpath);
+ GetFileNameFromFilePathW(src_setup_exe_filename, sizeof(src_setup_exe_filename), src_setup_exe_fullpath);
+
+ // Add the Setup program (themselves) to the copy list
+ Add(t->CopyTasks, (setup_exe = SwNewCopyTask(src_setup_exe_filename,
+ L"vpnsetup.exe", src_setup_exe_dir, sw->InstallDir, true, true)));
+
+ // Generate the file processing list for each component
+ if (c->Id == SW_CMP_VPN_SERVER)
+ {
+ // VPN Server
+ SW_TASK_COPY *ct;
+ SW_TASK_COPY *vpnserver, *vpncmd, *vpnsmgr;
+
+ CombinePathW(tmp, sizeof(tmp), sw->InstallDir, L"backup.vpn_server.config");
+ Add(t->SetSecurityPaths, CopyUniStr(tmp));
+
+ if (x64 == false)
+ {
+ vpnserver = SwNewCopyTask(L"vpnserver.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpncmd = SwNewCopyTask(L"vpncmd.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpnsmgr = SwNewCopyTask(L"vpnsmgr.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ }
+ else
+ {
+ vpnserver = SwNewCopyTask(L"vpnserver_x64.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpncmd = SwNewCopyTask(L"vpncmd_x64.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpnsmgr = SwNewCopyTask(L"vpnsmgr_x64.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ }
+
+ Add(t->CopyTasks, vpnserver);
+ Add(t->CopyTasks, vpncmd);
+ Add(t->CopyTasks, vpnsmgr);
+
+ Add(t->CopyTasks, (ct = SwNewCopyTask(L"|empty.config", L"vpn_server.config", sw->InstallSrc, sw->InstallDir, false, false)));
+ Add(t->CopyTasks, SwNewCopyTask(L"|backup_dir_readme.txt", L"readme.txt", sw->InstallSrc, tmp, false, false));
+
+ CombinePathW(tmp, sizeof(tmp), ct->DstDir, ct->DstFileName);
+ Add(t->SetSecurityPaths, CopyUniStr(tmp));
+
+ //// Definition of the shortcuts
+ // Desktop and Start menu
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpnsmgr->DstFileName, NULL, NULL, 0, dir_desktop,
+ _UU(sw->IsSystemMode ? "SW_LINK_NAME_VPNSMGR_SHORT" : "SW_LINK_NAME_VPNSMGR_SHORT_UM"),
+ _UU("SW_LINK_NAME_VPNSMGR_COMMENT"), true));
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpnsmgr->DstFileName, NULL, NULL, 0, dir_startmenu,
+ _UU(sw->IsSystemMode ? "SW_LINK_NAME_VPNSMGR_SHORT" : "SW_LINK_NAME_VPNSMGR_SHORT_UM"),
+ _UU("SW_LINK_NAME_VPNSMGR_COMMENT"), true));
+
+ // Programs\PacketiX VPN Server
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpnsmgr->DstFileName, NULL, NULL, 0, dir_app_program,
+ _UU("SW_LINK_NAME_VPNSMGR_FULL"),
+ _UU("SW_LINK_NAME_VPNSMGR_COMMENT"), false));
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpncmd->DstFileName, NULL, NULL, 0, dir_app_program,
+ _UU("SW_LINK_NAME_VPNCMD"),
+ _UU("SW_LINK_NAME_VPNCMD_COMMENT"), false));
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpnserver->DstFileName, L"/traffic", L"vpnsetup.exe", 2, dir_admin_tools,
+ _UU("SW_LINK_NAME_TRAFFIC"),
+ _UU("SW_LINK_NAME_TRAFFIC_COMMENT"), false));
+
+ // Programs\PacketiX VPN Server\Configuration tool
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpnserver->DstFileName, L"/tcp", L"vpnsetup.exe", 3, dir_config_program,
+ _UU("SW_LINK_NAME_TCP"),
+ _UU("SW_LINK_NAME_TCP_COMMENT"), false));
+
+ if (MsIsWin2000OrGreater())
+ {
+ Add(t->LinkTasks, SwNewLinkTask(MsGetSystem32DirW(), L"services.msc", NULL, L"filemgmt.dll", 0, dir_config_program,
+ _UU("SW_LINK_NAME_SERVICES"),
+ _UU("SW_LINK_NAME_SERVICES_COMMENT"), false));
+
+ if (sw->IsSystemMode)
+ {
+ // Debugging information collecting tool
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpncmd->DstFileName, L"/debug", L"vpnsetup.exe", 4, dir_admin_tools,
+ _UU("SW_LINK_NAME_DEBUG"),
+ _UU("SW_LINK_NAME_DEBUG_COMMENT"), false));
+ }
+ }
+
+ if (sw->IsSystemMode == false)
+ {
+ // Register to the start-up in the case of user mode
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpnserver->DstFileName, L"/usermode", NULL, 0, dir_startup,
+ _UU("SW_LINK_NAME_VPNSERVER_SVC"),
+ _UU("SW_LINK_NAME_VPNSERVER_SVC_COMMENT"), true));
+ }
+ }
+ else if (c->Id == SW_CMP_VPN_BRIDGE)
+ {
+ // VPN Bridge
+ SW_TASK_COPY *ct;
+ SW_TASK_COPY *vpnbridge, *vpncmd, *vpnsmgr;
+
+ CombinePathW(tmp, sizeof(tmp), sw->InstallDir, L"backup.vpn_bridge.config");
+ Add(t->SetSecurityPaths, CopyUniStr(tmp));
+
+ if (x64 == false)
+ {
+ vpnbridge = SwNewCopyTask(L"vpnbridge.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpncmd = SwNewCopyTask(L"vpncmd.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpnsmgr = SwNewCopyTask(L"vpnsmgr.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ }
+ else
+ {
+ vpnbridge = SwNewCopyTask(L"vpnbridge_x64.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpncmd = SwNewCopyTask(L"vpncmd_x64.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpnsmgr = SwNewCopyTask(L"vpnsmgr_x64.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ }
+
+ Add(t->CopyTasks, vpnbridge);
+ Add(t->CopyTasks, vpncmd);
+ Add(t->CopyTasks, vpnsmgr);
+
+ Add(t->CopyTasks, (ct = SwNewCopyTask(L"|empty.config", L"vpn_bridge.config", sw->InstallSrc, sw->InstallDir, false, false)));
+ Add(t->CopyTasks, SwNewCopyTask(L"|backup_dir_readme.txt", L"readme.txt", sw->InstallSrc, tmp, false, false));
+
+ CombinePathW(tmp, sizeof(tmp), ct->DstDir, ct->DstFileName);
+ Add(t->SetSecurityPaths, CopyUniStr(tmp));
+
+ //// Definition of the shortcuts
+ // Desktop and Start menu
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpnsmgr->DstFileName, NULL, NULL, 0, dir_desktop,
+ _UU(sw->IsSystemMode ? "SW_LINK_NAME_VPNSMGR_SHORT" : "SW_LINK_NAME_VPNSMGR_SHORT_UM"),
+ _UU("SW_LINK_NAME_VPNSMGR_COMMENT"), true));
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpnsmgr->DstFileName, NULL, NULL, 0, dir_startmenu,
+ _UU(sw->IsSystemMode ? "SW_LINK_NAME_VPNSMGR_SHORT" : "SW_LINK_NAME_VPNSMGR_SHORT_UM"),
+ _UU("SW_LINK_NAME_VPNSMGR_COMMENT"), true));
+
+ // Programs\PacketiX VPN Bridge
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpnsmgr->DstFileName, NULL, NULL, 0, dir_app_program,
+ _UU("SW_LINK_NAME_VPNSMGR_FULL"),
+ _UU("SW_LINK_NAME_VPNSMGR_COMMENT"), false));
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpncmd->DstFileName, NULL, NULL, 0, dir_app_program,
+ _UU("SW_LINK_NAME_VPNCMD"),
+ _UU("SW_LINK_NAME_VPNCMD_COMMENT"), false));
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpnbridge->DstFileName, L"/traffic", L"vpnsetup.exe", 2, dir_admin_tools,
+ _UU("SW_LINK_NAME_TRAFFIC"),
+ _UU("SW_LINK_NAME_TRAFFIC_COMMENT"), false));
+
+ // Programs\PacketiX VPN Bridge\Configuration tool
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpnbridge->DstFileName, L"/tcp", L"vpnsetup.exe", 3, dir_config_program,
+ _UU("SW_LINK_NAME_TCP"),
+ _UU("SW_LINK_NAME_TCP_COMMENT"), false));
+
+ if (MsIsWin2000OrGreater())
+ {
+ Add(t->LinkTasks, SwNewLinkTask(MsGetSystem32DirW(), L"services.msc", NULL, L"filemgmt.dll", 0, dir_config_program,
+ _UU("SW_LINK_NAME_SERVICES"),
+ _UU("SW_LINK_NAME_SERVICES_COMMENT"), false));
+
+ if (sw->IsSystemMode)
+ {
+ // Debugging information collecting tool
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpncmd->DstFileName, L"/debug", L"vpnsetup.exe", 4, dir_admin_tools,
+ _UU("SW_LINK_NAME_DEBUG"),
+ _UU("SW_LINK_NAME_DEBUG_COMMENT"), false));
+ }
+ }
+
+ if (sw->IsSystemMode == false)
+ {
+ // Register to the start-up in the case of user mode
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpnbridge->DstFileName, L"/usermode", NULL, 0, dir_startup,
+ _UU("SW_LINK_NAME_VPNBRIDGE_SVC"),
+ _UU("SW_LINK_NAME_VPNBRIDGE_SVC_COMMENT"), true));
+ }
+ }
+ else if (c->Id == SW_CMP_VPN_CLIENT)
+ {
+ // VPN Client
+ SW_TASK_COPY *ct;
+ SW_TASK_COPY *vpnclient, *vpncmd, *vpncmgr;
+ SW_TASK_COPY *vpnclient_gomi, *vpncmd_gomi, *vpncmgr_gomi;
+ SW_TASK_COPY *sfx_cache = NULL;
+ SW_TASK_COPY *vpnweb;
+ SW_TASK_COPY *vpninstall;
+ wchar_t *src_config_filename;
+
+ CombinePathW(tmp, sizeof(tmp), sw->InstallDir, L"backup.vpn_vpnclient.config");
+ Add(t->SetSecurityPaths, CopyUniStr(tmp));
+
+ if (x64 == false)
+ {
+ vpnclient = SwNewCopyTask(L"vpnclient.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpncmd = SwNewCopyTask(L"vpncmd.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpncmgr = SwNewCopyTask(L"vpncmgr.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpnclient_gomi = SwNewCopyTask(L"vpnclient_x64.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpncmd_gomi = SwNewCopyTask(L"vpncmd_x64.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpncmgr_gomi = SwNewCopyTask(L"vpncmgr_x64.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ }
+ else
+ {
+ vpnclient = SwNewCopyTask(L"vpnclient_x64.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpncmd = SwNewCopyTask(L"vpncmd_x64.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpncmgr = SwNewCopyTask(L"vpncmgr_x64.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpnclient_gomi = SwNewCopyTask(L"vpnclient.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpncmd_gomi = SwNewCopyTask(L"vpncmd.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpncmgr_gomi = SwNewCopyTask(L"vpncmgr.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ }
+
+ if (vpncmgr != NULL)
+ {
+ CombinePathW(sw->vpncmgr_path, sizeof(sw->vpncmgr_path),
+ vpncmgr->DstDir, vpncmgr->DstFileName);
+ }
+
+ if (UniIsEmptyStr(sw->CallerSfxPath) == false)
+ {
+ if (IsFileExistsW(sw->CallerSfxPath))
+ {
+ // Cache the calling SFX file body to the installation directory
+ wchar_t srcname[MAX_PATH];
+ wchar_t srcdir[MAX_PATH];
+
+ GetFileNameFromFilePathW(srcname, sizeof(srcname), sw->CallerSfxPath);
+ GetDirNameFromFilePathW(srcdir, sizeof(srcdir), sw->CallerSfxPath);
+
+ sfx_cache = SwNewCopyTask(srcname, SW_SFX_CACHE_FILENAME, srcdir, sw->InstallDir, true, false);
+ }
+ }
+
+ vpnweb = SwNewCopyTask(L"vpnweb.cab", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpninstall = SwNewCopyTask(L"vpninstall.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+
+ Add(t->CopyTasks, vpnclient);
+ Add(t->CopyTasks, vpncmd);
+ Add(t->CopyTasks, vpncmgr);
+ Add(t->CopyTasks, vpnclient_gomi);
+ Add(t->CopyTasks, vpncmd_gomi);
+ Add(t->CopyTasks, vpncmgr_gomi);
+ Add(t->CopyTasks, vpnweb);
+ Add(t->CopyTasks, vpninstall);
+
+
+ if (sfx_cache != NULL)
+ {
+ Add(t->CopyTasks, sfx_cache);
+ }
+
+ src_config_filename = L"|empty.config";
+
+ Add(t->CopyTasks, (ct = SwNewCopyTask(src_config_filename, L"vpn_client.config", sw->InstallSrc, sw->InstallDir, false, false)));
+
+ Add(t->CopyTasks, SwNewCopyTask(L"|backup_dir_readme.txt", L"readme.txt", sw->InstallSrc, tmp, false, false));
+
+ CombinePathW(tmp, sizeof(tmp), ct->DstDir, ct->DstFileName);
+ Add(t->SetSecurityPaths, CopyUniStr(tmp));
+
+ //// Definition of the shortcuts
+ // Desktop and Start menu
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpncmgr->DstFileName, NULL, NULL, 0, dir_desktop,
+ _UU("SW_LINK_NAME_VPNCMGR_SHORT"),
+ _UU("SW_LINK_NAME_VPNCMGR_COMMENT"), true));
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpncmgr->DstFileName, NULL, NULL, 0, dir_startmenu,
+ _UU("SW_LINK_NAME_VPNCMGR_SHORT"),
+ _UU("SW_LINK_NAME_VPNCMGR_COMMENT"), true));
+
+ // Programs\PacketiX VPN Client
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpncmgr->DstFileName, NULL, NULL, 0, dir_app_program,
+ _UU("SW_LINK_NAME_VPNCMGR_FULL"),
+ _UU("SW_LINK_NAME_VPNCMGR_COMMENT"), false));
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpncmgr->DstFileName, L"/remote", L"vpnsetup.exe", 1, dir_app_program,
+ _UU("SW_LINK_NAME_VPNCMGR2_FULL"),
+ _UU("SW_LINK_NAME_VPNCMGR2_COMMENT"), false));
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpncmd->DstFileName, NULL, NULL, 0, dir_app_program,
+ _UU("SW_LINK_NAME_VPNCMD"),
+ _UU("SW_LINK_NAME_VPNCMD_COMMENT"), false));
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpnclient->DstFileName, L"/traffic", L"vpnsetup.exe", 2, dir_admin_tools,
+ _UU("SW_LINK_NAME_TRAFFIC"),
+ _UU("SW_LINK_NAME_TRAFFIC_COMMENT"), false));
+
+ // Programs\PacketiX VPN Client\Configuration Tools
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpnclient->DstFileName, L"/tcp", L"vpnsetup.exe", 3, dir_config_program,
+ _UU("SW_LINK_NAME_TCP"),
+ _UU("SW_LINK_NAME_TCP_COMMENT"), false));
+
+ if (MsIsWin2000OrGreater())
+ {
+ Add(t->LinkTasks, SwNewLinkTask(MsGetSystem32DirW(), L"services.msc", NULL, L"filemgmt.dll", 0, dir_config_program,
+ _UU("SW_LINK_NAME_SERVICES"),
+ _UU("SW_LINK_NAME_SERVICES_COMMENT"), false));
+
+ if (sw->IsSystemMode)
+ {
+ // Debugging information collecting tool
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpncmd->DstFileName, L"/debug", L"vpnsetup.exe", 4, dir_admin_tools,
+ _UU("SW_LINK_NAME_DEBUG"),
+ _UU("SW_LINK_NAME_DEBUG_COMMENT"), false));
+ }
+ }
+
+ // Programs\PacketiX VPN Client\System administrators tool
+ if (MsIsNt())
+ {
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, L"vpnsetup.exe", L"/easy:true", L"vpnsetup.exe", 12, dir_admin_tools,
+ _UU("SW_LINK_NAME_EASYINSTALLER"),
+ _UU("SW_LINK_NAME_EASYINSTALLER_COMMENT"), false));
+
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, L"vpnsetup.exe", L"/web:true", L"vpnsetup.exe", 1, dir_admin_tools,
+ _UU("SW_LINK_NAME_WEBINSTALLER"),
+ _UU("SW_LINK_NAME_WEBINSTALLER_COMMENT"), false));
+ }
+
+ // Startup
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpncmgr->DstFileName, L"/startup", NULL, 0, dir_startup,
+ _UU("SW_LINK_NAME_VPNCMGRTRAY_FULL"),
+ _UU("SW_LINK_NAME_VPNCMGRTRAY_COMMENT"), true));
+ }
+ else if (c->Id == SW_CMP_VPN_SMGR)
+ {
+ // VPN Server Manager (Tools Only)
+ SW_TASK_COPY *vpncmd, *vpnsmgr;
+
+ if (x64 == false)
+ {
+ vpncmd = SwNewCopyTask(L"vpncmd.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpnsmgr = SwNewCopyTask(L"vpnsmgr.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ }
+ else
+ {
+ vpncmd = SwNewCopyTask(L"vpncmd_x64.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpnsmgr = SwNewCopyTask(L"vpnsmgr_x64.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ }
+
+ Add(t->CopyTasks, vpncmd);
+ Add(t->CopyTasks, vpnsmgr);
+
+ //// Definition of the shortcuts
+ // Desktop and Start menu
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpnsmgr->DstFileName, NULL, NULL, 0, dir_desktop,
+ _UU(sw->IsSystemMode ? "SW_LINK_NAME_VPNSMGR_SHORT_TOOLSONLY" : "SW_LINK_NAME_VPNSMGR_SHORT_TOOLSONLY_UM"),
+ _UU("SW_LINK_NAME_VPNSMGR_COMMENT"), true));
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpnsmgr->DstFileName, NULL, NULL, 0, dir_startmenu,
+ _UU(sw->IsSystemMode ? "SW_LINK_NAME_VPNSMGR_SHORT_TOOLSONLY" : "SW_LINK_NAME_VPNSMGR_SHORT_TOOLSONLY_UM"),
+ _UU("SW_LINK_NAME_VPNSMGR_COMMENT"), true));
+
+ // Programs\PacketiX VPN Server Manager (Tools Only)
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpnsmgr->DstFileName, NULL, NULL, 0, dir_app_program,
+ _UU("SW_LINK_NAME_VPNSMGR_FULL"),
+ _UU("SW_LINK_NAME_VPNSMGR_COMMENT"), false));
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpncmd->DstFileName, NULL, NULL, 0, dir_app_program,
+ _UU("SW_LINK_NAME_VPNCMD"),
+ _UU("SW_LINK_NAME_VPNCMD_COMMENT"), false));
+ }
+ else if (c->Id == SW_CMP_VPN_CMGR)
+ {
+ // VPN Client Manager (Tools Only)
+ SW_TASK_COPY *vpncmd, *vpncmgr;
+
+ if (x64 == false)
+ {
+ vpncmd = SwNewCopyTask(L"vpncmd.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpncmgr = SwNewCopyTask(L"vpncmgr.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ }
+ else
+ {
+ vpncmd = SwNewCopyTask(L"vpncmd_x64.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ vpncmgr = SwNewCopyTask(L"vpncmgr_x64.exe", NULL, sw->InstallSrc, sw->InstallDir, true, false);
+ }
+
+ Add(t->CopyTasks, vpncmd);
+ Add(t->CopyTasks, vpncmgr);
+
+ //// Definition of the shortcuts
+ // Desktop and Start menu
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpncmgr->DstFileName, L"/remote", L"vpnsetup.exe", 1, dir_desktop,
+ _UU(sw->IsSystemMode ? "SW_LINK_NAME_VPNCMGRTOOLS_SHORT" : "SW_LINK_NAME_VPNCMGRTOOLS_SHORT_UM"),
+ _UU("SW_LINK_NAME_VPNCMGR2_COMMENT"), true));
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpncmgr->DstFileName, L"/remote", L"vpnsetup.exe", 1, dir_startmenu,
+ _UU(sw->IsSystemMode ? "SW_LINK_NAME_VPNCMGRTOOLS_SHORT" : "SW_LINK_NAME_VPNCMGRTOOLS_SHORT_UM"),
+ _UU("SW_LINK_NAME_VPNCMGR2_COMMENT"), true));
+
+ // Programs\PacketiX VPN Client Manager (Tools Only)
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpncmgr->DstFileName, L"/remote", L"vpnsetup.exe", 1, dir_app_program,
+ _UU("SW_LINK_NAME_VPNCMGR2_FULL"),
+ _UU("SW_LINK_NAME_VPNCMGR2_COMMENT"), false));
+ Add(t->LinkTasks, SwNewLinkTask(sw->InstallDir, vpncmd->DstFileName, NULL, NULL, 0, dir_app_program,
+ _UU("SW_LINK_NAME_VPNCMD"),
+ _UU("SW_LINK_NAME_VPNCMD_COMMENT"), false));
+ }
+
+ // Uninstallation
+ UniFormat(tmp1, sizeof(tmp1), _UU("SW_LINK_NAME_UNINSTALL"), c->Title);
+ UniFormat(tmp2, sizeof(tmp2), _UU("SW_LINK_NAME_UNINSTALL_COMMENT"), c->Title);
+ Add(t->LinkTasks, SwNewLinkTask(setup_exe->DstDir, setup_exe->DstFileName, NULL, NULL, 0, dir_config_program,
+ tmp1,
+ tmp2, false));
+
+ // Language settings (except for Win9x)
+ if (MsIsNt())
+ {
+ UniFormat(tmp1, sizeof(tmp1), _UU("SW_LINK_NAME_LANGUAGE"), c->Title);
+ UniFormat(tmp2, sizeof(tmp2), _UU("SW_LINK_NAME_LANGUAGE_COMMENT"), c->Title);
+ Add(t->LinkTasks, SwNewLinkTask(setup_exe->DstDir, setup_exe->DstFileName, L"/language:yes",
+ L"vpnsetup.exe", 10, dir_config_language,
+ tmp1,
+ tmp2, false));
+ }
+
+ // Hamcore!
+ Add(t->CopyTasks, SwNewCopyTask(L"hamcore.se2", NULL, sw->InstallSrc, sw->InstallDir, true, true));
+}
+
+// Build the Web installer
+bool SwWebMain(SW *sw, WIZARD_PAGE *wp)
+{
+ bool ret = false;
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (sw == NULL || wp == NULL)
+ {
+ return false;
+ }
+
+ SwPerformPrint(wp, _UU("SW_PERFORM_MSG_WEB_INIT"));
+
+ if (true)
+ {
+ wchar_t installer_src_exe[MAX_PATH];
+ wchar_t src_cab[MAX_PATH];
+ wchar_t vpninstall_exe[MAX_PATH];
+ char inf_path[MAX_PATH];
+ char htm_path[MAX_PATH];
+ LANGLIST current_lang;
+ BUF *inf_buf = NULL;
+ BUF *htm_buf = NULL;
+ BUF *setting_buf = NULL;
+ char *inf_data = NULL;
+ UINT inf_data_size;
+ char *htm_data = NULL;
+ UINT htm_data_size;
+ char ver_major[64];
+ char ver_minor[64];
+ char ver_build[64];
+ char *normal_mode = (sw->Web_EasyMode ? "false" : "true");
+ char package_name[MAX_SIZE];
+ ZIP_PACKER *z = NULL;
+
+ ToStr(ver_major, CEDAR_VER / 100);
+ ToStr(ver_minor, CEDAR_VER % 100);
+ ToStr(ver_build, CEDAR_BUILD);
+
+ Format(package_name, sizeof(package_name),
+ GC_SW_SOFTETHER_PREFIX "vpnclient-v%u.%02u-%u-%04u-%02u-%02u-windows.exe",
+ CEDAR_VER / 100,
+ CEDAR_VER % 100,
+ CEDAR_BUILD,
+ BUILD_DATE_Y, BUILD_DATE_M, BUILD_DATE_D);
+
+ GetCurrentLang(&current_lang);
+
+ // Installer cache file
+ CombinePathW(installer_src_exe, sizeof(installer_src_exe), MsGetExeDirNameW(), SW_SFX_CACHE_FILENAME);
+
+ // Cab file
+ CombinePathW(src_cab, sizeof(src_cab), MsGetExeDirNameW(), L"vpnweb.cab");
+
+ // Vpninstall file
+ CombinePathW(vpninstall_exe, sizeof(vpninstall_exe), MsGetExeDirNameW(), L"vpninstall.exe");
+
+ // Confirm existence of the file
+ if (IsFileExistsW(installer_src_exe) == false)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SW_FILE_NOT_FOUNT"), installer_src_exe);
+ SwPerformMsgBox(wp, MB_ICONSTOP, tmp);
+ goto LABEL_CLEANUP;
+ }
+ if (IsFileExistsW(src_cab) == false)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SW_FILE_NOT_FOUNT"), src_cab);
+ SwPerformMsgBox(wp, MB_ICONSTOP, tmp);
+ goto LABEL_CLEANUP;
+ }
+ if (IsFileExistsW(vpninstall_exe) == false)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SW_FILE_NOT_FOUNT"), vpninstall_exe);
+ SwPerformMsgBox(wp, MB_ICONSTOP, tmp);
+ goto LABEL_CLEANUP;
+ }
+
+ // Read the configuration file
+ setting_buf = ReadDumpW(sw->Web_SettingFile);
+ if (setting_buf != NULL)
+ {
+ if (sw->Web_EraseSensitive)
+ {
+ // Remove the secret information
+ CiEraseSensitiveInAccount(setting_buf);
+ }
+ }
+
+ // Verify the signature of the installer cache file
+ if (MsCheckFileDigitalSignatureW(NULL, installer_src_exe, NULL) == false)
+ {
+ // Installer cache file is not signed
+ if (SwPerformMsgBox(wp, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2,
+ _UU("SW_INSTALLER_CACHE_IS_NOT_SIGNED")) == IDNO)
+ {
+ // Cancel
+ goto LABEL_CLEANUP;
+ }
+ }
+
+ // Read the .inf file
+ Format(inf_path, sizeof(inf_path), "|vpninstall_%s.inf", current_lang.Name);
+
+ inf_buf = ReadDump(inf_path);
+ if (inf_buf == NULL)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ inf_data_size = (inf_buf->Size + 1024) * 2;
+ inf_data = ZeroMalloc(inf_data_size);
+ Copy(inf_data, inf_buf->Buf, inf_buf->Size);
+
+ ReplaceStrEx(inf_data, inf_data_size, inf_data, "$VER_BUILD$", ver_build, false);
+ ReplaceStrEx(inf_data, inf_data_size, inf_data, "$PACKAGE_FILENAME$", package_name, false);
+ ReplaceStrEx(inf_data, inf_data_size, inf_data, "$NORMAL_MODE$", normal_mode, false);
+
+ // Read the .htm file
+ Format(htm_path, sizeof(htm_path), "|vpnweb_sample_%s.htm", current_lang.Name);
+
+ htm_buf = ReadDump(htm_path);
+ if (htm_buf == NULL)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ htm_data_size = (htm_buf->Size + 1024) * 2;
+ htm_data = ZeroMalloc(htm_data_size);
+ Copy(htm_data, htm_buf->Buf, htm_buf->Size);
+
+ ReplaceStrEx(htm_data, htm_data_size, htm_data, "$VER_MAJOR$", ver_major, false);
+ ReplaceStrEx(htm_data, htm_data_size, htm_data, "$VER_MINOR$", ver_minor, false);
+ ReplaceStrEx(htm_data, htm_data_size, htm_data, "$VER_BUILD$", ver_build, false);
+
+ // Creating a ZIP
+ z = NewZipPacker();
+
+ if (ZipAddRealFileW(z, "vpnweb.cab", 0, 0, src_cab) == false ||
+ ZipAddRealFileW(z, "vpninstall.exe", 0, 0, vpninstall_exe) == false ||
+ ZipAddRealFileW(z, package_name, 0, 0, installer_src_exe) == false)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ ZipAddFileSimple(z, "vpninstall.inf", 0, 0, inf_data, StrLen(inf_data));
+ ZipAddFileSimple(z, "index.html", 0, 0, htm_data, StrLen(htm_data));
+ ZipAddFileSimple(z, "auto_setting.vpn", 0, 0, setting_buf->Buf, setting_buf->Size);
+
+ // Export
+ if (ZipWriteW(z, sw->Web_OutFile))
+ {
+ ret = true;
+
+ UniFormat(sw->FinishMsg, sizeof(sw->FinishMsg),
+ _UU("SW_WEB_FINISHED"),
+ sw->Web_OutFile);
+ }
+
+LABEL_CLEANUP:
+ FreeZipPacker(z);
+ FreeBuf(setting_buf);
+ FreeBuf(inf_buf);
+ FreeBuf(htm_buf);
+ Free(inf_data);
+ Free(htm_data);
+ }
+
+
+ return ret;
+}
+
+// Build a simple installer
+bool SwEasyMain(SW *sw, WIZARD_PAGE *wp)
+{
+ LIST *o;
+ BUF *b;
+ bool ret = false;
+ wchar_t account_tmp[MAX_PATH];
+ // Validate arguments
+ if (sw == NULL || wp == NULL)
+ {
+ return false;
+ }
+
+ SwPerformPrint(wp, _UU("SW_PERFORM_MSG_EASY_INIT"));
+
+ o = SwNewSfxFileList();
+
+ SwAddBasicFilesToList(o, "vpnclient");
+
+ // Load a connection setting file
+ b = ReadDumpW(sw->Easy_SettingFile);
+ if (b != NULL)
+ {
+ if (sw->Easy_EraseSensitive)
+ {
+ // Remove secret information
+ CiEraseSensitiveInAccount(b);
+ }
+
+ // Save to a temporary folder
+ CombinePathW(account_tmp, sizeof(account_tmp), MsGetMyTempDirW(), L"vpn_setting.vpn");
+ if (DumpBufW(b, account_tmp))
+ {
+ // Add a connection settings to file list of SFX
+ Add(o, SwNewSfxFile(SW_AUTO_CONNECT_ACCOUNT_FILE_NAME, account_tmp));
+
+ if (sw->Easy_EasyMode)
+ {
+ // Set the connection manager to simple mode
+ Add(o, SwNewSfxFile(SW_FLAG_EASY_MODE, account_tmp));
+ }
+
+ if (SwCompileSfx(o, sw->Easy_OutFile))
+ {
+ ret = true;
+ }
+
+ FileDeleteW(account_tmp);
+ }
+
+ FreeBuf(b);
+ }
+
+ SwFreeSfxFileList(o);
+
+ if (ret)
+ {
+ // Completion message
+ UniFormat(sw->FinishMsg, sizeof(sw->FinishMsg), _UU("SW_EASY_FINISHED_MSG"), sw->Easy_OutFile);
+ }
+
+ return ret;
+}
+
+// Installation main
+bool SwInstallMain(SW *sw, WIZARD_PAGE *wp, SW_COMPONENT *c)
+{
+ SW_TASK *t;
+ bool ret = false;
+ UINT i;
+ wchar_t tmp[MAX_SIZE * 2];
+ bool ok;
+ bool x64 = MsIs64BitWindows();
+ // Validate arguments
+ if (sw == NULL || wp == NULL || c == NULL)
+ {
+ return false;
+ }
+
+ ok = true;
+ t = NULL;
+
+ // Create a Setup task
+ SwPerformPrint(wp, _UU("SW_PERFORM_MSG_INIT_TASKS"));
+ t = SwNewTask();
+
+ // Create a list of files to be installed
+ SwDefineTasks(sw, t, c);
+
+ if (sw->LanguageMode)
+ {
+ goto LABEL_CREATE_SHORTCUT;
+ }
+
+ if (sw->OnlyAutoSettingMode)
+ {
+ goto LABEL_IMPORT_SETTING;
+ }
+
+ // Install the SeLow
+ if (SuIsSupportedOs())
+ {
+ // Only in the system mode
+ if (c->InstallService && sw->IsSystemMode)
+ {
+ // Not to install in the case of the VPN Client
+ //if (c->Id != SW_CMP_VPN_CLIENT)
+ {
+ SwPerformPrint(wp, _UU("SW_PERFORM_MSG_INSTALL_SELOW"));
+
+ SuInstallDriver(false);
+ }
+ }
+ }
+
+ // Uninstall the old MSI
+ ok = true;
+ if (sw->IsSystemMode && c->OldMsiList != NULL)
+ {
+ bool reboot_required = false;
+
+ if (SwUninstallOldMsiInstalled(wp->Wizard->hWndWizard, wp, c, &reboot_required) == false)
+ {
+ // MSI uninstall Failed
+ ok = false;
+ }
+ else if (reboot_required)
+ {
+ // Require to restart
+ ok = false;
+
+ sw->MsiRebootRequired = true;
+ }
+ }
+
+ if (ok == false)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ // Stop the Service
+ ok = true;
+
+ if (c->InstallService)
+ {
+ char svc_title_name[MAX_SIZE];
+ wchar_t *svc_title;
+
+ Format(svc_title_name, sizeof(svc_title_name), "SVC_%s_TITLE", c->SvcName);
+
+ svc_title = _UU(svc_title_name);
+
+ if (UniIsEmptyStr(svc_title) == false)
+ {
+ if (sw->IsSystemMode && MsIsNt())
+ {
+ // WinNT and system mode
+ if (MsIsServiceRunning(c->SvcName))
+ {
+ wchar_t svc_exe[MAX_SIZE];
+ UINT64 giveup_tick;
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_STOP_SVC"), svc_title);
+ SwPerformPrint(wp, tmp);
+
+LABEL_RETRY_3:
+ if (MsStopService(c->SvcName) == false)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_STOP_SVC_ERROR"), svc_title, c->SvcName);
+ if (SwPerformMsgBox(wp, MB_ICONEXCLAMATION | MB_RETRYCANCEL, tmp) != IDRETRY)
+ {
+ // Cancel
+ ok = false;
+ }
+ else
+ {
+ if (MsIsServiceRunning(c->SvcName))
+ {
+ goto LABEL_RETRY_3;
+ }
+ }
+ }
+
+ // Wait for 5 seconds if stopped the service
+ SleepThread(5000);
+
+ // Wait until the EXE file for the service become ready to write
+ ConbinePathW(svc_exe, sizeof(svc_exe), sw->InstallDir, c->SvcFileName);
+
+ giveup_tick = Tick64() + (UINT64)10000;
+ while (IsFileWriteLockedW(svc_exe))
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_WAIT_FOR_FILE_UNLOCK"), svc_exe);
+ SwPerformPrint(wp, tmp);
+
+ SleepThread(100);
+
+ if (Tick64() >= giveup_tick)
+ {
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ // In the case of Win9x or user mode
+ wchar_t svc_exe[MAX_SIZE];
+ UINT64 giveup_tick;
+
+ // Stop the Service
+ MsStopUserModeSvc(c->SvcName);
+ SleepThread(3000);
+
+ // Wait until the EXE file for the service become ready to write
+ ConbinePathW(svc_exe, sizeof(svc_exe), sw->InstallDir, c->SvcFileName);
+
+ giveup_tick = Tick64() + (UINT64)10000;
+ while (IsFileWriteLockedW(svc_exe))
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_WAIT_FOR_FILE_UNLOCK"), svc_exe);
+ SwPerformPrint(wp, tmp);
+
+ SleepThread(100);
+
+ if (Tick64() >= giveup_tick)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (ok == false)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ // Examine preliminary whether files to be copied are writable successfully
+ ok = true;
+
+ SwPerformPrint(wp, _UU("SW_PERFORM_MSG_COPY_PREPARE"));
+
+ for (i = 0;i < LIST_NUM(t->CopyTasks);i++)
+ {
+ SW_TASK_COPY *ct = LIST_DATA(t->CopyTasks, i);
+
+ wchar_t fullpath[MAX_SIZE];
+ IO *io;
+ bool write_ok;
+ bool new_file;
+ bool new_dir;
+ UINT64 giveup_tick = Tick64() + 30000ULL;
+
+LABEL_RETRY_1:
+ new_dir = write_ok = new_file = false;
+
+ CombinePathW(fullpath, sizeof(fullpath), ct->DstDir, ct->DstFileName);
+
+ if (ct->Overwrite == false)
+ {
+ // Do not check if overwrite is Off
+ continue;
+ }
+
+ // If the process with the same name is running, kill it
+ if (MsKillProcessByExeName(fullpath) != 0)
+ {
+ // Wait for 1 second if killed the process
+ SleepThread(1000);
+ }
+
+ new_dir = MakeDirExW(ct->DstDir);
+
+ // Write check
+ io = FileOpenExW(fullpath, true, true);
+ if (io == NULL)
+ {
+ io = FileCreateW(fullpath);
+ new_file = true;
+ }
+ if (io != NULL)
+ {
+ // Writing OK
+ write_ok = true;
+
+ FileCloseEx(io, true);
+
+ if (new_file)
+ {
+ FileDeleteW(fullpath);
+ }
+ }
+
+ if (new_dir)
+ {
+ DeleteDirW(ct->DstDir);
+ }
+
+ if (write_ok == false)
+ {
+ UINT64 now = Tick64();
+
+ if (now <= giveup_tick)
+ {
+ // Do the auto-retry in 30 seconds
+ SleepThread(1000);
+ goto LABEL_RETRY_1;
+ }
+
+ // Show an error message if it fails
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_WRITE_ERROR"), fullpath, c->Title);
+ if (SwPerformMsgBox(wp, MB_ICONEXCLAMATION | MB_RETRYCANCEL, tmp) != IDRETRY)
+ {
+ // Cancel
+ ok = false;
+ break;
+ }
+ else
+ {
+ // Retry
+ goto LABEL_RETRY_1;
+ }
+ }
+ }
+
+ if (ok == false)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ // File Copy
+ ok = true;
+
+ for (i = 0;i < LIST_NUM(t->CopyTasks);i++)
+ {
+ SW_TASK_COPY *ct = LIST_DATA(t->CopyTasks, i);
+ wchar_t fullpath_src[MAX_SIZE];
+ wchar_t fullpath_dst[MAX_SIZE];
+ bool skip;
+
+LABEL_RETRY_2:
+
+ if (UniStartWith(ct->SrcFileName, L"|") == false)
+ {
+ CombinePathW(fullpath_src, sizeof(fullpath_src), ct->SrcDir, ct->SrcFileName);
+ }
+ else
+ {
+ UniStrCpy(fullpath_src, sizeof(fullpath_src), ct->SrcFileName);
+ }
+
+ CombinePathW(fullpath_dst, sizeof(fullpath_dst), ct->DstDir, ct->DstFileName);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_COPY_FILE"), fullpath_dst);
+ SwPerformPrint(wp, tmp);
+
+ skip = false;
+
+ if (ct->Overwrite == false)
+ {
+ if (IsFileExistsW(fullpath_dst))
+ {
+ // Do nothing because the destination file already exists
+ skip = true;
+ }
+ }
+
+ if (skip == false)
+ {
+ // Create a directory
+ if (MakeDirExW(ct->DstDir))
+ {
+ SwAddLog(sw, sw->LogFile, SW_LOG_TYPE_DIR, ct->DstDir);
+ }
+
+ // Copy
+ if (FileCopyW(fullpath_src, fullpath_dst) == false && ct->Overwrite)
+ {
+ // Show an error message if it fails
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_COPY_ERROR"), fullpath_dst);
+ if (SwPerformMsgBox(wp, MB_ICONEXCLAMATION | MB_RETRYCANCEL, tmp) != IDRETRY)
+ {
+ // Cancel
+ ok = false;
+ break;
+ }
+ else
+ {
+ // Retry
+ goto LABEL_RETRY_2;
+ }
+ }
+ else
+ {
+ if (ct->Overwrite && ct->SetupFile == false)
+ {
+ SwAddLog(sw, sw->LogFile, SW_LOG_TYPE_FILE, fullpath_dst);
+ }
+ }
+ }
+ }
+
+ if (ok == false)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+
+ if (sw->IsSystemMode && MsIsNt())
+ {
+ // ACL settings only in the system mode
+ for (i = 0;i < LIST_NUM(t->SetSecurityPaths);i++)
+ {
+ // Security Settings
+ wchar_t *path = LIST_DATA(t->SetSecurityPaths, i);
+
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_SET_SECURITY"), path);
+ SwPerformPrint(wp, tmp);
+
+ MsSetFileSecureAcl(path);
+ }
+ }
+
+ // Set the language of the destination
+ if (true)
+ {
+ LANGLIST current_lang;
+ wchar_t langfilename[MAX_PATH];
+
+ Zero(&current_lang, sizeof(current_lang));
+ GetCurrentLang(&current_lang);
+
+ ConbinePathW(langfilename, sizeof(langfilename), sw->InstallDir, L"lang.config");
+
+ SaveLangConfig(langfilename, current_lang.Name);
+ }
+
+ // Firewall registration
+ if (true)
+ {
+ char dira[MAX_PATH];
+
+ UniToStr(dira, sizeof(dira), sw->InstallDir);
+
+ RegistWindowsFirewallAllEx(dira);
+ }
+
+ if (c->Id == SW_CMP_VPN_SERVER || c->Id == SW_CMP_VPN_BRIDGE)
+ {
+ // Disable the off-loading
+ MsDisableNetworkOffloadingEtc();
+ }
+
+ // Install the service
+ ok = true;
+
+ if (c->InstallService)
+ {
+ char svc_title_name[MAX_SIZE];
+ char svc_description_name[MAX_SIZE];
+ wchar_t *svc_title;
+
+ Format(svc_title_name, sizeof(svc_title_name), "SVC_%s_TITLE", c->SvcName);
+ Format(svc_description_name, sizeof(svc_description_name), "SVC_%s_DESCRIPT", c->SvcName);
+
+ svc_title = _UU(svc_title_name);
+
+ if (UniIsEmptyStr(svc_title) == false)
+ {
+ if (sw->IsSystemMode == false || MsIsNt() == false)
+ {
+ // Just simply start in user mode or Win9x mode
+ wchar_t fullpath[MAX_SIZE];
+
+LABEL_RETRY_USERMODE_EXEC:
+
+ CombinePathW(fullpath, sizeof(fullpath), sw->InstallDir, c->SvcFileName);
+
+ if (MsExecuteW(fullpath, (MsIsNt() ? L"/usermode" : L"/win9x_service")) == false)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_SVC_USERMODE_EXEC_FAILED"), fullpath);
+
+ if (SwPerformMsgBox(wp, MB_ICONEXCLAMATION | MB_RETRYCANCEL, tmp) != IDRETRY)
+ {
+ // Cancel
+ ok = false;
+ }
+ else
+ {
+ // Retry
+ goto LABEL_RETRY_USERMODE_EXEC;
+ }
+ }
+ else
+ {
+ if (MsIsNt() == false)
+ {
+ // Register into the registry as a background service in the case of Win9x
+ wchar_t fullpath2[MAX_SIZE];
+
+ UniFormat(fullpath2, sizeof(fullpath2), L"\"%s\" /win9x_service", fullpath);
+
+ MsRegWriteStrW(REG_LOCAL_MACHINE, WIN9X_SVC_REGKEY_1, c->SvcName, fullpath2);
+ MsRegWriteStrW(REG_LOCAL_MACHINE, WIN9X_SVC_REGKEY_2, c->SvcName, fullpath2);
+ }
+ }
+ }
+ else
+ {
+ // System mode
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_INSTALL_SVC"), svc_title);
+ SwPerformPrint(wp, tmp);
+
+LABEL_RETRY_4:
+
+ if (MsIsServiceInstalled(c->SvcName))
+ {
+ // Stop the service if it is running by any chance
+ MsStopService(c->SvcName);
+ }
+
+ if (MsIsServiceInstalled(c->SvcName))
+ {
+ // Uninstall the old service
+ if (MsUninstallService(c->SvcName) == false)
+ {
+ // Show an error message if it fails
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_SVC_UNINSTALL_FAILED"), svc_title, c->SvcName);
+ if (SwPerformMsgBox(wp, MB_ICONEXCLAMATION | MB_RETRYCANCEL, tmp) != IDRETRY)
+ {
+ // Cancel
+ ok = false;
+ }
+ else
+ {
+ // Retry
+ goto LABEL_RETRY_4;
+ }
+ }
+ }
+
+ if (ok)
+ {
+ wchar_t fullpath[MAX_SIZE];
+ wchar_t fullpath2[MAX_SIZE];
+
+ CombinePathW(fullpath2, sizeof(fullpath), sw->InstallDir, c->SvcFileName);
+ UniFormat(fullpath, sizeof(fullpath), L"\"%s\" /service", fullpath2);
+
+ // Install a new service
+ if (MsInstallServiceW(c->SvcName, svc_title, _UU(svc_description_name), fullpath) == false)
+ {
+ // Show the error message if it fails
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_SVC_INSTALL_FAILED"), svc_title, c->SvcName);
+ if (SwPerformMsgBox(wp, MB_ICONEXCLAMATION | MB_RETRYCANCEL, tmp) != IDRETRY)
+ {
+ // Cancel
+ ok = false;
+ }
+ else
+ {
+ // Retry
+ goto LABEL_RETRY_4;
+ }
+ }
+ else
+ {
+ wchar_t wtmp[256];
+
+ StrToUni(wtmp, sizeof(wtmp), c->SvcName);
+ SwAddLog(sw, sw->LogFile, SW_LOG_TYPE_SVC, wtmp);
+ }
+ }
+
+ if (ok)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_START_SVC"), svc_title);
+ SwPerformPrint(wp, tmp);
+
+ MsRegWriteIntEx2(REG_LOCAL_MACHINE, "Software\\" GC_REG_COMPANY_NAME "\\Update Service Config", c->SvcName, 0, false, true);
+
+LABEL_RETRY_5:
+ // Start the service
+ if (MsStartService(c->SvcName) == false)
+ {
+ // Show the error message if it fails
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_START_SVC_ERROR"), svc_title, c->SvcName);
+ if (SwPerformMsgBox(wp, MB_ICONEXCLAMATION | MB_RETRYCANCEL, tmp) != IDRETRY)
+ {
+ // Cancel
+ ok = false;
+ }
+ else
+ {
+ // Retry
+ if (MsIsServiceRunning(c->SvcName) == false)
+ {
+ goto LABEL_RETRY_5;
+ }
+ }
+ }
+ }
+ }
+
+ if (c->Id == SW_CMP_VPN_CLIENT)
+ {
+ // In the VPN Client service, wait until the service port can be connected
+ SwWaitForVpnClientPortReady(SW_VPNCLIENT_SERVICE_WAIT_READY_TIMEOUT);
+ }
+ }
+ }
+
+ if (ok == false)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+LABEL_CREATE_SHORTCUT:
+
+ // Create a shortcut
+ SwInstallShortcuts(sw, wp, c, t);
+
+ if (sw->LanguageMode)
+ {
+ // Update the Description of the service if in the language setting mode
+ if (c->InstallService)
+ {
+ char svc_description_name[MAX_SIZE];
+ wchar_t *svc_description;
+
+ Format(svc_description_name, sizeof(svc_description_name), "SVC_%s_DESCRIPT", c->SvcName);
+
+ svc_description = _UU(svc_description_name);
+
+ if (UniIsEmptyStr(svc_description) == false)
+ {
+ if (sw->IsSystemMode && MsIsNt())
+ {
+ MsSetServiceDescription(c->SvcName, svc_description);
+ }
+ }
+ }
+
+ goto LABEL_REGISTER_UNINSTALL;
+ }
+
+ if (c->Id == SW_CMP_VPN_CLIENT)
+ {
+ // Register the UI Helper in the Run in the case of the VPN Client
+ wchar_t fullpath[MAX_PATH];
+ wchar_t fullcmd[MAX_SIZE];
+
+ ConbinePathW(fullpath, sizeof(fullpath), sw->InstallDir, c->SvcFileName);
+
+ UniFormat(fullcmd, sizeof(fullcmd), L"\"%s\" /uihelp", fullpath);
+
+ MsRegWriteStrEx2W(REG_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
+ SW_VPN_CLIENT_UIHELPER_REGVALUE, fullcmd, false, true);
+
+ // Start the UI Helper
+ MsExecuteW(fullpath, L"/uihelp");
+
+ SleepThread(3000);
+ }
+
+ if (true)
+ {
+ // Run the vpncmd and exit immediately
+ wchar_t fullpath[MAX_PATH];
+
+ ConbinePathW(fullpath, sizeof(fullpath), sw->InstallDir, (MsIsX64() ? L"vpncmd_x64.exe" : L"vpncmd.exe"));
+
+ RunW(fullpath, L"/?", true, false);
+ }
+
+ if (c->Id == SW_CMP_VPN_CLIENT)
+ {
+ wchar_t dst_vpnclient_exe[MAX_PATH];
+ wchar_t vpnclient_arg[MAX_SIZE];
+
+ ConbinePathW(dst_vpnclient_exe, sizeof(dst_vpnclient_exe), sw->InstallDir, c->SvcFileName);
+ UniFormat(vpnclient_arg, sizeof(vpnclient_arg), L"\"%s\" \"%%1\"", dst_vpnclient_exe);
+
+ // Register the association to .vpn file in the case of VPN Client
+ MsRegWriteStrEx2(REG_LOCAL_MACHINE, SW_VPN_CLIENT_EXT_REGKEY, NULL, SW_VPN_CLIENT_EXT_REGVALUE, false, true);
+ SwAddLogA(sw, sw->LogFile, SW_LOG_TYPE_REGISTRY, SW_VPN_CLIENT_EXT_REGKEY);
+
+ MsRegNewKeyEx2(REG_LOCAL_MACHINE, SW_VPN_CLIENT_EXT_REGKEY_SUB1, false, true);
+ MsRegNewKeyEx2(REG_LOCAL_MACHINE, SW_VPN_CLIENT_EXT_REGKEY_SUB2, false, true);
+ SwAddLogA(sw, sw->LogFile, SW_LOG_TYPE_REGISTRY, SW_VPN_CLIENT_EXT_REGKEY_SUB1);
+ SwAddLogA(sw, sw->LogFile, SW_LOG_TYPE_REGISTRY, SW_VPN_CLIENT_EXT_REGKEY_SUB2);
+
+ MsRegWriteStrEx2(REG_LOCAL_MACHINE, SW_VPN_CLIENT_VPNFILE_REGKEY, NULL, SW_VPN_CLIENT_VPNFILE_REGVALUE, false, true);
+ SwAddLogA(sw, sw->LogFile, SW_LOG_TYPE_REGISTRY, SW_VPN_CLIENT_VPNFILE_REGKEY);
+
+ MsRegWriteStrEx2W(REG_LOCAL_MACHINE, SW_VPN_CLIENT_VPNFILE_ICON_REGKEY, NULL, dst_vpnclient_exe, false, true);
+ SwAddLogA(sw, sw->LogFile, SW_LOG_TYPE_REGISTRY, SW_VPN_CLIENT_VPNFILE_ICON_REGKEY);
+
+ MsRegWriteStrEx2W(REG_LOCAL_MACHINE, SW_VPN_CLIENT_VPNFILE_SHELLOPEN_CMD_REGKEY, NULL, vpnclient_arg, false, true);
+ SwAddLogA(sw, sw->LogFile, SW_LOG_TYPE_REGISTRY, SW_VPN_CLIENT_VPNFILE_SHELLOPEN_CMD_REGKEY_SUB2);
+ SwAddLogA(sw, sw->LogFile, SW_LOG_TYPE_REGISTRY, SW_VPN_CLIENT_VPNFILE_SHELLOPEN_CMD_REGKEY_SUB1);
+ SwAddLogA(sw, sw->LogFile, SW_LOG_TYPE_REGISTRY, SW_VPN_CLIENT_VPNFILE_SHELLOPEN_CMD_REGKEY);
+ }
+
+ if (c->Id == SW_CMP_VPN_CLIENT)
+ {
+ // Disable the MMCSS
+ MsSetMMCSSNetworkThrottlingEnable(false);
+ }
+
+LABEL_IMPORT_SETTING:
+ if (c->Id == SW_CMP_VPN_CLIENT)
+ {
+ if (UniIsEmptyStr(sw->auto_setting_path) == false)
+ {
+ if (UniIsEmptyStr(sw->vpncmgr_path) == false)
+ {
+ if (sw->DisableAutoImport == false)
+ {
+ wchar_t tmp_setting_path[MAX_PATH];
+ wchar_t arg[MAX_PATH];
+ void *handle;
+ bool easy_mode = IsFileExists(SW_FLAG_EASY_MODE_2);
+ // Run the vpncmgr, and start a connection by importing the connection configuration file
+ // Store a connection setting file to stable temporally directory
+
+ SwPerformPrint(wp, _UU("SW_PERFORM_MSG_IMPORTING_ACCOUNT"));
+
+ ConbinePathW(tmp_setting_path, sizeof(tmp_setting_path), MsGetTempDirW(), L"vpn_auto_connect.vpn");
+ FileCopyW(sw->auto_setting_path, tmp_setting_path);
+
+ // Start the vpncmgr
+ UniFormat(arg, sizeof(arg), L"/%S \"%s\"", (easy_mode ? "easy" : "normal"), tmp_setting_path);
+ handle = MsRunAsUserExW(sw->vpncmgr_path, arg, false);
+
+ if (handle != NULL)
+ {
+ sw->HideStartCommand = true;
+
+ CloseHandle(handle);
+ }
+ }
+ }
+ }
+ }
+
+ if (sw->OnlyAutoSettingMode)
+ {
+ goto LABEL_FINISHED;
+ }
+
+LABEL_REGISTER_UNINSTALL:
+ // Register the uninstall information
+ if (sw->IsSystemMode)
+ {
+ char uninstall_keyname[MAX_SIZE];
+ wchar_t uninstall_keyname_w[MAX_SIZE];
+ char uninstall_version[MAX_SIZE];
+ wchar_t dst_setup_exe[MAX_PATH];
+ wchar_t setup_icon[MAX_SIZE];
+ wchar_t uninstaller_exe[MAX_PATH];
+ SYSTEMTIME st;
+ char install_date[MAX_PATH];
+
+ SwPerformPrint(wp, _UU("SW_PERFORM_MSG_REGISTER_UNINSTALL"));
+
+ Zero(&st, sizeof(st));
+ LocalTime(&st);
+
+ Format(install_date, sizeof(install_date), "%04u/%02u/%02u", st.wYear, st.wMonth, st.wDay);
+
+ CombinePathW(dst_setup_exe, sizeof(dst_setup_exe), sw->InstallDir, L"vpnsetup.exe");
+
+ Format(uninstall_keyname, sizeof(uninstall_keyname),
+ "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\softether_" GC_SW_SOFTETHER_PREFIX "%s", c->Name);
+ StrToUni(uninstall_keyname_w, sizeof(uninstall_keyname_w), uninstall_keyname);
+
+ GetCedarVersion(uninstall_version, sizeof(uninstall_version));
+
+ // Display name
+ MsRegWriteStrEx2W(REG_LOCAL_MACHINE, uninstall_keyname, "DisplayName", c->LongName,
+ false, true);
+
+ // Version
+ MsRegWriteStrEx2(REG_LOCAL_MACHINE, uninstall_keyname, "DisplayVersion", uninstall_version,
+ false, true);
+
+ // Icon
+ UniFormat(setup_icon, sizeof(setup_icon), L"\"%s\",%u", dst_setup_exe, c->IconExeIndex);
+ MsRegWriteStrEx2W(REG_LOCAL_MACHINE, uninstall_keyname, "DisplayIcon", setup_icon,
+ false, true);
+
+ // Information
+ MsRegWriteIntEx2(REG_LOCAL_MACHINE, uninstall_keyname, "NoModify", 1, false, true);
+ MsRegWriteIntEx2(REG_LOCAL_MACHINE, uninstall_keyname, "NoRepair", 1, false, true);
+
+ // Link
+ MsRegWriteStrEx2(REG_LOCAL_MACHINE, uninstall_keyname, "HelpLink", _SS("SW_UNINSTALLINFO_URL"),
+ false, true);
+ MsRegWriteStrEx2(REG_LOCAL_MACHINE, uninstall_keyname, "URLInfoAbout", _SS("SW_UNINSTALLINFO_URL"),
+ false, true);
+ MsRegWriteStrEx2(REG_LOCAL_MACHINE, uninstall_keyname, "URLUpdateInfo", _SS("SW_UNINSTALLINFO_URL"),
+ false, true);
+
+ // Publisher
+ MsRegWriteStrEx2W(REG_LOCAL_MACHINE, uninstall_keyname, "Publisher", _UU("SW_UNINSTALLINFO_PUBLISHER"),
+ false, true);
+
+ // Date of installation
+ MsRegWriteStrEx2(REG_LOCAL_MACHINE, uninstall_keyname, "InstallDate", install_date,
+ false, true);
+
+ // Uninstaller
+ UniFormat(uninstaller_exe, sizeof(uninstaller_exe), L"\"%s\"", dst_setup_exe);
+ MsRegWriteStrEx2W(REG_LOCAL_MACHINE, uninstall_keyname, "UninstallString", uninstaller_exe,
+ false, true);
+
+ if (sw->LanguageMode == false)
+ {
+ SwAddLog(sw, sw->LogFile, SW_LOG_TYPE_REGISTRY, uninstall_keyname_w);
+ }
+ }
+
+ // Write the log
+ if (true)
+ {
+ wchar_t log_filename[MAX_SIZE];
+
+L_RETRY_LOG:
+
+ SwPerformPrint(wp, _UU("SW_PERFORM_MSG_WRITE_LOG"));
+
+ CombinePathW(log_filename, sizeof(log_filename), sw->InstallDir, L"setuplog.dat");
+
+ if (sw->LanguageMode == false)
+ {
+ SwAddLog(sw, sw->LogFile, SW_LOG_TYPE_FILE, log_filename);
+ }
+
+ sw->LogFile->IsSystemMode = sw->IsSystemMode;
+ sw->LogFile->Component = sw->CurrentComponent;
+ sw->LogFile->Build = CEDAR_BUILD;
+
+ if (SwSaveLogFile(sw, log_filename, sw->LogFile) == false)
+ {
+ // Show the error message if it fails
+ UINT msgret;
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_WRITE_LOG_ERROR"), log_filename);
+ msgret = SwPerformMsgBox(wp, MB_ICONEXCLAMATION | MB_YESNO, tmp);
+
+ if (msgret == IDYES)
+ {
+ // Retry
+ goto L_RETRY_LOG;
+ }
+ }
+ }
+
+ if (true)
+ {
+ // Record the installed build number and directory in the registry
+ char keyname[MAX_SIZE];
+ LANGLIST current_lang;
+ LANGLIST current_os_lang;
+
+ GetCurrentLang(&current_lang);
+ GetCurrentLang(&current_os_lang);
+
+ Format(keyname, sizeof(keyname), "%s\\%s", SW_REG_KEY, sw->CurrentComponent->Name);
+ MsRegWriteStrEx2W(sw->IsSystemMode ? REG_LOCAL_MACHINE : REG_CURRENT_USER,
+ keyname, "InstalledDir", sw->InstallDir, false, true);
+ MsRegWriteIntEx2(sw->IsSystemMode ? REG_LOCAL_MACHINE : REG_CURRENT_USER,
+ keyname, "InstalledBuild", CEDAR_BUILD, false, true);
+
+ // Set the language to registry
+ MsRegWriteStrEx2(REG_CURRENT_USER, SW_REG_KEY, "Last User Language",
+ current_lang.Name, false, true);
+ MsRegWriteStrEx2(REG_CURRENT_USER, SW_REG_KEY, "Last Operating System Language",
+ current_os_lang.Name, false, true);
+
+ // Save the EULA agreement record
+ if (sw->EulaAgreed && sw->CurrentEulaHash != 0)
+ {
+ MsRegWriteIntEx2(REG_CURRENT_USER, SW_REG_KEY_EULA, sw->CurrentComponent->Name,
+ sw->CurrentEulaHash, false, true);
+ }
+ }
+
+ SwPerformPrint(wp, _UU("SW_PERFORM_MSG_UPDATING"));
+
+ // Notify the update to the system
+ MsUpdateSystem();
+
+ if (sw->LanguageMode)
+ {
+ // Show a message that the language configuration is complete
+ wchar_t msg[MAX_SIZE];
+
+ UniFormat(msg, sizeof(msg), _UU("SW_LANG_OK"), c->Title, c->Title);
+
+ if (c->InstallService)
+ {
+ UniStrCat(msg, sizeof(msg), _UU("SW_LANG_OK_SERVICE"));
+ }
+
+ if (c->Id == SW_CMP_VPN_CLIENT)
+ {
+ UniStrCat(msg, sizeof(msg), _UU("SW_LANG_OK_VPNCMGR"));
+ }
+
+ UniStrCpy(sw->FinishMsg, sizeof(sw->FinishMsg), msg);
+ }
+
+LABEL_FINISHED:
+
+ // Completion message
+ SwPerformPrint(wp, _UU("SW_PERFORM_MSG_FINISHED"));
+
+ ret = true;
+
+LABEL_CLEANUP:
+ // Release the task
+ if (t != NULL)
+ {
+ SwFreeTask(t);
+ }
+
+ return ret;
+}
+
+// Wait for that the listening port of the VPN Client service becomes available
+bool SwWaitForVpnClientPortReady(UINT timeout)
+{
+ UINT64 start, giveup;
+ bool ret = false;
+ if (timeout == 0)
+ {
+ timeout = SW_VPNCLIENT_SERVICE_WAIT_READY_TIMEOUT;
+ }
+
+ start = Tick64();
+ giveup = start + (UINT64)timeout;
+
+ while (Tick64() < giveup)
+ {
+ if (CheckTCPPortEx("localhost", CLIENT_CONFIG_PORT, 1000))
+ {
+ ret = true;
+ break;
+ }
+
+ SleepThread(1000);
+ }
+
+ return ret;
+}
+
+// Create a Shortcut file (Delete the old one)
+void SwInstallShortcuts(SW *sw, WIZARD_PAGE *wp, SW_COMPONENT *c, SW_TASK *t)
+{
+ UINT i;
+ wchar_t tmp[MAX_SIZE];
+ wchar_t setuplog[MAX_PATH];
+ LIST *o;
+ SW_LOGFILE *oldlog;
+ // Validate arguments
+ if (sw == NULL || wp == NULL || c == NULL || t == NULL)
+ {
+ return;
+ }
+
+ // If there is an old setup log, read it
+ CombinePathW(setuplog, sizeof(setuplog), sw->InstallDir, L"setuplog.dat");
+ oldlog = SwLoadLogFile(sw, setuplog);
+ if (oldlog != NULL)
+ {
+ SwPerformPrint(wp, _UU("SW_PERFORM_MSG_DELETE_OLD_LINKS"));
+
+ SwDeleteShortcuts(oldlog);
+
+ SwFreeLogFile(oldlog);
+ }
+
+ // Remove only the shortcut setup log from the current log
+ o = NewListFast(NULL);
+
+ for (i = 0;i < LIST_NUM(sw->LogFile->LogList);i++)
+ {
+ SW_LOG *g = LIST_DATA(sw->LogFile->LogList, i);
+
+ if (g->Type == SW_LOG_TYPE_LNK || g->Type == SW_LOG_TYPE_LNK_DIR)
+ {
+ Add(o, g);
+ }
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ SW_LOG *g = LIST_DATA(o, i);
+
+ Delete(sw->LogFile->LogList, g);
+
+ Free(g);
+ }
+
+ ReleaseList(o);
+
+ for (i = 0;i < LIST_NUM(t->LinkTasks);i++)
+ {
+ SW_TASK_LINK *lt = LIST_DATA(t->LinkTasks, i);
+ wchar_t lnk_fullpath[MAX_SIZE];
+ wchar_t lnk_dirname[MAX_SIZE];
+ wchar_t target_fullpath[MAX_SIZE];
+ wchar_t target_dirname[MAX_SIZE];
+ wchar_t icon_fullpath[MAX_SIZE];
+
+L_RETRY_LINK:
+
+ SwPerformPrint(wp, _UU("SW_PERFORM_MSG_CREATE_LINKS"));
+
+ // Generate the full path of the LNK file
+ CombinePathW(lnk_fullpath, sizeof(lnk_fullpath), lt->DestDir, lt->DestName);
+ UniStrCat(lnk_fullpath, sizeof(lnk_fullpath), L".lnk");
+
+ // Get the directory name to be saved the LNK file
+ GetDirNameFromFilePathW(lnk_dirname, sizeof(lnk_dirname), lnk_fullpath);
+
+ // Generate the full path to the link destination
+ CombinePathW(target_fullpath, sizeof(target_fullpath), lt->TargetDir, lt->TargetExe);
+
+ // Create the full path of the icon
+ CombinePathW(icon_fullpath, sizeof(icon_fullpath), lt->TargetDir, lt->IconExe);
+
+ // Get the directory name of the full path to the link destination
+ GetDirNameFromFilePathW(target_dirname, sizeof(target_dirname), target_fullpath);
+
+ // Create a directory
+ MakeDirExW(lnk_dirname);
+ if (lt->NoDeleteDir == false)
+ {
+ SwAddLog(sw, sw->LogFile, SW_LOG_TYPE_LNK_DIR, lnk_dirname);
+ }
+
+ // Create the LNK file
+ if (CreateLink(lnk_fullpath, target_fullpath, target_dirname, lt->TargetArg,
+ lt->DestDescription, icon_fullpath, lt->IconIndex) == false)
+ {
+ // Show the error message if it fails
+ UINT msgret;
+ UniFormat(tmp, sizeof(tmp), _UU("SW_PERFORM_MSG_CRAETE_LINK_ERROR"), lnk_fullpath);
+ msgret = SwPerformMsgBox(wp, MB_ICONEXCLAMATION | MB_YESNO, tmp);
+
+ if (msgret == IDYES)
+ {
+ // Retry
+ goto L_RETRY_LINK;
+ }
+ }
+ else
+ {
+ SwAddLog(sw, sw->LogFile, SW_LOG_TYPE_LNK, lnk_fullpath);
+ }
+ }
+}
+
+// Search component
+SW_COMPONENT *SwFindComponent(SW *sw, char *name)
+{
+ UINT i;
+ // Validate arguments
+ if (sw == NULL || IsEmptyStr(name))
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(sw->ComponentList);i++)
+ {
+ SW_COMPONENT *c = LIST_DATA(sw->ComponentList, i);
+
+ if (StrCmpi(c->Name, name) == 0)
+ {
+ return c;
+ }
+ }
+
+ return NULL;
+}
+
+// Release the log file
+void SwFreeLogFile(SW_LOGFILE *logfile)
+{
+ UINT i;
+ // Validate arguments
+ if (logfile == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(logfile->LogList);i++)
+ {
+ SW_LOG *g = LIST_DATA(logfile->LogList, i);
+
+ Free(g);
+ }
+
+ ReleaseList(logfile->LogList);
+
+ Free(logfile);
+}
+
+// Create a new log file
+SW_LOGFILE *SwNewLogFile()
+{
+ SW_LOGFILE *logfile = ZeroMalloc(sizeof(SW_LOGFILE));
+
+ logfile->LogList = NewListFast(NULL);
+
+ return logfile;
+}
+
+// Read the log file
+SW_LOGFILE *SwLoadLogFile(SW *sw, wchar_t *filename)
+{
+ FOLDER *r = NULL;
+ FOLDER *items = NULL;
+ FOLDER *info = NULL;
+ UINT i;
+ TOKEN_LIST *t = NULL;
+ bool is_system_mode = false;
+ char component_name[MAX_SIZE] = { 0 };
+ UINT build;
+ SW_COMPONENT *c = NULL;
+ SW_LOGFILE *ret = NULL;
+ // Validate arguments
+ if (sw == NULL || filename == NULL)
+ {
+ return NULL;
+ }
+
+ r = CfgReadW(filename);
+ if (r == NULL)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ items = CfgGetFolder(r, "Items");
+ info = CfgGetFolder(r, "Info");
+ if (items == NULL || info == NULL)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ t = CfgEnumFolderToTokenList(items);
+ if (t == NULL)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ // Mode and components
+ is_system_mode = CfgGetBool(info, "IsSystemMode");
+ CfgGetStr(info, "ComponentName", component_name, sizeof(component_name));
+ build = CfgGetInt(info, "Build");
+
+ if (build == 0)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ c = SwFindComponent(sw, component_name);
+ if (c == NULL)
+ {
+ goto LABEL_CLEANUP;
+ }
+
+ ret = ZeroMalloc(sizeof(SW_LOGFILE));
+ ret->IsSystemMode = is_system_mode;
+ ret->Component = c;
+ ret->Build = build;
+ ret->LogList = NewListFast(NULL);
+
+ // Item List
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ char *name = t->Token[i];
+ FOLDER *f = CfgGetFolder(items, name);
+
+ if (f != NULL)
+ {
+ UINT type = CfgGetInt(f, "Type");
+ wchar_t value[MAX_SIZE];
+
+ if (CfgGetUniStr(f, "Path", value, sizeof(value)))
+ {
+ if (IsEmptyUniStr(value) == false && type != 0)
+ {
+ SW_LOG *g = ZeroMalloc(sizeof(SW_LOG));
+
+ g->Type = type;
+ UniStrCpy(g->Path, sizeof(g->Path), value);
+
+ Add(ret->LogList, g);
+ }
+ }
+ }
+ }
+
+LABEL_CLEANUP:
+ if (r != NULL)
+ {
+ CfgDeleteFolder(r);
+ }
+
+ if (t != NULL)
+ {
+ FreeToken(t);
+ }
+
+ return ret;
+}
+
+// Save the log file
+bool SwSaveLogFile(SW *sw, wchar_t *dst_name, SW_LOGFILE *logfile)
+{
+ FOLDER *r;
+ FOLDER *items;
+ FOLDER *info;
+ UINT i;
+ bool ret;
+ // Validate arguments
+ if (sw == NULL || dst_name == NULL || logfile == NULL)
+ {
+ return false;
+ }
+
+ r = CfgCreateRoot();
+
+ items = CfgCreateFolder(r, "Items");
+
+ info = CfgCreateFolder(r, "Info");
+
+ CfgAddBool(info, "IsSystemMode", logfile->IsSystemMode);
+ CfgAddStr(info, "ComponentName", logfile->Component->Name);
+ CfgAddInt(info, "Build", logfile->Build);
+
+ for (i = 0;i < LIST_NUM(logfile->LogList);i++)
+ {
+ FOLDER *f;
+ SW_LOG *g = LIST_DATA(logfile->LogList, i);
+ char name[MAX_PATH];
+
+ Format(name, sizeof(name), "Item%04u", i);
+
+ f = CfgCreateFolder(items, name);
+
+ CfgAddInt(f, "Type", g->Type);
+ CfgAddUniStr(f, "Path", g->Path);
+ }
+
+ ret = CfgSaveExW3(NULL, r, dst_name, NULL, true);
+
+ CfgDeleteFolder(r);
+
+ return ret;
+}
+
+// Display the string to the status screen
+void SwPerformPrint(WIZARD_PAGE *wp, wchar_t *str)
+{
+ SW_UI ui;
+ // Validate arguments
+ if (wp == NULL || str == NULL)
+ {
+ return;
+ }
+
+ Zero(&ui, sizeof(ui));
+ ui.Type = SW_UI_TYPE_PRINT;
+ ui.Message = str;
+
+ SwInteractUi(wp, &ui);
+}
+
+// Show a message box on the screen
+UINT SwPerformMsgBox(WIZARD_PAGE *wp, UINT flags, wchar_t *msg)
+{
+ SW_UI ui;
+ // Validate arguments
+ if (wp == NULL || msg == NULL)
+ {
+ return 0;
+ }
+
+ Zero(&ui, sizeof(ui));
+ ui.Type = SW_UI_TYPE_MSGBOX;
+ ui.Message = msg;
+ ui.Param = flags;
+
+ return SwInteractUi(wp, &ui);
+}
+
+// Call the UI interaction
+UINT SwInteractUi(WIZARD_PAGE *wp, SW_UI *ui)
+{
+ // Validate arguments
+ if (wp == NULL || ui == NULL)
+ {
+ return 0;
+ }
+
+ SendMsg(wp->hWndPage, 0, WM_SW_INTERACT_UI, 0xCAFE, (LPARAM)ui);
+
+ SleepThread(50);
+
+ return ui->RetCode;
+}
+
+// UI interaction is called
+void SwInteractUiCalled(HWND hWnd, SW *sw, WIZARD_PAGE *wp, SW_UI *ui)
+{
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL || wp == NULL || ui == NULL)
+ {
+ return;
+ }
+
+ switch (ui->Type)
+ {
+ case SW_UI_TYPE_PRINT: // Display the message
+ SetText(hWnd, S_STATUS, ui->Message);
+ break;
+
+ case SW_UI_TYPE_MSGBOX: // Show a message box
+ ui->RetCode = MsgBox(hWnd, ui->Param, ui->Message);
+ break;
+
+ case SW_UI_TYPE_FINISH: // Complete
+ PostMessageA(hWnd, WM_SW_EXIT, 0xCAFE, 1);
+ break;
+
+ case SW_UI_TYPE_ERROR: // Error
+ PostMessageA(hWnd, WM_SW_EXIT, 0xCAFE, 0);
+ break;
+ }
+}
+
+// Initialize the setup process screen
+void SwPerformInit(HWND hWnd, SW *sw, WIZARD_PAGE *wp)
+{
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL || wp == NULL)
+ {
+ return;
+ }
+
+ DlgFont(hWnd, S_INFO, 10, true);
+
+ if (sw->EasyMode)
+ {
+ SetIcon(hWnd, S_ICON, ICO_SETUP);
+
+ SetText(hWnd, S_INFO, _UU("SW_PERFORM_MSG_EASY_INFO"));
+ }
+ else if (sw->WebMode)
+ {
+ SetIcon(hWnd, S_ICON, ICO_SETUP);
+
+ SetText(hWnd, S_INFO, _UU("SW_PERFORM_MSG_WEB_INFO"));
+ }
+ else
+ {
+ SetIcon(hWnd, S_ICON, sw->CurrentComponent->Icon);
+
+ FormatText(hWnd, S_INFO, sw->CurrentComponent->Title);
+ }
+
+ SetTextA(hWnd, S_STATUS, "");
+
+ if (MsIsWinXPOrWinVista())
+ {
+ // Display the progress bar for Windows XP or later
+ SendMsg(hWnd, IDC_PROGRESS1, PBM_SETMARQUEE, TRUE, 100);
+ SetStyle(hWnd, IDC_PROGRESS1, PBS_MARQUEE);
+ }
+ else
+ {
+ // Hide the progress bar in the case of Windows 2000 or earlier
+ Hide(hWnd, IDC_PROGRESS1);
+ }
+}
+
+// Do the set-up process
+UINT SwPerform(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param)
+{
+ SW *sw = (SW *)param;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SwPerformInit(hWnd, sw, wizard_page);
+ break;
+
+ case WM_WIZ_SHOW:
+ SetWizardButton(wizard_page, false, false, false, false);
+
+ SetTimer(hWnd, 1, 100, NULL);
+ break;
+
+ case WM_TIMER:
+ KillTimer(hWnd, 1);
+
+ // Main thread execution
+ if (sw->PerformThread == NULL)
+ {
+ sw->PerformThread = NewThread(SwPerformThread, wizard_page);
+ }
+ break;
+
+ case WM_WIZ_HIDE:
+ break;
+
+ case WM_CLOSE:
+ break;
+
+ case WM_WIZ_NEXT:
+ break;
+
+ case WM_WIZ_BACK:
+ break;
+
+ case WM_SW_INTERACT_UI:
+ // UI interaction is called
+ if (wParam == 0xCAFE)
+ {
+ SwInteractUiCalled(hWnd, sw, wizard_page, (SW_UI *)lParam);
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ }
+ break;
+
+ case WM_SW_EXIT:
+ // Close this screen since the process completed
+ if (wParam == 0xCAFE)
+ {
+ JumpWizard(wizard_page, (lParam == 0 ? D_SW_ERROR : D_SW_FINISH));
+
+ if (sw->PerformThread != NULL)
+ {
+ WaitThread(sw->PerformThread, INFINITE);
+ ReleaseThread(sw->PerformThread);
+ sw->PerformThread = NULL;
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Final confirmation screen
+UINT SwReady(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param)
+{
+ SW *sw = (SW *)param;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ FormatText(hWnd, S_INFO, sw->CurrentComponent->Title);
+ break;
+
+ case WM_WIZ_SHOW:
+ SetWizardButton(wizard_page, true, true, true, false);
+ break;
+
+ case WM_WIZ_HIDE:
+ break;
+
+ case WM_CLOSE:
+ break;
+
+ case WM_WIZ_NEXT:
+ return D_SW_PERFORM;
+
+ case WM_WIZ_BACK:
+ return D_SW_DIR;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Uninstall all the old MSI products
+bool SwUninstallOldMsiInstalled(HWND hWnd, WIZARD_PAGE *wp, SW_COMPONENT *c, bool *reboot_required)
+{
+ UINT i;
+ bool dummy_bool = false;
+ // Validate arguments
+ if (c == NULL || wp == NULL)
+ {
+ return true;
+ }
+ if (reboot_required == NULL)
+ {
+ reboot_required = &dummy_bool;
+ }
+
+ *reboot_required = false;
+
+ if (c->OldMsiList == NULL)
+ {
+ return true;
+ }
+
+ for (i = 0;i < c->NumOldMsi;i++)
+ {
+ SW_OLD_MSI *m = &c->OldMsiList[i];
+ wchar_t tmp[MAX_SIZE];
+
+ if (MsGetMsiInstalledDir(m->ComponentCode, tmp, sizeof(tmp)))
+ {
+ bool rr = false;
+ wchar_t msg[MAX_SIZE];
+
+LABEL_RETRY:
+
+ UniFormat(msg, sizeof(msg), _UU("SW_PERFORM_MSG_UNINSTALL_MSI"), c->Title);
+ SwPerformPrint(wp, msg);
+
+ if (MsMsiUninstall(m->ProductCode, hWnd, &rr) == false)
+ {
+ UniFormat(msg, sizeof(msg), _UU("SW_MSI_UNINSTALL_FAILED"), c->Title, m->ProductCode);
+
+ if (SwPerformMsgBox(wp, MB_ICONEXCLAMATION | MB_RETRYCANCEL, msg) == IDRETRY)
+ {
+ goto LABEL_RETRY;
+ }
+
+ return false;
+ }
+ else
+ {
+ if (rr)
+ {
+ *reboot_required = true;
+ return true;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+// Get the directory where the old MSI products are installed
+wchar_t *SwGetOldMsiInstalledDir(SW_COMPONENT *c)
+{
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return NULL;
+ }
+
+ if (c->OldMsiList == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < c->NumOldMsi;i++)
+ {
+ SW_OLD_MSI *m = &c->OldMsiList[i];
+ wchar_t tmp[MAX_SIZE];
+
+ if (MsGetMsiInstalledDir(m->ComponentCode, tmp, sizeof(tmp)))
+ {
+ return UniCopyStr(tmp);
+ }
+ }
+
+ return NULL;
+}
+
+// Initialize the default installation directory
+void SwInitDefaultInstallDir(SW *sw)
+{
+ char keyname[MAX_SIZE];
+ wchar_t *reg_dir_system;
+ wchar_t *reg_dir_user;
+ wchar_t *msi_dir_system = NULL;
+ // Validate arguments
+ if (sw == NULL)
+ {
+ return;
+ }
+
+ msi_dir_system = SwGetOldMsiInstalledDir(sw->CurrentComponent);
+
+ Format(keyname, sizeof(keyname), "%s\\%s", SW_REG_KEY, sw->CurrentComponent->Name);
+
+ if (UniIsEmptyStr(msi_dir_system) == false)
+ {
+ MsRegWriteStrEx2W(REG_LOCAL_MACHINE, keyname, "InstalledDir", msi_dir_system, false, true);
+ }
+
+ reg_dir_system = MsRegReadStrEx2W(REG_LOCAL_MACHINE, keyname, "InstalledDir", false, true);
+ reg_dir_user = MsRegReadStrEx2W(REG_CURRENT_USER, keyname, "InstalledDir", false, true);
+
+ // Generate a directory name in the case of system mode
+ CombinePathW(sw->DefaultInstallDir_System, sizeof(sw->DefaultInstallDir_System),
+ MsGetProgramFilesDirX64W(), sw->CurrentComponent->DefaultDirName);
+
+ // Generate a directory name in the case of user mode
+ CombinePathW(sw->DefaultInstallDir_User, sizeof(sw->DefaultInstallDir_User),
+ MsGetPersonalAppDataDirW(), sw->CurrentComponent->DefaultDirName);
+
+ if (UniIsEmptyStr(reg_dir_system) == false)
+ {
+ UniStrCpy(sw->DefaultInstallDir_System, sizeof(sw->DefaultInstallDir_System), reg_dir_system);
+ }
+
+ if (UniIsEmptyStr(reg_dir_user) == false)
+ {
+ UniStrCpy(sw->DefaultInstallDir_User, sizeof(sw->DefaultInstallDir_User), reg_dir_user);
+ }
+
+ if (MsIsNt() == false)
+ {
+ // Set to system mode for Win9x
+ sw->IsSystemMode = true;
+ }
+
+ if (MsIsAdmin() == false)
+ {
+ sw->IsAvailableSystemMode = false;
+ sw->IsAvailableUserMode = true;
+ }
+ else if (MsIsNt() == false)
+ {
+ sw->IsAvailableSystemMode = true;
+ sw->IsAvailableUserMode = false;
+ }
+ else
+ {
+ sw->IsAvailableSystemMode = true;
+ sw->IsAvailableUserMode = !sw->CurrentComponent->SystemModeOnly;
+ }
+
+ sw->ShowWarningForUserMode = sw->CurrentComponent->InstallService;
+
+ Free(reg_dir_system);
+ Free(reg_dir_user);
+ Free(msi_dir_system);
+}
+
+// Update the installation directory setting screen
+void SwDirUpdate(HWND hWnd, SW *sw, WIZARD_PAGE *wizard_page)
+{
+ bool user_mode_selected;
+ bool show_custom;
+ bool change_dir;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL || wizard_page == NULL)
+ {
+ return;
+ }
+
+ change_dir = IsChecked(hWnd, R_CUSTOM);
+
+ SetShow(hWnd, S_DEST, change_dir);
+ SetShow(hWnd, E_DIR, change_dir);
+ SetShow(hWnd, B_BROWSE, change_dir);
+
+ show_custom = IsChecked(hWnd, R_SHOWCUSTOM);
+
+ SetShow(hWnd, R_FOR_SYSTEM, show_custom);
+ SetShow(hWnd, R_FOR_USER, show_custom);
+
+ user_mode_selected = IsChecked(hWnd, R_FOR_USER);
+
+ SetText(hWnd, R_DEFAULT, user_mode_selected ? sw->DefaultInstallDir_User : sw->DefaultInstallDir_System);
+
+ if (user_mode_selected == false)
+ {
+ Hide(hWnd, S_WARNING);
+ Hide(hWnd, S_WARNING2);
+ }
+ else
+ {
+ SetShow(hWnd, S_WARNING, sw->ShowWarningForUserMode);
+ SetShow(hWnd, S_WARNING2, sw->ShowWarningForUserMode);
+ }
+
+ SetEnable(hWnd, R_SHOWCUSTOM, !user_mode_selected);
+
+ DlgFont(hWnd, R_DEFAULT, 0, !change_dir);
+}
+
+// Check the directory name planned to be created newly
+bool SwCheckNewDirName(wchar_t *name)
+{
+ char tmp[MAX_SIZE];
+ UCHAR rand[16];
+ wchar_t testname[MAX_SIZE];
+ IO *io;
+ bool new_dir;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return false;
+ }
+
+ // Create a directory
+ new_dir = MakeDirExW(name);
+
+ // Writes the appropriate files
+ Rand(rand, sizeof(rand));
+ BinToStr(tmp, sizeof(tmp), rand, sizeof(rand));
+ UniFormat(testname, sizeof(testname), L"%s\\%S.dat", name, tmp);
+
+ io = FileCreateW(testname);
+
+ if (io == NULL)
+ {
+ return false;
+ }
+
+ FileClose(io);
+
+ FileDeleteW(testname);
+
+ if (new_dir)
+ {
+ DeleteDirW(name);
+ }
+
+ return true;
+}
+
+// Set the installation directory
+UINT SwDir(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param)
+{
+ SW *sw = (SW *)param;
+ wchar_t tmp[MAX_SIZE];
+ wchar_t setuplog[MAX_SIZE];
+ wchar_t *s;
+ SW_LOGFILE *logfile;
+ bool is_system_mode;
+ bool skip_ver_check = false;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetIcon(hWnd, S_ICON, sw->CurrentComponent->Icon);
+
+ SwInitDefaultInstallDir(sw);
+
+ FormatText(hWnd, S_INFO, sw->CurrentComponent->Title);
+ FormatText(hWnd, R_FOR_USER, MsGetUserNameW());
+ FormatText(hWnd, S_WARNING, MsGetUserNameW(), sw->CurrentComponent->Title);
+
+ Check(hWnd, R_FOR_SYSTEM, sw->IsSystemMode);
+ Check(hWnd, R_FOR_USER, !sw->IsSystemMode);
+
+ if (sw->IsSystemMode == false)
+ {
+ Check(hWnd, R_SHOWCUSTOM, true);
+ }
+
+ SetText(hWnd, E_DIR, sw->IsSystemMode ? sw->DefaultInstallDir_System : sw->DefaultInstallDir_User);
+
+ Check(hWnd, R_DEFAULT, true);
+
+ SetEnable(hWnd, R_FOR_SYSTEM, sw->IsAvailableSystemMode);
+ SetEnable(hWnd, R_FOR_USER, sw->IsAvailableUserMode);
+
+ SwDirUpdate(hWnd, sw, wizard_page);
+
+ break;
+
+ case WM_WIZ_SHOW:
+ SetWizardButton(wizard_page, true, false, true, false);
+
+ SwDirUpdate(hWnd, sw, wizard_page);
+ break;
+
+ case WM_WIZ_HIDE:
+ break;
+
+ case WM_CLOSE:
+ break;
+
+ case WM_WIZ_NEXT:
+ if (IsChecked(hWnd, R_CUSTOM))
+ {
+ GetTxt(hWnd, E_DIR, tmp, sizeof(tmp));
+ }
+ else
+ {
+ if (IsChecked(hWnd, R_FOR_SYSTEM))
+ {
+ UniStrCpy(tmp, sizeof(tmp), sw->DefaultInstallDir_System);
+ }
+ else
+ {
+ UniStrCpy(tmp, sizeof(tmp), sw->DefaultInstallDir_User);
+ }
+ }
+
+ is_system_mode = IsChecked(hWnd, R_FOR_SYSTEM);
+
+ if (is_system_mode == false)
+ {
+ if (sw->CurrentComponent->InstallService)
+ {
+ if (MsIsServiceInstalled(sw->CurrentComponent->SvcName))
+ {
+ // If the type of installation is user mode and the same software
+ // is running in system mode already, warn about it
+ if (MsgBoxEx(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, _UU("SW_SYSTEM_MODE_ALREADY_INSTALLED"),
+ sw->CurrentComponent->Title) == IDNO)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ UniTrim(tmp);
+
+ Win32NukuEnW(tmp, sizeof(tmp), tmp);
+
+ // Check Length
+ if (UniStrLen(tmp) > 110)
+ {
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SW_DIR_MORE_THAN_110"));
+ FocusEx(hWnd, E_DIR);
+ break;
+ }
+
+ // Check whether it's a full path
+ if (UniStartWith(tmp, L"\\\\") == false &&
+ (tmp[1] != L':' || tmp[2] != L'\\'))
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SW_DIR_IS_NOT_FULLPATH"), tmp);
+ FocusEx(hWnd, E_DIR);
+ break;
+ }
+
+ NormalizePathW(tmp, sizeof(tmp), tmp);
+
+ // Check the type of the drive
+ if (IsChecked(hWnd, R_FOR_SYSTEM))
+ {
+ // System mode service is installed only on the hard disk
+ bool ok = true;
+
+ if (UniStartWith(tmp, L"\\\\"))
+ {
+ ok = false;
+ }
+ else
+ {
+ char tmpa[MAX_SIZE];
+ UINT ret;
+
+ UniToStr(tmpa, sizeof(tmpa), tmp);
+
+ tmpa[3] = 0;
+
+ ret = GetDriveTypeA(tmpa);
+
+ if (ret != DRIVE_FIXED && ret != DRIVE_RAMDISK)
+ {
+ ok = false;
+ }
+ }
+
+ if (ok == false)
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SW_DIR_IS_NOT_HDD"), tmp, sw->CurrentComponent->Title);
+ FocusEx(hWnd, E_DIR);
+ break;
+ }
+ }
+
+ // Write check
+ if (SwCheckNewDirName(tmp) == false)
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SW_DIR_WRITE_ERROR"), tmp);
+ FocusEx(hWnd, E_DIR);
+ break;
+ }
+
+ // Analyze if there is a setuplog.dat on destination
+ CombinePathW(setuplog, sizeof(setuplog), tmp, L"setuplog.dat");
+ logfile = SwLoadLogFile(sw, setuplog);
+ if (logfile == NULL && IsFileExistsW(setuplog))
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SW_DIR_DST_IS_BROKEN"), setuplog);
+ FocusEx(hWnd, E_DIR);
+ break;
+ }
+
+ if (logfile != NULL && (logfile->Build > CEDAR_BUILD) && UniIsEmptyStr(sw->auto_setting_path) == false &&
+ sw->CurrentComponent->Id == SW_CMP_VPN_CLIENT && logfile->Component->Id == SW_CMP_VPN_CLIENT)
+ {
+ // In the case of the VPN Client, show a message if a newer version is installed and
+ // the automatic connection setting by simple installer should be applied
+ if (MsgBox(hWnd, MB_ICONINFORMATION | MB_OKCANCEL, _UU("SW_DIR_DST_IS_NEWER_2")) == IDCANCEL)
+ {
+ // Cancel
+ FocusEx(hWnd, E_DIR);
+ break;
+ }
+
+ skip_ver_check = true;
+ }
+
+ if (logfile != NULL)
+ {
+ wchar_t *errmsg = NULL;
+ if (logfile->Component != sw->CurrentComponent)
+ {
+ errmsg = _UU("SW_DIR_DST_IS_OTHER_PRODUCT");
+ }
+ else if ((skip_ver_check == false) && (logfile->Build > CEDAR_BUILD))
+ {
+ errmsg = _UU("SW_DIR_DST_IS_NEWER");
+ }
+ else if (logfile->IsSystemMode && is_system_mode == false)
+ {
+ errmsg = _UU("SW_DIR_DST_IS_SYSTEM_MODE");
+ }
+ else if (logfile->IsSystemMode == false && is_system_mode)
+ {
+ errmsg = _UU("SW_DIR_DST_IS_USER_MODE");
+ }
+
+ SwFreeLogFile(logfile);
+
+ if (errmsg != NULL)
+ {
+ MsgBox(hWnd, MB_ICONEXCLAMATION, errmsg);
+ FocusEx(hWnd, E_DIR);
+ break;
+ }
+ }
+
+ // Check whether installation destination and installation source are not same
+ if (UniStrCmpi(tmp, sw->InstallSrc) == 0)
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SW_DIR_DST_IS_SAME_TO_SRC"), tmp);
+ FocusEx(hWnd, E_DIR);
+ break;
+ }
+
+ UniStrCpy(sw->InstallDir, sizeof(sw->InstallDir), tmp);
+ sw->IsSystemMode = IsChecked(hWnd, R_FOR_SYSTEM);
+
+ sw->OnlyAutoSettingMode = skip_ver_check;
+
+ return D_SW_READY;
+
+ case WM_WIZ_BACK:
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case R_DEFAULT:
+ case R_CUSTOM:
+ case R_SHOWCUSTOM:
+ case R_FOR_SYSTEM:
+ case R_FOR_USER:
+ SwDirUpdate(hWnd, sw, wizard_page);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case R_FOR_SYSTEM:
+ SetText(hWnd, E_DIR, sw->DefaultInstallDir_System);
+ break;
+
+ case R_FOR_USER:
+ SetText(hWnd, E_DIR, sw->DefaultInstallDir_User);
+ break;
+
+ case B_BROWSE:
+ GetTxt(hWnd, E_DIR, tmp, sizeof(tmp));
+ s = FolderDlgW(hWnd, _UU("SW_DIR_SELECT"), tmp);
+
+ if (s != NULL)
+ {
+ if (UniEndWith(s, sw->CurrentComponent->DefaultDirName))
+ {
+ UniStrCpy(tmp, sizeof(tmp), s);
+ }
+ else
+ {
+ CombinePathW(tmp, sizeof(tmp), s, sw->CurrentComponent->DefaultDirName);
+ }
+
+ SetText(hWnd, E_DIR, tmp);
+ FocusEx(hWnd, E_DIR);
+
+ Free(s);
+ }
+ break;
+ }
+
+ break;
+ }
+
+ return 0;
+}
+
+// Warning screen
+UINT SwWarning(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param)
+{
+ SW *sw = (SW *)param;
+ BUF *b;
+ UCHAR c = 0;
+ wchar_t *str;
+ char warning_filename[MAX_PATH];
+ LANGLIST t;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ break;
+
+ case WM_WIZ_SHOW:
+ DlgFont(hWnd, B_AGREE, 0, true);
+
+ GetCurrentLang(&t);
+
+ SetFont(hWnd, E_TEXT, GetFont((t.Id == SE_LANG_JAPANESE && MsIsWindows7()) ? "Meiryo UI" : NULL, 10, false , false, false, false));
+
+ Format(warning_filename, sizeof(warning_filename), "|warning_%s.txt", t.Name);
+ b = ReadDump(warning_filename);
+
+ SeekBuf(b, b->Size, 0);
+ c = 0;
+ WriteBuf(b, &c, 1);
+
+ str = CopyUtfToUni(b->Buf);
+
+ UniIsEmptyStr(str);
+
+ SetText(hWnd, E_TEXT, str);
+
+ FreeBuf(b);
+
+ Free(str);
+
+ UnselectEdit(hWnd, E_TEXT);
+
+ Focus(hWnd, E_TEXT);
+
+ SetWizardButton(wizard_page, true, true, true, false);
+ break;
+
+ case WM_WIZ_HIDE:
+ break;
+
+ case WM_CLOSE:
+ break;
+
+ case WM_WIZ_NEXT:
+ if (SwEnterSingle(sw) == false)
+ {
+ // Multiple-starts prevention
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("SW_OTHER_INSTANCE_EXISTS"));
+ break;
+ }
+ return D_SW_DIR;
+
+ case WM_WIZ_BACK:
+ return D_SW_EULA;
+
+ case WM_COMMAND:
+ break;
+ }
+
+ return 0;
+}
+
+// Update the license agreement screen
+void SwEulaUpdate(HWND hWnd, SW *sw, WIZARD *wizard, WIZARD_PAGE *wizard_page)
+{
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL || wizard == NULL || wizard_page == NULL)
+ {
+ return;
+ }
+
+ sw->EulaAgreed = IsChecked(hWnd, B_AGREE);
+
+ if (sw->EulaAgreed == false)
+ {
+ // Delete the agreement record in the case of non-agreement for the EULA
+ MsRegDeleteValueEx2(REG_CURRENT_USER, SW_REG_KEY_EULA, sw->CurrentComponent->Name, false, true);
+ }
+
+ SetWizardButton(wizard_page, sw->EulaAgreed, true, true, false);
+}
+
+// License Agreement
+UINT SwEula(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param)
+{
+ SW *sw = (SW *)param;
+ BUF *b;
+ UCHAR c = 0;
+ wchar_t *str;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ break;
+
+ case WM_WIZ_SHOW:
+ SetFont(hWnd, E_TEXT, GetFont((MsIsWindows7() ? "Segoe UI" : "Verdana"), 10, false, false, false, false));
+ //DlgFont(hWnd, B_AGREE, 10, true);
+
+ b = ReadDump("|eula.txt");
+
+ SeekBuf(b, b->Size, 0);
+ c = 0;
+ WriteBuf(b, &c, 1);
+
+ str = CopyUtfToUni(b->Buf);
+
+ UniIsEmptyStr(str);
+
+ SetText(hWnd, E_TEXT, str);
+
+ sw->CurrentEulaHash = HashToUINT(b->Buf, b->Size);
+
+ FreeBuf(b);
+
+ Free(str);
+
+ if (sw->CurrentComponent != NULL && sw->CurrentEulaHash != 0 && sw->CurrentEulaHash == MsRegReadIntEx2(REG_CURRENT_USER, SW_REG_KEY_EULA, sw->CurrentComponent->Name, false, true))
+ {
+ // Check the consent check box in advance if the user accepts the same EULA during the last installation
+ sw->EulaAgreed = true;
+ }
+
+ Check(hWnd, B_AGREE, sw->EulaAgreed);
+
+ UnselectEdit(hWnd, E_TEXT);
+
+ Focus(hWnd, E_TEXT);
+
+ SwEulaUpdate(hWnd, sw, wizard, wizard_page);
+ break;
+
+ case WM_WIZ_HIDE:
+ break;
+
+ case WM_CLOSE:
+ break;
+
+ case WM_WIZ_NEXT:
+ SwEulaUpdate(hWnd, sw, wizard, wizard_page);
+
+ if (sw->EulaAgreed)
+ {
+ return D_SW_WARNING;
+ }
+ break;
+
+ case WM_WIZ_BACK:
+ sw->EulaAgreed = false;
+ return D_SW_COMPONENTS;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_AGREE:
+ SwEulaUpdate(hWnd, sw, wizard, wizard_page);
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Initialize a component list
+void SwComponentsInit(HWND hWnd, SW *sw)
+{
+ LVB *b;
+ UINT i;
+ SW_COMPONENT *default_select = NULL;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return;
+ }
+
+ LvReset(hWnd, L_LIST);
+
+ b = LvInsertStart();
+
+ for (i = 0;i < LIST_NUM(sw->ComponentList);i++)
+ {
+ SW_COMPONENT *c = LIST_DATA(sw->ComponentList, i);
+
+ if (c->Detected)
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ UniFormat(tmp, sizeof(tmp), L" %s", c->Title);
+
+ LvInsertAdd(b, c->Icon, c, 1, tmp);
+
+ if (c->SystemModeOnly == false || MsIsAdmin())
+ {
+ if (default_select == NULL)
+ {
+ default_select = c;
+ }
+ }
+ }
+ }
+
+ LvInsertEnd(b, hWnd, L_LIST);
+
+ if (sw->CurrentComponent == NULL)
+ {
+ LvSelectByParam(hWnd, L_LIST, default_select);
+ }
+ else
+ {
+ LvSelectByParam(hWnd, L_LIST, sw->CurrentComponent);
+ }
+
+ Focus(hWnd, L_LIST);
+}
+
+// Update the Component Selection screen
+void SwComponentsUpdate(HWND hWnd, SW *sw, WIZARD *wizard, WIZARD_PAGE *wizard_page)
+{
+ SW_COMPONENT *c;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL || wizard == NULL || wizard_page == NULL)
+ {
+ return;
+ }
+
+ c = (SW_COMPONENT *)LvGetSelectedParam(hWnd, L_LIST);
+
+ if (c == NULL)
+ {
+ Hide(hWnd, S_TITLE);
+ Hide(hWnd, S_DESCRIPTION);
+ Hide(hWnd, S_ICON);
+
+ SetWizardButton(wizard_page, false, true, true, false);
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+
+ if (c->SystemModeOnly && MsIsAdmin() == false)
+ {
+ // Components to be installed only in system mode is set to unselectable
+ SetText(hWnd, S_TITLE, _UU("SW_COMPONENTS_REQUIRE_ADMIN"));
+ UniFormat(tmp, sizeof(tmp), _UU("SW_COMPONENTS_REQUIRE_ADMIN_TEXT"), c->Title);
+ SetText(hWnd, S_DESCRIPTION, tmp);
+ SetIcon(hWnd, S_ICON, ICO_WARNING);
+
+ SetWizardButton(wizard_page, false, true, true, false);
+ }
+ else
+ {
+ // Show the description of the component
+ UniFormat(tmp, sizeof(tmp), _UU("SW_COMPONENTS_ABOUT_TAG"), c->Title);
+ SetText(hWnd, S_TITLE, tmp);
+ SetText(hWnd, S_DESCRIPTION, c->Description);
+ SetIcon(hWnd, S_ICON, c->Icon);
+
+ SetWizardButton(wizard_page, true, true, true, false);
+ }
+
+ Show(hWnd, S_TITLE);
+ Show(hWnd, S_DESCRIPTION);
+ Show(hWnd, S_ICON);
+ }
+}
+
+// Component selection screen
+UINT SwComponents(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param)
+{
+ SW *sw = (SW *)param;
+ NMHDR *n;
+ SW_COMPONENT *c;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ LvInitEx2(hWnd, L_LIST, false, true);
+
+ if (MsIsVista())
+ {
+ SetFont(hWnd, L_LIST, GetMeiryoFontEx(12));
+ SetFont(hWnd, S_TITLE, GetMeiryoFontEx(11));
+ }
+ else
+ {
+ DlgFont(hWnd, L_LIST, 12, false);
+ DlgFont(hWnd, S_TITLE, 11, false);
+ }
+
+ LvInsertColumn(hWnd, L_LIST, 0, L"Component", 515);
+ break;
+
+ case WM_WIZ_SHOW:
+ SetWizardButton(wizard_page, true, true, true, false);
+
+ SwComponentsInit(hWnd, sw);
+
+ SwComponentsUpdate(hWnd, sw, wizard, wizard_page);
+
+ break;
+
+ case WM_WIZ_HIDE:
+ break;
+
+ case WM_CLOSE:
+ break;
+
+ case WM_WIZ_NEXT:
+ c = (SW_COMPONENT *)LvGetSelectedParam(hWnd, L_LIST);
+
+ if (c != NULL)
+ {
+ if (SwCheckOs(sw, c) == false)
+ {
+ // OS Check Failed
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SW_OS_FAILED"), c->Title);
+ break;
+ }
+
+ sw->CurrentComponent = c;
+
+ if (sw->CurrentComponent->SystemModeOnly == false || MsIsAdmin())
+ {
+ if (sw->CurrentComponent->Id == SW_CMP_VPN_SERVER && MsIsServiceInstalled(GC_SVC_NAME_VPNBRIDGE))
+ {
+ // The user is trying to install the VPN Server but, VPN Bridge already exists
+ if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, _UU("SW_NOTICE_VPNBRIDGE_IS_INSTALLED")) == IDNO)
+ {
+ break;
+ }
+ }
+ else if (sw->CurrentComponent->Id == SW_CMP_VPN_BRIDGE && MsIsServiceInstalled(GC_SVC_NAME_VPNSERVER))
+ {
+ // The user is trying to install the VPN Bridge, but a VPN Server already exists
+ if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, _UU("SW_NOTICE_VPNSERVER_IS_INSTALLED")) == IDNO)
+ {
+ break;
+ }
+ }
+
+ // Continue
+ return D_SW_EULA;
+ }
+ }
+ break;
+
+ case WM_WIZ_BACK:
+ if (MsIsAdmin())
+ {
+ return D_SW_WELCOME;
+ }
+ else
+ {
+ return D_SW_MODE;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ }
+ break;
+
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+
+ switch (n->idFrom)
+ {
+ case L_LIST:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ SwComponentsUpdate(hWnd, sw, wizard, wizard_page);
+ break;
+ }
+ break;
+ }
+
+ break;
+ }
+
+ return 0;
+}
+
+// Screen that is displayed when the user don't have administrative privileges
+UINT SwNotAdminDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param)
+{
+ SW *sw = (SW *)param;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ break;
+
+ case WM_WIZ_SHOW:
+ FormatText(hWnd, S_INFO, MsGetUserNameW());
+
+ SetShow(hWnd, S_INFO2, (sw->UninstallMode ? false : true));
+
+ SetWizardButton(wizard_page, true, ((sw->UninstallMode && sw->IsReExecForUac) ? false : true), true, true);
+ break;
+
+ case WM_WIZ_HIDE:
+ break;
+
+ case WM_CLOSE:
+ break;
+
+ case WM_WIZ_NEXT:
+ break;
+
+ case WM_WIZ_BACK:
+ if (sw->UninstallMode == false)
+ {
+ return D_SW_MODE;
+ }
+ else
+ {
+ return D_SW_UNINST1;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Choose the setup mode
+UINT SwModeDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param)
+{
+ SW *sw = (SW *)param;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ break;
+
+ case WM_WIZ_SHOW:
+ SetWizardButton(wizard_page, true, true, true, false);
+ FormatText(hWnd, S_USER, MsGetUserNameW());
+
+ // Choose the initial state
+ Check(hWnd, R_SYSTEM, sw->IsSystemMode);
+ Check(hWnd, R_USER, !sw->IsSystemMode);
+
+ Focus(hWnd, (sw->IsSystemMode ? R_SYSTEM : R_USER));
+
+ sw->DoubleClickBlocker = false;
+ SetUacIcon(hWnd, S_UAC);
+
+ break;
+
+ case WM_WIZ_HIDE:
+ break;
+
+ case WM_CLOSE:
+ break;
+
+ case WM_WIZ_NEXT:
+ // Mode
+ sw->IsSystemMode = IsChecked(hWnd, R_SYSTEM);
+
+ if (sw->DoubleClickBlocker)
+ {
+ break;
+ }
+
+ sw->DoubleClickBlocker = true;
+
+ if (sw->IsSystemMode)
+ {
+ if (MsIsVista() && MsIsAdmin() == false && sw->IsReExecForUac == false)
+ {
+ // If UAC is available and this isn't invoked via UAC,
+ // give the user a chance to get administrator privileges on UAC start again
+ if (SwReExecMyself(sw, NULL, true))
+ {
+ // Terminate itself if it succeeds to start the child process
+ CloseWizard(wizard_page);
+ }
+ else
+ {
+ // Jump to screen prompts to re-start as a administrator if it fails to start the child process
+ return D_SW_NOT_ADMIN;
+ }
+ }
+ else
+ {
+ if (MsIsAdmin())
+ {
+ // Jump to the component list screen if the user has administrator privileges
+ return D_SW_COMPONENTS;
+ }
+ else
+ {
+ // Jump to screen prompts to re-start as a administrator if the user doesn't have administrator privileges
+ return D_SW_NOT_ADMIN;
+ }
+ }
+ }
+ else
+ {
+ // Jump to the component list screen
+ return D_SW_COMPONENTS;
+ }
+
+ break;
+
+ case WM_WIZ_BACK:
+ return D_SW_WELCOME;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Welcome screen
+UINT SwWelcomeDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param)
+{
+ SW *sw = (SW *)param;
+ // Validate arguments
+ if (hWnd == NULL || sw == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ break;
+
+ case WM_WIZ_SHOW:
+ DlgFont(hWnd, S_WELCOME, 10, false);
+ DlgFont(hWnd, S_TITLE, 11, true);
+ SetWizardButtonEx(wizard_page, true, false, true, false, true);
+
+ sw->DoubleClickBlocker = false;
+
+ break;
+
+ case WM_WIZ_HIDE:
+ break;
+
+ case WM_CLOSE:
+ break;
+
+ case WM_WIZ_NEXT:
+ if (IsFileExistsW(L"@install_src.dat") == false)
+ {
+ // Vpnsetup.exe is launched from other than the installation source
+ MsgBoxEx(hWnd, MB_ICONSTOP, _UU("SW_NOT_INSTALL_SRC"));
+ break;
+ }
+
+ if (sw->DoubleClickBlocker)
+ {
+ break;
+ }
+
+ sw->DoubleClickBlocker = true;
+
+ if (MsIsAdmin() == false)
+ {
+ if (MsIsVista())
+ {
+ if (sw->IsReExecForUac == false)
+ {
+ // If there is no Admin privileges in Vista or later, attempt to acquire Admin rights by UAC first during the first run
+ if (SwReExecMyself(sw, NULL, true))
+ {
+ // Terminate itself if it succeeds to start the child process
+ CloseWizard(wizard_page);
+ break;
+ }
+ else
+ {
+ // Jump to mode selection screen if it fails to start the
+ // child process (including user presses the cancel of UAC)
+ return D_SW_MODE;
+ }
+ }
+ else
+ {
+ // Jump to mode selection screen when the user don't have Admin rights after being activated by UAC
+ return D_SW_MODE;
+ }
+ }
+ else
+ {
+ // Jump to the mode selection screen in the case of older than Vista
+ return D_SW_MODE;
+ }
+ }
+ else
+ {
+ // Skip to the component list screen if the user has Admin privileges
+ return D_SW_COMPONENTS;
+ }
+ break;
+
+ case WM_WIZ_BACK:
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Restart itself
+bool SwReExecMyself(SW *sw, wchar_t *additional_params, bool as_admin)
+{
+ wchar_t *current_params;
+ wchar_t new_param[MAX_SIZE];
+ void *handle;
+ bool ret = false;
+ // Validate arguments
+ if (sw == NULL)
+ {
+ return false;
+ }
+ if (sw->ReExecProcessHandle != NULL)
+ {
+ return false;
+ }
+
+ current_params = GetCommandLineUniStr();
+
+ if (IsEmptyUniStr(additional_params))
+ {
+ additional_params = L"";
+ }
+
+ UniFormat(new_param, sizeof(new_param), L"%s %s %s", current_params, (as_admin ? L"/UAC:true" : L""), additional_params);
+
+ UniTrim(new_param);
+
+ handle = NULL;
+ ret = MsExecuteEx2W(MsGetExeFileNameW(), new_param, &handle, as_admin);
+
+ Free(current_params);
+
+ if (ret == false)
+ {
+ return false;
+ }
+
+ sw->ReExecProcessHandle = handle;
+
+ return true;
+}
+
+// Show the UI
+void SwUiMain(SW *sw)
+{
+ WIZARD *w;
+ wchar_t verstr[MAX_SIZE];
+ char ver[MAX_SIZE];
+ // Validate arguments
+ if (sw == NULL)
+ {
+ return;
+ }
+
+ // Define the wizard UI
+ GetCedarVersion(ver, sizeof(ver));
+ UniFormat(verstr, sizeof(verstr), _UU("SW_TITLE"), ver);
+
+ // DO NOT REMOVE THIS INDICATION !!!
+ UniStrCat(verstr, sizeof(verstr), L" - Customized Version");
+
+ w = NewWizard(ICO_SETUP, BMP_SELOGO49x49, verstr, sw);
+
+ w->CloseConfirmMsg = _UU("SW_EXIT_CONFIRM");
+
+ AddWizardPage(w, NewWizardPage(D_SW_WELCOME, SwWelcomeDlg, _UU("SW_WELCOME_TITLE")));
+ AddWizardPage(w, NewWizardPage(D_SW_MODE, SwModeDlg, _UU("SW_MODE_TITLE")));
+ AddWizardPage(w, NewWizardPage(D_SW_NOT_ADMIN, SwNotAdminDlg, _UU("SW_NOT_ADMIN_TITLE")));
+ AddWizardPage(w, NewWizardPage(D_SW_COMPONENTS, SwComponents, _UU("SW_COMPONENTS_TITLE")));
+ AddWizardPage(w, NewWizardPage(D_SW_EULA, SwEula, _UU("SW_EULA_TITLE")));
+ AddWizardPage(w, NewWizardPage(D_SW_WARNING, SwWarning, _UU("SW_WARNING_TITLE")));
+ AddWizardPage(w, NewWizardPage(D_SW_DIR, SwDir, _UU("SW_DIR_TITLE")));
+ AddWizardPage(w, NewWizardPage(D_SW_READY, SwReady, _UU("SW_READY_TITLE")));
+ AddWizardPage(w, NewWizardPage(D_SW_PERFORM, SwPerform, _UU("SW_PERFORM_TITLE")));
+ AddWizardPage(w, NewWizardPage(D_SW_ERROR, SwError, _UU("SW_ERROR_TITLE")));
+ AddWizardPage(w, NewWizardPage(D_SW_FINISH, SwFinish, _UU("SW_FINISH_TITLE")));
+ AddWizardPage(w, NewWizardPage(D_SW_UNINST1, SwUninst1, _UU("SW_UNINST1_TITLE")));
+ AddWizardPage(w, NewWizardPage(D_SW_LANG1, SwLang1, _UU("SW_LANG1_TITLE")));
+ AddWizardPage(w, NewWizardPage(D_SW_EASY1, SwEasy1, _UU("SW_EASY1_TITLE")));
+ AddWizardPage(w, NewWizardPage(D_SW_EASY2, SwEasy2, _UU("SW_EASY2_TITLE")));
+ AddWizardPage(w, NewWizardPage(D_SW_WEB1, SwWeb1, _UU("SW_WEB1_TITLE")));
+ AddWizardPage(w, NewWizardPage(D_SW_WEB2, SwWeb2, _UU("SW_WEB2_TITLE")));
+
+ if (MsIsVista())
+ {
+ w->IsAreoStyle = true;
+ }
+
+ if (sw->UninstallMode)
+ {
+ // Uninstall mode
+ UINT start_page = D_SW_UNINST1;
+
+ if (sw->IsReExecForUac)
+ {
+ // In the case of this have been executed for UAC
+ if (MsIsAdmin())
+ {
+ // Uninstall
+ start_page = D_SW_PERFORM;
+ }
+ else
+ {
+ // Error screen
+ start_page = D_SW_NOT_ADMIN;
+ }
+ }
+
+ ShowWizard(NULL, w, start_page);
+ }
+ else if (sw->WebMode)
+ {
+ // Web installer creation mode
+ UINT start_page = D_SW_WEB1;
+
+ ShowWizard(NULL, w, start_page);
+ }
+ else if (sw->EasyMode)
+ {
+ // Simple installer creation mode
+ UINT start_page = D_SW_EASY1;
+
+ ShowWizard(NULL, w, start_page);
+ }
+ else if (sw->LanguageMode)
+ {
+ // Language setting mode
+ UINT start_page = D_SW_LANG1;
+
+ w->CloseConfirmMsg = NULL;
+
+ if (sw->IsReExecForUac)
+ {
+ // In the case of this have been executed for UAC
+ if (MsIsAdmin())
+ {
+ // Do the language setting
+ start_page = D_SW_PERFORM;
+ }
+ else
+ {
+ // Error screen
+ start_page = D_SW_NOT_ADMIN;
+ }
+ }
+ else
+ {
+ if (sw->LangNow)
+ {
+ // If not via UAC but Lang Now is set
+ start_page = D_SW_PERFORM;
+ }
+ }
+
+ if (sw->SetLangAndReboot && sw->LangNow == false)
+ {
+ // Restart myself immediately by changing the lang.config
+ LIST *o = LoadLangList();
+
+ if (o == NULL)
+ {
+ MsgBox(NULL, MB_ICONSTOP, _UU("SW_LANG_LIST_LOAD_FAILED"));
+ }
+ else
+ {
+ LANGLIST *new_lang = GetLangById(o, sw->LangId);
+ LANGLIST old_lang;
+
+ Zero(&old_lang, sizeof(old_lang));
+ GetCurrentLang(&old_lang);
+
+ if (new_lang == NULL)
+ {
+ MsgBox(NULL, MB_ICONSTOP, _UU("SW_LANG_LIST_LOAD_FAILED"));
+ }
+ else
+ {
+ if (SaveLangConfigCurrentDir(new_lang->Name) == false)
+ {
+ MsgBox(NULL, MB_ICONSTOP, _UU("SW_LANG_SET_FAILED"));
+ }
+ else
+ {
+ if (SwReExecMyself(sw, L"/LANGNOW:true ", false) == false)
+ {
+ SaveLangConfigCurrentDir(old_lang.Name);
+
+ MsgBox(NULL, MB_ICONSTOP, _UU("SW_CHILD_PROCESS_ERROR"));
+
+ sw->ExitCode = SW_EXIT_CODE_INTERNAL_ERROR;
+ }
+ }
+ }
+
+ FreeLangList(o);
+ }
+ }
+ else
+ {
+ // Show the wizard
+ ShowWizard(NULL, w, start_page);
+ }
+ }
+ else
+ {
+ // Installation mode
+ UINT start_page = D_SW_WELCOME;
+
+ if (sw->IsReExecForUac)
+ {
+ // In the case of this have been executed for UAC
+ if (MsIsAdmin())
+ {
+ // Jump to component list if the user have system administrator privileges
+ start_page = D_SW_COMPONENTS;
+ }
+ else
+ {
+ // Jump to the setup mode selection screen when fail
+ // to get admin privileges even executed by enabling UAC
+ start_page = D_SW_MODE;
+ }
+ }
+
+ ShowWizard(NULL, w, start_page);
+
+ if (sw->Run)
+ {
+ // Auto run the app
+ wchar_t tmp[MAX_PATH];
+ HANDLE h;
+ UNI_TOKEN_LIST *t;
+
+ t = UniParseToken(sw->CurrentComponent->StartExeName, L" ");
+
+ if (t != NULL)
+ {
+ wchar_t exe[MAX_PATH];
+ wchar_t arg[MAX_PATH];
+
+ Zero(exe, sizeof(exe));
+ Zero(arg, sizeof(arg));
+
+ if (t->NumTokens >= 1)
+ {
+ UniStrCpy(exe, sizeof(exe), t->Token[0]);
+ }
+ if (t->NumTokens >= 2)
+ {
+ UniStrCpy(arg, sizeof(arg), t->Token[1]);
+ }
+
+ if (UniIsEmptyStr(exe) == false)
+ {
+ CombinePathW(tmp, sizeof(tmp), sw->InstallDir, exe);
+
+ h = MsRunAsUserExW(tmp, arg, false);
+ if (h != NULL)
+ {
+ CloseHandle(h);
+ }
+ }
+
+ UniFreeToken(t);
+ }
+ }
+ }
+
+ FreeWizard(w);
+}
+
+// Release the component
+void SwFreeComponent(SW_COMPONENT *c)
+{
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ FreeStrList(c->NeedFiles);
+ Free(c->Name);
+ Free(c->SvcName);
+ Free(c->LongName);
+ Free(c->Title);
+ Free(c->Description);
+ Free(c->DefaultDirName);
+ Free(c->SvcFileName);
+ Free(c->StartExeName);
+ Free(c->StartDescription);
+
+ Free(c);
+}
+
+// Create a component
+SW_COMPONENT *SwNewComponent(char *name, char *svc_name, UINT id, UINT icon, UINT icon_index, wchar_t *svc_filename,
+ wchar_t *long_name, bool system_mode_only, UINT num_files, char *files[],
+ wchar_t *start_exe_name, wchar_t *start_description,
+ SW_OLD_MSI *old_msis, UINT num_old_msis)
+{
+ SW_COMPONENT *c;
+ UINT i;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (name == NULL || files == NULL || long_name == NULL)
+ {
+ return NULL;
+ }
+ if (svc_name == NULL)
+ {
+ svc_name = name;
+ }
+
+ c = ZeroMalloc(sizeof(SW_COMPONENT));
+
+ c->Id = id;
+
+ c->NeedFiles = NewListFast(NULL);
+
+ for (i = 0;i < num_files;i++)
+ {
+ Add(c->NeedFiles, CopyStr(files[i]));
+ }
+
+ c->SystemModeOnly = system_mode_only;
+ c->Name = CopyStr(name);
+ c->SvcName = CopyStr(svc_name);
+ c->DefaultDirName = CopyUniStr(long_name);
+ c->LongName = CopyUniStr(long_name);
+
+ Format(tmp, sizeof(tmp), "SW_COMPONENT_%s_TITLE", name);
+ c->Title = CopyUniStr(_UU(tmp));
+
+ Format(tmp, sizeof(tmp), "SW_COMPONENT_%s_DESCRIPTION", name);
+ c->Description = CopyUniStr(_UU(tmp));
+
+ c->Icon = icon;
+ c->IconExeIndex = icon_index;
+
+ if (UniIsEmptyStr(svc_filename) == false)
+ {
+ c->InstallService = true;
+ c->SvcFileName = UniCopyStr(svc_filename);
+ }
+
+ if (UniIsEmptyStr(start_exe_name) == false && UniIsEmptyStr(start_description) == false)
+ {
+ c->StartExeName = UniCopyStr(start_exe_name);
+ c->StartDescription = UniCopyStr(start_description);
+ }
+
+ c->OldMsiList = old_msis;
+ c->NumOldMsi = num_old_msis;
+
+ return c;
+}
+
+// Examine the OS requirements
+bool SwCheckOs(SW *sw, SW_COMPONENT *c)
+{
+ // Validate arguments
+ if (sw == NULL || c == NULL)
+ {
+ return false;
+ }
+
+ if (c->Id == SW_CMP_VPN_CLIENT)
+ {
+ OS_INFO *info = GetOsInfo();
+
+ if (OS_IS_WINDOWS_NT(info->OsType))
+ {
+ if (MsIsWin2000OrGreater() == false)
+ {
+ // It doesn't work with WinNT 4.0
+ return false;
+ }
+ }
+ else
+ {
+ if (GET_KETA(info->OsType, 100) <= 1)
+ {
+ // It doesn't work with Win95
+ return false;
+ }
+ else if (info->OsType == OSTYPE_WINDOWS_98)
+ {
+ if (EndWith(info->OsVersion, "A") == false)
+ {
+ // It doesn't work in Win98 First Edition
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+// Define the component
+void SwDefineComponents(SW *sw)
+{
+ SW_COMPONENT *c;
+ char *vpn_server_files[] =
+ {
+ "vpnserver.exe",
+ "vpnserver_x64.exe",
+ "vpnsmgr.exe",
+ "vpnsmgr_x64.exe",
+ "vpncmd.exe",
+ "vpncmd_x64.exe",
+ "hamcore.se2",
+ };
+ char *vpn_client_files[] =
+ {
+ "vpnclient.exe",
+ "vpnclient_x64.exe",
+ "vpncmgr.exe",
+ "vpncmgr_x64.exe",
+ "vpncmd.exe",
+ "vpncmd_x64.exe",
+ "hamcore.se2",
+ "vpninstall.exe",
+ "vpnweb.cab",
+ };
+ char *vpn_bridge_files[] =
+ {
+ "vpnbridge.exe",
+ "vpnbridge_x64.exe",
+ "vpnsmgr.exe",
+ "vpnsmgr_x64.exe",
+ "vpncmd.exe",
+ "vpncmd_x64.exe",
+ "hamcore.se2",
+ };
+ char *vpn_smgr_files[] =
+ {
+ "vpnsmgr.exe",
+ "vpnsmgr_x64.exe",
+ "vpncmd.exe",
+ "vpncmd_x64.exe",
+ "hamcore.se2",
+ };
+ char *vpn_cmgr_files[] =
+ {
+ "vpncmgr.exe",
+ "vpncmgr_x64.exe",
+ "vpncmd.exe",
+ "vpncmd_x64.exe",
+ "hamcore.se2",
+ };
+ // Validate arguments
+ if (sw == NULL)
+ {
+ return;
+ }
+
+ // VPN Server
+ c = SwNewComponent(SW_NAME_VPNSERVER, GC_SVC_NAME_VPNSERVER, SW_CMP_VPN_SERVER, ICO_VPNSERVER, 5, (MsIsX64() ? L"vpnserver_x64.exe" : L"vpnserver.exe"),
+ SW_LONG_VPNSERVER, false, sizeof(vpn_server_files) / sizeof(char *), vpn_server_files,
+ (MsIsX64() ? L"vpnsmgr_x64.exe" : L"vpnsmgr.exe"), _UU("SW_RUN_TEXT_VPNSMGR"),
+ old_msi_vpnserver, sizeof(old_msi_vpnserver) / sizeof(SW_OLD_MSI));
+ Add(sw->ComponentList, c);
+
+ // VPN Client
+ c = SwNewComponent(SW_NAME_VPNCLIENT, GC_SVC_NAME_VPNCLIENT, SW_CMP_VPN_CLIENT, ICO_VPN, 6, (MsIsX64() ? L"vpnclient_x64.exe" : L"vpnclient.exe"),
+ SW_LONG_VPNCLIENT, true, sizeof(vpn_client_files) / sizeof(char *), vpn_client_files,
+ (MsIsX64() ? L"vpncmgr_x64.exe" : L"vpncmgr.exe"), _UU("SW_RUN_TEXT_VPNCMGR"),
+ old_msi_vpnclient, sizeof(old_msi_vpnclient) / sizeof(SW_OLD_MSI));
+
+#ifdef GC_ENABLE_VPNGATE
+#endif // GC_ENABLE_VPNGATE
+
+ Add(sw->ComponentList, c);
+
+ // VPN Bridge
+ c = SwNewComponent(SW_NAME_VPNBRIDGE, GC_SVC_NAME_VPNBRIDGE, SW_CMP_VPN_BRIDGE, ICO_CASCADE, 7, (MsIsX64() ? L"vpnbridge_x64.exe" : L"vpnbridge.exe"),
+ SW_LONG_VPNBRIDGE, false, sizeof(vpn_bridge_files) / sizeof(char *), vpn_bridge_files,
+ (MsIsX64() ? L"vpnsmgr_x64.exe" : L"vpnsmgr.exe"), _UU("SW_RUN_TEXT_VPNSMGR"),
+ old_msi_vpnbridge, sizeof(old_msi_vpnbridge) / sizeof(SW_OLD_MSI));
+ Add(sw->ComponentList, c);
+
+ // VPN Server Manager (Tools Only)
+ c = SwNewComponent(SW_NAME_VPNSMGR, NULL, SW_CMP_VPN_SMGR, ICO_USER_ADMIN, 8, NULL,
+ SW_LONG_VPNSMGR, false, sizeof(vpn_smgr_files) / sizeof(char *), vpn_smgr_files,
+ (MsIsX64() ? L"vpnsmgr_x64.exe" : L"vpnsmgr.exe"), _UU("SW_RUN_TEXT_VPNSMGR"),
+ NULL, 0);
+ Add(sw->ComponentList, c);
+
+ // VPN Client Manager (Tools Only)
+ c = SwNewComponent(SW_NAME_VPNCMGR, NULL, SW_CMP_VPN_CMGR, ICO_INTERNET, 9, NULL,
+ SW_LONG_VPNCMGR, false, sizeof(vpn_cmgr_files) / sizeof(char *), vpn_cmgr_files,
+ (MsIsX64() ? L"vpncmgr_x64.exe /remote" : L"vpncmgr.exe /remote"), _UU("SW_RUN_TEXT_VPNCMGR"),
+ NULL, 0);
+ Add(sw->ComponentList, c);
+}
+
+// Detect the available components
+void SwDetectComponents(SW *sw)
+{
+ UINT i;
+ // Validate arguments
+ if (sw == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(sw->ComponentList);i++)
+ {
+ SW_COMPONENT *c = LIST_DATA(sw->ComponentList, i);
+
+ c->Detected = SwIsComponentDetected(sw, c);
+ }
+
+ // Determine whether the automatic connection configuration file exists in the same directory
+ if (true)
+ {
+ wchar_t tmp[MAX_PATH];
+
+ ConbinePathW(tmp, sizeof(tmp), MsGetExeDirNameW(), SW_AUTO_CONNECT_ACCOUNT_FILE_NAME_W);
+
+ if (IsFileExistsW(tmp))
+ {
+ // Exist
+ UniStrCpy(sw->auto_setting_path, sizeof(sw->auto_setting_path), tmp);
+ }
+ }
+}
+
+// Determine whether detection of the component is successful
+bool SwIsComponentDetected(SW *sw, SW_COMPONENT *c)
+{
+ UINT i;
+ bool ret = true;
+ // Validate arguments
+ if (sw == NULL || c == NULL)
+ {
+ return false;
+ }
+
+ for (i = 0;i < LIST_NUM(c->NeedFiles);i++)
+ {
+ char *name = LIST_DATA(c->NeedFiles, i);
+ wchar_t name_w[MAX_SIZE];
+ wchar_t fullpath[MAX_SIZE];
+
+ StrToUni(name_w, sizeof(name_w), name);
+
+ CombinePathW(fullpath, sizeof(fullpath), sw->InstallSrc, name_w);
+
+ if (IsFileExistsW(fullpath) == false)
+ {
+ ret = false;
+ break;
+ }
+ }
+
+ if (c->InstallService == false)
+ {
+ if (sw->IsEasyInstaller || sw->IsWebInstaller)
+ {
+ // Prevent installing only management tool
+ // for Web installer or a simple installer
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+// Add a new log
+void SwAddLog(SW *sw, SW_LOGFILE *logfile, UINT type, wchar_t *path)
+{
+ SW_LOG *g;
+ // Validate arguments
+ if (sw == NULL || path == NULL || logfile == NULL)
+ {
+ return;
+ }
+
+ g = ZeroMalloc(sizeof(SW_LOG));
+ g->Type = type;
+ UniStrCpy(g->Path, sizeof(g->Path), path);
+
+ Add(logfile->LogList, g);
+}
+void SwAddLogA(SW *sw, SW_LOGFILE *logfile, UINT type, char *path)
+{
+ wchar_t *w;
+ // Validate arguments
+ if (sw == NULL || path == NULL || logfile == NULL)
+ {
+ return;
+ }
+
+ w = CopyStrToUni(path);
+
+ SwAddLog(sw, logfile, type, w);
+
+ Free(w);
+}
+
+// Create a SW
+SW *NewSw()
+{
+ SW *sw = ZeroMalloc(sizeof(SW));
+
+ sw->IsSystemMode = true;
+
+ sw->ComponentList = NewListFast(NULL);
+
+ sw->ExitCode = SW_EXIT_CODE_USER_CANCEL;
+
+ UniStrCpy(sw->InstallSrc, sizeof(sw->InstallSrc), MsGetExeDirNameW());
+
+ SwDefineComponents(sw);
+
+ return sw;
+}
+
+// Release the SW
+UINT FreeSw(SW *sw)
+{
+ UINT i;
+ UINT ret;
+ // Validate arguments
+ if (sw == NULL)
+ {
+ return SW_EXIT_CODE_INTERNAL_ERROR;
+ }
+
+ SwLeaveSingle(sw);
+
+ for (i = 0;i < LIST_NUM(sw->ComponentList);i++)
+ {
+ SW_COMPONENT *c = LIST_DATA(sw->ComponentList, i);
+
+ SwFreeComponent(c);
+ }
+
+ ReleaseList(sw->ComponentList);
+
+ SwFreeLogFile(sw->LogFile);
+
+ if (sw->ReExecProcessHandle != NULL)
+ {
+ // If you have started the child process, wait for the termination of child process
+ sw->ExitCode = MsWaitProcessExit(sw->ReExecProcessHandle);
+ }
+
+ ret = sw->ExitCode;
+
+ Free(sw);
+
+ return ret;
+}
+
+// Exit the multi-starts prevention mode
+void SwLeaveSingle(SW *sw)
+{
+ // Validate arguments
+ if (sw == NULL)
+ {
+ return;
+ }
+
+ if (sw->Single != NULL)
+ {
+ FreeSingleInstance(sw->Single);
+ sw->Single = NULL;
+ }
+}
+
+// Enter multiple-starts prevention mode
+bool SwEnterSingle(SW *sw)
+{
+ // Validate arguments
+ if (sw == NULL)
+ {
+ return false;
+ }
+
+ if (sw->Single != NULL)
+ {
+ return true;
+ }
+
+ sw->Single = NewSingleInstance(SW_SINGLE_INSTANCE_NAME);
+
+ if (sw->Single == NULL)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Parse the command line
+void SwParseCommandLine(SW *sw)
+{
+ CONSOLE *c;
+ wchar_t *cmdline;
+ LIST *o;
+ PARAM args[] =
+ {
+ {"UAC", NULL, NULL, NULL, NULL, },
+ {"LANGUAGE", NULL, NULL, NULL, NULL, },
+ {"LANGID", NULL, NULL, NULL, NULL, },
+ {"LANGNOW", NULL, NULL, NULL, NULL, },
+ {"SETLANGANDREBOOT", NULL, NULL, NULL, NULL, },
+ {"EASY", NULL, NULL, NULL, NULL, },
+ {"WEB", NULL, NULL, NULL, NULL, },
+ {"SFXMODE", NULL, NULL, NULL, NULL, },
+ {"SFXOUT", NULL, NULL, NULL, NULL, },
+ {"HIDESTARTCOMMAND", NULL, NULL, NULL, NULL, },
+ {"CALLERSFXPATH", NULL, NULL, NULL, NULL, },
+ {"ISEASYINSTALLER", NULL, NULL, NULL, NULL, },
+ {"DISABLEAUTOIMPORT", NULL, NULL, NULL, NULL, },
+ {"ISWEBINSTALLER", NULL, NULL, NULL, NULL, },
+ };
+ // Validate arguments
+ if (sw == NULL)
+ {
+ return;
+ }
+
+ c = NewLocalConsole(NULL, NULL);
+ if (c == NULL)
+ {
+ return;
+ }
+
+ cmdline = GetCommandLineUniStr();
+
+ if (UniIsEmptyStr(cmdline) == false)
+ {
+ o = ParseCommandList(c, "setup", cmdline, args, sizeof(args) / sizeof(args[0]));
+
+ if (o != NULL)
+ {
+ sw->IsReExecForUac = GetParamYes(o, "UAC");
+ sw->LanguageMode = GetParamYes(o, "LANGUAGE");
+ sw->LangId = GetParamInt(o, "LANGID");
+ sw->LangNow = GetParamYes(o, "LANGNOW");
+ sw->SetLangAndReboot = GetParamYes(o, "SETLANGANDREBOOT");
+ sw->HideStartCommand = GetParamYes(o, "HIDESTARTCOMMAND");
+
+ // Special mode
+ if (sw->LanguageMode == false)
+ {
+ sw->EasyMode = GetParamYes(o, "EASY");
+
+ if (sw->EasyMode == false)
+ {
+ sw->WebMode = GetParamYes(o, "WEB");
+ }
+ }
+
+ StrCpy(sw->SfxMode, sizeof(sw->SfxMode), GetParamStr(o, "SFXMODE"));
+ UniStrCpy(sw->SfxOut, sizeof(sw->SfxOut), GetParamUniStr(o, "SFXOUT"));
+ UniStrCpy(sw->CallerSfxPath, sizeof(sw->CallerSfxPath), GetParamUniStr(o, "CALLERSFXPATH"));
+ sw->IsEasyInstaller = GetParamYes(o, "ISEASYINSTALLER");
+ sw->IsWebInstaller = GetParamYes(o, "ISWEBINSTALLER");
+ sw->DisableAutoImport = GetParamYes(o, "DISABLEAUTOIMPORT");
+
+ FreeParamValueList(o);
+ }
+ }
+
+ Free(cmdline);
+
+ c->Free(c);
+}
+
+// Start the Setup Wizard
+UINT SWExecMain()
+{
+ SW *sw;
+ UINT ret;
+ SW_LOGFILE *logfile = NULL;
+ wchar_t verstr[MAX_SIZE];
+ char ver[MAX_SIZE];
+
+ // Define the wizard UI
+ GetCedarVersion(ver, sizeof(ver));
+ UniFormat(verstr, sizeof(verstr), _UU("SW_TITLE"), ver);
+
+ InitWinUi(verstr, _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+
+ // Create a SW
+ sw = NewSw();
+
+ // Read the setting
+ sw->Easy_EraseSensitive = MsRegReadInt(REG_CURRENT_USER, SW_REG_KEY, "Easy_EraseSensitive");
+ sw->Easy_EasyMode = MsRegReadInt(REG_CURRENT_USER, SW_REG_KEY, "Easy_EasyMode");
+ sw->Web_EraseSensitive = MsRegReadInt(REG_CURRENT_USER, SW_REG_KEY, "Web_EraseSensitive");
+ sw->Web_EasyMode = MsRegReadInt(REG_CURRENT_USER, SW_REG_KEY, "Web_EasyMode");
+
+ // Parse the command line
+ SwParseCommandLine(sw);
+
+ // Test!
+ //sw->WebMode = true;
+
+ // Detect the installable components
+ SwDetectComponents(sw);
+
+ if (IsEmptyStr(sw->SfxMode) == false && UniIsEmptyStr(sw->SfxOut) == false)
+ {
+ // SFX generation mode
+ if (SwGenSfxModeMain(sw->SfxMode, sw->SfxOut))
+ {
+ // Success
+ sw->ExitCode = 0;
+ }
+ }
+ else
+ {
+ // Normal mode
+ // Load setuplog.dat
+ if (IsFileExistsW(L"@" L"setuplog.dat") && (logfile = SwLoadLogFile(sw, L"@" L"setuplog.dat")) == NULL)
+ {
+ // Setuplog.dat is broken
+ MsgBox(NULL, MB_ICONSTOP, _UU("SW_SETUPLOG_CORRUPTED"));
+ }
+ else
+ {
+ sw->LogFile = logfile;
+ if (sw->LogFile == NULL)
+ {
+ // Setuplog.dat does not exist
+ sw->LogFile = SwNewLogFile();
+ }
+ else
+ {
+ // When setuplog.dat exists, it is in either of language-setting-change-mode, simple-installer-creation-mode, uninstall-mode
+ sw->CurrentComponent = sw->LogFile->Component;
+ sw->IsSystemMode = sw->LogFile->IsSystemMode;
+ UniStrCpy(sw->InstallDir, sizeof(sw->InstallDir), MsGetExeDirNameW());
+
+ if (sw->LanguageMode == false && sw->EasyMode == false && sw->WebMode == false)
+ {
+ // Uninstall mode
+ sw->UninstallMode = true;
+ }
+ }
+
+ // UI main
+ SwUiMain(sw);
+ }
+ }
+
+ // Release the SW
+ ret = FreeSw(sw);
+
+ FreeWinUi();
+
+ return ret;
+}
+
+
+#endif // WIN32
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/SW.h b/src/Cedar/SW.h
new file mode 100644
index 00000000..45710f99
--- /dev/null
+++ b/src/Cedar/SW.h
@@ -0,0 +1,105 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// SW.h
+// Header of SW.c
+
+#ifndef SW_H
+#define SW_H
+
+#define SW_REG_KEY "Software\\" GC_REG_COMPANY_NAME "\\Setup Wizard Settings"
+
+
+UINT SWExec();
+UINT SWExecMain();
+LIST *SwNewSfxFileList();
+void SwFreeSfxFileList(LIST *o);
+bool SwAddBasicFilesToList(LIST *o, char *component_name);
+bool SwCompileSfx(LIST *o, wchar_t *dst_filename);
+bool SwGenSfxModeMain(char *mode, wchar_t *dst);
+bool SwWaitForVpnClientPortReady(UINT timeout);
+
+#endif // SW_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/SWInner.h b/src/Cedar/SWInner.h
new file mode 100644
index 00000000..a7f56c64
--- /dev/null
+++ b/src/Cedar/SWInner.h
@@ -0,0 +1,425 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// SWInner.h
+// Header of SW.c (for internal use)
+
+#ifndef SW_INNER_H
+#define SW_INNER_H
+
+// Component string
+#define SW_NAME_VPNSERVER "vpnserver"
+#define SW_LONG_VPNSERVER _UU("SW_LONG_VPNSERVER")
+
+#define SW_NAME_VPNCLIENT "vpnclient"
+#define SW_LONG_VPNCLIENT _UU("SW_LONG_VPNCLIENT")
+
+#define SW_NAME_VPNBRIDGE "vpnbridge"
+#define SW_LONG_VPNBRIDGE _UU("SW_LONG_VPNBRIDGE")
+
+#define SW_NAME_VPNSMGR "vpnsmgr"
+#define SW_LONG_VPNSMGR _UU("SW_LONG_VPNSMGR")
+
+#define SW_NAME_VPNCMGR "vpncmgr"
+#define SW_LONG_VPNCMGR _UU("SW_LONG_VPNCMGR")
+
+#define SW_VPN_CLIENT_UIHELPER_REGVALUE GC_SW_UIHELPER_REGVALUE
+
+#define SW_VPN_CLIENT_EXT_REGKEY "SOFTWARE\\Classes\\.vpn"
+#define SW_VPN_CLIENT_EXT_REGVALUE "vpnfile"
+#define SW_VPN_CLIENT_EXT_REGKEY_SUB1 "SOFTWARE\\Classes\\.vpn\\vpnfile"
+#define SW_VPN_CLIENT_EXT_REGKEY_SUB2 "SOFTWARE\\Classes\\.vpn\\vpnfile\\ShellNew"
+
+#define SW_VPN_CLIENT_VPNFILE_REGKEY "SOFTWARE\\Classes\\vpnfile"
+#define SW_VPN_CLIENT_VPNFILE_REGVALUE "VPN Client Connection Setting File"
+#define SW_VPN_CLIENT_VPNFILE_ICON_REGKEY "SOFTWARE\\Classes\\vpnfile\\DefaultIcon"
+#define SW_VPN_CLIENT_VPNFILE_SHELLOPEN_CMD_REGKEY "SOFTWARE\\Classes\\vpnfile\\shell\\open\\command"
+#define SW_VPN_CLIENT_VPNFILE_SHELLOPEN_CMD_REGKEY_SUB1 "SOFTWARE\\Classes\\vpnfile\\shell\\open"
+#define SW_VPN_CLIENT_VPNFILE_SHELLOPEN_CMD_REGKEY_SUB2 "SOFTWARE\\Classes\\vpnfile\\shell"
+
+#define SW_REG_KEY_EULA "Software\\" GC_REG_COMPANY_NAME "\\Setup Wizard Settings\\Eula"
+
+
+// Component ID
+#define SW_CMP_VPN_SERVER 1 // VPN Server
+#define SW_CMP_VPN_CLIENT 2 // VPN Client
+#define SW_CMP_VPN_BRIDGE 3 // VPN Bridge
+#define SW_CMP_VPN_SMGR 4 // VPN Server Manager (Tools Only)
+#define SW_CMP_VPN_CMGR 5 // VPN Client Manager (Tools Only)
+
+// Exit code
+#define SW_EXIT_CODE_USER_CANCEL 1000000001 // Cancel by the user
+#define SW_EXIT_CODE_INTERNAL_ERROR 1000000002 // Internal error
+
+// Special messages to be used in the setup wizard
+#define WM_SW_BASE (WM_APP + 251)
+#define WM_SW_INTERACT_UI (WM_SW_BASE + 0) // UI processing
+#define WM_SW_EXIT (WM_SW_BASE + 1) // Close
+
+// Automatic connection setting file
+#define SW_AUTO_CONNECT_ACCOUNT_FILE_NAME "auto_connect.vpn"
+#define SW_AUTO_CONNECT_ACCOUNT_FILE_NAME_W L"auto_connect.vpn"
+
+// Installer cache file to be stored in the VPN Client installation folder
+#define SW_SFX_CACHE_FILENAME L"installer.cache"
+
+// Flag file
+#define SW_FLAG_EASY_MODE "easy_mode.flag"
+#define SW_FLAG_EASY_MODE_2 "@easy_mode.flag"
+
+// Multiple-starts prevention name
+#define SW_SINGLE_INSTANCE_NAME "SoftEther_VPN_Setup_Wizard"
+
+// Time to wait for the VPN Client service startup
+#define SW_VPNCLIENT_SERVICE_WAIT_READY_TIMEOUT (30 * 1000)
+
+// UI interaction
+typedef struct SW_UI
+{
+ UINT Type; // Type
+ wchar_t *Message; // Message string
+ UINT Param; // Parameters
+ UINT RetCode; // Return value
+} SW_UI;
+
+// Type of UI interaction
+#define SW_UI_TYPE_PRINT 0 // Display the message
+#define SW_UI_TYPE_MSGBOX 1 // Show a message box
+#define SW_UI_TYPE_FINISH 2 // Completion
+#define SW_UI_TYPE_ERROR 3 // Error
+
+// Resource type of the file stored in the setup.exe
+#define SW_SFX_RESOURCE_TYPE "DATAFILE"
+
+// Code of old MSI
+typedef struct SW_OLD_MSI
+{
+ char *ProductCode; // Product code
+ char *ComponentCode; // Component code
+} SW_OLD_MSI;
+
+// Component
+typedef struct SW_COMPONENT
+{
+ UINT Id; // ID
+ bool Detected; // Whether it has been detected as an installation source
+ LIST *NeedFiles; // Necessary files
+ char *Name; // Internal name
+ char *SvcName; // Service name
+ wchar_t *Title; // Display name
+ wchar_t *Description; // Detail
+ wchar_t *DefaultDirName; // Installation directory name of the default
+ wchar_t *LongName; // Long name
+ UINT Icon; // Icon
+ UINT IconExeIndex; // The index number of the icon within the Setup.exe
+ bool SystemModeOnly; // Only system mode
+ bool InstallService; // Installation of service
+ wchar_t *SvcFileName; // Service file name
+ wchar_t *StartExeName; // Start EXE file name
+ wchar_t *StartDescription; // Description of the running software
+ SW_OLD_MSI *OldMsiList; // Old MSI Product List
+ UINT NumOldMsi; // The number of old MSI Product List
+ bool CopyVGDat; // Copy of the VPN Gate DAT file
+} SW_COMPONENT;
+
+// File copy task
+typedef struct SW_TASK_COPY
+{
+ wchar_t SrcFileName[MAX_SIZE]; // Original file name
+ wchar_t DstFileName[MAX_SIZE]; // Destination file name
+ wchar_t SrcDir[MAX_SIZE]; // Source directory
+ wchar_t DstDir[MAX_SIZE]; // Destination directory
+ bool Overwrite; // Override flag
+ bool SetupFile; // Setup file flag
+} SW_TASK_COPY;
+
+// Link creation task
+typedef struct SW_TASK_LINK
+{
+ wchar_t TargetDir[MAX_SIZE]; // Target directory
+ wchar_t TargetExe[MAX_SIZE]; // Target EXE file name
+ wchar_t TargetArg[MAX_SIZE]; // Arguments to pass to the target
+ wchar_t IconExe[MAX_SIZE]; // Icon EXE file name
+ UINT IconIndex; // Icon Index number
+ wchar_t DestDir[MAX_SIZE]; // Directory name to be created
+ wchar_t DestName[MAX_SIZE]; // File name to be created
+ wchar_t DestDescription[MAX_SIZE]; // Description string
+ bool NoDeleteDir; // Do not delete the directory on uninstall
+} SW_TASK_LINK;
+
+// Setup Tasks
+typedef struct SW_TASK
+{
+ LIST *CopyTasks; // File copy task
+ LIST *SetSecurityPaths; // List of paths to set the security
+ LIST *LinkTasks; // Link creation task
+} SW_TASK;
+
+// Setup log
+typedef struct SW_LOG
+{
+ UINT Type; // Type of log
+ wchar_t Path[MAX_PATH]; // Path
+} SW_LOG;
+
+// Type of setup log
+#define SW_LOG_TYPE_FILE 1 // File
+#define SW_LOG_TYPE_DIR 2 // Directory
+#define SW_LOG_TYPE_REGISTRY 3 // Registry
+#define SW_LOG_TYPE_LNK 4 // Shortcut file
+#define SW_LOG_TYPE_LNK_DIR 5 // Shortcut directory
+#define SW_LOG_TYPE_SVC 6 // Service
+
+// Setup log files
+typedef struct SW_LOGFILE
+{
+ LIST *LogList; // List of log
+ bool IsSystemMode; // Whether the system mode
+ UINT Build; // Build Number
+ SW_COMPONENT *Component; // Component
+} SW_LOGFILE;
+
+// SFX file
+typedef struct SW_SFX_FILE
+{
+ char InnerFileName[MAX_PATH]; // Internal file name
+ wchar_t DiskFileName[MAX_PATH]; // File name of the disk
+} SW_SFX_FILE;
+
+// SW instance
+typedef struct SW
+{
+ LIST *ComponentList; // List of components
+ wchar_t InstallSrc[MAX_SIZE]; // Source directory
+ bool IsSystemMode; // Whether the system mode
+ bool UninstallMode; // Uninstall mode
+ UINT ExitCode; // Exit code
+ void *ReExecProcessHandle; // Child process handle of a result of the re-run itself
+ bool IsReExecForUac; // Whether the process was re-run for UAC handling
+ SW_COMPONENT *CurrentComponent; // Component that is currently selected
+ bool EulaAgreed; // Whether the user accepted the license agreement
+ bool DoubleClickBlocker; // Double-click blocker
+ bool LanguageMode; // Language setting mode
+ UINT LangId; // Language ID in the language setting mode
+ bool SetLangAndReboot; // Prompt to restart after making the language setting
+ bool LangNow; // Start the language setting process right now
+ bool EasyMode; // Simple installer creation mode
+ bool WebMode; // Web installer creation mode
+ bool OnlyAutoSettingMode; // Apply only mode of connection settings of VPN Client
+
+ INSTANCE *Single; // Multiple-starts check
+ wchar_t DefaultInstallDir_System[MAX_PATH]; // Default system installation directory
+ wchar_t DefaultInstallDir_User[MAX_PATH]; // Default user installation directory
+ bool IsAvailableSystemMode; // Whether the system mode is selectable
+ bool IsAvailableUserMode; // Whether the user mode is selectable
+ bool ShowWarningForUserMode; // Whether to display a warning for the user-mode
+ wchar_t InstallDir[MAX_PATH]; // Destination directory
+ THREAD *PerformThread; // Set up processing thread
+ bool Run; // Whether to start the tool after Setup finishes
+ SW_LOGFILE *LogFile; // Log file
+ bool MsiRebootRequired; // Need to be re-started as a result of MSI
+ bool LangNotChanged; // Language has not changed
+ wchar_t FinishMsg[MAX_SIZE * 2]; // Completion message
+ wchar_t Easy_SettingFile[MAX_PATH]; // Connection settings file name of the Simple installer creation kit:
+ wchar_t Easy_OutFile[MAX_PATH]; // Destination file name of the simple installer creation kit
+ bool Easy_EraseSensitive; // Simple installer creation kit: Delete the confidential information
+ bool Easy_EasyMode; // Simple installer creation kit: simple mode
+ wchar_t Web_SettingFile[MAX_PATH]; // Connection setting file name for the Web installer creation Kit
+ wchar_t Web_OutFile[MAX_PATH]; // Destination file name of the Web installer creation Kit
+ bool Web_EraseSensitive; // Web installer creation Kit: removing confidential information
+ bool Web_EasyMode; // Web installer creation kit: simple mode
+ wchar_t vpncmgr_path[MAX_PATH]; // Path of vpncmgr.exe
+ wchar_t auto_setting_path[MAX_PATH]; // Path of automatic connection setting
+ bool HideStartCommand; // Not to show the option to start the program on installation complete screen
+ char SfxMode[MAX_SIZE]; // SFX generation mode
+ wchar_t SfxOut[MAX_PATH]; // SFX destination
+ wchar_t CallerSfxPath[MAX_PATH]; // Calling SFX path
+ bool IsEasyInstaller; // Whether the calling SFX was built by the simple installer creation kit
+ bool IsWebInstaller; // Whether Web installer
+ bool DisableAutoImport; // Not to use the automatic import process
+ UINT CurrentEulaHash; // Hash of the license agreement
+} SW;
+
+
+// Function prototype
+SW *NewSw();
+UINT FreeSw(SW *sw);
+
+void SwDefineComponents(SW *sw);
+SW_COMPONENT *SwNewComponent(char *name, char *svc_name, UINT id, UINT icon, UINT icon_index, wchar_t *svc_filename,
+ wchar_t *long_name, bool system_mode_only, UINT num_files, char *files[],
+ wchar_t *start_exe_name, wchar_t *start_description,
+ SW_OLD_MSI *old_msis, UINT num_old_msis);
+void SwFreeComponent(SW_COMPONENT *c);
+void SwDetectComponents(SW *sw);
+bool SwIsComponentDetected(SW *sw, SW_COMPONENT *c);
+void SwParseCommandLine(SW *sw);
+SW_COMPONENT *SwFindComponent(SW *sw, char *name);
+
+void SwInitDefaultInstallDir(SW *sw);
+void SwUiMain(SW *sw);
+bool SwCheckNewDirName(wchar_t *name);
+wchar_t *SwGetOldMsiInstalledDir(SW_COMPONENT *c);
+bool SwUninstallOldMsiInstalled(HWND hWnd, WIZARD_PAGE *wp, SW_COMPONENT *c, bool *reboot_required);
+
+bool SwReExecMyself(SW *sw, wchar_t *additional_params, bool as_admin);
+
+SW_TASK *SwNewTask();
+void SwFreeTask(SW_TASK *t);
+SW_TASK_COPY *SwNewCopyTask(wchar_t *srcfilename, wchar_t *dstfilename, wchar_t *srcdir, wchar_t *dstdir, bool overwrite, bool setup_file);
+void SwFreeCopyTask(SW_TASK_COPY *ct);
+void SwDefineTasks(SW *sw, SW_TASK *t, SW_COMPONENT *c);
+SW_TASK_LINK *SwNewLinkTask(wchar_t *target_dir, wchar_t *target_exe, wchar_t *target_arg,
+ wchar_t *icon_exe, UINT icon_index,
+ wchar_t *dest_dir, wchar_t *dest_name, wchar_t *dest_desc,
+ bool no_delete_dir);
+void SwFreeLinkTask(SW_TASK_LINK *lt);
+
+void SwAddLog(SW *sw, SW_LOGFILE *logfile, UINT type, wchar_t *path);
+void SwAddLogA(SW *sw, SW_LOGFILE *logfile, UINT type, char *path);
+bool SwSaveLogFile(SW *sw, wchar_t *dst_name, SW_LOGFILE *logfile);
+SW_LOGFILE *SwLoadLogFile(SW *sw, wchar_t *filename);
+SW_LOGFILE *SwNewLogFile();
+void SwFreeLogFile(SW_LOGFILE *logfile);
+
+void SwInstallShortcuts(SW *sw, WIZARD_PAGE *wp, SW_COMPONENT *c, SW_TASK *t);
+void SwDeleteShortcuts(SW_LOGFILE *logfile);
+
+bool SwCheckOs(SW *sw, SW_COMPONENT *c);
+
+bool SwEnterSingle(SW *sw);
+void SwLeaveSingle(SW *sw);
+
+UINT SwWelcomeDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param);
+UINT SwModeDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param);
+UINT SwNotAdminDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param);
+UINT SwComponents(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param);
+void SwComponentsInit(HWND hWnd, SW *sw);
+void SwComponentsUpdate(HWND hWnd, SW *sw, WIZARD *wizard, WIZARD_PAGE *wizard_page);
+UINT SwEula(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param);
+void SwEulaUpdate(HWND hWnd, SW *sw, WIZARD *wizard, WIZARD_PAGE *wizard_page);
+UINT SwDir(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param);
+void SwDirUpdate(HWND hWnd, SW *sw, WIZARD_PAGE *wizard_page);
+UINT SwReady(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param);
+UINT SwPerform(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param);
+void SwPerformInit(HWND hWnd, SW *sw, WIZARD_PAGE *wp);
+void SwPerformThread(THREAD *thread, void *param);
+void SwPerformPrint(WIZARD_PAGE *wp, wchar_t *str);
+UINT SwPerformMsgBox(WIZARD_PAGE *wp, UINT flags, wchar_t *msg);
+UINT SwInteractUi(WIZARD_PAGE *wp, SW_UI *ui);
+void SwInteractUiCalled(HWND hWnd, SW *sw, WIZARD_PAGE *wp, SW_UI *ui);
+bool SwInstallMain(SW *sw, WIZARD_PAGE *wp, SW_COMPONENT *c);
+UINT SwError(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param);
+UINT SwFinish(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param);
+UINT SwUninst1(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param);
+bool SwUninstallMain(SW *sw, WIZARD_PAGE *wp, SW_COMPONENT *c);
+UINT SwLang1(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param);
+void SwLang1Init(HWND hWnd, SW *sw);
+UINT SwGetLangIcon(char *name);
+void SwLang1Update(HWND hWnd, SW *sw, WIZARD *wizard, WIZARD_PAGE *wizard_page);
+UINT SwEasy1(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param);
+UINT SwEasy2(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param);
+void SwEasy2Update(HWND hWnd, SW *sw, WIZARD *wizard, WIZARD_PAGE *wizard_page);
+bool SwEasyMain(SW *sw, WIZARD_PAGE *wp);
+UINT SwWeb1(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param);
+UINT SwWeb2(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, WIZARD *wizard, WIZARD_PAGE *wizard_page, void *param);
+void SwWeb2Update(HWND hWnd, SW *sw, WIZARD *wizard, WIZARD_PAGE *wizard_page);
+bool SwWebMain(SW *sw, WIZARD_PAGE *wp);
+
+
+void SwGenerateDefaultSfxFileName(wchar_t *name, UINT size);
+void SwGenerateDefaultZipFileName(wchar_t *name, UINT size);
+
+bool CALLBACK SwEnumResourceNamesProc(HMODULE hModule, const char *type, char *name, LONG_PTR lParam);
+
+UINT SwSfxModeMain();
+bool CALLBACK SfxModeMainDialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+bool SwSfxExtractProcess(HWND hWnd, bool *hide_error_msg);
+bool SwSfxExtractFile(HWND hWnd, void *data, UINT size, wchar_t *dst, bool compressed);
+SW_SFX_FILE *SwNewSfxFile(char *inner_file_name, wchar_t *disk_file_name);
+bool SwSfxCopyVgFiles(HWND hWnd, wchar_t *src, wchar_t *dst);
+
+#endif // SW_INNER_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Sam.c b/src/Cedar/Sam.c
new file mode 100644
index 00000000..ac0a0ae2
--- /dev/null
+++ b/src/Cedar/Sam.c
@@ -0,0 +1,415 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Sam.c
+// Security Accounts Manager
+
+#include "CedarPch.h"
+
+// Password encryption
+void SecurePassword(void *secure_password, void *password, void *random)
+{
+ BUF *b;
+ // Validate arguments
+ if (secure_password == NULL || password == NULL || random == NULL)
+ {
+ return;
+ }
+
+ b = NewBuf();
+ WriteBuf(b, password, SHA1_SIZE);
+ WriteBuf(b, random, SHA1_SIZE);
+ Hash(secure_password, b->Buf, b->Size, true);
+
+ FreeBuf(b);
+}
+
+// Generate 160bit random number
+void GenRamdom(void *random)
+{
+ // Validate arguments
+ if (random == NULL)
+ {
+ return;
+ }
+
+ Rand(random, SHA1_SIZE);
+}
+
+// Anonymous authentication of user
+bool SamAuthUserByAnonymous(HUB *h, char *username)
+{
+ bool b = false;
+ // Validate arguments
+ if (h == NULL || username == NULL)
+ {
+ return false;
+ }
+
+ AcLock(h);
+ {
+ USER *u = AcGetUser(h, username);
+ if (u)
+ {
+ Lock(u->lock);
+ {
+ if (u->AuthType == AUTHTYPE_ANONYMOUS)
+ {
+ b = true;
+ }
+ }
+ Unlock(u->lock);
+ }
+ ReleaseUser(u);
+ }
+ AcUnlock(h);
+
+ return b;
+}
+
+// Plaintext password authentication of user
+bool SamAuthUserByPlainPassword(CONNECTION *c, HUB *hub, char *username, char *password, bool ast, UCHAR *mschap_v2_server_response_20)
+{
+ return false;
+}
+
+// Certificate authentication of user
+bool SamAuthUserByCert(HUB *h, char *username, X *x)
+{
+ return false;
+}
+
+// Get the root certificate that signed the specified certificate from the list
+X *GetIssuerFromList(LIST *cert_list, X *cert)
+{
+ UINT i;
+ X *ret = NULL;
+ // Validate arguments
+ if (cert_list == NULL || cert == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(cert_list);i++)
+ {
+ X *x = LIST_DATA(cert_list, i);
+ // Name comparison
+ if (CheckXDateNow(x))
+ {
+ if (CompareName(x->subject_name, cert->issuer_name))
+ {
+ // Get the public key of the root certificate
+ K *k = GetKFromX(x);
+
+ if (k != NULL)
+ {
+ // Check the signature
+ if (CheckSignature(cert, k))
+ {
+ ret = x;
+ }
+ FreeK(k);
+ }
+ }
+ }
+ if (CompareX(x, cert))
+ {
+ // Complete identical
+ ret = x;
+ }
+ }
+
+ return ret;
+}
+
+// Get the policy to be applied for the user
+POLICY *SamGetUserPolicy(HUB *h, char *username)
+{
+ POLICY *ret = NULL;
+ // Validate arguments
+ if (h == NULL || username == NULL)
+ {
+ return NULL;
+ }
+
+ AcLock(h);
+ {
+ USER *u;
+ u = AcGetUser(h, username);
+ if (u)
+ {
+ USERGROUP *g = NULL;
+ Lock(u->lock);
+ {
+ if (u->Policy != NULL)
+ {
+ ret = ClonePolicy(u->Policy);
+ }
+
+ g = u->Group;
+
+ if (g != NULL)
+ {
+ AddRef(g->ref);
+ }
+ }
+ Unlock(u->lock);
+
+ ReleaseUser(u);
+ u = NULL;
+
+ if (ret == NULL)
+ {
+ if (g != NULL)
+ {
+ Lock(g->lock);
+ {
+ ret = ClonePolicy(g->Policy);
+ }
+ Unlock(g->lock);
+ }
+ }
+
+ if (g != NULL)
+ {
+ ReleaseGroup(g);
+ }
+ }
+ }
+ AcUnlock(h);
+
+ return ret;
+}
+
+// Password authentication of user
+bool SamAuthUserByPassword(HUB *h, char *username, void *random, void *secure_password, char *mschap_v2_password, UCHAR *mschap_v2_server_response_20, UINT *err)
+{
+ bool b = false;
+ UCHAR secure_password_check[SHA1_SIZE];
+ bool is_mschap = false;
+ IPC_MSCHAP_V2_AUTHINFO mschap;
+ UINT dummy = 0;
+ // Validate arguments
+ if (h == NULL || username == NULL || secure_password == NULL)
+ {
+ return false;
+ }
+ if (err == NULL)
+ {
+ err = &dummy;
+ }
+
+ *err = 0;
+
+ Zero(&mschap, sizeof(mschap));
+
+ is_mschap = ParseAndExtractMsChapV2InfoFromPassword(&mschap, mschap_v2_password);
+
+ if (StrCmpi(username, ADMINISTRATOR_USERNAME) == 0)
+ {
+ // Administrator mode
+ SecurePassword(secure_password_check, h->SecurePassword, random);
+ if (Cmp(secure_password_check, secure_password, SHA1_SIZE) == 0)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ AcLock(h);
+ {
+ USER *u;
+ u = AcGetUser(h, username);
+ if (u)
+ {
+ Lock(u->lock);
+ {
+ if (u->AuthType == AUTHTYPE_PASSWORD)
+ {
+ AUTHPASSWORD *auth = (AUTHPASSWORD *)u->AuthData;
+
+ if (is_mschap == false)
+ {
+ // Normal password authentication
+ SecurePassword(secure_password_check, auth->HashedKey, random);
+ if (Cmp(secure_password_check, secure_password, SHA1_SIZE) == 0)
+ {
+ b = true;
+ }
+ }
+ else
+ {
+ // MS-CHAP v2 authentication via PPP
+ UCHAR challenge8[8];
+ UCHAR client_response[24];
+
+ if (IsZero(auth->NtLmSecureHash, MD5_SIZE))
+ {
+ // NTLM hash is not registered in the user account
+ *err = ERR_MSCHAP2_PASSWORD_NEED_RESET;
+ }
+ else
+ {
+ UCHAR nt_pw_hash_hash[16];
+ Zero(challenge8, sizeof(challenge8));
+ Zero(client_response, sizeof(client_response));
+
+ MsChapV2_GenerateChallenge8(challenge8, mschap.MsChapV2_ClientChallenge, mschap.MsChapV2_ServerChallenge,
+ mschap.MsChapV2_PPPUsername);
+
+ MsChapV2Client_GenerateResponse(client_response, challenge8, auth->NtLmSecureHash);
+
+ if (Cmp(client_response, mschap.MsChapV2_ClientResponse, 24) == 0)
+ {
+ // Hash matched
+ b = true;
+
+ // Calculate the response
+ GenerateNtPasswordHashHash(nt_pw_hash_hash, auth->NtLmSecureHash);
+ MsChapV2Server_GenerateResponse(mschap_v2_server_response_20, nt_pw_hash_hash,
+ client_response, challenge8);
+ }
+ }
+ }
+ }
+ }
+ Unlock(u->lock);
+ ReleaseUser(u);
+ }
+ }
+ AcUnlock(h);
+
+ return b;
+}
+
+// Make sure that the user exists
+bool SamIsUser(HUB *h, char *username)
+{
+ bool b;
+ // Validate arguments
+ if (h == NULL || username == NULL)
+ {
+ return false;
+ }
+
+ AcLock(h);
+ {
+ b = AcIsUser(h, username);
+ }
+ AcUnlock(h);
+
+ return b;
+}
+
+// Get the type of authentication used by the user
+UINT SamGetUserAuthType(HUB *h, char *username)
+{
+ UINT authtype;
+ // Validate arguments
+ if (h == NULL || username == NULL)
+ {
+ return INFINITE;
+ }
+
+ AcLock(h);
+ {
+ USER *u = AcGetUser(h, username);
+ if (u == NULL)
+ {
+ authtype = INFINITE;
+ }
+ else
+ {
+ authtype = u->AuthType;
+ ReleaseUser(u);
+ }
+ }
+ AcUnlock(h);
+
+ return authtype;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Sam.h b/src/Cedar/Sam.h
new file mode 100644
index 00000000..fca9ab84
--- /dev/null
+++ b/src/Cedar/Sam.h
@@ -0,0 +1,106 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Sam.h
+// Header of Sam.c
+
+#ifndef SAM_H
+#define SAM_H
+
+
+// Function prototype
+bool SamIsUser(HUB *h, char *username);
+UINT SamGetUserAuthType(HUB *h, char *username);
+bool SamAuthUserByPassword(HUB *h, char *username, void *random, void *secure_password, char *mschap_v2_password, UCHAR *mschap_v2_server_response_20, UINT *err);
+bool SamAuthUserByAnonymous(HUB *h, char *username);
+bool SamAuthUserByCert(HUB *h, char *username, X *x);
+bool SamAuthUserByPlainPassword(CONNECTION *c, HUB *hub, char *username, char *password, bool ast, UCHAR *mschap_v2_server_response_20);
+POLICY *SamGetUserPolicy(HUB *h, char *username);
+
+void GenRamdom(void *random);
+void SecurePassword(void *secure_password, void *password, void *random);
+X *GetIssuerFromList(LIST *cert_list, X *cert);
+
+#endif // SAM_H
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/SeLowUser.c b/src/Cedar/SeLowUser.c
new file mode 100644
index 00000000..14eb422a
--- /dev/null
+++ b/src/Cedar/SeLowUser.c
@@ -0,0 +1,772 @@
+// SoftEther VPN Source Code
+// SeLow: SoftEther Lightweight Network Protocol
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// SeLowUser.c
+// SoftEther Lightweight Network Protocol User-mode Library
+
+#include <GlobalConst.h>
+
+#ifdef WIN32
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+
+// Install the driver
+bool SuInstallDriver(bool force)
+{
+ bool ret;
+ void *wow;
+
+ wow = MsDisableWow64FileSystemRedirection();
+
+ ret = SuInstallDriverInner(force);
+
+ MsRestoreWow64FileSystemRedirection(wow);
+
+ return ret;
+}
+bool SuInstallDriverInner(bool force)
+{
+ wchar_t sys_fullpath[MAX_PATH];
+ UINT current_sl_ver = 0;
+ bool ret = false;
+ wchar_t src_cat[MAX_PATH];
+ wchar_t src_inf[MAX_PATH];
+ wchar_t src_sys[MAX_PATH];
+ wchar_t dst_cat[MAX_PATH];
+ wchar_t dst_inf[MAX_PATH];
+ wchar_t dst_sys[MAX_PATH];
+ wchar_t tmp_dir[MAX_PATH];
+ char *cpu_type = MsIsX64() ? "x64" : "x86";
+
+ if (SuIsSupportedOs() == false)
+ {
+ // Unsupported OS
+ return false;
+ }
+
+ CombinePathW(tmp_dir, sizeof(tmp_dir), MsGetWindowsDirW(), L"Temp");
+ MakeDirExW(tmp_dir);
+
+ UniStrCat(tmp_dir, sizeof(tmp_dir), L"\\selowtmp");
+ MakeDirExW(tmp_dir);
+
+ // Confirm whether the driver is currently installed
+ CombinePathW(sys_fullpath, sizeof(sys_fullpath), MsGetSystem32DirW(), L"drivers\\SeLow_%S.sys");
+ UniFormat(sys_fullpath, sizeof(sys_fullpath), sys_fullpath, cpu_type);
+
+ if (IsFileExistsW(sys_fullpath))
+ {
+ char *path;
+
+ // Read the current version from the registry
+ current_sl_ver = MsRegReadIntEx2(REG_LOCAL_MACHINE, SL_REG_KEY_NAME, SL_REG_VER_VALUE, false, true);
+
+ path = MsRegReadStrEx2(REG_LOCAL_MACHINE, SL_REG_KEY_NAME, "ImagePath", false, true);
+
+ if (IsEmptyStr(path))
+ {
+ current_sl_ver = 0;
+ }
+
+ Free(path);
+ }
+
+ if (force == false && current_sl_ver >= SL_VER)
+ {
+ // Newer version has already been installed
+ Debug("Newer SeLow is Installed. %u >= %u\n", current_sl_ver, SL_VER);
+ return true;
+ }
+
+ // Copy necessary files to a temporary directory
+ UniFormat(src_sys, sizeof(src_sys), L"|SeLow_%S.sys", cpu_type);
+ UniFormat(src_cat, sizeof(src_cat), L"|inf\\selow_%S\\inf.cat", cpu_type);
+ UniFormat(src_inf, sizeof(src_inf), L"|inf\\selow_%S\\SeLow_%S.inf", cpu_type, cpu_type);
+
+ UniFormat(dst_sys, sizeof(dst_cat), L"%s\\SeLow_%S.sys", tmp_dir, cpu_type);
+ UniFormat(dst_cat, sizeof(dst_cat), L"%s\\inf_selow.cat", tmp_dir);
+ UniFormat(dst_inf, sizeof(dst_inf), L"%s\\SeLow_%S.inf", tmp_dir, cpu_type);
+
+ if (FileCopyW(src_sys, dst_sys) &&
+ FileCopyW(src_cat, dst_cat) &&
+ FileCopyW(src_inf, dst_inf))
+ {
+ NO_WARNING *nw;
+
+ nw = MsInitNoWarningEx(SL_USER_AUTO_PUSH_TIMER);
+
+ // Call the installer
+ if (InstallNdisProtocolDriver(dst_inf, L"SeLow", SL_USER_INSTALL_LOCK_TIMEOUT) == false)
+ {
+ Debug("InstallNdisProtocolDriver Error.\n");
+ }
+ else
+ {
+ Debug("InstallNdisProtocolDriver Ok.\n");
+
+ // Copy manually because there are cases where .sys file is not copied successfully for some reason
+ FileCopyW(src_sys, sys_fullpath);
+
+ ret = true;
+
+ // Write the version number into the registry
+ MsRegWriteIntEx2(REG_LOCAL_MACHINE, SL_REG_KEY_NAME, SL_REG_VER_VALUE, SL_VER, false, true);
+
+ // Set to automatic startup
+ MsRegWriteIntEx2(REG_LOCAL_MACHINE, SL_REG_KEY_NAME, "Start", SERVICE_SYSTEM_START, false, true);
+ }
+
+ MsFreeNoWarning(nw);
+ }
+ else
+ {
+ Debug("Fail Copying Files.\n");
+ }
+
+ if (ret)
+ {
+ // If the service is installed this time, start and wait until the enumeration is completed
+ SuFree(SuInitEx(180 * 1000));
+ }
+
+ return ret;
+}
+
+// Get whether the current OS is supported by SeLow
+bool SuIsSupportedOs()
+{
+ // At present, this doesn't support any OS.
+ return false;
+ //return MsIsWindows7();
+}
+
+// Write the next packet to the driver
+bool SuPutPacket(SU_ADAPTER *a, void *buf, UINT size)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return false;
+ }
+ if (a->Halt)
+ {
+ return false;
+ }
+ if (size > MAX_PACKET_SIZE)
+ {
+ return false;
+ }
+
+ // First, examine whether the current buffer is full
+ if ((SL_NUM_PACKET(a->PutBuffer) >= SL_MAX_PACKET_EXCHANGE) ||
+ (buf == NULL && SL_NUM_PACKET(a->PutBuffer) != 0))
+ {
+ // Write all current packets to the driver
+ if (SuPutPacketsToDriver(a) == false)
+ {
+ return false;
+ }
+
+ SL_NUM_PACKET(a->PutBuffer) = 0;
+ }
+
+ // Add the next packet to the buffer
+ if (buf != NULL)
+ {
+ UINT i = SL_NUM_PACKET(a->PutBuffer);
+ SL_NUM_PACKET(a->PutBuffer)++;
+
+ SL_SIZE_OF_PACKET(a->PutBuffer, i) = size;
+ Copy(SL_ADDR_OF_PACKET(a->PutBuffer, i), buf, size);
+
+ Free(buf);
+ }
+
+ return true;
+}
+
+// Write all current packets to the driver
+bool SuPutPacketsToDriver(SU_ADAPTER *a)
+{
+ DWORD write_size;
+ // Validate arguments
+ if (a == NULL)
+ {
+ return false;
+ }
+ if (a->Halt)
+ {
+ return false;
+ }
+
+ if (WriteFile(a->hFile, a->PutBuffer, SL_EXCHANGE_BUFFER_SIZE, &write_size, NULL) == false)
+ {
+ a->Halt = true;
+
+ SuCloseAdapterHandleInner(a);
+ return false;
+ }
+
+ if (write_size != SL_EXCHANGE_BUFFER_SIZE)
+ {
+ a->Halt = true;
+ return false;
+ }
+
+ return true;
+}
+
+// Read the next packet from the driver
+bool SuGetNextPacket(SU_ADAPTER *a, void **buf, UINT *size)
+{
+ // Validate arguments
+ if (a == NULL || buf == NULL || size == NULL)
+ {
+ return false;
+ }
+
+ if (a->Halt)
+ {
+ return false;
+ }
+
+ while (true)
+ {
+ if (a->CurrentPacketCount < SL_NUM_PACKET(a->GetBuffer))
+ {
+ // There are still packets that have been already read
+ *size = SL_SIZE_OF_PACKET(a->GetBuffer, a->CurrentPacketCount);
+ *buf = Malloc(*size);
+ Copy(*buf, SL_ADDR_OF_PACKET(a->GetBuffer, a->CurrentPacketCount), *size);
+
+ // Increment the packet number
+ a->CurrentPacketCount++;
+
+ return true;
+ }
+ else
+ {
+ // Read the next packet from the driver
+ if (SuGetPacketsFromDriver(a) == false)
+ {
+ return false;
+ }
+
+ if (SL_NUM_PACKET(a->GetBuffer) == 0)
+ {
+ // Packet is not received yet
+ *buf = NULL;
+ *size = 0;
+ return true;
+ }
+
+ a->CurrentPacketCount = 0;
+ }
+ }
+}
+
+// Read the next packet from the driver
+bool SuGetPacketsFromDriver(SU_ADAPTER *a)
+{
+ DWORD read_size;
+ // Validate arguments
+ if (a == NULL)
+ {
+ return false;
+ }
+
+ if (a->Halt)
+ {
+ return false;
+ }
+
+ if (ReadFile(a->hFile, a->GetBuffer, SL_EXCHANGE_BUFFER_SIZE, &read_size, NULL) == false)
+ {
+ a->Halt = true;
+
+ SuCloseAdapterHandleInner(a);
+ return false;
+ }
+
+ if (read_size != SL_EXCHANGE_BUFFER_SIZE)
+ {
+ a->Halt = true;
+ return false;
+ }
+
+ return true;
+}
+
+// Close the adapter
+void SuCloseAdapter(SU_ADAPTER *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ if (a->hEvent != NULL)
+ {
+ CloseHandle(a->hEvent);
+ }
+
+ if (a->hFile != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(a->hFile);
+ a->hFile = INVALID_HANDLE_VALUE;
+ }
+
+ Free(a);
+}
+
+// Close the adapter handle
+void SuCloseAdapterHandleInner(SU_ADAPTER *a)
+{
+ return;//////////// ****************
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ if (a->hFile != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(a->hFile);
+ a->hFile = INVALID_HANDLE_VALUE;
+ }
+}
+
+// Open the adapter
+SU_ADAPTER *SuOpenAdapter(SU *u, char *adapter_id)
+{
+ char filename[MAX_PATH];
+ void *h;
+ SU_ADAPTER *a;
+ SL_IOCTL_EVENT_NAME t;
+ UINT read_size;
+ // Validate arguments
+ if (u == NULL || adapter_id == NULL)
+ {
+ return NULL;
+ }
+
+ Format(filename, sizeof(filename), SL_ADAPTER_DEVICE_FILENAME_WIN32, adapter_id);
+
+ h = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ Debug("Create File %s failed. %u\n", filename, GetLastError());
+ return NULL;
+ }
+ else
+ {
+ Debug("Create File %s ok.\n", filename);
+ }
+
+ a = ZeroMalloc(sizeof(SU_ADAPTER));
+
+ StrCpy(a->AdapterId, sizeof(a->AdapterId), adapter_id);
+ StrCpy(a->DeviceName, sizeof(a->DeviceName), filename);
+
+ a->hFile = h;
+
+ Zero(&t, sizeof(t));
+
+ // Get the event name
+ if (DeviceIoControl(h, SL_IOCTL_GET_EVENT_NAME, &t, sizeof(t), &t, sizeof(t), &read_size, NULL) == false)
+ {
+ // Acquisition failure
+ SuCloseAdapter(a);
+ return NULL;
+ }
+
+ Debug("Event Name: %s\n", t.EventNameWin32);
+
+ // Get the event
+ a->hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, t.EventNameWin32);
+
+ if (a->hEvent == NULL)
+ {
+ // Acquisition failure
+ SuCloseAdapter(a);
+ return NULL;
+ }
+
+ return a;
+}
+
+// Enumerate adapters
+TOKEN_LIST *SuEnumAdapters(SU *u)
+{
+ UINT i;
+ UINT ret_size;
+ TOKEN_LIST *ret;
+ // Validate arguments
+ if (u == NULL)
+ {
+ return NullToken();
+ }
+
+ Zero(&u->AdapterInfoList, sizeof(u->AdapterInfoList));
+ if (ReadFile(u->hFile, &u->AdapterInfoList, sizeof(u->AdapterInfoList),
+ &ret_size, NULL) == false ||
+ u->AdapterInfoList.Signature != SL_SIGNATURE)
+ {
+ Debug("SuEnumAdapters: ReadFile error.\n");
+ return NullToken();
+ }
+
+ ret = ZeroMalloc(sizeof(TOKEN_LIST));
+
+ ret->NumTokens = u->AdapterInfoList.NumAdapters;
+ ret->Token = ZeroMalloc(sizeof(char *) * ret->NumTokens);
+ Debug("SuEnumAdapters: u->AdapterInfoList.NumAdapters = %u\n", u->AdapterInfoList.NumAdapters);
+
+ for (i = 0;i < ret->NumTokens;i++)
+ {
+ ret->Token[i] = CopyUniToStr(u->AdapterInfoList.Adapters[i].AdapterId);
+
+ UniPrint(L"%s %u %S\n",
+ u->AdapterInfoList.Adapters[i].AdapterId,
+ u->AdapterInfoList.Adapters[i].MtuSize,
+ u->AdapterInfoList.Adapters[i].FriendlyName);
+ }
+
+ return ret;
+}
+
+// Create an adapters list
+LIST *SuGetAdapterList(SU *u)
+{
+ LIST *ret;
+ UINT read_size;
+ UINT i;
+ // Validate arguments
+ if (u == NULL)
+ {
+ return NULL;
+ }
+
+ ret = NewList(SuCmpAdaterList);
+
+ // Enumerate adapters
+ Zero(&u->AdapterInfoList, sizeof(u->AdapterInfoList));
+ if (ReadFile(u->hFile, &u->AdapterInfoList, sizeof(u->AdapterInfoList),
+ &read_size, NULL) == false ||
+ u->AdapterInfoList.Signature != SL_SIGNATURE)
+ {
+ SuFreeAdapterList(ret);
+ return NULL;
+ }
+
+ for (i = 0;i < u->AdapterInfoList.NumAdapters;i++)
+ {
+ SL_ADAPTER_INFO *info = &u->AdapterInfoList.Adapters[i];
+ SU_ADAPTER_LIST *a = SuAdapterInfoToAdapterList(info);
+
+ if (a != NULL)
+ {
+ Add(ret, a);
+ }
+ }
+
+ // Sort
+ Sort(ret);
+
+ return ret;
+}
+
+// Comparison function of the adapter list
+int SuCmpAdaterList(void *p1, void *p2)
+{
+ int r;
+ SU_ADAPTER_LIST *a1, *a2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ a1 = *(SU_ADAPTER_LIST **)p1;
+ a2 = *(SU_ADAPTER_LIST **)p2;
+ if (a1 == NULL || a2 == NULL)
+ {
+ return 0;
+ }
+
+ r = StrCmpi(a1->SortKey, a2->SortKey);
+ if (r != 0)
+ {
+ return 0;
+ }
+
+ return StrCmpi(a1->Guid, a2->Guid);
+}
+
+// Release the adapter list
+void SuFreeAdapterList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ SU_ADAPTER_LIST *a = LIST_DATA(o, i);
+
+ Free(a);
+ }
+
+ ReleaseList(o);
+}
+
+// Create an adapter list item
+SU_ADAPTER_LIST *SuAdapterInfoToAdapterList(SL_ADAPTER_INFO *info)
+{
+ SU_ADAPTER_LIST t;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (info == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&t, sizeof(t));
+ Copy(&t.Info, info, sizeof(SL_ADAPTER_INFO));
+
+ UniToStr(tmp, sizeof(tmp), info->AdapterId);
+ if (IsEmptyStr(tmp) || IsEmptyStr(info->FriendlyName) || StartWith(tmp, SL_ADAPTER_ID_PREFIX) == false)
+ {
+ // Name is invalid
+ return NULL;
+ }
+
+ // GUID (Part after "SELOW_A_" prefix)
+ StrCpy(t.Guid, sizeof(t.Guid), tmp + StrLen(SL_ADAPTER_ID_PREFIX));
+
+ // Name
+ StrCpy(t.Name, sizeof(t.Name), tmp);
+
+ // Key for sort
+ if (GetClassRegKeyWin32(t.SortKey, sizeof(t.SortKey), tmp, sizeof(tmp), t.Guid) == false)
+ {
+ // Can not be found
+ return NULL;
+ }
+
+ return Clone(&t, sizeof(t));
+}
+
+// Initialize the driver
+SU *SuInit()
+{
+ return SuInitEx(0);
+}
+SU *SuInitEx(UINT wait_for_bind_complete_tick)
+{
+ void *h;
+ SU *u;
+ UINT read_size;
+ bool flag = false;
+ UINT64 giveup_tick = 0;
+
+ if (SuIsSupportedOs() == false)
+ {
+ // Unsupported OS
+ return NULL;
+ }
+
+LABEL_RETRY:
+
+ // Open the device driver
+ h = CreateFileA(SL_BASIC_DEVICE_FILENAME_WIN32, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ Debug("CreateFileA(%s) Failed.\n", SL_BASIC_DEVICE_FILENAME_WIN32);
+
+ // Start the service if it fails to start the device driver
+ if (flag == false)
+ {
+ if (MsStartService(SL_PROTOCOL_NAME) == false)
+ {
+ Debug("MsStartService(%s) Failed.\n", SL_PROTOCOL_NAME);
+ }
+ else
+ {
+ Debug("MsStartService(%s) Ok.\n", SL_PROTOCOL_NAME);
+ flag = true;
+
+ goto LABEL_RETRY;
+ }
+ }
+ return NULL;
+ }
+
+ //Debug("CreateFileA(%s) Ok.\n", SL_BASIC_DEVICE_FILENAME_WIN32);
+
+ u = ZeroMalloc(sizeof(SU));
+
+ giveup_tick = Tick64() + (UINT64)wait_for_bind_complete_tick;
+
+ if (wait_for_bind_complete_tick == 0)
+ {
+ if (ReadFile(h, &u->AdapterInfoList, sizeof(u->AdapterInfoList), &read_size, NULL) == false ||
+ u->AdapterInfoList.Signature != SL_SIGNATURE)
+ {
+ // Signature reception failure
+ Debug("Bad Signature.\n");
+
+ Free(u);
+ CloseHandle(h);
+
+ return NULL;
+ }
+ }
+ else
+ {
+ while (giveup_tick >= Tick64())
+ {
+ // Wait until the enumeration is completed
+ if (ReadFile(h, &u->AdapterInfoList, sizeof(u->AdapterInfoList), &read_size, NULL) == false ||
+ u->AdapterInfoList.Signature != SL_SIGNATURE)
+ {
+ // Signature reception failure
+ Debug("Bad Signature.\n");
+
+ Free(u);
+ CloseHandle(h);
+
+ return NULL;
+ }
+
+ if (u->AdapterInfoList.EnumCompleted)
+ {
+ // Complete enumeration
+ Debug("Bind Completed! %u\n", u->AdapterInfoList.EnumCompleted);
+ break;
+ }
+
+ // Incomplete enumeration
+ Debug("Waiting for Bind Complete.\n");
+
+ SleepThread(25);
+ }
+ }
+
+ u->hFile = h;
+
+ return u;
+}
+
+// Release the driver
+void SuFree(SU *u)
+{
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+
+ CloseHandle(u->hFile);
+
+ Free(u);
+}
+
+#endif // WIN32
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/SeLowUser.h b/src/Cedar/SeLowUser.h
new file mode 100644
index 00000000..c71e947e
--- /dev/null
+++ b/src/Cedar/SeLowUser.h
@@ -0,0 +1,154 @@
+// SoftEther VPN Source Code
+// SeLow: SoftEther Lightweight Network Protocol
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// SeLowUser.h
+// Header for SeLowUser.c
+
+#ifndef SELOWUSER_H
+#define SELOWUSER_H
+
+#include <SeLow/SeLowCommon.h>
+
+//// Macro
+#define SL_USER_INSTALL_LOCK_TIMEOUT 60000 // Lock acquisition timeout
+#define SL_USER_AUTO_PUSH_TIMER 60000 // Timer to start the installation automatically
+
+//// Type
+
+// SU
+struct SU
+{
+ void *hFile; // File handle
+ SL_ADAPTER_INFO_LIST AdapterInfoList; // Adapter list cache
+};
+
+// Adapter
+struct SU_ADAPTER
+{
+ char AdapterId[MAX_PATH]; // Adapter ID
+ char DeviceName[MAX_PATH]; // Device name
+ void *hFile; // File handle
+ void *hEvent; // Event handle
+ bool Halt;
+ UINT CurrentPacketCount;
+ UCHAR GetBuffer[SL_EXCHANGE_BUFFER_SIZE]; // Read buffer
+ UCHAR PutBuffer[SL_EXCHANGE_BUFFER_SIZE]; // Write buffer
+};
+
+// Adapter list items
+struct SU_ADAPTER_LIST
+{
+ SL_ADAPTER_INFO Info; // Adapter information
+ char Guid[128]; // GUID
+ char Name[MAX_SIZE]; // Name
+ char SortKey[MAX_SIZE]; // Sort key
+};
+
+
+//// Function prototype
+SU *SuInit();
+SU *SuInitEx(UINT wait_for_bind_complete_tick);
+void SuFree(SU *u);
+TOKEN_LIST *SuEnumAdapters(SU *u);
+SU_ADAPTER *SuOpenAdapter(SU *u, char *adapter_id);
+void SuCloseAdapter(SU_ADAPTER *a);
+void SuCloseAdapterHandleInner(SU_ADAPTER *a);
+bool SuGetPacketsFromDriver(SU_ADAPTER *a);
+bool SuGetNextPacket(SU_ADAPTER *a, void **buf, UINT *size);
+bool SuPutPacketsToDriver(SU_ADAPTER *a);
+bool SuPutPacket(SU_ADAPTER *a, void *buf, UINT size);
+
+SU_ADAPTER_LIST *SuAdapterInfoToAdapterList(SL_ADAPTER_INFO *info);
+LIST *SuGetAdapterList(SU *u);
+void SuFreeAdapterList(LIST *o);
+int SuCmpAdaterList(void *p1, void *p2);
+
+bool SuInstallDriver(bool force);
+bool SuInstallDriverInner(bool force);
+bool SuIsSupportedOs();
+
+#endif // SELOWUSER_H
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/SecureInfo.c b/src/Cedar/SecureInfo.c
new file mode 100644
index 00000000..97e66758
--- /dev/null
+++ b/src/Cedar/SecureInfo.c
@@ -0,0 +1,90 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// SecureInfo.c
+// Code related to a secure VPN tunnel data for system administrators
+
+#include "CedarPch.h"
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/SecureInfo.h b/src/Cedar/SecureInfo.h
new file mode 100644
index 00000000..dedb2006
--- /dev/null
+++ b/src/Cedar/SecureInfo.h
@@ -0,0 +1,94 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// SecureInfo.h
+// Header of SecureInfo.c
+
+#ifndef SECUREINFO_H
+#define SECUREINFO_H
+
+
+#endif // SECUREINFO_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/SecureNAT.c b/src/Cedar/SecureNAT.c
new file mode 100644
index 00000000..bf2f81bc
--- /dev/null
+++ b/src/Cedar/SecureNAT.c
@@ -0,0 +1,228 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// SecureNAT.c
+// SecureNAT code
+
+#include "CedarPch.h"
+
+// SecureNAT server-side thread
+void SnSecureNATThread(THREAD *t, void *param)
+{
+ SNAT *s;
+ CONNECTION *c;
+ SESSION *se;
+ POLICY *policy;
+ HUB *h;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ s = (SNAT *)param;
+ // Create a server connection
+ c = NewServerConnection(s->Cedar, NULL, t);
+ c->Protocol = CONNECTION_HUB_SECURE_NAT;
+
+ // Apply the default policy
+ policy = ClonePolicy(GetDefaultPolicy());
+
+ // Not to limit the number of broadcast
+ policy->NoBroadcastLimiter = true;
+
+ h = s->Hub;
+ AddRef(h->ref);
+
+ // create a server session
+ se = NewServerSession(s->Cedar, c, s->Hub, SNAT_USER_NAME, policy);
+ se->SecureNATMode = true;
+ se->SecureNAT = s;
+ c->Session = se;
+ ReleaseConnection(c);
+
+ HLog(se->Hub, "LH_NAT_START", se->Name);
+
+ // User name
+ se->Username = CopyStr(SNAT_USER_NAME_PRINT);
+
+ s->Session = se;
+ AddRef(se->ref);
+
+ // Notification initialization completion
+ NoticeThreadInit(t);
+
+ ReleaseCancel(s->Nat->Virtual->Cancel);
+ s->Nat->Virtual->Cancel = se->Cancel1;
+ AddRef(se->Cancel1->ref);
+
+ if (s->Nat->Virtual->NativeNat != NULL)
+ {
+ CANCEL *old_cancel = NULL;
+
+ Lock(s->Nat->Virtual->NativeNat->CancelLock);
+ {
+ if (s->Nat->Virtual->NativeNat->Cancel != NULL)
+ {
+ old_cancel = s->Nat->Virtual->NativeNat->Cancel;
+
+ s->Nat->Virtual->NativeNat->Cancel = se->Cancel1;
+
+ AddRef(se->Cancel1->ref);
+ }
+ }
+ Unlock(s->Nat->Virtual->NativeNat->CancelLock);
+
+ if (old_cancel != NULL)
+ {
+ ReleaseCancel(old_cancel);
+ }
+ }
+
+ // Main function of the session
+ Debug("SecureNAT Start.\n");
+ SessionMain(se);
+ Debug("SecureNAT Stop.\n");
+
+ HLog(se->Hub, "LH_NAT_STOP");
+
+ ReleaseHub(h);
+
+ ReleaseSession(se);
+}
+
+// Release the SecureNAT
+void SnFreeSecureNAT(SNAT *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ // Stop the session
+ StopSession(s->Session);
+ ReleaseSession(s->Session);
+
+ // Virtual machine release
+ Virtual_Free(s->Nat->Virtual);
+
+ // NAT release
+ NiFreeNat(s->Nat);
+
+ DeleteLock(s->lock);
+
+ Free(s);
+}
+
+// Create a new SecureNAT
+SNAT *SnNewSecureNAT(HUB *h, VH_OPTION *o)
+{
+ SNAT *s;
+ THREAD *t;
+ // Validate arguments
+ if (h == NULL || o == NULL)
+ {
+ return NULL;
+ }
+
+ s = ZeroMalloc(sizeof(SNAT));
+ s->Cedar = h->Cedar;
+ s->Hub = h;
+ s->lock = NewLock();
+
+ // Create a NAT
+ s->Nat = NiNewNatEx(s, o);
+
+ // Initialize the virtual machine
+ VirtualInit(s->Nat->Virtual);
+
+ // Create a thread
+ t = NewThread(SnSecureNATThread, s);
+ WaitThreadInit(t);
+ ReleaseThread(t);
+
+ return s;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/SecureNAT.h b/src/Cedar/SecureNAT.h
new file mode 100644
index 00000000..ba387a88
--- /dev/null
+++ b/src/Cedar/SecureNAT.h
@@ -0,0 +1,108 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// SecureNAT.h
+// Header of SecureNAT.c
+
+#ifndef SECURENAT_H
+#define SECURENAT_H
+
+struct SNAT
+{
+ LOCK *lock; // Lock
+ CEDAR *Cedar; // Cedar
+ HUB *Hub; // HUB
+ SESSION *Session; // Session
+ POLICY *Policy; // Policy
+ NAT *Nat; // NAT
+};
+
+
+SNAT *SnNewSecureNAT(HUB *h, VH_OPTION *o);
+void SnFreeSecureNAT(SNAT *s);
+void SnSecureNATThread(THREAD *t, void *param);
+
+
+#endif // SECURENAT_H
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Server.c b/src/Cedar/Server.c
new file mode 100644
index 00000000..aa5ba62d
--- /dev/null
+++ b/src/Cedar/Server.c
@@ -0,0 +1,10466 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Server.c
+// VPN Server module
+
+#include "CedarPch.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 *BRIDGE_CONFIG_FILE_NAME = "@vpn_bridge.config";
+
+static bool server_reset_setting = false;
+
+// Set the OpenVPN and SSTP setting
+void SiSetOpenVPNAndSSTPConfig(SERVER *s, OPENVPN_SSTP_CONFIG *c)
+{
+ // Validate arguments
+ if (s == NULL || c == NULL)
+ {
+ return;
+ }
+
+ Lock(s->OpenVpnSstpConfigLock);
+ {
+ // Save the settings
+ if (s->Cedar->Bridge || s->ServerType != SERVER_TYPE_STANDALONE)
+ {
+ s->DisableSSTPServer = true;
+ s->DisableOpenVPNServer = true;
+ }
+ else
+ {
+ s->DisableSSTPServer = !c->EnableSSTP;
+ s->DisableOpenVPNServer = !c->EnableOpenVPN;
+ }
+
+ NormalizeIntListStr(s->OpenVpnServerUdpPorts, sizeof(s->OpenVpnServerUdpPorts),
+ c->OpenVPNPortList, true, ", ");
+
+ // Apply the OpenVPN configuration
+ if (s->OpenVpnServerUdp != NULL)
+ {
+ if (s->DisableOpenVPNServer)
+ {
+ OvsApplyUdpPortList(s->OpenVpnServerUdp, "");
+ }
+ else
+ {
+ OvsApplyUdpPortList(s->OpenVpnServerUdp, s->OpenVpnServerUdpPorts);
+ }
+ }
+ }
+ Unlock(s->OpenVpnSstpConfigLock);
+}
+
+// Get the OpenVPN and SSTP setting
+void SiGetOpenVPNAndSSTPConfig(SERVER *s, OPENVPN_SSTP_CONFIG *c)
+{
+ // Validate arguments
+ if (s == NULL || c == NULL)
+ {
+ return;
+ }
+
+ Zero(c, sizeof(OPENVPN_SSTP_CONFIG));
+
+ Lock(s->OpenVpnSstpConfigLock);
+ {
+ if (s->DisableOpenVPNServer == false)
+ {
+ c->EnableOpenVPN = true;
+ }
+
+ if (s->DisableSSTPServer == false)
+ {
+ c->EnableSSTP = true;
+ }
+
+ StrCpy(c->OpenVPNPortList, sizeof(c->OpenVPNPortList), s->OpenVpnServerUdpPorts);
+ }
+ Unlock(s->OpenVpnSstpConfigLock);
+}
+
+// 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;
+}
+
+// Get the number of user objects that are registered in the VPN Server
+UINT SiGetServerNumUserObjects(SERVER *s)
+{
+ CEDAR *c;
+ UINT ret = 0;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return 0;
+ }
+
+ c = s->Cedar;
+
+ LockList(c->HubList);
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(c->HubList);i++)
+ {
+ HUB *h = LIST_DATA(c->HubList, i);
+
+ if (h->HubDb != NULL)
+ {
+ ret += LIST_NUM(h->HubDb->UserList);
+ }
+ }
+ }
+ UnlockList(c->HubList);
+
+ return ret;
+}
+
+
+typedef struct SI_DEBUG_PROC_LIST
+{
+ UINT Id;
+ char *Description;
+ char *Args;
+ SI_DEBUG_PROC *Proc;
+} SI_DEBUG_PROC_LIST;
+
+// Debugging function
+UINT SiDebug(SERVER *s, RPC_TEST *ret, UINT i, char *str)
+{
+ SI_DEBUG_PROC_LIST proc_list[] =
+ {
+ {1, "Hello World", "<test string>", SiDebugProcHelloWorld},
+ {2, "Terminate process now", "", SiDebugProcExit},
+ {3, "Write memory dumpfile", "", SiDebugProcDump},
+ {4, "Restore process priority", "", SiDebugProcRestorePriority},
+ {5, "Set the process priority high", "", SiDebugProcSetHighPriority},
+ {6, "Get the .exe filename of the process", "", SiDebugProcGetExeFileName},
+ {7, "Crash the process", "", SiDebugProcCrash},
+ {8, "Get IPsecMessageDisplayed Flag", "", SiDebugProcGetIPsecMessageDisplayedValue},
+ {9, "Set IPsecMessageDisplayed Flag", "", SiDebugProcSetIPsecMessageDisplayedValue},
+ {10, "Get VgsMessageDisplayed Flag", "", SiDebugProcGetVgsMessageDisplayedValue},
+ {11, "Set VgsMessageDisplayed Flag", "", SiDebugProcSetVgsMessageDisplayedValue},
+ };
+ 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 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);
+
+
+ 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->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)
+{
+}
+
+// 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
+}
+
+// Adjoin the enumerations of log files
+void AdjoinEnumLogFile(LIST *o, LIST *src)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL || src == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(src);i++)
+ {
+ LOG_FILE *f = LIST_DATA(src, i);
+
+ Insert(o, Clone(f, sizeof(LOG_FILE)));
+ }
+}
+
+// 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;
+ }
+
+ GetExeDir(exe_dir, sizeof(exe_dir));
+
+ // Enumerate in the server_log
+ if (hubname == NULL)
+ {
+ EnumLogFileDir(o, "server_log");
+ }
+
+ // Enumerate in the packet_log
+ Format(tmp, sizeof(tmp), "%s/packet_log", exe_dir);
+ 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];
+
+ if (hubname == NULL || StrCmpi(hubname, e->FileName) == 0)
+ {
+ Format(dir_name, sizeof(dir_name), "packet_log/%s", e->FileName);
+ EnumLogFileDir(o, dir_name);
+ }
+ }
+ }
+
+ FreeDir(dir);
+ }
+
+ // Enumerate in the security_log
+ Format(tmp, sizeof(tmp), "%s/security_log", exe_dir);
+ 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];
+
+ if (hubname == NULL || StrCmpi(hubname, e->FileName) == 0)
+ {
+ Format(dir_name, sizeof(dir_name), "security_log/%s", e->FileName);
+ EnumLogFileDir(o, dir_name);
+ }
+ }
+ }
+
+ FreeDir(dir);
+ }
+
+ 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;
+ }
+
+ GetExeDir(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;
+ }
+
+ Zero(&t, sizeof(t));
+ GetServerCaps(s, &t);
+
+ ret = GetCapsInt(&t, name);
+
+ 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);
+}
+
+// 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(s->CapsListCache));
+ }
+ Unlock(s->CapsCacheLock);
+}
+
+// Main of the aquisition of Caps of the server
+void GetServerCapsMain(SERVER *s, CAPSLIST *t)
+{
+ // Validate arguments
+ if (s == NULL || t == NULL)
+ {
+ return;
+ }
+
+ // 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", false);
+
+ // 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);
+
+ 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 connction
+ 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);
+
+ AddCapsBool(t, "b_support_radius", 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 is available (only Linux)
+ AddCapsBool(t, "b_tap_supported", GetOsInfo()->OsType == OSTYPE_LINUX ? true : false);
+ }
+
+ // Cascade connction
+ 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);
+
+ AddCapsBool(t, "b_support_config_log", false);
+
+ // 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 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", (OS_IS_WINDOWS_NT(GetOsType()) && GET_KETA(GetOsType(), 100) >= 2));
+
+ // 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);
+
+ // Intel AES Acceleration function
+ AddCapsBool(t, "b_support_intel_aes", IsIntelAesNiSupported());
+
+#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);
+
+}
+
+// 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;
+ }
+
+ for (i = 0;i < LIST_NUM(t->CapsList);i++)
+ {
+ char tmp[MAX_SIZE];
+ CAPS *c = LIST_DATA(t->CapsList, i);
+
+ Format(tmp, sizeof(tmp), "caps_%s", c->Name);
+ PackAddInt(p, tmp, c->Value);
+ }
+}
+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");
+
+ 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, MAX(GetDaysUntil2038(), SERVER_DEFAULT_CERT_DAYS), 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);
+}
+
+// Initialize the Bridge
+void SiInitBridge(SERVER *s)
+{
+ HUB *h;
+ HUB_OPTION o;
+ HUB_LOG g;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Zero(&o, sizeof(o));
+ o.MaxSession = 0;
+
+ h = NewHub(s->Cedar, SERVER_DEFAULT_BRIDGE_NAME, &o);
+ AddHub(s->Cedar, h);
+
+ h->Offline = true;
+ SetHubOnline(h);
+
+ // Log settings
+ SiSetDefaultLogSetting(&g);
+ SetHubLogSetting(h, &g);
+
+ ReleaseHub(h);
+}
+
+// Set the default value of the Virtual HUB options
+void SiSetDefaultHubOption(HUB_OPTION *o)
+{
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ o->MaxSession = 0;
+ o->VlanTypeId = MAC_PROTO_TAGVLAN;
+ o->NoIPv6DefaultRouterInRAWhenIPv6 = true;
+ o->ManageOnlyPrivateIP = true;
+ o->ManageOnlyLocalUnicastIPv6 = true;
+ o->NoMacAddressLog = true;
+ o->NoDhcpPacketLogOutsideHub = true;
+ o->AccessListIncludeFileCacheLifetime = ACCESS_LIST_INCLUDE_FILE_CACHE_LIFETIME;
+ o->RemoveDefGwOnDhcpForLocalhost = true;
+}
+
+// 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);
+
+ {
+ UINT i;
+ for (i = 0;i < 0;i++)
+ {
+ char tmp[MAX_SIZE];
+ USER *u;
+ sprintf(tmp, "user%u", i);
+ AcLock(h);
+ u = NewUser(tmp, L"test", L"", AUTHTYPE_ANONYMOUS, NULL);
+ AcAddUser(h, u);
+ ReleaseUser(u);
+ AcUnlock(h);
+ }
+ }
+
+ 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;
+}
+
+// Test
+void SiTest(SERVER *s)
+{
+}
+
+// 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;
+
+ // 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
+ {
+ Hash(s->HashedPassword, "", 0, true);
+ }
+
+ // Set the encryption algorithm name to default
+ SiInitCipherName(s);
+
+ // Set the server certificate to default
+ SiInitDefaultServerCert(s);
+
+ // 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)
+ {
+ // SSTP, OpenVPN, and NAT traversal function can not be used in the bridge environment
+ s->DisableNatTraversal = true;
+ s->DisableSSTPServer = true;
+ s->DisableOpenVPNServer = true;
+ }
+ else
+ {
+ // Enable the SSTP and OpenVPN for default setting
+ OPENVPN_SSTP_CONFIG c;
+
+ Zero(&c, sizeof(c));
+ c.EnableOpenVPN = true;
+ c.EnableSSTP = true;
+
+ {
+ ToStr(c.OpenVPNPortList, OPENVPN_UDP_PORT);
+ }
+
+ SiSetOpenVPNAndSSTPConfig(s, &c);
+
+ {
+ // Enable VPN-over-ICMP" and VPN-over-DNS for default setting
+ s->EnableVpnOverIcmp = SiCanOpenVpnOverIcmpPort();
+ s->EnableVpnOverDns = SiCanOpenVpnOverDnsPort();
+
+#ifdef OS_WIN32
+ // Over-DNS is disabled on Windows by default
+ s->EnableVpnOverDns = false;
+#endif // OS_WIN32
+ }
+ }
+
+ 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 = NewCfgRw(&root,
+ s->Cedar->Bridge == false ? server_config_filename : BRIDGE_CONFIG_FILE_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;
+
+ // IPsec server
+ if (s->Cedar->Bridge == false)
+ {
+ s->IPsecServer = NewIPsecServer(s->Cedar);
+ }
+
+ // OpenVPN server (UDP)
+ if (s->Cedar->Bridge == false)
+ {
+ s->OpenVpnServerUdp = NewOpenVpnServerUdp(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);
+
+ 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->DisableDosProction)
+ {
+ 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;
+}
+
+// Get the state of Enabled / Disabled of Azure Client
+bool SiGetAzureEnable(SERVER *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ if (s->AzureClient != NULL)
+ {
+ return AcGetEnable(s->AzureClient);
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// 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, *f;
+ bool is_vgs_enabled = false;
+ // Validate arguments
+ if (s == NULL || root == NULL)
+ {
+ return false;
+ }
+
+ f = NULL;
+
+
+ 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");
+
+ 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)
+ {
+ 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);
+ }
+
+ 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);
+ }
+ }
+ }
+ }
+
+
+ {
+ HUB *h = NULL;
+
+ // Remove the virtual HUB "VPNGATE" when VGS disabled
+ LockHubList(s->Cedar);
+ {
+ h = GetHub(s->Cedar, VG_HUBNAME);
+ }
+ UnlockHubList(s->Cedar);
+
+ if (h != NULL)
+ {
+ StopHub(h);
+ DelHub(s->Cedar, h);
+ ReleaseHub(h);
+ }
+ }
+
+ 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
+
+ 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
+
+ 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;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ root = CfgCreateFolder(NULL, TAG_ROOT);
+
+ 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)
+ {
+ 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);
+ }
+ }
+ }
+
+ 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);
+
+ 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");
+ b = CfgGetBuf(f, "ServerCert");
+ if (b != NULL)
+ {
+ k->ServerCert = BufToX(b, false);
+ FreeBuf(b);
+ }
+
+ if (online)
+ {
+ k->Offline = true;
+ SetLinkOnline(k);
+ }
+ else
+ {
+ k->Offline = false;
+ SetLinkOffline(k);
+ }
+ 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];
+ UINT id = ToInt(name);
+ 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->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");
+ o->DoNotSaveHeavySecurityLogs = CfgGetBool(f, "DoNotSaveHeavySecurityLogs");
+ 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->DisableUserModeSecureNAT = CfgGetBool(f, "DisableUserModeSecureNAT");
+ o->DisableCheckMacOnLocalBridge = CfgGetBool(f, "DisableCheckMacOnLocalBridge");
+ o->DisableCorrectIpOffloadChecksum = CfgGetBool(f, "DisableCorrectIpOffloadChecksum");
+
+ // 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;
+ }
+
+ 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);
+ CfgAddBool(f, "DoNotSaveHeavySecurityLogs", o->DoNotSaveHeavySecurityLogs);
+ 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, "DisableUserModeSecureNAT", o->DisableUserModeSecureNAT);
+ CfgAddBool(f, "DisableCheckMacOnLocalBridge", o->DisableCheckMacOnLocalBridge);
+ CfgAddBool(f, "DisableCorrectIpOffloadChecksum", o->DisableCorrectIpOffloadChecksum);
+}
+
+// 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);
+ }
+ 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));
+
+ 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))
+ {
+ Hash(h->HashedPassword, "", 0, true);
+ }
+ 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;
+ CEDAR *c;
+ TOKEN_LIST *t;
+ bool b = false;
+ // Validate arguments
+ if (f == NULL || s == NULL)
+ {
+ return;
+ }
+ c = s->Cedar;
+
+ 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;
+ bool cluster_allowed = false;
+ UINT num_connections_per_ip = 0;
+ // 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);
+ }
+
+ s->DontBackupConfig = CfgGetBool(f, "DontBackupConfig");
+
+ if (CfgIsItem(f, "BackupConfigOnlyWhenModified"))
+ {
+ s->BackupConfigOnlyWhenModified = CfgGetBool(f, "BackupConfigOnlyWhenModified");
+ }
+ else
+ {
+ s->BackupConfigOnlyWhenModified = true;
+ }
+
+ c = s->Cedar;
+ Lock(c->lock);
+ {
+ OPENVPN_SSTP_CONFIG config;
+ FOLDER *syslog_f;
+ {
+ 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
+ syslog_f = CfgGetFolder(f, "SyslogSettings");
+ if (syslog_f != NULL && GetServerCapsBool(s, "b_support_syslog"))
+ {
+ SYSLOG_SETTING set;
+
+ Zero(&set, sizeof(set));
+
+ set.SaveType = CfgGetInt(syslog_f, "SaveType");
+ CfgGetStr(syslog_f, "HostName", set.Hostname, sizeof(set.Hostname));
+ set.Port = CfgGetInt(syslog_f, "Port");
+
+ SiSetSysLogSetting(s, &set);
+ }
+
+ // Whether to disable the IPv6 listener
+ s->Cedar->DisableIPv6Listener = CfgGetBool(f, "DisableIPv6Listener");
+
+ // DoS
+ s->DisableDosProction = CfgGetBool(f, "DisableDosProction");
+
+ // Num Connections Per IP
+ SetMaxConnectionsPerIp(CfgGetInt(f, "MaxConnectionsPerIP"));
+
+ // MaxUnestablishedConnections
+ SetMaxUnestablishedConnections(CfgGetInt(f, "MaxUnestablishedConnections"));
+
+ // DeadLock
+ s->DisableDeadLockCheck = CfgGetBool(f, "DisableDeadLockCheck");
+
+ // Eraser
+ 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 SSTP server function
+ s->DisableSSTPServer = CfgGetBool(f, "DisableSSTPServer");
+
+ // Disable the OpenVPN server function
+ s->DisableOpenVPNServer = CfgGetBool(f, "DisableOpenVPNServer");
+
+ // Disable the NAT-traversal feature
+ s->DisableNatTraversal = CfgGetBool(f, "DisableNatTraversal");
+
+ // Intel AES
+ s->DisableIntelAesAcceleration = CfgGetBool(f, "DisableIntelAesAcceleration");
+
+ if (s->Cedar->Bridge == false)
+ {
+ // Enable the VPN-over-ICMP
+ if (CfgIsItem(f, "EnableVpnOverIcmp"))
+ {
+ s->EnableVpnOverIcmp = CfgGetBool(f, "EnableVpnOverIcmp");
+ }
+ else
+ {
+ s->EnableVpnOverIcmp = SiCanOpenVpnOverIcmpPort();;
+ }
+
+ // Enable the VPN-over-DNS
+ if (CfgIsItem(f, "EnableVpnOverDns"))
+ {
+ s->EnableVpnOverDns = CfgGetBool(f, "EnableVpnOverDns");
+ }
+ else
+ {
+ s->EnableVpnOverDns = SiCanOpenVpnOverDnsPort();
+ }
+ }
+
+ // 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);
+ }
+
+ if (x == NULL || k == NULL || CheckXandK(x, k) == false)
+ {
+ FreeX(x);
+ FreeK(k);
+ SiGenerateDefaultCert(&x, &k);
+
+ SetCedarCert(c, x, k);
+
+ FreeX(x);
+ FreeK(k);
+ }
+ else
+ {
+ SetCedarCert(c, x, k);
+
+ FreeX(x);
+ FreeK(k);
+ }
+
+ // Cipher Name
+ if (CfgGetStr(f, "CipherName", tmp, sizeof(tmp)))
+ {
+ StrUpper(tmp);
+ if (CheckCipherListName(tmp))
+ {
+ SetCedarCipherList(c, tmp);
+ }
+ }
+
+ // Traffic information
+ Lock(c->TrafficLock);
+ {
+ SiLoadTraffic(f, "ServerTraffic", c->Traffic);
+ }
+ Unlock(c->TrafficLock);
+
+ // Get whether the current license allows cluster mode
+ cluster_allowed = true;
+
+
+ // Type of server
+ s->UpdatedServerType = s->ServerType =
+ cluster_allowed ? CfgGetInt(f, "ServerType") : SERVER_TYPE_STANDALONE;
+
+ // Password
+ if (CfgGetByte(f, "HashedPassword", s->HashedPassword, sizeof(s->HashedPassword)) != sizeof(s->HashedPassword))
+ {
+ Hash(s->HashedPassword, "", 0, true);
+ }
+
+ 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)
+ {
+ // SSTP, OpenVPN, and NAT traversal can not be used in a cluster environment
+ s->DisableNatTraversal = true;
+ s->DisableSSTPServer = true;
+ s->DisableOpenVPNServer = true;
+ }
+
+ if (s->Cedar->Bridge)
+ {
+ // SSTP, OpenVPN, and NAT traversal function can not be used in the bridge environment
+ s->DisableNatTraversal = true;
+ s->DisableSSTPServer = true;
+ s->DisableOpenVPNServer = true;
+ }
+
+ // Read the OpenVPN Port List
+ if (CfgGetStr(f, "OpenVPN_UdpPortList", tmp, sizeof(tmp)) == false)
+ {
+ {
+ ToStr(tmp, OPENVPN_UDP_PORT);
+ }
+ }
+
+ // Apply the configuration of SSTP and OpenVPN
+ Zero(&config, sizeof(config));
+ config.EnableOpenVPN = !s->DisableOpenVPNServer;
+ config.EnableSSTP = !s->DisableSSTPServer;
+ StrCpy(config.OpenVPNPortList, sizeof(config.OpenVPNPortList), tmp);
+
+ SiSetOpenVPNAndSSTPConfig(s, &config);
+
+ 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");
+ }
+ Unlock(c->lock);
+}
+
+// Write the server-specific settings
+void SiWriteServerCfg(FOLDER *f, SERVER *s)
+{
+ BUF *b;
+ CEDAR *c;
+ // Validate arguments
+ if (f == NULL || s == NULL)
+ {
+ return;
+ }
+
+ CfgAddInt(f, "CurrentBuild", s->Cedar->Build);
+
+ CfgAddInt(f, "AutoSaveConfigSpan", s->AutoSaveConfigSpanSaved / 1000);
+
+ CfgAddBool(f, "DontBackupConfig", s->DontBackupConfig);
+ CfgAddBool(f, "BackupConfigOnlyWhenModified", s->BackupConfigOnlyWhenModified);
+
+ c = s->Cedar;
+
+ Lock(c->lock);
+ {
+ bool is_vgs_cert = false;
+ FOLDER *syslog_f;
+ 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
+ syslog_f = CfgCreateFolder(f, "SyslogSettings");
+ if (syslog_f != NULL)
+ {
+ SYSLOG_SETTING set;
+
+ SiGetSysLogSetting(s, &set);
+
+ CfgAddInt(syslog_f, "SaveType", set.SaveType);
+ CfgAddStr(syslog_f, "HostName", set.Hostname);
+ CfgAddInt(syslog_f, "Port", set.Port);
+ }
+
+ // IPv6 listener disable setting
+ CfgAddBool(f, "DisableIPv6Listener", s->Cedar->DisableIPv6Listener);
+
+ // DoS
+ CfgAddBool(f, "DisableDosProction", s->DisableDosProction);
+
+ // MaxConnectionsPerIP
+ CfgAddInt(f, "MaxConnectionsPerIP", GetMaxConnectionsPerIp());
+
+ // MaxUnestablishedConnections
+ CfgAddInt(f, "MaxUnestablishedConnections", GetMaxUnestablishedConnections());
+
+ // DeadLock
+ CfgAddBool(f, "DisableDeadLockCheck", s->DisableDeadLockCheck);
+
+ // Eraser related
+ CfgAddInt64(f, "AutoDeleteCheckDiskFreeSpaceMin", s->Eraser->MinFreeSpace);
+
+ // 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);
+
+ // Disable the SSTP server function
+ CfgAddBool(f, "DisableSSTPServer", s->DisableSSTPServer);
+
+ // Disable the OpenVPN server function
+ CfgAddBool(f, "DisableOpenVPNServer", s->DisableOpenVPNServer);
+ }
+ }
+
+ if (c->Bridge == false)
+ {
+ // VPN over ICMP
+ CfgAddBool(f, "EnableVpnOverIcmp", s->EnableVpnOverIcmp);
+
+ // VPN over DNS
+ CfgAddBool(f, "EnableVpnOverDns", s->EnableVpnOverDns);
+ }
+
+ // Intel AES
+ CfgAddBool(f, "DisableIntelAesAcceleration", s->DisableIntelAesAcceleration);
+
+ if (c->Bridge == false)
+ {
+ OPENVPN_SSTP_CONFIG config;
+
+ SiGetOpenVPNAndSSTPConfig(s, &config);
+
+ CfgAddStr(f, "OpenVPN_UdpPortList", config.OpenVPNPortList);
+ }
+
+ // 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);
+
+
+ if (is_vgs_cert == false)
+ {
+ // 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);
+ }
+
+ // 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);
+ }
+ }
+ Unlock(c->lock);
+}
+
+// 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 IPsec server
+ if (s->IPsecServer != NULL)
+ {
+ FreeIPsecServer(s->IPsecServer);
+ s->IPsecServer = NULL;
+ }
+
+ // Terminate the OpenVPN server
+ if (s->OpenVpnServerUdp != NULL)
+ {
+ FreeOpenVpnServerUdp(s->OpenVpnServerUdp);
+ s->OpenVpnServerUdp = 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();
+}
+
+// Get the server
+SERVER *StGetServer()
+{
+ if (server == NULL)
+ {
+ return NULL;
+ }
+ return server;
+}
+
+// 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);
+
+ 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);
+ PackAddInt64Ex(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);
+ PackAddInt64(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;
+ UINT num = 0;
+ // 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", LIST_NUM(h->MacTable), i, num);
+
+ PackAddIntEx(p, "NumIpTables", LIST_NUM(h->IpTable), i, num);
+
+ PackAddInt64Ex(p, "LastCommTime", h->LastCommTime, i, num);
+ PackAddInt64Ex(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.DoNotSaveHeavySecurityLogs = PackGetBool(p, "DoNotSaveHeavySecurityLogs");
+ o.VlanTypeId = PackGetInt(p, "VlanTypeId");
+ 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.DisableUserModeSecureNAT = PackGetBool(p, "DisableUserModeSecureNAT");
+ o.DisableCheckMacOnLocalBridge = PackGetBool(p, "DisableCheckMacOnLocalBridge");
+ o.DisableCorrectIpOffloadChecksum = PackGetBool(p, "DisableCorrectIpOffloadChecksum");
+
+ 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;
+ }
+
+ LockList(h->MacTable);
+ {
+ if (IsInList(h->MacTable, (void *)key))
+ {
+ MAC_TABLE_ENTRY *e = (MAC_TABLE_ENTRY *)key;
+ Delete(h->MacTable, e);
+ Free(e);
+ }
+ }
+ UnlockList(h->MacTable);
+
+ 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 (asynchronous start)
+void SiCallEnumHubBegin(SERVER *s, FARM_MEMBER *f)
+{
+ // Validate arguments
+ if (s == NULL || f == NULL)
+ {
+ return;
+ }
+}
+
+// HUB enumeration directive (asynchronous end)
+void SiCallEnumHubEnd(SERVER *s, FARM_MEMBER *f)
+{
+ // Validate arguments
+ if (s == NULL || f == NULL)
+ {
+ return;
+ }
+}
+
+
+// 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);
+
+ LockList(h->MacTable);
+ {
+ hh->NumMacTables = LIST_NUM(h->MacTable);
+ }
+ UnlockList(h->MacTable);
+
+ 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);
+ PackAddBool(p, "DoNotSaveHeavySecurityLogs", h->Option->DoNotSaveHeavySecurityLogs);
+ PackAddInt(p, "ClientMinimumRequiredBuild", h->Option->ClientMinimumRequiredBuild);
+ 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, "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);
+
+ 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->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 (asynchronous)
+FARM_TASK *SiCallTaskAsyncBegin(FARM_MEMBER *f, PACK *p, char *taskname)
+{
+ char tmp[MAX_PATH];
+ FARM_TASK *t;
+ // Validate arguments
+ if (f == NULL || p == NULL || taskname == NULL)
+ {
+ return NULL;
+ }
+
+ PackAddStr(p, "taskname", taskname);
+
+ Debug("Call Async Task [%s] (%s)\n", taskname, f->hostname);
+
+ Format(tmp, sizeof(tmp), "CLUSTER_CALL_ASYNC: Entering Call [%s] to %s", taskname, f->hostname);
+ SiDebugLog(f->Cedar->Server, tmp);
+
+ t = SiFarmServPostTask(f, p);
+ StrCpy(t->TaskName, sizeof(t->TaskName), taskname);
+ StrCpy(t->HostName, sizeof(t->HostName), f->hostname);
+ t->FarmMember = f;
+
+ return t;
+}
+
+// Get the results of the asynchronous task
+PACK *SiCallTaskAsyncEnd(CEDAR *c, FARM_TASK *t)
+{
+ PACK *p;
+ char taskname[MAX_PATH];
+ char hostname[MAX_PATH];
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (t == NULL || c == NULL)
+ {
+ return NULL;
+ }
+
+ StrCpy(taskname, sizeof(taskname), t->TaskName);
+ StrCpy(hostname, sizeof(hostname), t->HostName);
+
+ p = SiFarmServWaitTask(t);
+ if (p == NULL)
+ {
+ Format(tmp, sizeof(tmp), "CLUSTER_CALL_ASYNC: Call ERROR [%s] to %s", taskname, hostname);
+ SiDebugLog(c->Server, tmp);
+ return NULL;
+ }
+
+ Format(tmp, sizeof(tmp), "CLUSTER_CALL_ASYNC: Retrieving Call Result [%s] to %s", taskname, hostname);
+ SiDebugLog(c->Server, tmp);
+
+ return p;
+}
+
+// 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 = HttpServerRecv(sock);
+
+ t->Response = p;
+ Set(t->CompleteEvent);
+
+ send_noop = false;
+ }
+ }
+ 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);
+}
+
+// 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;
+
+ f->StartedTime = SystemTime64();
+
+ 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;
+}
+
+// Create a server
+SERVER *SiNewServer(bool bridge)
+{
+ return SiNewServerEx(bridge, false);
+}
+SERVER *SiNewServerEx(bool bridge, bool in_client_inner_server)
+{
+ SERVER *s;
+ LISTENER *inproc;
+ LISTENER *azure;
+ LISTENER *rudp;
+
+ s = ZeroMalloc(sizeof(SERVER));
+
+ 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->StartTime = SystemTime64();
+ s->Syslog = NewSysLog(NULL, 0);
+ s->SyslogLock = NewLock();
+ 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);
+
+
+ if (s->DisableIntelAesAcceleration)
+ {
+ // Disable the Intel AES acceleration
+ DisableIntelAesAccel();
+ }
+
+ // Raise the priority
+ if (s->NoHighPriorityProcess == false)
+ {
+ OSSetHighPriority();
+ }
+
+ 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);
+
+ return s;
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Server.h b/src/Cedar/Server.h
new file mode 100644
index 00000000..a1532c78
--- /dev/null
+++ b/src/Cedar/Server.h
@@ -0,0 +1,664 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Server.h
+// Header of Server.c
+
+#ifndef SERVER_H
+#define SERVER_H
+
+// Default ports
+#define SERVER_DEF_PORTS_1 443
+#define SERVER_DEF_PORTS_2 992
+#define SERVER_DEF_PORTS_3 1194
+#define SERVER_DEF_PORTS_4 GC_DEFAULT_PORT
+
+#define SERVER_DEF_PORTS_INCLIENT_1 995
+#define SERVER_DEF_PORTS_INCLIENT_2 465
+#define SERVER_DEF_PORTS_INCLIENT_3 9008 // for admin (in client)
+#define SERVER_DEF_PORTS_INCLIENT_4 1195
+
+#define SERVER_DEF_PORTS_INCLIENT_DYN_MIN 1201
+#define SERVER_DEF_PORTS_INCLIENT_DYN_MAX 1999
+
+extern char *SERVER_CONFIG_FILE_NAME;
+#define SERVER_DEFAULT_CIPHER_NAME "RC4-MD5"
+#define SERVER_DEFAULT_CERT_DAYS (365 * 10)
+#define SERVER_DEFAULT_HUB_NAME "DEFAULT"
+#define SERVER_DEFAULT_BRIDGE_NAME "BRIDGE"
+#define SERVER_CONTROL_TCP_TIMEOUT (60 * 1000)
+#define SERVER_FARM_CONTROL_INTERVAL (10 * 1000)
+
+#define SERVER_FILE_SAVE_INTERVAL_DEFAULT (5 * 60 * 1000)
+#define SERVER_FILE_SAVE_INTERVAL_MIN (5 * 1000)
+#define SERVER_FILE_SAVE_INTERVAL_MAX (3600 * 1000)
+#define SERVER_FILE_SAVE_INTERVAL_USERMODE (1 * 60 * 1000)
+
+#define SERVER_LICENSE_VIOLATION_SPAN (SERVER_FARM_CONTROL_INTERVAL * 2)
+
+
+#define SERVER_DEADLOCK_CHECK_SPAN (2 * 60 * 1000)
+#define SERVER_DEADLOCK_CHECK_TIMEOUT (10 * 60 * 1000)
+
+
+#define RETRY_CONNECT_TO_CONTROLLER_INTERVAL (1 * 1000)
+
+#define MAX_PUBLIC_PORT_NUM 128
+
+#define MEMBER_SELECTOR_TXT_FILENAME "@member_selector.config"
+#define MEMBER_SELECTOR_CONNECT_TIMEOUT 2000
+#define MEMBER_SELECTOR_DATA_TIMEOUT 5000
+
+
+// Virtual HUB list hosted by each farm member
+struct HUB_LIST
+{
+ struct FARM_MEMBER *FarmMember; // Farm member
+ bool DynamicHub; // Dynamic HUB
+ char Name[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT NumSessions; // Number of sessions
+ UINT NumSessionsClient; // Number of client sessions
+ UINT NumSessionsBridge; // Number of bridge sessions
+ UINT NumMacTables; // Number of MAC table entries
+ UINT NumIpTables; // Number of IP table entries
+};
+
+// Task
+struct FARM_TASK
+{
+ EVENT *CompleteEvent; // Completion notice
+ PACK *Request; // Request
+ PACK *Response; // Response
+ FARM_MEMBER *FarmMember; // Destination farm member
+ char TaskName[MAX_PATH]; // Task name
+ char HostName[MAX_PATH]; // Host name
+};
+
+// Farm member
+struct FARM_MEMBER
+{
+ CEDAR *Cedar; // Cedar
+ UINT64 ConnectedTime; // Connection date and time
+ UINT Me; // Myself
+ UINT Ip; // IP address
+ UINT NumPort; // Number of port numbers
+ UINT *Ports; // Port number
+ char hostname[MAX_HOST_NAME_LEN + 1]; // Host name
+ X *ServerCert; // Server certificate
+ LIST *HubList; // Virtual HUB list
+ QUEUE *TaskQueue; // Task queue
+ EVENT *TaskPostEvent; // Task queuing event
+ UINT Point; // Point
+ volatile bool Halting; // Stopped
+ UINT NumSessions; // Number of sessions
+ UINT MaxSessions; // Maximum number of sessions
+ UINT NumTcpConnections; // Number of TCP connections
+ TRAFFIC Traffic; // Traffic information
+ UINT AssignedClientLicense; // Number of assigned client licenses
+ UINT AssignedBridgeLicense; // Number of assigned bridge licenses
+ UINT Weight; // Performance ratio
+ UCHAR RandomKey[SHA1_SIZE]; // Random number key (license check)
+ UINT64 SystemId; // System ID (license check)
+};
+
+// Connection to the farm controller
+struct FARM_CONTROLLER
+{
+ LOCK *lock; // Lock
+ struct SERVER *Server; // Server
+ THREAD *Thread; // Thread
+ SOCK *Sock; // Socket
+ SESSION *Session; // Session
+ volatile bool Halt; // Halting flag
+ EVENT *HaltEvent; // Halting event
+ UINT LastError; // Last error
+ bool Online; // Online flag
+ UINT64 StartedTime; // Connection start time
+ UINT64 CurrentConnectedTime; // Connection time of this time
+ UINT64 FirstConnectedTime; // First connection time
+ UINT NumConnected; // Number of connection count
+ UINT NumTry; // Number of trials
+ UINT NumFailed; // Connection failure count
+ bool IsConnected; // Whether it's connected
+};
+
+// Server listener
+struct SERVER_LISTENER
+{
+ UINT Port; // Port number
+ bool Enabled; // Active flag
+ LISTENER *Listener; // Listener object
+ bool DisableDos; // Disable the DoS detection
+};
+
+// Syslog configuration
+struct SYSLOG_SETTING
+{
+ UINT SaveType; // Save type
+ char Hostname[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT Port; // Port number
+};
+
+// Setting of SSTP and OpenVPN
+struct OPENVPN_SSTP_CONFIG
+{
+ bool EnableOpenVPN; // OpenVPN is enabled
+ char OpenVPNPortList[MAX_SIZE]; // OpenVPN UDP port number list
+ bool EnableSSTP; // SSTP is enabled
+};
+
+// Server object
+struct SERVER
+{
+ UINT ServerType; // Type of server
+ UINT UpdatedServerType; // Type of updated server
+ LIST *ServerListenerList; // Server listener list
+ UCHAR HashedPassword[SHA1_SIZE]; // Password
+ char ControllerName[MAX_HOST_NAME_LEN + 1]; // Controller name
+ UINT ControllerPort; // Controller port
+ UINT Weight; // Performance ratio
+ bool ControllerOnly; // Only controller function
+ UCHAR MemberPassword[SHA1_SIZE]; // Password for farm members
+ UINT PublicIp; // Public IP
+ UINT NumPublicPort; // Number of public ports
+ UINT *PublicPorts; // Public port array
+ UINT64 StartTime; // Start-up time
+ UINT AutoSaveConfigSpan; // Auto save interval
+ UINT AutoSaveConfigSpanSaved; // Auto save interval (stored value)
+ bool DontBackupConfig; // Do not save a backup of the configuration automatically
+ bool BackupConfigOnlyWhenModified; // Save a backup of the configuration only if there is a modification
+ UINT ConfigRevision; // Configuration file revision
+ bool DisableDosProction; // Disable the DoS attack protection
+ UCHAR MyRandomKey[SHA1_SIZE]; // Their own random key
+ bool FarmControllerInited; // Initialization of farm controller has been completed
+ bool DisableDeadLockCheck; // Disable the deadlock check
+ bool UseWebUI; // Use the WebUI
+ bool SaveDebugLog; // Save the debug log
+ bool NoSendSignature; // Let the client not to send a signature
+ bool UseWebTimePage; // Use WebTimePage
+ bool NoLinuxArpFilter; // Not to set arp_filter in Linux
+ bool NoHighPriorityProcess; // Not to raise the priority of the process
+ bool NoDebugDump; // Not to output the debug dump
+ bool DisableSSTPServer; // Disable the SSTP server function
+ bool DisableOpenVPNServer; // Disable the OpenVPN server function
+ bool DisableNatTraversal; // Disable the NAT-traversal feature
+ bool EnableVpnOverIcmp; // VPN over ICMP is enabled
+ bool EnableVpnOverDns; // VPN over DNS is enabled
+ bool DisableIntelAesAcceleration; // Disable the Intel AES acceleration
+ bool NoMoreSave; // Do not save any more
+ bool EnableConditionalAccept; // Apply the Conditional Accept the Listener
+
+ volatile bool Halt; // Halting flag
+ LOCK *lock; // Lock
+ REF *ref; // Reference counter
+ CEDAR *Cedar; // Cedar
+ CFG_RW *CfgRw; // Configuration file R/W
+ LOCK *SaveCfgLock; // Settings saving lock
+ EVENT *SaveHaltEvent; // Saving thread halting event
+ THREAD *SaveThread; // Settings saving thread
+ FARM_CONTROLLER *FarmController; // Farm controller
+ LOCK *TasksFromFarmControllerLock; // Lock while processing tasks from farm controller
+ LIST *FarmMemberList; // Farm members list
+ FARM_MEMBER *Me; // Register myself as a farm member
+ THREAD *FarmControlThread; // Farm control thread
+ EVENT *FarmControlThreadHaltEvent; // Farm control thread halting event
+ LIST *HubCreateHistoryList; // Virtual HUB creation history list
+
+ KEEP *Keep; // Maintaining connections
+ LOG *Logger; // Server logger
+ ERASER *Eraser; // Eraser
+
+ bool Led; // Use the LED display board
+ bool LedSpecial; // LED Special
+
+ UINT CurrentTotalNumSessionsOnFarm; // Total number of sessions in this server farm
+ UINT CurrentAssignedClientLicense; // Current number of assigned client licenses
+ UINT CurrentAssignedBridgeLicense; // Current number of assigned bridge license
+
+
+ LOCK *SyslogLock; // The lock of the syslog configuration
+ SYSLOG_SETTING SyslogSetting; // Syslog configuration
+ SLOG *Syslog; // Syslog object
+
+ LOCK *CapsCacheLock; // Lock for Caps cache
+ CAPSLIST *CapsListCache; // Caps cache
+ UINT LicenseHash; // Hash value of the license list
+
+ bool SnapshotInited;
+ EVENT *SnapshotHaltEvent; // Snapshot halting event
+ volatile bool HaltSnapshot; // Snapshot halting flag
+ THREAD *SnapshotThread; // Snapshot thread
+ LOG *SnapshotLogger; // Snapshot logger
+ UINT64 LastSnapshotTime; // Time that the last snapshot created
+
+ THREAD *DeadLockCheckThread; // Deadlock check thread
+ volatile bool HaltDeadLockThread; // Halting flag
+ EVENT *DeadLockWaitEvent; // Waiting Event
+
+ IPSEC_SERVER *IPsecServer; // IPsec server function
+ OPENVPN_SERVER_UDP *OpenVpnServerUdp; // OpenVPN server function
+ char OpenVpnServerUdpPorts[MAX_SIZE]; // UDP port list string
+ DDNS_CLIENT *DDnsClient; // DDNS client feature
+ LOCK *OpenVpnSstpConfigLock; // Lock OpenVPN and SSTP configuration
+
+ AZURE_CLIENT *AzureClient; // VPN Azure client
+ bool EnableVpnAzure; // Flag whether VPN Azure client is enabled
+
+ TINY_LOG *DebugLog; // Debug log
+
+ DYNAMIC_LISTENER *DynListenerIcmp; // VPN over ICMP listener
+ DYNAMIC_LISTENER *DynListenerDns; // VPN over DNS listener
+
+ bool IPsecMessageDisplayed; // Flag for whether the message about IPsec is displayed
+
+ bool IsInVm; // Whether I'm within the VM
+
+
+
+ volatile UINT NatTGlobalUdpPort; // NAT-T global UDP port
+};
+
+
+// Enumerate sessions *
+struct RPC_ENUM_SESSION
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ UINT NumSession; // Number of sessions
+ struct RPC_ENUM_SESSION_ITEM *Sessions; // Session list
+};
+
+// Session status *
+struct RPC_SESSION_STATUS
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // HUB Name
+ char Name[MAX_SESSION_NAME_LEN + 1]; // Session name
+ char Username[MAX_USERNAME_LEN + 1]; // User name
+ char RealUsername[MAX_USERNAME_LEN + 1]; // Real user name
+ char GroupName[MAX_USERNAME_LEN + 1]; // Group name
+ bool LinkMode; // Link mode
+ RPC_CLIENT_GET_CONNECTION_STATUS Status; // Status
+ UINT ClientIp; // Client IP address
+ UCHAR ClientIp6[16]; // Client IPv6 address
+ char ClientHostName[MAX_HOST_NAME_LEN + 1]; // Client host name
+ NODE_INFO NodeInfo; // Node information
+};
+
+
+// Type of server
+#define SERVER_TYPE_STANDALONE 0 // Stand-alone server
+#define SERVER_TYPE_FARM_CONTROLLER 1 // Farm controller server
+#define SERVER_TYPE_FARM_MEMBER 2 // Farm member server
+
+
+// Caps related
+struct CAPS
+{
+ char *Name; // Name
+ UINT Value; // Value
+};
+struct CAPSLIST
+{
+ LIST *CapsList; // Caps list
+};
+
+// Log file
+struct LOG_FILE
+{
+ char Path[MAX_PATH]; // Path name
+ char ServerName[MAX_HOST_NAME_LEN + 1]; // Server name
+ UINT FileSize; // File size
+ UINT64 UpdatedTime; // Updating date
+};
+
+
+// Virtual HUB creation history
+struct SERVER_HUB_CREATE_HISTORY
+{
+ char HubName[MAX_HUBNAME_LEN + 1];
+ UINT64 CreatedTime;
+};
+
+// Function prototype declaration
+SERVER *SiNewServer(bool bridge);
+SERVER *SiNewServerEx(bool bridge, bool in_client_inner_server);
+void SiReleaseServer(SERVER *s);
+void SiCleanupServer(SERVER *s);
+void StStartServer(bool bridge);
+void StStopServer();
+void SiInitConfiguration(SERVER *s);
+void SiFreeConfiguration(SERVER *s);
+UINT SiWriteConfigurationFile(SERVER *s);
+void SiLoadInitialConfiguration(SERVER *s);
+bool SiLoadConfigurationFile(SERVER *s);
+bool SiLoadConfigurationFileMain(SERVER *s, FOLDER *root);
+void SiInitDefaultServerCert(SERVER *s);
+void SiInitCipherName(SERVER *s);
+void SiGenerateDefaultCert(X **server_x, K **server_k);
+void SiGenerateDefaultCertEx(X **server_x, K **server_k, char *common_name);
+void SiInitListenerList(SERVER *s);
+void SiLockListenerList(SERVER *s);
+void SiUnlockListenerList(SERVER *s);
+bool SiAddListener(SERVER *s, UINT port, bool enabled);
+bool SiAddListenerEx(SERVER *s, UINT port, bool enabled, bool disable_dos);
+bool SiEnableListener(SERVER *s, UINT port);
+bool SiDisableListener(SERVER *s, UINT port);
+bool SiDeleteListener(SERVER *s, UINT port);
+SERVER_LISTENER *SiGetListener(SERVER *s, UINT port);
+int CompareServerListener(void *p1, void *p2);
+void SiStopAllListener(SERVER *s);
+void SiInitDefaultHubList(SERVER *s);
+void SiSetDefaultHubOption(HUB_OPTION *o);
+void SiInitBridge(SERVER *s);
+void SiTest(SERVER *s);
+FOLDER *SiWriteConfigurationToCfg(SERVER *s);
+bool SiLoadConfigurationCfg(SERVER *s, FOLDER *root);
+void SiWriteLocalBridges(FOLDER *f, SERVER *s);
+void SiLoadLocalBridges(SERVER *s, FOLDER *f);
+void SiWriteLocalBridgeCfg(FOLDER *f, LOCALBRIDGE *br);
+void SiLoadLocalBridgeCfg(SERVER *s, FOLDER *f);
+void SiWriteListeners(FOLDER *f, SERVER *s);
+void SiLoadListeners(SERVER *s, FOLDER *f);
+void SiWriteListenerCfg(FOLDER *f, SERVER_LISTENER *r);
+void SiLoadListenerCfg(SERVER *s, FOLDER *f);
+void SiWriteServerCfg(FOLDER *f, SERVER *s);
+void SiLoadServerCfg(SERVER *s, FOLDER *f);
+void SiWriteTraffic(FOLDER *parent, char *name, TRAFFIC *t);
+void SiWriteTrafficInner(FOLDER *parent, char *name, TRAFFIC_ENTRY *e);
+void SiLoadTrafficInner(FOLDER *parent, char *name, TRAFFIC_ENTRY *e);
+void SiLoadTraffic(FOLDER *parent, char *name, TRAFFIC *t);
+void SiSaverThread(THREAD *thread, void *param);
+void SiLoadLicenseManager(SERVER *s, FOLDER *f);
+void SiWriteLicenseManager(FOLDER *f, SERVER *s);
+void SiLoadL3Switchs(SERVER *s, FOLDER *f);
+void SiLoadL3SwitchCfg(L3SW *sw, FOLDER *f);
+void SiWriteL3Switchs(FOLDER *f, SERVER *s);
+void SiWriteL3SwitchCfg(FOLDER *f, L3SW *sw);
+void SiLoadIPsec(SERVER *s, FOLDER *f);
+void SiWriteIPsec(FOLDER *f, SERVER *s);
+void SiWriteHubs(FOLDER *f, SERVER *s);
+void SiLoadHubs(SERVER *s, FOLDER *f);
+void SiWriteHubCfg(FOLDER *f, HUB *h);
+void SiLoadHubCfg(SERVER *s, FOLDER *f, char *name);
+void SiLoadHubLogCfg(HUB_LOG *g, FOLDER *f);
+void SiWriteHubOptionCfg(FOLDER *f, HUB_OPTION *o);
+void SiWriteHubLogCfg(FOLDER *f, HUB_LOG *g);
+void SiWriteHubLogCfgEx(FOLDER *f, HUB_LOG *g, bool el_mode);
+void SiLoadHubOptionCfg(FOLDER *f, HUB_OPTION *o);
+void SiWriteHubLinks(FOLDER *f, HUB *h);
+void SiLoadHubLinks(HUB *h, FOLDER *f);
+void SiWriteHubAdminOptions(FOLDER *f, HUB *h);
+void SiLoadHubAdminOptions(HUB *h, FOLDER *f);
+void SiWriteHubLinkCfg(FOLDER *f, LINK *k);
+void SiLoadHubLinkCfg(FOLDER *f, HUB *h);
+void SiWriteHubAccessLists(FOLDER *f, HUB *h);
+void SiLoadHubAccessLists(HUB *h, FOLDER *f);
+void SiWriteHubAccessCfg(FOLDER *f, ACCESS *a);
+void SiLoadHubAccessCfg(HUB *h, FOLDER *f);
+void SiWriteHubDb(FOLDER *f, HUBDB *db, bool no_save_ac_list);
+void SiLoadHubDb(HUB *h, FOLDER *f);
+void SiWriteUserList(FOLDER *f, LIST *o);
+void SiLoadUserList(HUB *h, FOLDER *f);
+void SiWriteUserCfg(FOLDER *f, USER *u);
+void SiLoadUserCfg(HUB *h, FOLDER *f);
+void SiWriteGroupList(FOLDER *f, LIST *o);
+void SiLoadGroupList(HUB *h, FOLDER *f);
+void SiWriteGroupCfg(FOLDER *f, USERGROUP *g);
+void SiLoadGroupCfg(HUB *h, FOLDER *f);
+void SiWriteCertList(FOLDER *f, LIST *o);
+void SiLoadCertList(LIST *o, FOLDER *f);
+void SiWriteCrlList(FOLDER *f, LIST *o);
+void SiLoadCrlList(LIST *o, FOLDER *f);
+void SiWriteAcList(FOLDER *f, LIST *o);
+void SiLoadAcList(LIST *o, FOLDER *f);
+void SiWritePolicyCfg(FOLDER *f, POLICY *p, bool cascade_mode);
+void SiLoadPolicyCfg(POLICY *p, FOLDER *f);
+void SiLoadSecureNAT(HUB *h, FOLDER *f);
+void SiWriteSecureNAT(HUB *h, FOLDER *f);
+void SiRebootServerEx(bool bridge, bool reset_setting);
+void SiRebootServer(bool bridge);
+void SiRebootServerThread(THREAD *thread, void *param);
+void StInit();
+void StFree();
+SERVER *StGetServer();
+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);
+FARM_CONTROLLER *SiStartConnectToController(SERVER *s);
+void SiStopConnectToController(FARM_CONTROLLER *f);
+void SiFarmServ(SERVER *server, SOCK *sock, X *cert, UINT ip, UINT num_port, UINT *ports, char *hostname, UINT point, UINT weight, UINT max_sessions);
+int CompareHubList(void *p1, void *p2);
+void SiFarmServMain(SERVER *server, SOCK *sock, FARM_MEMBER *f);
+FARM_TASK *SiFarmServPostTask(FARM_MEMBER *f, PACK *request);
+PACK *SiFarmServWaitTask(FARM_TASK *t);
+PACK *SiExecTask(FARM_MEMBER *f, PACK *p);
+PACK *SiCallTask(FARM_MEMBER *f, PACK *p, char *taskname);
+FARM_TASK *SiCallTaskAsyncBegin(FARM_MEMBER *f, PACK *p, char *taskname);
+PACK *SiCallTaskAsyncEnd(CEDAR *c, FARM_TASK *t);
+void SiAcceptTasksFromController(FARM_CONTROLLER *f, SOCK *sock);
+void SiAcceptTasksFromControllerMain(FARM_CONTROLLER *f, SOCK *sock);
+PACK *SiCalledTask(FARM_CONTROLLER *f, PACK *p, char *taskname);
+void SiHubOnlineProc(HUB *h);
+void SiHubOfflineProc(HUB *h);
+FARM_MEMBER *SiGetNextFarmMember(SERVER *s, CONNECTION *c, HUB *h);
+bool SiGetMemberSelectorUrl(char *url, UINT url_size);
+void SiCallCreateHub(SERVER *s, FARM_MEMBER *f, HUB *h);
+void SiCallUpdateHub(SERVER *s, FARM_MEMBER *f, HUB *h);
+void SiCallDeleteHub(SERVER *s, FARM_MEMBER *f, HUB *h);
+void SiCallEnumSession(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_SESSION *t);
+void SiCallEnumNat(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_NAT *t);
+void SiCallEnumDhcp(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_DHCP *t);
+void SiCallGetNatStatus(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_NAT_STATUS *t);
+void SiCallEnumMacTable(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_MAC_TABLE *t);
+void SiCallEnumIpTable(SERVER *s, FARM_MEMBER *f, char *hubname, RPC_ENUM_IP_TABLE *t);
+void SiCallDeleteSession(SERVER *s, FARM_MEMBER *f, char *hubname, char *session_name);
+void SiCallCreateTicket(SERVER *s, FARM_MEMBER *f, char *hubname, char *username, char *realusername, POLICY *policy, UCHAR *ticket, UINT counter, char *groupname);
+void SiCallDeleteMacTable(SERVER *s, FARM_MEMBER *f, char *hubname, UINT key);
+void SiCallDeleteIpTable(SERVER *s, FARM_MEMBER *f, char *hubname, UINT key);
+void SiCalledCreateHub(SERVER *s, PACK *p);
+void SiCalledUpdateHub(SERVER *s, PACK *p);
+void SiCalledDeleteHub(SERVER *s, PACK *p);
+void SiCalledDeleteSession(SERVER *s, PACK *p);
+void SiCalledDeleteMacTable(SERVER *s, PACK *p);
+void SiCalledDeleteIpTable(SERVER *s, PACK *p);
+PACK *SiCalledCreateTicket(SERVER *s, PACK *p);
+PACK *SiCalledEnumSession(SERVER *s, PACK *p);
+PACK *SiCalledEnumNat(SERVER *s, PACK *p);
+PACK *SiCalledEnumDhcp(SERVER *s, PACK *p);
+PACK *SiCalledGetNatStatus(SERVER *s, PACK *p);
+PACK *SiCalledEnumMacTable(SERVER *s, PACK *p);
+PACK *SiCalledEnumIpTable(SERVER *s, PACK *p);
+void SiCalledEnumHub(SERVER *s, PACK *p, PACK *req);
+void SiPackAddCreateHub(PACK *p, HUB *h);
+FARM_MEMBER *SiGetHubHostingMember(SERVER *s, HUB *h, bool admin_mode, CONNECTION *c);
+void SiCallEnumHub(SERVER *s, FARM_MEMBER *f);
+void SiCallEnumHubBegin(SERVER *s, FARM_MEMBER *f);
+void SiCallEnumHubEnd(SERVER *s, FARM_MEMBER *f);
+void SiStartFarmControl(SERVER *s);
+void SiStopFarmControl(SERVER *s);
+void SiFarmControlThread(THREAD *thread, void *param);
+void SiAccessListToPack(PACK *p, LIST *o);
+void SiAccessToPack(PACK *p, ACCESS *a, UINT i, UINT total);
+ACCESS *SiPackToAccess(PACK *p, UINT i);
+UINT SiNumAccessFromPack(PACK *p);
+void SiHubUpdateProc(HUB *h);
+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);
+UINT SiGetPoint(SERVER *s);
+UINT SiCalcPoint(SERVER *s, UINT num, UINT weight);
+bool SiCallGetSessionStatus(SERVER *s, FARM_MEMBER *f, RPC_SESSION_STATUS *t);
+PACK *SiCalledGetSessionStatus(SERVER *s, PACK *p);
+bool SiCallEnumLogFileList(SERVER *s, FARM_MEMBER *f, RPC_ENUM_LOG_FILE *t, char *hubname);
+PACK *SiCalledEnumLogFileList(SERVER *s, PACK *p);
+bool SiCallReadLogFile(SERVER *s, FARM_MEMBER *f, RPC_READ_LOG_FILE *t);
+PACK *SiCalledReadLogFile(SERVER *s, PACK *p);
+int CmpLogFile(void *p1, void *p2);
+LIST *EnumLogFile(char *hubname);
+void EnumLogFileDir(LIST *o, char *dirname);
+void FreeEnumLogFile(LIST *o);
+bool CheckLogFileNameFromEnumList(LIST *o, char *name, char *server_name);
+void AdjoinEnumLogFile(LIST *o, LIST *src);
+void IncrementServerConfigRevision(SERVER *s);
+void GetServerProductName(SERVER *s, char *name, UINT size);
+void GetServerProductNameInternal(SERVER *s, char *name, UINT size);
+
+
+void SiSetSysLogSetting(SERVER *s, SYSLOG_SETTING *setting);
+void SiGetSysLogSetting(SERVER *s, SYSLOG_SETTING *setting);
+void SiWriteSysLog(SERVER *s, char *typestr, char *hubname, wchar_t *message);
+UINT SiGetSysLogSaveStatus(SERVER *s);
+void SiInitDeadLockCheck(SERVER *s);
+void SiFreeDeadLockCheck(SERVER *s);
+void SiDeadLockCheckThread(THREAD *t, void *param);
+void SiCheckDeadLockMain(SERVER *s, UINT timeout);
+void SiDebugLog(SERVER *s, char *msg);
+UINT SiDebug(SERVER *s, RPC_TEST *ret, UINT i, char *str);
+UINT SiDebugProcHelloWorld(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+UINT SiDebugProcExit(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+UINT SiDebugProcDump(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+UINT SiDebugProcRestorePriority(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+UINT SiDebugProcSetHighPriority(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+UINT SiDebugProcGetExeFileName(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+UINT SiDebugProcCrash(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+UINT SiDebugProcGetIPsecMessageDisplayedValue(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+UINT SiDebugProcSetIPsecMessageDisplayedValue(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+UINT SiDebugProcGetVgsMessageDisplayedValue(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+UINT SiDebugProcSetVgsMessageDisplayedValue(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+
+typedef UINT (SI_DEBUG_PROC)(SERVER *s, char *in_str, char *ret_str, UINT ret_str_size);
+
+CAPS *NewCaps(char *name, UINT value);
+void FreeCaps(CAPS *c);
+CAPSLIST *NewCapsList();
+int CompareCaps(void *p1, void *p2);
+void AddCaps(CAPSLIST *caps, CAPS *c);
+CAPS *GetCaps(CAPSLIST *caps, char *name);
+void FreeCapsList(CAPSLIST *caps);
+bool GetCapsBool(CAPSLIST *caps, char *name);
+UINT GetCapsInt(CAPSLIST *caps, char *name);
+void AddCapsBool(CAPSLIST *caps, char *name, bool b);
+void AddCapsInt(CAPSLIST *caps, char *name, UINT i);
+void InRpcCapsList(CAPSLIST *t, PACK *p);
+void OutRpcCapsList(PACK *p, CAPSLIST *t);
+void FreeRpcCapsList(CAPSLIST *t);
+void InitCapsList(CAPSLIST *t);
+void InRpcSysLogSetting(SYSLOG_SETTING *t, PACK *p);
+void OutRpcSysLogSetting(PACK *p, SYSLOG_SETTING *t);
+
+void GetServerCaps(SERVER *s, CAPSLIST *t);
+bool GetServerCapsBool(SERVER *s, char *name);
+UINT GetServerCapsInt(SERVER *s, char *name);
+void GetServerCapsMain(SERVER *s, CAPSLIST *t);
+void InitServerCapsCache(SERVER *s);
+void FreeServerCapsCache(SERVER *s);
+void DestroyServerCapsCache(SERVER *s);
+
+
+bool IsAdminPackSupportedServerProduct(char *name);
+
+void SiInitHubCreateHistory(SERVER *s);
+void SiFreeHubCreateHistory(SERVER *s);
+void SiDeleteOldHubCreateHistory(SERVER *s);
+void SiAddHubCreateHistory(SERVER *s, char *name);
+void SiDelHubCreateHistory(SERVER *s, char *name);
+bool SiIsHubRegistedOnCreateHistory(SERVER *s, char *name);
+
+UINT SiGetServerNumUserObjects(SERVER *s);
+bool SiTooManyUserObjectsInServer(SERVER *s, bool oneMore);
+
+void SiGetOpenVPNAndSSTPConfig(SERVER *s, OPENVPN_SSTP_CONFIG *c);
+void SiSetOpenVPNAndSSTPConfig(SERVER *s, OPENVPN_SSTP_CONFIG *c);
+
+bool SiCanOpenVpnOverDnsPort();
+bool SiCanOpenVpnOverIcmpPort();
+void SiApplySpecialListenerStatus(SERVER *s);
+
+bool SiIsAzureEnabled(SERVER *s);
+bool SiIsAzureSupported(SERVER *s);
+void SiApplyAzureConfig(SERVER *s, DDNS_CLIENT_STATUS *ddns_status);
+void SiSetAzureEnable(SERVER *s, bool enabled);
+bool SiGetAzureEnable(SERVER *s);
+
+#endif // SERVER_H
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Session.c b/src/Cedar/Session.c
new file mode 100644
index 00000000..685529d2
--- /dev/null
+++ b/src/Cedar/Session.c
@@ -0,0 +1,2242 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Session.c
+// Session Manager
+
+#include "CedarPch.h"
+
+// Main routine of the session
+void SessionMain(SESSION *s)
+{
+ CONNECTION *c;
+ POLICY *policy;
+ UINT64 now;
+ UINT i = 0;
+ PACKET_ADAPTER *pa;
+ bool pa_inited = false;
+ UINT packet_size;
+ void *packet;
+ bool packet_put;
+ bool pa_fail = false;
+ UINT test = 0;
+ bool update_hub_last_comm = false;
+ UINT err = ERR_SESSION_TIMEOUT;
+ UINT64 next_black_list_check = 0;
+ UINT64 next_update_hub_last_comm = 0;
+ UINT64 auto_disconnect_tick = 0;
+ bool block_all_packets = false;
+ UINT64 next_check_block_all_packets = 0;
+ TRAFFIC t;
+ SOCK *msgdlg_sock = NULL;
+ SOCK *nicinfo_sock = NULL;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+ Debug("SessionMain: %s\n", s->Name);
+
+ Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);
+
+ // Generate a string from the session key
+ BinToStr(s->SessionKeyStr, sizeof(s->SessionKeyStr), s->SessionKey, sizeof(s->SessionKey));
+
+ // Reset the number of retries
+ s->CurrentRetryCount = 0;
+ s->ConnectSucceed = true;
+ s->SessionTimeOuted = false;
+ s->NumDisconnected = 0;
+
+ c = s->Connection;
+ policy = s->Policy;
+
+ // Initialize the packet adapter
+ pa = s->PacketAdapter;
+ if (pa->Init(s) == false)
+ {
+ // Initialization Failed
+ if (s->VLanDeviceErrorCount >= 2)
+ {
+ s->ForceStopFlag = true;
+ }
+ else
+ {
+ s->VLanDeviceErrorCount++;
+ }
+ err = ERR_DEVICE_DRIVER_ERROR;
+ goto CLEANUP;
+ }
+ pa_inited = true;
+
+ if (s->BridgeMode == false)
+ {
+ s->Cancel2 = pa->GetCancel(s);
+ }
+ else
+ {
+ CANCEL *c = pa->GetCancel(s);
+ CANCEL *old = s->Cancel1;
+ s->Cancel1 = c;
+ ReleaseCancel(old);
+ }
+
+ s->RetryFlag = false;
+
+ s->LastCommTime = Tick64();
+ if (s->ServerMode == false)
+ {
+ s->NextConnectionTime = Tick64() + (UINT64)(s->ClientOption->AdditionalConnectionInterval * 1000);
+ }
+
+ s->NumConnectionsEatablished++;
+ s->CurrentConnectionEstablishTime = Tick64();
+ if (s->FirstConnectionEstablisiedTime == 0)
+ {
+ s->FirstConnectionEstablisiedTime = Tick64();
+ }
+
+ if (s->ServerMode == false && s->Cedar->Client != NULL)
+ {
+ if (s->Policy != NULL)
+ {
+ if (s->Policy->AutoDisconnect)
+ {
+ auto_disconnect_tick = s->CurrentConnectionEstablishTime +
+ (UINT64)s->Policy->AutoDisconnect * 1000ULL;
+ }
+ }
+ }
+
+ s->LastIncrementTraffic = Tick64();
+
+ c->Err = ERR_SESSION_TIMEOUT;
+ s->VLanDeviceErrorCount = 0;
+
+ s->LastTryAddConnectTime = Tick64();
+
+ Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);
+
+ if (policy != NULL)
+ {
+ // Determine the mode by referencing the contents of the policy
+ if (policy->MonitorPort)
+ {
+ s->IsMonitorMode = true;
+ }
+
+ if (policy->NoRouting == false || policy->NoBridge == false)
+ {
+ s->IsBridgeMode = true;
+ }
+ }
+
+ if (s->ServerMode == false && s->Cedar->Client != NULL)
+ {
+ if (IsEmptyUniStr(s->Client_Message) == false)
+ {
+ UI_MSG_DLG dlg;
+
+ Zero(&dlg, sizeof(dlg));
+ if (s->ClientOption != NULL)
+ {
+ StrCpy(dlg.HubName, sizeof(dlg.HubName), s->ClientOption->HubName);
+ StrCpy(dlg.ServerName, sizeof(dlg.ServerName), s->ClientOption->Hostname);
+ }
+
+ dlg.Msg = s->Client_Message;
+
+ msgdlg_sock = CncMsgDlg(&dlg);
+ }
+
+ if (s->Win32HideNicInfoWindow == false)
+ {
+ UI_NICINFO info;
+
+ Zero(&info, sizeof(info));
+ if (s->ClientOption != NULL)
+ {
+ StrCpy(info.NicName, sizeof(info.NicName), s->ClientOption->DeviceName);
+ UniStrCpy(info.AccountName, sizeof(info.AccountName), s->ClientOption->AccountName);
+ }
+
+ nicinfo_sock = CncNicInfo(&info);
+ }
+ }
+
+ while (true)
+ {
+ now = Tick64();
+ Zero(&t, sizeof(t));
+
+
+ if (next_update_hub_last_comm == 0 ||
+ (next_update_hub_last_comm <= now))
+ {
+ next_update_hub_last_comm = now + 1000;
+
+ if (s->Hub != NULL)
+ {
+ if (update_hub_last_comm)
+ {
+ Lock(s->Hub->lock);
+ {
+ s->Hub->LastCommTime = SystemTime64();
+ }
+ Unlock(s->Hub->lock);
+
+ update_hub_last_comm = false;
+ }
+ }
+ }
+
+
+ if (s->InProcMode)
+ {
+ if (c->TubeSock == NULL || IsTubeConnected(c->TubeSock->SendTube) == false || IsTubeConnected(c->TubeSock->RecvTube) == false)
+ {
+ // Disconnection occurs in the in-process mode
+ err = ERR_DISCONNECTED;
+ pa_fail = true;
+ }
+ }
+
+ if (s->IsRUDPSession)
+ {
+ if (s->NumDisconnected >= 1 && s->EnableUdpRecovery == false)
+ {
+ // Disconnection occurs in the R-UDP session (UDP recovery is invalid)
+ err = ERR_DISCONNECTED;
+ pa_fail = true;
+ }
+ }
+
+ // Chance of additional connection
+ ClientAdditionalConnectChance(s);
+
+ // Receive a block
+ ConnectionReceive(c, s->Cancel1, s->Cancel2);
+
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL && s->UdpAccel->FatalError)
+ {
+ // A serious error occurs during sending any data on UDP socket
+ // in the case of using UDP acceleration function
+ err = ERR_DISCONNECTED;
+ pa_fail = true;
+ }
+
+ // Pass the received block to the PacketAdapter
+ LockQueue(c->ReceivedBlocks);
+ {
+ BLOCK *b;
+ packet_put = false;
+ while (true)
+ {
+ b = GetNext(c->ReceivedBlocks);
+ if (b == NULL)
+ {
+ break;
+ }
+
+ PROBE_DATA2("GetNext", b->Buf, b->Size);
+
+ update_hub_last_comm = true;
+
+ if (s->ServerMode == false && b->Size >= 14)
+ {
+ if (b->Buf[0] & 0x40)
+ {
+ t.Recv.BroadcastCount++;
+ t.Recv.BroadcastBytes += (UINT64)b->Size;
+ }
+ else
+ {
+ t.Recv.UnicastCount++;
+ t.Recv.UnicastBytes += (UINT64)b->Size;
+ }
+ }
+
+ packet_put = true;
+ PROBE_DATA2("pa->PutPacket", b->Buf, b->Size);
+ if (pa->PutPacket(s, b->Buf, b->Size) == false)
+ {
+ pa_fail = true;
+ err = ERR_DEVICE_DRIVER_ERROR;
+ Free(b->Buf);
+ Debug(" Error: pa->PutPacket(Packet) Failed.\n");
+ }
+ Free(b);
+ }
+
+ if (packet_put || s->ServerMode)
+ {
+ PROBE_DATA2("pa->PutPacket", NULL, 0);
+ if (pa->PutPacket(s, NULL, 0) == false)
+ {
+ Debug(" Error: pa->PutPacket(NULL) Failed.\n");
+ pa_fail = true;
+ err = ERR_DEVICE_DRIVER_ERROR;
+ }
+ }
+ }
+ UnlockQueue(c->ReceivedBlocks);
+
+ // Add the packet to be transmitted to SendBlocks by acquiring from PacketAdapter
+ LockQueue(c->SendBlocks);
+ {
+ UINT i, max_num = MAX_SEND_SOCKET_QUEUE_NUM;
+ i = 0;
+ while (packet_size = pa->GetNextPacket(s, &packet))
+ {
+ BLOCK *b;
+ if (packet_size == INFINITE)
+ {
+ err = ERR_DEVICE_DRIVER_ERROR;
+ pa_fail = true;
+ Debug(" Error: pa->GetNextPacket() Failed.\n");
+ break;
+ }
+
+ update_hub_last_comm = true;
+
+ if ((c->CurrentSendQueueSize > MAX_BUFFERING_PACKET_SIZE) ||
+ block_all_packets)
+ {
+// WHERE;
+ // Discard because it exceeded the buffer size limit
+ Free(packet);
+ }
+ else
+ {
+ bool priority;
+ // Buffering
+ if (s->ServerMode == false && packet_size >= 14)
+ {
+ UCHAR *buf = (UCHAR *)packet;
+ if (buf[0] & 0x01)
+ {
+ t.Send.BroadcastCount++;
+ t.Send.BroadcastBytes += (UINT64)packet_size;
+ }
+ else
+ {
+ t.Send.UnicastCount++;
+ t.Send.UnicastBytes += (UINT64)packet_size;
+ }
+ }
+ priority = IsPriorityHighestPacketForQoS(packet, packet_size);
+ b = NewBlock(packet, packet_size, s->UseCompress ? 1 : 0);
+ b->PriorityQoS = priority;
+ c->CurrentSendQueueSize += b->Size;
+
+ if (b->PriorityQoS && c->Protocol == CONNECTION_TCP && s->QoS)
+ {
+ InsertQueue(c->SendBlocks2, b);
+ }
+ else
+ {
+ InsertQueue(c->SendBlocks, b);
+ }
+ }
+ i++;
+ if (i >= max_num)
+ {
+ break;
+ }
+ }
+ }
+ UnlockQueue(c->SendBlocks);
+
+ AddTrafficForSession(s, &t);
+
+ // Send a block
+ ConnectionSend(c);
+
+ // Determine the automatic disconnection
+ if (auto_disconnect_tick != 0 && auto_disconnect_tick <= Tick64())
+ {
+ err = ERR_AUTO_DISCONNECTED;
+ s->CurrentRetryCount = INFINITE;
+ break;
+ }
+
+ // Stop determination
+ if (s->Halt)
+ {
+ if (s->ForceStopFlag)
+ {
+ err = ERR_USER_CANCEL;
+ }
+ break;
+ }
+
+ // Get the current time
+ now = Tick64();
+
+ // Increments the number of logins for user object and Virtual HUB object.
+ // (It's incremented only if the time 30 seconds passed after connection.
+ // If not do this, it will be incremented on DoS attacks or any error.)
+ if (s->NumLoginIncrementTick != 0 && s->NumLoginIncrementTick <= now)
+ {
+ s->NumLoginIncrementTick = 0;
+
+ if (s->NumLoginIncrementHubObject != NULL)
+ {
+ s->NumLoginIncrementHubObject->NumLogin++;
+ }
+
+ if (s->NumLoginIncrementUserObject != NULL)
+ {
+ s->NumLoginIncrementUserObject->NumLogin++;
+ }
+ }
+
+ if (s->ServerMode)
+ {
+ HUB *hub;
+
+ // Update of traffic data of the user
+ if ((s->LastIncrementTraffic + INCREMENT_TRAFFIC_INTERVAL) <= now)
+ {
+ IncrementUserTraffic(s->Hub, s->UserNameReal, s);
+ s->LastIncrementTraffic = now;
+ }
+
+ hub = s->Hub;
+
+ if (hub != NULL)
+ {
+ Lock(hub->lock);
+ {
+ if ((hub->LastIncrementTraffic + INCREMENT_TRAFFIC_INTERVAL) <= now)
+ {
+ IncrementHubTraffic(s->Hub);
+ hub->LastIncrementTraffic = now;
+ }
+ }
+ Unlock(hub->lock);
+ }
+ }
+
+ if (s->LinkModeServer == false && s->SecureNATMode == false && s->BridgeMode == false && s->L3SwitchMode == false && s->InProcMode == false)
+ {
+ bool timeouted = false;
+
+ if ((now > s->LastCommTime) && ((now - s->LastCommTime) >= ((UINT64)s->Timeout)))
+ {
+ // When communication is not possible for the predetermined time
+ timeouted = true;
+ WHERE;
+ }
+
+ if (s->ServerMode == false && s->ClientOption != NULL && s->ClientOption->ConnectionDisconnectSpan == 0)
+ {
+ if (LIST_NUM(s->Connection->Tcp->TcpSockList) < s->MaxConnection)
+ {
+ if ((s->LastTryAddConnectTime +
+ (UINT64)(s->ClientOption->AdditionalConnectionInterval * 1000 * 2 + CONNECTING_TIMEOUT * 2))
+ <= Tick64())
+ {
+ if (s->IsRUDPSession == false || LIST_NUM(s->Connection->Tcp->TcpSockList) == 0)
+ {
+ timeouted = true;
+ WHERE;
+ }
+ }
+ }
+ }
+
+ if (timeouted)
+ {
+ // Timeout occurs
+ Debug("** Session Timeouted.\n");
+ s->SessionTimeOuted = true;
+ err = ERR_SESSION_TIMEOUT;
+ }
+ }
+
+ // Time-out decision
+ if (pa_fail || s->SessionTimeOuted)
+ {
+ s->Halt = true;
+ s->RetryFlag = true; // Retry flag
+ break;
+ }
+ }
+
+CLEANUP:
+ Debug("Session %s Finishing...\n", s->Name);
+
+ // Remove from the session list of the HUB
+ if (s->ServerMode)
+ {
+ // Update the user information
+ IncrementUserTraffic(s->Hub, s->UserNameReal, s);
+
+ DelSession(s->Hub, s);
+ }
+
+ s->ConnectSucceed = false;
+ Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);
+
+ if (s->Connection)
+ {
+ s->Connection->Halt = true;
+ }
+
+ // Release the packet adapter
+ if (pa_inited)
+ {
+ pa->Free(s);
+ }
+
+ if (s->ServerMode == false)
+ {
+ // Cancel to make all additional connection
+ StopAllAdditionalConnectThread(s->Connection);
+ }
+
+ if (s->BridgeMode)
+ {
+ // Terminate the bridge
+ if (s->Bridge->Active)
+ {
+ CloseEth(s->Bridge->Eth);
+ s->Bridge->Eth = NULL;
+ }
+ }
+
+ if (s->Cancel2 != NULL)
+ {
+ // Release the Cancel 2
+ ReleaseCancel(s->Cancel2);
+ s->Cancel2 = NULL;
+ }
+
+ // Terminate the connection
+ EndTunnelingMode(c);
+
+ if (nicinfo_sock != NULL)
+ {
+ CncNicInfoFree(nicinfo_sock);
+ }
+
+ if (msgdlg_sock != NULL)
+ {
+ CndMsgDlgFree(msgdlg_sock);
+ }
+
+ c->Err = err;
+}
+
+// Get the time for the next delayed packet
+UINT GetNextDelayedPacketTickDiff(SESSION *s)
+{
+ UINT i;
+ UINT ret = 0x7fffffff;
+ UINT64 now;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return 0;
+ }
+
+ if (LIST_NUM(s->DelayedPacketList) >= 1)
+ {
+ now = TickHighres64();
+
+ LockList(s->DelayedPacketList);
+ {
+ for (i = 0;i < LIST_NUM(s->DelayedPacketList);i++)
+ {
+ PKT *p = LIST_DATA(s->DelayedPacketList, i);
+ UINT64 t = p->DelayedForwardTick;
+ UINT d = 0x7fffffff;
+
+ if (now >= t)
+ {
+ d = 0;
+ }
+ else
+ {
+ d = (UINT)(t - now);
+ }
+
+ ret = MIN(ret, d);
+ }
+ }
+ UnlockList(s->DelayedPacketList);
+ }
+
+ return ret;
+}
+
+// Determine whether the packet have priority in the VoIP / QoS function
+bool IsPriorityHighestPacketForQoS(void *data, UINT size)
+{
+ UCHAR *buf;
+ // Validate arguments
+ if (data == NULL)
+ {
+ return false;
+ }
+
+ buf = (UCHAR *)data;
+ if (size >= 16)
+ {
+ if (buf[12] == 0x08 && buf[13] == 0x00 && buf[15] != 0x00 && buf[15] != 0x08)
+ {
+ // IPv4 packet and ToS != 0
+ return true;
+ }
+
+ if (size >= 34 && size <= 128)
+ {
+ if (buf[12] == 0x08 && buf[13] == 0x00 && buf[23] == 0x01)
+ {
+ // IMCPv4 packet
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+// Update the traffic information of the user
+void IncrementUserTraffic(HUB *hub, char *username, SESSION *s)
+{
+ TRAFFIC report_traffic;
+ // Validate arguments
+ if (hub == NULL || username == NULL || s == NULL)
+ {
+ return;
+ }
+
+ Lock(s->TrafficLock);
+ {
+ // Calculate the traffic information (difference between last time) to be reported
+ report_traffic.Send.BroadcastBytes =
+ s->Traffic->Send.BroadcastBytes - s->OldTraffic->Send.BroadcastBytes;
+ report_traffic.Send.BroadcastCount =
+ s->Traffic->Send.BroadcastCount - s->OldTraffic->Send.BroadcastCount;
+ report_traffic.Send.UnicastBytes =
+ s->Traffic->Send.UnicastBytes - s->OldTraffic->Send.UnicastBytes;
+ report_traffic.Send.UnicastCount =
+ s->Traffic->Send.UnicastCount - s->OldTraffic->Send.UnicastCount;
+ report_traffic.Recv.BroadcastBytes =
+ s->Traffic->Recv.BroadcastBytes - s->OldTraffic->Recv.BroadcastBytes;
+ report_traffic.Recv.BroadcastCount =
+ s->Traffic->Recv.BroadcastCount - s->OldTraffic->Recv.BroadcastCount;
+ report_traffic.Recv.UnicastBytes =
+ s->Traffic->Recv.UnicastBytes - s->OldTraffic->Recv.UnicastBytes;
+ report_traffic.Recv.UnicastCount =
+ s->Traffic->Recv.UnicastCount - s->OldTraffic->Recv.UnicastCount;
+ Copy(s->OldTraffic, s->Traffic, sizeof(TRAFFIC));
+
+ if (hub->FarmMember == false)
+ {
+ // Update the user information in the local database if it is not a farm member
+ AcLock(hub);
+ {
+ USER *u = AcGetUser(hub, username);
+ if (u != NULL)
+ {
+ Lock(u->lock);
+ {
+ AddTraffic(u->Traffic, &report_traffic);
+ }
+ Unlock(u->lock);
+ if (u->Group != NULL)
+ {
+ Lock(u->Group->lock);
+ {
+ AddTraffic(u->Group->Traffic, &report_traffic);
+ }
+ Unlock(u->Group->lock);
+ }
+ ReleaseUser(u);
+ }
+ }
+ AcUnlock(hub);
+ }
+ else
+ {
+ // Update the traffic difference report list in the case of farm member
+ AddTrafficDiff(hub, username, TRAFFIC_DIFF_USER, &report_traffic);
+ }
+ }
+ Unlock(s->TrafficLock);
+}
+
+// Cummulate the traffic information of the connection
+void AddTrafficForSession(SESSION *s, TRAFFIC *t)
+{
+ HUB *h;
+ TRAFFIC t2;
+ // Validate arguments
+ if (s == NULL || t == NULL)
+ {
+ return;
+ }
+
+ Lock(s->TrafficLock);
+ {
+ AddTraffic(s->Traffic, t);
+ }
+ Unlock(s->TrafficLock);
+
+ if (s->ServerMode)
+ {
+ Copy(&t2.Recv, &t->Send, sizeof(TRAFFIC_ENTRY));
+ Copy(&t2.Send, &t->Recv, sizeof(TRAFFIC_ENTRY));
+ Lock(s->Cedar->TrafficLock);
+ {
+ AddTraffic(s->Cedar->Traffic, &t2);
+ }
+ Unlock(s->Cedar->TrafficLock);
+
+ h = s->Hub;
+ Lock(h->TrafficLock);
+ {
+ AddTraffic(h->Traffic, &t2);
+ }
+ Unlock(h->TrafficLock);
+ }
+}
+
+// A chance to establish an additional connection for client
+void ClientAdditionalConnectChance(SESSION *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ if (s->ServerMode)
+ {
+ // Do not connect additionally in the server mode
+ return;
+ }
+ if (s->Connection->Protocol != CONNECTION_TCP)
+ {
+ // Connect additionally only in the case of TCP protocol
+ return;
+ }
+ if (s->IsRUDPSession && s->EnableUdpRecovery == false)
+ {
+ // Do not connect additionally if the UDP recovery is disabled in the case of R-UDP session
+ return;
+ }
+
+ if (s->IsRUDPSession && (s->Connection->AdditionalConnectionFailedCounter > MAX_ADDITONAL_CONNECTION_FAILED_COUNTER))
+ {
+ // Not to make a large amount of repeated connection retry within a certain time in the case of R-UDP session
+ return;
+ }
+
+ while (true)
+ {
+ if (s->Halt)
+ {
+ return;
+ }
+ // Consider whether there is a need to put an additional connection
+ // by examining the number of current connections and MaxConnection property
+ if (Count(s->Connection->CurrentNumConnection) < s->MaxConnection)
+ {
+ // Get the current time
+ UINT64 now = Tick64();
+
+ // Examine the NextConnectionTime, and if the time passed,
+ // attempt to make a connection
+ if (s->NextConnectionTime == 0 ||
+ s->ClientOption->AdditionalConnectionInterval == 0 ||
+ (s->NextConnectionTime <= now))
+ {
+ // Start the work to put an additional connection
+ s->NextConnectionTime = now + (UINT64)(s->ClientOption->AdditionalConnectionInterval * 1000);
+ SessionAdditionalConnect(s);
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+// Release the packet adapter
+void FreePacketAdapter(PACKET_ADAPTER *pa)
+{
+ // Validate arguments
+ if (pa == NULL)
+ {
+ return;
+ }
+
+ Free(pa);
+}
+
+// Create a new packet adapter
+PACKET_ADAPTER *NewPacketAdapter(PA_INIT *init, PA_GETCANCEL *getcancel, PA_GETNEXTPACKET *getnext,
+ PA_PUTPACKET *put, PA_FREE *free)
+{
+ PACKET_ADAPTER *pa;
+ // Validate arguments
+ if (init == NULL || getcancel == NULL || getnext == NULL || put == NULL || free == NULL)
+ {
+ return NULL;
+ }
+
+ pa = ZeroMalloc(sizeof(PACKET_ADAPTER));
+
+ pa->Init = init;
+ pa->Free = free;
+ pa->GetCancel = getcancel;
+ pa->GetNextPacket = getnext;
+ pa->PutPacket = put;
+
+ return pa;
+}
+
+// Thread for putting an additional connection
+void ClientAdditionalThread(THREAD *t, void *param)
+{
+ SESSION *s;
+ CONNECTION *c;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ s = (SESSION *)param;
+
+ s->LastTryAddConnectTime = Tick64();
+
+ c = s->Connection;
+ // Increment of connection counter
+ Inc(c->CurrentNumConnection);
+ LockList(c->ConnectingThreads);
+ {
+ // Add to processing thread
+ Add(c->ConnectingThreads, t);
+ AddRef(t->ref);
+ }
+ UnlockList(c->ConnectingThreads);
+
+ // Notify the completion of initialization
+ NoticeThreadInit(t);
+
+ Debug("Additional Connection #%u\n", Count(c->CurrentNumConnection));
+
+ // Put an additional connection
+ if (ClientAdditionalConnect(c, t) == false)
+ {
+ // Decrement the counter which is currently processing
+ Dec(c->CurrentNumConnection);
+
+ if (c->AdditionalConnectionFailedCounter == 0)
+ {
+ c->LastCounterResetTick = Tick64();
+ }
+
+ c->AdditionalConnectionFailedCounter++;
+
+ if ((c->LastCounterResetTick + (UINT64)ADDITIONAL_CONNECTION_COUNTER_RESET_INTERVAL) <= Tick64())
+ {
+ // Reset the number of failures periodically
+ c->AdditionalConnectionFailedCounter = 0;
+ c->LastCounterResetTick = Tick64();
+ }
+ }
+ else
+ {
+ s->LastTryAddConnectTime = Tick64();
+ c->AdditionalConnectionFailedCounter = 0;
+ c->LastCounterResetTick = Tick64();
+ }
+
+ // Remove from the processing thread
+ LockList(c->ConnectingThreads);
+ {
+ // Remove from the processing thread
+ if (Delete(c->ConnectingThreads, t))
+ {
+ ReleaseThread(t);
+ }
+ }
+ UnlockList(c->ConnectingThreads);
+ ReleaseSession(s);
+}
+
+// Put an additional connection from the client to the server
+void SessionAdditionalConnect(SESSION *s)
+{
+ THREAD *t;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ // s->LastTryAddConnectTime = Tick64();
+
+ AddRef(s->ref);
+ t = NewThread(ClientAdditionalThread, (void *)s);
+ WaitThreadInit(t);
+ ReleaseThread(t);
+}
+
+// Connect the client session to the server
+bool SessionConnect(SESSION *s)
+{
+ CONNECTION *c;
+ bool ret = false;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ s->ClientStatus = CLIENT_STATUS_CONNECTING;
+
+ Debug("SessionConnect() Started.\n");
+
+ // Initialize the session
+ Lock(s->lock);
+ {
+ s->Err = ERR_NO_ERROR;
+ if (s->Policy != NULL)
+ {
+ Free(s->Policy);
+ s->Policy = NULL;
+ }
+ }
+ Unlock(s->lock);
+
+ s->CancelConnect = false;
+
+ // Create a Client Connection
+ c = NewClientConnection(s);
+ s->Connection = c;
+
+ // Connect the client to the server
+ ret = ClientConnect(c);
+ s->Err = c->Err;
+
+ s->CancelConnect = false;
+
+ if (s->Cedar->Client != NULL)
+ {
+ if (s->Policy != NULL)
+ {
+ if (s->Policy->NoSavePassword)
+ {
+ s->Client_NoSavePassword = true;
+
+ if (s->Account != NULL)
+ {
+ Lock(s->Account->lock);
+ {
+ if (s->Account->ClientAuth != NULL)
+ {
+ if (s->Account->ClientAuth->AuthType == AUTHTYPE_PASSWORD ||
+ s->Account->ClientAuth->AuthType == AUTHTYPE_RADIUS)
+ {
+ Zero(s->Account->ClientAuth->HashedPassword, sizeof(s->Account->ClientAuth->HashedPassword));
+ Zero(s->Account->ClientAuth->PlainPassword, sizeof(s->Account->ClientAuth->PlainPassword));
+ }
+ }
+ }
+ Unlock(s->Account->lock);
+
+ CiSaveConfigurationFile(s->Cedar->Client);
+ }
+ }
+ }
+ }
+
+ if (c->ClientConnectError_NoSavePassword)
+ {
+ s->Client_NoSavePassword = true;
+ }
+
+ // Release the client connection
+ s->Connection = NULL;
+ ReleaseConnection(c);
+
+ Lock(s->lock);
+ {
+ if (s->Policy != NULL)
+ {
+ Free(s->Policy);
+ s->Policy = NULL;
+ }
+ }
+ Unlock(s->lock);
+
+ return ret;
+}
+
+// Stop the session
+void StopSession(SESSION *s)
+{
+ StopSessionEx(s, false);
+}
+void StopSessionEx(SESSION *s, bool no_wait)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ // Halting flag
+ s->UserCanceled = true;
+ s->CancelConnect = true;
+ s->Halt = true;
+
+ Debug("Stop Session %s\n", s->Name);
+
+ // Cancel
+ Cancel(s->Cancel1);
+
+ // Event
+ Set(s->HaltEvent);
+
+ if (s->ServerMode == false)
+ {
+ // Client mode
+ if (s->Connection)
+ {
+ StopConnection(s->Connection, no_wait);
+ }
+ }
+ else
+ {
+ // Server mode
+ if (s->Connection)
+ {
+ StopConnection(s->Connection, no_wait);
+ }
+ }
+
+ // Wait until the stop
+ if (no_wait == false)
+ {
+ while (true)
+ {
+ s->ForceStopFlag = true;
+ s->Halt = true;
+ if (WaitThread(s->Thread, 20))
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ s->ForceStopFlag = true;
+ s->Halt = true;
+ }
+}
+
+// Cleanup the session
+void CleanupSession(SESSION *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ // Release the delayed packet list
+ if (s->DelayedPacketList != NULL)
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(s->DelayedPacketList);i++)
+ {
+ PKT *p = LIST_DATA(s->DelayedPacketList, i);
+
+ Free(p->PacketData);
+ FreePacket(p);
+ }
+
+ ReleaseList(s->DelayedPacketList);
+ }
+
+ // Release the client connection options
+ if (s->ClientOption != NULL)
+ {
+ Free(s->ClientOption);
+ }
+
+ // Release the client authentication data
+ if (s->ClientAuth != NULL)
+ {
+ if (s->ClientAuth->ClientX != NULL)
+ {
+ FreeX(s->ClientAuth->ClientX);
+ }
+ if (s->ClientAuth->ClientX != NULL)
+ {
+ FreeK(s->ClientAuth->ClientK);
+ }
+ Free(s->ClientAuth);
+ }
+
+ FreeTraffic(s->Traffic);
+ Free(s->Name);
+
+ if (s->Thread != NULL)
+ {
+ ReleaseThread(s->Thread);
+ }
+
+ DeleteLock(s->lock);
+
+ ReleaseEvent(s->HaltEvent);
+
+ if (s->Cancel1)
+ {
+ ReleaseCancel(s->Cancel1);
+ }
+
+ if (s->Cancel2)
+ {
+ ReleaseCancel(s->Cancel2);
+ }
+
+ if (s->Policy)
+ {
+ Free(s->Policy);
+ }
+
+ if (s->Connection)
+ {
+ ReleaseConnection(s->Connection);
+ }
+
+ Free(s->Username);
+
+ if (s->PacketAdapter)
+ {
+ FreePacketAdapter(s->PacketAdapter);
+ }
+
+ if (s->OldTraffic != NULL)
+ {
+ FreeTraffic(s->OldTraffic);
+ }
+
+ DeleteLock(s->TrafficLock);
+
+ if (s->CancelList != NULL)
+ {
+ ReleaseCancelList(s->CancelList);
+ }
+
+ if (s->Client_Message != NULL)
+ {
+ Free(s->Client_Message);
+ }
+
+ DeleteCounter(s->LoggingRecordCount);
+
+ Free(s);
+}
+
+// Release the session
+void ReleaseSession(SESSION *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ if (Release(s->ref) == 0)
+ {
+ CleanupSession(s);
+ }
+}
+
+// Display the total data transfer size of the session
+void PrintSessionTotalDataSize(SESSION *s)
+{
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ Debug(
+ "-- SESSION TOTAL PKT INFORMATION --\n\n"
+ " TotalSendSize: %I64u\n"
+ " TotalSendSizeReal: %I64u\n"
+ " TotalRecvSize: %I64u\n"
+ " TotalRecvSizeReal: %I64u\n"
+ " Compression Rate: %.2f%% (Send)\n"
+ " %.2f%% (Recv)\n",
+ s->TotalSendSize, s->TotalSendSizeReal,
+ s->TotalRecvSize, s->TotalRecvSizeReal,
+ (float)((double)s->TotalSendSizeReal / (double)s->TotalSendSize * 100.0f),
+ (float)((double)s->TotalRecvSizeReal / (double)s->TotalRecvSize * 100.0f)
+ );
+
+}
+
+// Client thread
+void ClientThread(THREAD *t, void *param)
+{
+ SESSION *s;
+ bool use_password_dlg;
+ bool no_save_password = false;
+ bool is_vpngate_connection = false;
+ CEDAR *cedar;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ CiIncrementNumActiveSessions();
+
+ Debug("ClientThread 0x%x Started.\n", t);
+
+ s = (SESSION *)param;
+ AddRef(s->ref);
+ s->Thread = t;
+ AddRef(t->ref);
+ NoticeThreadInit(t);
+
+ cedar = s->Cedar;
+
+ s->ClientStatus = CLIENT_STATUS_CONNECTING;
+ s->RetryFlag = true;
+ s->CurrentRetryCount = 0;
+
+ Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);
+
+ if (s->Cedar->Client != NULL)
+ {
+ no_save_password = s->Cedar->Client->DontSavePassword;
+ }
+
+ s->Win32HideConnectWindow = s->ClientOption->HideStatusWindow;
+ s->Win32HideNicInfoWindow = s->ClientOption->HideNicInfoWindow;
+
+
+ while (true)
+ {
+ CLog(s->Cedar->Client, "LC_CONNECT_1", s->ClientOption->AccountName, s->CurrentRetryCount + 1);
+ if (s->LinkModeClient && s->Link != NULL)
+ {
+ HLog(s->Link->Hub, "LH_CONNECT_1", s->ClientOption->AccountName, s->CurrentRetryCount + 1);
+ }
+
+ Debug("Trying to Connect to Server... (%u / %u)\n", s->CurrentRetryCount + 0,
+ s->ClientOption->NumRetry);
+
+ // Initialize
+// s->TotalRecvSize = s->TotalRecvSizeReal =
+// s->TotalSendSize = s->TotalSendSizeReal = 0;
+ s->NextConnectionTime = 0;
+
+ // Connect
+ s->ClientStatus = CLIENT_STATUS_CONNECTING;
+ s->Halt = false;
+ SessionConnect(s);
+ if (s->UserCanceled)
+ {
+ s->Err = ERR_USER_CANCEL;
+ }
+ Debug("Disconnected. Err = %u : %S\n", s->Err, _E(s->Err));
+
+ PrintSessionTotalDataSize(s);
+
+ CLog(s->Cedar->Client, "LC_CONNECT_ERROR", s->ClientOption->AccountName,
+ GetUniErrorStr(s->Err), s->Err);
+
+ if (s->LinkModeClient && s->Link != NULL)
+ {
+ HLog(s->Link->Hub, "LH_CONNECT_ERROR", s->ClientOption->AccountName,
+ GetUniErrorStr(s->Err), s->Err);
+ }
+
+ s->ClientStatus = CLIENT_STATUS_RETRY;
+
+ if (s->Link != NULL)
+ {
+ ((LINK *)s->Link)->LastError = s->Err;
+ }
+
+ if (s->Halt && (s->RetryFlag == false) || s->ForceStopFlag)
+ {
+ // Must be aborted
+ if (s->Err == ERR_DEVICE_DRIVER_ERROR)
+ {
+#ifdef OS_WIN32
+ wchar_t tmp[MAX_SIZE];
+ if (s->Account != NULL && s->Cedar->Client != NULL)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("ERRDLG_DEVICE_ERROR"), s->ClientOption->DeviceName,
+ s->Err, _E(s->Err));
+ MsgBox(NULL, 0x10000 | 0x40000 | 0x200000 | 0x30, tmp);
+ }
+#endif // OS_WIN32
+ }
+ break;
+ }
+ // Determine whether to display the password re-entry dialog
+ use_password_dlg = false;
+
+ if (s->Account != NULL && s->Cedar->Client != NULL)
+ {
+#ifdef OS_WIN32
+ if (s->ClientAuth->AuthType == CLIENT_AUTHTYPE_PASSWORD || s->ClientAuth->AuthType == CLIENT_AUTHTYPE_PLAIN_PASSWORD)
+ {
+ if (s->Err == ERR_AUTH_FAILED || s->Err == ERR_PROXY_AUTH_FAILED)
+ {
+ use_password_dlg = true;
+ }
+ }
+#endif // OS_WIN32
+ }
+
+ // Failed to connect or the connection is disconnected
+ // Wait for retry interval
+ if (use_password_dlg == false)
+ {
+ UINT retry_interval = s->RetryInterval;
+
+ if (s->Err == ERR_HUB_IS_BUSY || s->Err == ERR_LICENSE_ERROR ||
+ s->Err == ERR_HUB_STOPPING || s->Err == ERR_TOO_MANY_USER_SESSION)
+ {
+ retry_interval = RETRY_INTERVAL_SPECIAL;
+ }
+
+ if (s->CurrentRetryCount >= s->ClientOption->NumRetry)
+ {
+ // Retry count excess
+
+#ifndef OS_WIN32
+
+ break;
+
+#else // OS_WIN32
+
+ if (s->Win32HideConnectWindow == false &&
+ s->Cedar->Client != NULL && s->Account != NULL)
+ {
+ // Show a reconnection dialog
+ UI_CONNECTERROR_DLG p;
+ Zero(&p, sizeof(p));
+ UniStrCpy(p.AccountName, sizeof(p.AccountName), s->ClientOption->AccountName);
+ StrCpy(p.ServerName, sizeof(p.ServerName), s->ClientOption->Hostname);
+ p.Err = s->Err;
+ p.CurrentRetryCount = s->CurrentRetryCount + 1;
+ s->Halt = false;
+ p.RetryLimit = 0;
+ p.RetryIntervalSec = 0;
+ p.CancelEvent = s->HaltEvent;
+ p.HideWindow = s->Win32HideConnectWindow;
+ if (CncConnectErrorDlg(s, &p) == false)
+ {
+ // Abort
+ break;
+ }
+ else
+ {
+ s->Win32HideConnectWindow = p.HideWindow;
+ goto SKIP;
+ }
+ }
+ else
+ {
+ break;
+ }
+
+#endif
+ }
+
+#ifndef OS_WIN32
+
+ // Simple wait
+ Wait(s->HaltEvent, retry_interval);
+
+#else // OS_WIN32
+
+ if (s->Win32HideConnectWindow == false &&
+ s->Cedar->Client != NULL && s->Account != NULL)
+ {
+ // Show a reconnection dialog
+ UI_CONNECTERROR_DLG p;
+ Zero(&p, sizeof(p));
+ UniStrCpy(p.AccountName, sizeof(p.AccountName), s->ClientOption->AccountName);
+ StrCpy(p.ServerName, sizeof(p.ServerName), s->ClientOption->Hostname);
+ p.Err = s->Err;
+ p.CurrentRetryCount = s->CurrentRetryCount + 1;
+ p.RetryLimit = s->ClientOption->NumRetry;
+ p.RetryIntervalSec = retry_interval;
+ p.CancelEvent = s->HaltEvent;
+ s->Halt = false;
+ p.HideWindow = s->Win32HideConnectWindow;
+ if (CncConnectErrorDlg(s, &p) == false)
+ {
+ // Abort
+ break;
+ }
+ s->Win32HideConnectWindow = p.HideWindow;
+ }
+ else
+ {
+ // Simple wait
+ Wait(s->HaltEvent, s->RetryInterval);
+ }
+
+#endif // OS_WIN32
+ }
+ else
+ {
+#ifdef OS_WIN32
+ // Wait for re-entry the password
+ UI_PASSWORD_DLG p;
+ Zero(&p, sizeof(p));
+ if (s->Client_NoSavePassword == false)
+ {
+ p.ShowNoSavePassword = true;
+ }
+ p.NoSavePassword = no_save_password;
+ p.CancelEvent = s->HaltEvent;
+ if (s->Err == ERR_PROXY_AUTH_FAILED)
+ {
+ p.ProxyServer = true;
+ }
+
+ if (p.ProxyServer)
+ {
+ StrCpy(p.Username, sizeof(p.Username), s->ClientOption->ProxyUsername);
+ StrCpy(p.Password, sizeof(p.Password), s->ClientOption->ProxyPassword);
+ StrCpy(p.ServerName, sizeof(p.ServerName), s->ClientOption->ProxyName);
+ }
+ else
+ {
+ bool empty = false;
+
+ StrCpy(p.Username, sizeof(p.Username), s->ClientAuth->Username);
+ if (s->ClientAuth->AuthType == AUTHTYPE_RADIUS)
+ {
+ if (StrLen(s->ClientAuth->PlainPassword) == 0)
+ {
+ empty = true;
+ }
+ }
+ else if (s->ClientAuth->AuthType == AUTHTYPE_PASSWORD)
+ {
+ if (IsZero(s->ClientAuth->HashedPassword, sizeof(s->ClientAuth->HashedPassword)))
+ {
+ empty = true;
+ }
+ }
+
+ StrCpy(p.Password, sizeof(p.Password), empty ? "" : HIDDEN_PASSWORD);
+ StrCpy(p.ServerName, sizeof(p.ServerName), s->ClientOption->Hostname);
+ }
+
+ p.RetryIntervalSec = s->RetryInterval / 1000;
+ p.Type = s->ClientAuth->AuthType;
+
+ // Display the password re-entry dialog
+ if (CncPasswordDlg(s, &p) == false)
+ {
+ // Abort the connection
+ break;
+ }
+ else
+ {
+ // Overwrite the user name
+ if (p.ProxyServer)
+ {
+ // User name of the proxy
+ StrCpy(s->ClientOption->ProxyUsername, sizeof(s->ClientOption->ProxyUsername), p.Username);
+ }
+ else
+ {
+ // The user name for connecting to the server
+ StrCpy(s->ClientAuth->Username, sizeof(s->ClientAuth->Username), p.Username);
+ s->ClientAuth->AuthType = p.Type;
+ }
+
+ if (StrCmp(p.Password, HIDDEN_PASSWORD) != 0)
+ {
+ // Password is re-entered
+ if (p.ProxyServer)
+ {
+ // Password for the proxy server
+ StrCpy(s->ClientOption->ProxyPassword, sizeof(s->ClientOption->ProxyPassword), p.Password);
+ }
+ else
+ {
+ if (s->ClientAuth->AuthType == CLIENT_AUTHTYPE_PLAIN_PASSWORD)
+ {
+ // Plaintext password authentication
+ StrCpy(s->ClientAuth->PlainPassword, sizeof(s->ClientAuth->PlainPassword), p.Password);
+ }
+ else
+ {
+ // Encrypted password authentication
+ HashPassword(s->ClientAuth->HashedPassword, s->ClientAuth->Username, p.Password);
+ }
+ }
+ }
+
+ no_save_password = p.NoSavePassword;
+
+ if (s->Account != NULL && s->Cedar->Client != NULL)
+ {
+ s->Cedar->Client->DontSavePassword = no_save_password;
+ if (p.NoSavePassword == false)
+ {
+ // Update the account database of the client
+ if (p.ProxyServer == false)
+ {
+ // Update the Server connection information
+ ACCOUNT *a = s->Account;
+ Lock(a->lock);
+ {
+ CiFreeClientAuth(a->ClientAuth);
+ a->ClientAuth = CopyClientAuth(s->ClientAuth);
+ }
+ Unlock(a->lock);
+ CiSaveConfigurationFile(s->Cedar->Client);
+ }
+ else
+ {
+ // Update the proxy connection information
+ ACCOUNT *a = s->Account;
+ Lock(a->lock);
+ {
+ Copy(a->ClientOption, s->ClientOption, sizeof(CLIENT_OPTION));
+ }
+ Unlock(a->lock);
+ CiSaveConfigurationFile(s->Cedar->Client);
+ }
+ }
+ }
+ }
+#endif // OS_WIN32
+ }
+
+SKIP:
+ // Increase the number of retries
+ if (s->ConnectSucceed == false)
+ {
+ s->CurrentRetryCount++;
+ }
+
+ if (s->ForceStopFlag)
+ {
+ break;
+ }
+ }
+
+ Debug("Session Halt.\n");
+
+ s->ClientStatus = CLIENT_STATUS_IDLE;
+
+ // Regard as that the session is ended here
+ if (s->Account != NULL)
+ {
+ s->Account->ClientSession = NULL;
+ ReleaseSession(s);
+ }
+
+ Notify(s, CLIENT_NOTIFY_ACCOUNT_CHANGED);
+
+
+ ReleaseSession(s);
+
+ CiDecrementNumActiveSessions();
+}
+
+// Name comparison of sessions
+int CompareSession(void *p1, void *p2)
+{
+ SESSION *s1, *s2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ s1 = *(SESSION **)p1;
+ s2 = *(SESSION **)p2;
+ if (s1 == NULL || s2 == NULL)
+ {
+ return 0;
+ }
+ return StrCmpi(s1->Name, s2->Name);
+}
+
+// Create an RPC session
+SESSION *NewRpcSession(CEDAR *cedar, CLIENT_OPTION *option)
+{
+ return NewRpcSessionEx(cedar, option, NULL, NULL);
+}
+SESSION *NewRpcSessionEx(CEDAR *cedar, CLIENT_OPTION *option, UINT *err, char *client_str)
+{
+ return NewRpcSessionEx2(cedar, option, err, client_str, NULL);
+}
+SESSION *NewRpcSessionEx2(CEDAR *cedar, CLIENT_OPTION *option, UINT *err, char *client_str, void *hWnd)
+{
+ SESSION *s;
+ CONNECTION *c;
+ SOCK *sock;
+ // Validate arguments
+ if (cedar == NULL || option == NULL)
+ {
+ return NULL;
+ }
+
+ s = ZeroMalloc(sizeof(SESSION));
+
+ s->LoggingRecordCount = NewCounter();
+ s->lock = NewLock();
+ s->ref = NewRef();
+ s->Cedar = cedar;
+ s->ServerMode = false;
+ s->Name = CopyStr("CLIENT_RPC_SESSION");
+ s->CreatedTime = s->LastCommTime = Tick64();
+ s->Traffic = NewTraffic();
+ s->HaltEvent = NewEvent();
+ s->TrafficLock = NewLock();
+ s->Cancel1 = NewCancel();
+
+ // Copy the client connection options
+ s->ClientOption = Malloc(sizeof(CLIENT_OPTION));
+ Copy(s->ClientOption, option, sizeof(CLIENT_OPTION));
+
+ s->MaxConnection = option->MaxConnection;
+ s->UseEncrypt = option->UseEncrypt;
+ s->UseCompress = option->UseCompress;
+
+ // Create a connection
+ c = s->Connection = NewClientConnectionEx(s, client_str, cedar->Version, cedar->Build);
+ c->hWndForUI = hWnd;
+
+ // Connect to the server
+ sock = ClientConnectToServer(c);
+ if (sock == NULL)
+ {
+ // Connection failure
+ if (err != NULL)
+ {
+ *err = c->Err;
+ }
+ ReleaseSession(s);
+ return NULL;
+ }
+
+ // Send a signature
+ if (ClientUploadSignature(sock) == false)
+ {
+ // Failure
+ if (err != NULL)
+ {
+ *err = c->Err;
+ }
+ ReleaseSession(s);
+ return NULL;
+ }
+
+ // Receive a Hello packet
+ if (ClientDownloadHello(c, sock) == false)
+ {
+ // Failure
+ if (err != NULL)
+ {
+ *err = c->Err;
+ }
+ ReleaseSession(s);
+ return NULL;
+ }
+
+ return s;
+}
+
+// Create a client session
+SESSION *NewClientSessionEx(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, PACKET_ADAPTER *pa, ACCOUNT *account)
+{
+ SESSION *s;
+ THREAD *t;
+ // Validate arguments
+ if (cedar == NULL || option == NULL || auth == NULL || pa == NULL ||
+ (auth->AuthType == CLIENT_AUTHTYPE_SECURE && auth->SecureSignProc == NULL))
+ {
+ return NULL;
+ }
+
+ // Initialize the SESSION object
+ s = ZeroMalloc(sizeof(SESSION));
+
+ s->LoggingRecordCount = NewCounter();
+
+ s->lock = NewLock();
+ s->ref = NewRef();
+ s->Cedar = cedar;
+ s->ServerMode = false;
+ s->Name = CopyStr("CLIENT_SESSION");
+ s->CreatedTime = s->LastCommTime = Tick64();
+ s->Traffic = NewTraffic();
+ s->HaltEvent = NewEvent();
+ s->PacketAdapter = pa;
+ s->TrafficLock = NewLock();
+ s->OldTraffic = NewTraffic();
+ s->Cancel1 = NewCancel();
+ s->CancelList = NewCancelList();
+
+ // Copy the client connection options
+ s->ClientOption = Malloc(sizeof(CLIENT_OPTION));
+ Copy(s->ClientOption, option, sizeof(CLIENT_OPTION));
+
+ s->MaxConnection = option->MaxConnection;
+ s->UseEncrypt = option->UseEncrypt;
+ s->UseCompress = option->UseCompress;
+
+ // Set the retry interval
+ s->RetryInterval = MAKESURE(option->RetryInterval, 0, 4000000) * 1000;
+ s->RetryInterval = MAKESURE(s->RetryInterval, MIN_RETRY_INTERVAL, MAX_RETRY_INTERVAL);
+
+ // Interval for additional connection creation is at least 1 second
+ s->ClientOption->AdditionalConnectionInterval = MAX(s->ClientOption->AdditionalConnectionInterval, 1);
+
+ // Hold whether the virtual LAN card is used in client mode
+ s->ClientModeAndUseVLan = (StrLen(s->ClientOption->DeviceName) == 0) ? false : true;
+ if (s->ClientOption->NoRoutingTracking)
+ {
+ s->ClientModeAndUseVLan = false;
+ }
+
+ if (StrLen(option->DeviceName) == 0)
+ {
+ // NAT mode
+ s->ClientModeAndUseVLan = false;
+ s->VirtualHost = true;
+ }
+
+ if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType))
+ {
+ // Prohibit the half-duplex mode in the case of Win9x
+ s->ClientOption->HalfConnection = false;
+ }
+
+ // Copy the client authentication data
+ s->ClientAuth = Malloc(sizeof(CLIENT_AUTH));
+ Copy(s->ClientAuth, auth, sizeof(CLIENT_AUTH));
+
+ // Clone the certificate and the private key
+ if (s->ClientAuth->ClientX != NULL)
+ {
+ s->ClientAuth->ClientX = CloneX(s->ClientAuth->ClientX);
+ }
+ if (s->ClientAuth->ClientK != NULL)
+ {
+ s->ClientAuth->ClientK = CloneK(s->ClientAuth->ClientK);
+ }
+
+ if (StrCmpi(s->ClientOption->DeviceName, LINK_DEVICE_NAME) == 0)
+ {
+ // Link client mode
+ s->LinkModeClient = true;
+ s->Link = (LINK *)s->PacketAdapter->Param;
+ }
+
+ if (StrCmpi(s->ClientOption->DeviceName, SNAT_DEVICE_NAME) == 0)
+ {
+ // SecureNAT mode
+ s->SecureNATMode = true;
+ }
+
+ if (StrCmpi(s->ClientOption->DeviceName, BRIDGE_DEVICE_NAME) == 0)
+ {
+ // Bridge mode
+ s->BridgeMode = true;
+ }
+
+ if (s->VirtualHost)
+ {
+ VH *v = (VH *)s->PacketAdapter->Param;
+
+ // Add the session object to VH
+ v->Session = s;
+ AddRef(s->ref);
+ }
+
+ s->Account = account;
+
+ if (s->ClientAuth->AuthType == CLIENT_AUTHTYPE_SECURE)
+ {
+ // Do not retry in the case of a smart card authentication
+ s->ClientOption->NumRetry = 0;
+ }
+
+ // Create a client thread
+ t = NewThread(ClientThread, (void *)s);
+ WaitThreadInit(t);
+ ReleaseThread(t);
+
+ return s;
+}
+SESSION *NewClientSession(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, PACKET_ADAPTER *pa)
+{
+ return NewClientSessionEx(cedar, option, auth, pa, NULL);
+}
+
+// Get the session from the 32bit session key
+SESSION *GetSessionFromKey32(CEDAR *cedar, UINT key32)
+{
+ HUB *h;
+ UINT i, j;
+ // Validate arguments
+ if (cedar == NULL)
+ {
+ return NULL;
+ }
+
+ LockList(cedar->HubList);
+ {
+ for (i = 0;i < LIST_NUM(cedar->HubList);i++)
+ {
+ h = LIST_DATA(cedar->HubList, i);
+ LockList(h->SessionList);
+ {
+ for (j = 0;j < LIST_NUM(h->SessionList);j++)
+ {
+ SESSION *s = LIST_DATA(h->SessionList, j);
+ Lock(s->lock);
+ {
+ if (s->SessionKey32 == key32)
+ {
+ // Session found
+ AddRef(s->ref);
+
+ // Unlock
+ Unlock(s->lock);
+ UnlockList(h->SessionList);
+ UnlockList(cedar->HubList);
+ return s;
+ }
+ }
+ Unlock(s->lock);
+ }
+ }
+ UnlockList(h->SessionList);
+ }
+ }
+ UnlockList(cedar->HubList);
+
+ return NULL;
+}
+
+// Get the session from the session key
+SESSION *GetSessionFromKey(CEDAR *cedar, UCHAR *session_key)
+{
+ HUB *h;
+ UINT i, j;
+ // Validate arguments
+ if (cedar == NULL || session_key == NULL)
+ {
+ return NULL;
+ }
+
+ LockList(cedar->HubList);
+ {
+ for (i = 0;i < LIST_NUM(cedar->HubList);i++)
+ {
+ h = LIST_DATA(cedar->HubList, i);
+ LockList(h->SessionList);
+ {
+ for (j = 0;j < LIST_NUM(h->SessionList);j++)
+ {
+ SESSION *s = LIST_DATA(h->SessionList, j);
+ Lock(s->lock);
+ {
+ if (Cmp(s->SessionKey, session_key, SHA1_SIZE) == 0)
+ {
+ // Session found
+ AddRef(s->ref);
+
+ // Unlock
+ Unlock(s->lock);
+ UnlockList(h->SessionList);
+ UnlockList(cedar->HubList);
+ return s;
+ }
+ }
+ Unlock(s->lock);
+ }
+ }
+ UnlockList(h->SessionList);
+ }
+ }
+ UnlockList(cedar->HubList);
+
+ return NULL;
+}
+
+// Create a new session key
+void NewSessionKey(CEDAR *cedar, UCHAR *session_key, UINT *session_key_32)
+{
+ // Validate arguments
+ if (cedar == NULL || session_key == NULL || session_key_32 == NULL)
+ {
+ return;
+ }
+
+ Rand(session_key, SHA1_SIZE);
+ *session_key_32 = Rand32();
+}
+
+bool if_init(SESSION *s);
+CANCEL *if_getcancel(SESSION *s);
+UINT if_getnext(SESSION *s, void **data);
+bool if_putpacket(SESSION *s, void *data, UINT size);
+void if_free(SESSION *s);
+
+
+// Create a server session
+SESSION *NewServerSession(CEDAR *cedar, CONNECTION *c, HUB *h, char *username, POLICY *policy)
+{
+ return NewServerSessionEx(cedar, c, h, username, policy, false);
+}
+SESSION *NewServerSessionEx(CEDAR *cedar, CONNECTION *c, HUB *h, char *username, POLICY *policy, bool inproc_mode)
+{
+ SESSION *s;
+ char name[MAX_SIZE];
+ char hub_name_upper[MAX_SIZE];
+ char user_name_upper[MAX_USERNAME_LEN + 1];
+ // Validate arguments
+ if (cedar == NULL || c == NULL || h == NULL || username == NULL || policy == NULL)
+ {
+ return NULL;
+ }
+
+ // Initialize the SESSION object
+ s = ZeroMalloc(sizeof(SESSION));
+
+ s->LoggingRecordCount = NewCounter();
+ s->lock = NewLock();
+ s->ref = NewRef();
+ s->Cedar = cedar;
+ s->ServerMode = true;
+ s->CreatedTime = s->LastCommTime = Tick64();
+ s->Traffic = NewTraffic();
+ s->HaltEvent = NewEvent();
+ s->Cancel1 = NewCancel();
+ s->CancelList = NewCancelList();
+ s->Thread = c->Thread;
+ s->TrafficLock = NewLock();
+ s->OldTraffic = NewTraffic();
+ s->QoS = GetServerCapsBool(cedar->Server, "b_support_qos");
+ AddRef(s->Thread->ref);
+ s->Hub = h;
+ s->ClientStatus = CLIENT_STATUS_ESTABLISHED;
+
+ // Delayed packet list
+ s->DelayedPacketList = NewList(NULL);
+
+ // Packet adapter for the HUB
+ s->PacketAdapter = GetHubPacketAdapter();
+
+ s->Connection = c;
+ AddRef(c->ref);
+
+ // Determine the new session name
+ StrCpy(hub_name_upper, sizeof(hub_name_upper), h->Name);
+ StrUpper(hub_name_upper);
+ StrCpy(user_name_upper, sizeof(user_name_upper), username);
+ StrUpper(user_name_upper);
+
+ if ((StrCmpi(username, ADMINISTRATOR_USERNAME) != 0) && (StrCmpi(username, BRIDGE_USER_NAME) != 0) || (cedar->Server == NULL || cedar->Server->ServerType == SERVER_TYPE_STANDALONE))
+ {
+ if (IsEmptyStr(c->InProcPrefix))
+ {
+ Format(name, sizeof(name), "SID-%s-%u", user_name_upper, Inc(h->SessionCounter));
+ }
+ else
+ {
+ Format(name, sizeof(name), "SID-%s-[%s]-%u", user_name_upper, c->InProcPrefix, Inc(h->SessionCounter));
+ }
+ }
+ else
+ {
+ UCHAR rand[SHA1_SIZE];
+ char tmp[MAX_SIZE];
+ Rand(rand, sizeof(rand));
+ BinToStr(tmp, sizeof(tmp), rand, 3);
+
+ if (StrCmpi(username, BRIDGE_USER_NAME) != 0)
+ {
+ Format(name, sizeof(name), "SID-%s-%s", user_name_upper,
+ tmp);
+ }
+ else
+ {
+ char pc_name[MAX_SIZE];
+ TOKEN_LIST *t;
+
+ GetMachineName(tmp, sizeof(tmp));
+ t = ParseToken(tmp, ".");
+ if (t->NumTokens >= 1)
+ {
+ StrCpy(pc_name, sizeof(pc_name), t->Token[0]);
+ }
+ else
+ {
+ StrCpy(pc_name, sizeof(pc_name), "pc");
+ }
+ FreeToken(t);
+
+ StrUpper(pc_name);
+
+ Format(name, sizeof(name), "SID-%s-%s-%u", user_name_upper, pc_name,
+ Inc(h->SessionCounter));
+ }
+ }
+
+ s->Name = CopyStr(name);
+ s->Policy = policy;
+ s->InProcMode = inproc_mode;
+
+ // Add a SESSION to the HUB
+ AddSession(h, s);
+
+ // Create a key
+ NewSessionKey(cedar, s->SessionKey, &s->SessionKey32);
+
+ // Generate a MAC address for IPC
+ if (s->InProcMode)
+ {
+ char tmp[MAX_SIZE];
+ char machine[MAX_SIZE];
+ UCHAR hash[SHA1_SIZE];
+
+ GetMachineName(machine, sizeof(machine));
+
+ Format(tmp, sizeof(tmp), "%s@%s@%u", machine, h->Name, s->UniqueId);
+
+ StrUpper(tmp);
+ Trim(tmp);
+
+ Hash(hash, tmp, StrLen(tmp), true);
+
+ s->IpcMacAddress[0] = 0xCA;
+ s->IpcMacAddress[1] = hash[1];
+ s->IpcMacAddress[2] = hash[2];
+ s->IpcMacAddress[3] = hash[3];
+ s->IpcMacAddress[4] = hash[4];
+ s->IpcMacAddress[5] = hash[5];
+
+ MacToStr(tmp, sizeof(tmp), s->IpcMacAddress);
+ Debug("MAC Address for IPC: %s\n", tmp);
+ }
+
+ return s;
+}
+
+// Display the session key for debugging
+void DebugPrintSessionKey(UCHAR *session_key)
+{
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (session_key == NULL)
+ {
+ return;
+ }
+
+ Bit160ToStr(tmp, session_key);
+ Debug("SessionKey: %s\n", tmp);
+}
+
+// Display the status on the client
+void PrintStatus(SESSION *s, wchar_t *str)
+{
+ // Validate arguments
+ if (s == NULL || str == NULL || s->Account == NULL || s->Cedar->Client == NULL
+ || s->Account->StatusPrinter == NULL)
+ {
+ return;
+ }
+
+ // Inform the status to the callback function
+ s->Account->StatusPrinter(s, str);
+}
+
+// Create a cancellation list
+LIST *NewCancelList()
+{
+ return NewList(NULL);
+}
+
+// Add a Cancel to the cancellation list
+void AddCancelList(LIST *o, CANCEL *c)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL || c == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ CANCEL *t = LIST_DATA(o, i);
+ if (t == c)
+ {
+ return;
+ }
+ }
+
+ AddRef(c->ref);
+ Add(o, c);
+}
+
+// Issue all cancellations in the cancellation list
+void CancelList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ CANCEL *c = LIST_DATA(o, i);
+ Cancel(c);
+ ReleaseCancel(c);
+ }
+
+ DeleteAll(o);
+}
+
+// Release the cancellation list
+void ReleaseCancelList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ CANCEL *c = LIST_DATA(o, i);
+ ReleaseCancel(c);
+ }
+
+ ReleaseList(o);
+}
+
+// Notify to the client
+void Notify(SESSION *s, UINT code)
+{
+ // Validate arguments
+ if (s == NULL || s->Account == NULL || s->Cedar->Client == NULL)
+ {
+ return;
+ }
+
+ CiNotify(s->Cedar->Client);
+}
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Session.h b/src/Cedar/Session.h
new file mode 100644
index 00000000..1214604f
--- /dev/null
+++ b/src/Cedar/Session.h
@@ -0,0 +1,408 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Session.h
+// Header of Session.c
+
+#ifndef SESSION_H
+#define SESSION_H
+
+
+// Interval to increment the number of logins after the connection
+#define NUM_LOGIN_INCREMENT_INTERVAL (30 * 1000)
+
+// Packet adapter function
+typedef bool (PA_INIT)(SESSION *s);
+typedef CANCEL *(PA_GETCANCEL)(SESSION *s);
+typedef UINT (PA_GETNEXTPACKET)(SESSION *s, void **data);
+typedef bool (PA_PUTPACKET)(SESSION *s, void *data, UINT size);
+typedef void (PA_FREE)(SESSION *s);
+
+// Client related function
+typedef void (CLIENT_STATUS_PRINTER)(SESSION *s, wchar_t *status);
+
+// Node information
+struct NODE_INFO
+{
+ char ClientProductName[64]; // Client product name
+ UINT ClientProductVer; // Client version
+ UINT ClientProductBuild; // Client build number
+ char ServerProductName[64]; // Server product name
+ UINT ServerProductVer; // Server version
+ UINT ServerProductBuild; // Server build number
+ char ClientOsName[64]; // Client OS name
+ char ClientOsVer[128]; // Client OS version
+ char ClientOsProductId[64]; // Client OS Product ID
+ char ClientHostname[64]; // Client host name
+ UINT ClientIpAddress; // Client IP address
+ UINT ClientPort; // Client port number
+ char ServerHostname[64]; // Server host name
+ UINT ServerIpAddress; // Server IP address
+ UINT ServerPort; // Server port number
+ char ProxyHostname[64]; // Proxy host name
+ UINT ProxyIpAddress; // Proxy Server IP Address
+ UINT ProxyPort; // Proxy port number
+ char HubName[64]; // HUB name
+ UCHAR UniqueId[16]; // Unique ID
+ // The following is for IPv6 support
+ UCHAR ClientIpAddress6[16]; // Client IPv6 address
+ UCHAR ServerIpAddress6[16]; // Server IP address
+ UCHAR ProxyIpAddress6[16]; // Proxy Server IP Address
+ char Padding[304 - (16 * 3)]; // Padding
+};
+
+// Packet adapter
+struct PACKET_ADAPTER
+{
+ PA_INIT *Init;
+ PA_GETCANCEL *GetCancel;
+ PA_GETNEXTPACKET *GetNextPacket;
+ PA_PUTPACKET *PutPacket;
+ PA_FREE *Free;
+ void *Param;
+};
+
+// Session structure
+struct SESSION
+{
+ LOCK *lock; // Lock
+ REF *ref; // Reference counter
+ CEDAR *Cedar; // Cedar
+ bool LocalHostSession; // Local host session
+ bool ServerMode; // Server mode session
+ bool NormalClient; // Connecting session from a regular client (not such as localbridge)
+ bool LinkModeClient; // Link mode client
+ bool LinkModeServer; // Link mode server
+ bool SecureNATMode; // SecureNAT session
+ bool BridgeMode; // Bridge session
+ bool BridgeIsEthLoopbackBlock; // Loopback is disabled on the Ethernet level
+ bool VirtualHost; // Virtual host mode
+ bool L3SwitchMode; // Layer-3 switch mode
+ bool InProcMode; // In-process mode
+ THREAD *Thread; // Management thread
+ CONNECTION *Connection; // Connection
+ CLIENT_OPTION *ClientOption; // Client connection options
+ CLIENT_AUTH *ClientAuth; // Client authentication data
+ volatile bool Halt; // Halting flag
+ volatile bool CancelConnect; // Cancel the connection
+ EVENT *HaltEvent; // Halting event
+ UINT Err; // Error value
+ HUB *Hub; // HUB
+ CANCEL *Cancel1; // Cancel object 1
+ CANCEL *Cancel2; // Cancel object 2
+ PACKET_ADAPTER *PacketAdapter; // Packet adapter
+ UCHAR UdpSendKey[16]; // UDP encryption key for transmission
+ UCHAR UdpRecvKey[16]; // UDP encryption key for reception
+ UINT ClientStatus; // Client Status
+ bool RetryFlag; // Retry flag (client)
+ bool ForceStopFlag; // Forced stop flag (client)
+ UINT CurrentRetryCount; // Current retry counter (client)
+ UINT RetryInterval; // Retry interval (client)
+ bool ConnectSucceed; // Connection success flag (client)
+ bool SessionTimeOuted; // Session times out
+ UINT Timeout; // Time-out period
+ UINT64 NextConnectionTime; // Time to put next additional connection
+ IP ServerIP; // IP address of the server
+ bool ClientModeAndUseVLan; // Use a virtual LAN card in client mode
+ bool UseSSLDataEncryption; // Use SSL data encryption
+ LOCK *TrafficLock; // Traffic data lock
+ LINK *Link; // A reference to the link object
+ SNAT *SecureNAT; // A reference to the SecureNAT object
+ BRIDGE *Bridge; // A reference to the Bridge object
+ NODE_INFO NodeInfo; // Node information
+ UINT64 LastIncrementTraffic; // Last time that updated the traffic data of the user
+ bool AdministratorMode; // Administrator mode
+ LIST *CancelList; // Cancellation list
+ L3IF *L3If; // Layer-3 interface
+ IP DefaultDns; // IP address of the default DNS server
+ bool IPv6Session; // IPv6 session (Physical communication is IPv6)
+ UINT VLanId; // VLAN ID
+ UINT UniqueId; // Unique ID
+ UCHAR IpcMacAddress[6]; // MAC address for IPC
+ UCHAR Padding[2];
+
+ UINT64 CreatedTime; // Creation date and time
+ UINT64 LastCommTime; // Last communication date and time
+ TRAFFIC *Traffic; // Traffic data
+ TRAFFIC *OldTraffic; // Old traffic data
+ UINT64 TotalSendSize; // Total transmitted data size
+ UINT64 TotalRecvSize; // Total received data size
+ UINT64 TotalSendSizeReal; // Total transmitted data size (no compression)
+ UINT64 TotalRecvSizeReal; // Total received data size (no compression)
+ char *Name; // Session name
+ char *Username; // User name
+ char UserNameReal[MAX_USERNAME_LEN + 1]; // User name (real)
+ char GroupName[MAX_USERNAME_LEN + 1]; // Group name
+ POLICY *Policy; // Policy
+ UCHAR SessionKey[SHA1_SIZE]; // Session key
+ UINT SessionKey32; // 32bit session key
+ char SessionKeyStr[64]; // Session key string
+ UINT MaxConnection; // Maximum number of concurrent TCP connections
+ bool UseEncrypt; // Use encrypted communication
+ bool UseFastRC4; // Use high speed RC4 encryption
+ bool UseCompress; // Use data compression
+ bool HalfConnection; // Half connection mode
+ bool QoS; // VoIP / QoS
+ bool NoSendSignature; // Do not send a signature
+ bool IsOpenVPNL3Session; // Whether OpenVPN L3 session
+ bool IsOpenVPNL2Session; // Whether OpenVPN L2 session
+ UINT NumDisconnected; // Number of socket disconnection
+ bool NoReconnectToSession; // Disable to reconnect to the session
+ char UnderlayProtocol[64]; // Physical communication protocol
+ UINT64 FirstConnectionEstablisiedTime; // Connection completion time of the first connection
+ UINT64 CurrentConnectionEstablishTime; // Completion time of this connection
+ UINT NumConnectionsEatablished; // Number of connections established so far
+ UINT AdjustMss; // MSS adjustment value
+
+ bool IsRUDPSession; // Whether R-UDP session
+ UINT RUdpMss; // The value of the MSS should be applied while the R-UDP is used
+ bool EnableBulkOnRUDP; // Allow the bulk transfer in the R-UDP session
+ bool EnableHMacOnBulkOfRUDP; // Use the HMAC to sign the bulk transfer of R-UDP session
+ bool EnableUdpRecovery; // Enable the R-UDP recovery
+
+ bool UseUdpAcceleration; // Use of UDP acceleration mode
+ bool UseHMacOnUdpAcceleration; // Use the HMAC in the UDP acceleration mode
+ UDP_ACCEL *UdpAccel; // UDP acceleration
+ bool IsUsingUdpAcceleration; // Flag of whether the UDP acceleration is used
+ UINT UdpAccelMss; // MSS value to be applied while the UDP acceleration is used
+ bool UdpAccelFastDisconnectDetect; // Fast disconnection detection is enabled
+
+ bool IsAzureSession; // Whether the session via VPN Azure
+ IP AzureRealServerGlobalIp; // Real global IP of the server-side in the case of session via VPN Azure
+
+ ACCOUNT *Account; // Client account
+ UINT VLanDeviceErrorCount; // Number of times that the error occurred in the virtual LAN card
+ bool Win32HideConnectWindow; // Hide the status window
+ bool Win32HideNicInfoWindow; // Hide the NIC information window
+ bool UserCanceled; // Canceled by the user
+ UINT64 LastTryAddConnectTime; // Last time that attempted to add a connection
+
+ bool IsMonitorMode; // Whether the monitor mode
+ bool IsBridgeMode; // Whether the bridge mode
+ bool UseClientLicense; // Number of assigned client licenses
+ bool UseBridgeLicense; // Number of assigned bridge licenses
+
+ COUNTER *LoggingRecordCount; // Counter for the number of logging records
+
+ bool FreeInfoShowed; // Whether a warning about Free Edition has already displayed
+
+ bool Client_NoSavePassword; // Prohibit the password saving
+ wchar_t *Client_Message; // Message that has been sent from the server
+
+ LIST *DelayedPacketList; // Delayed packet list
+ UINT Flag1;
+
+ USER *NumLoginIncrementUserObject; // User objects to increment the nymber of logins
+ HUB *NumLoginIncrementHubObject; // Virtual HUB object to increment the number of logins
+ UINT64 NumLoginIncrementTick; // Time to perform increment a number of log
+
+ bool FirstTimeHttpRedirect; // Redirect HTTP only for the first time
+ char FirstTimeHttpRedirectUrl[128]; // URL for redirection only the first time
+ UINT FirstTimeHttpAccessCheckIp; // IP address for access checking
+
+ // To examine the maximum number of alowed logging target packets per minute
+ UINT64 MaxLoggedPacketsPerMinuteStartTick; // Inspection start time
+ UINT CurrentNumPackets; // Current number of packets
+
+ // Measures for D-Link bug
+ UINT64 LastDLinkSTPPacketSendTick; // Last D-Link STP packet transmission time
+ UCHAR LastDLinkSTPPacketDataHash[MD5_SIZE]; // Last D-Link STP packet hash
+};
+
+// Password dialog
+struct UI_PASSWORD_DLG
+{
+ UINT Type; // Type of password
+ char Username[MAX_USERNAME_LEN + 1]; // User name
+ char Password[MAX_PASSWORD_LEN + 1]; // Password
+ char ServerName[MAX_HOST_NAME_LEN + 1]; // Server name
+ UINT RetryIntervalSec; // Time to retry
+ EVENT *CancelEvent; // Event to cancel the dialog display
+ bool ProxyServer; // The authentication by the proxy server
+ UINT64 StartTick; // Start time
+ bool AdminMode; // Administrative mode
+ bool ShowNoSavePassword; // Whether to display a check box that does not save the password
+ bool NoSavePassword; // Mode that not to save the password
+ SOCK *Sock; // Socket
+};
+
+// Message dialog
+struct UI_MSG_DLG
+{
+ char ServerName[MAX_HOST_NAME_LEN + 1]; // Server name
+ char HubName[MAX_HUBNAME_LEN + 1]; // Virtual HUB name
+ wchar_t *Msg; // Body
+ SOCK *Sock; // Socket
+ bool Halt; // Flag to close
+};
+
+// NIC information
+struct UI_NICINFO
+{
+ wchar_t AccountName[MAX_SIZE]; // Connection setting name
+ char NicName[MAX_SIZE]; // Virtual NIC name
+
+ SOCK *Sock; // Socket
+ bool Halt; // Flag to close
+ ROUTE_CHANGE *RouteChange; // Routing table change notification
+ UINT CurrentIcon; // Current icon
+ UINT64 CloseAfterTime; // Close automatically
+};
+
+// Connection Error dialog
+struct UI_CONNECTERROR_DLG
+{
+ EVENT *CancelEvent; // Event to cancel the dialog display
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+ char ServerName[MAX_HOST_NAME_LEN + 1]; // Server name
+ UINT Err; // Error code
+ UINT CurrentRetryCount; // Current retry count
+ UINT RetryLimit; // Limit of the number of retries
+ UINT64 StartTick; // Start time
+ UINT RetryIntervalSec; // Time to retry
+ bool HideWindow; // Hide the window
+ SOCK *Sock; // Socket
+};
+
+// Server certificate checking dialog
+struct UI_CHECKCERT
+{
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1]; // Account name
+ char ServerName[MAX_HOST_NAME_LEN + 1]; // Server name
+ X *x; // Server certificate
+ X *parent_x; // Parent certificate
+ X *old_x; // Certificate of previous
+ bool DiffWarning; // Display a warning of certificate forgery
+ bool Ok; // Connection permission flag
+ bool SaveServerCert; // Save the server certificate
+ SESSION *Session; // Session
+ volatile bool Halt; // Halting flag
+ SOCK *Sock; // Socket
+};
+
+
+// Function prototype
+SESSION *NewClientSessionEx(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, PACKET_ADAPTER *pa, struct ACCOUNT *account);
+SESSION *NewClientSession(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, PACKET_ADAPTER *pa);
+SESSION *NewRpcSession(CEDAR *cedar, CLIENT_OPTION *option);
+SESSION *NewRpcSessionEx(CEDAR *cedar, CLIENT_OPTION *option, UINT *err, char *client_str);
+SESSION *NewRpcSessionEx2(CEDAR *cedar, CLIENT_OPTION *option, UINT *err, char *client_str, void *hWnd);
+SESSION *NewServerSession(CEDAR *cedar, CONNECTION *c, HUB *h, char *username, POLICY *policy);
+SESSION *NewServerSessionEx(CEDAR *cedar, CONNECTION *c, HUB *h, char *username, POLICY *policy, bool inproc_mode);
+void ClientThread(THREAD *t, void *param);
+void ReleaseSession(SESSION *s);
+void CleanupSession(SESSION *s);
+void StopSession(SESSION *s);
+void StopSessionEx(SESSION *s, bool no_wait);
+bool SessionConnect(SESSION *s);
+bool ClientConnect(CONNECTION *c);
+int CompareSession(void *p1, void *p2);
+PACKET_ADAPTER *NewPacketAdapter(PA_INIT *init, PA_GETCANCEL *getcancel, PA_GETNEXTPACKET *getnext,
+ PA_PUTPACKET *put, PA_FREE *free);
+void FreePacketAdapter(PACKET_ADAPTER *pa);
+void SessionMain(SESSION *s);
+void NewSessionKey(CEDAR *cedar, UCHAR *session_key, UINT *session_key_32);
+SESSION *GetSessionFromKey(CEDAR *cedar, UCHAR *session_key);
+SESSION *GetSessionFromKey32(CEDAR *cedar, UINT key32);
+void DebugPrintSessionKey(UCHAR *session_key);
+void ClientAdditionalConnectChance(SESSION *s);
+void SessionAdditionalConnect(SESSION *s);
+void ClientAdditionalThread(THREAD *t, void *param);
+void PrintSessionTotalDataSize(SESSION *s);
+void AddTrafficForSession(SESSION *s, TRAFFIC *t);
+void IncrementUserTraffic(HUB *hub, char *username, SESSION *s);
+void Notify(SESSION *s, UINT code);
+void PrintStatus(SESSION *s, wchar_t *str);
+LIST *NewCancelList();
+void ReleaseCancelList(LIST *o);
+void AddCancelList(LIST *o, CANCEL *c);
+void CancelList(LIST *o);
+bool CompareNodeInfo(NODE_INFO *a, NODE_INFO *b);
+bool IsPriorityHighestPacketForQoS(void *data, UINT size);
+UINT GetNextDelayedPacketTickDiff(SESSION *s);
+
+#endif // SESSION_H
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/UT.c b/src/Cedar/UT.c
new file mode 100644
index 00000000..957a7079
--- /dev/null
+++ b/src/Cedar/UT.c
@@ -0,0 +1,393 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// UT.c
+// SoftEther Network Utility For Win32
+
+#include <GlobalConst.h>
+
+#ifdef WIN32
+
+#define UT_C
+
+#define _WIN32_WINNT 0x0502
+#define WINVER 0x0502
+#include <winsock2.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <wininet.h>
+#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+#include "../PenCore/resource.h"
+
+static char *selected_adapter = NULL;
+
+// Update status
+void UtSpeedMeterDlgRefreshStatus(HWND hWnd)
+{
+ char *title;
+ MS_ADAPTER *a;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ title = selected_adapter;
+
+ a = MsGetAdapter(title);
+ if (a == NULL)
+ {
+ LbReset(hWnd, L_STATUS);
+ Disable(hWnd, L_STATUS);
+ }
+ else
+ {
+ LVB *b;
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ char str[MAX_SIZE];
+ b = LvInsertStart();
+
+ UniStrCpy(tmp, sizeof(tmp), a->TitleW);
+ LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_TITLE"), tmp);
+
+ StrToUni(tmp, sizeof(tmp), a->Guid);
+ LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_GUID"), tmp);
+
+ LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_TYPE"), MsGetAdapterTypeStr(a->Type));
+
+ LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_TYPE2"), (!a->IsNotEthernetLan ? _UU("SEC_YES") : _UU("SEC_NO")));
+
+ LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_STATUS"), MsGetAdapterStatusStr(a->Status));
+
+ UniToStr3(tmp, sizeof(tmp), a->Mtu);
+ LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_MTU"), tmp);
+
+ UniToStr3(tmp, sizeof(tmp), a->Speed);
+ LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_SPEED"), tmp);
+
+ Zero(str, sizeof(str));
+ BinToStrEx2(str, sizeof(str), a->Address, a->AddressSize, '-');
+ StrToUni(tmp, sizeof(tmp), str);
+ LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_ADDRESS"), tmp);
+
+ UniToStr3(tmp, sizeof(tmp), a->RecvBytes);
+ LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_RECV_BYTES"), tmp);
+
+ UniToStr3(tmp, sizeof(tmp), a->RecvPacketsBroadcast);
+ LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_RECV_BCASTS"), tmp);
+
+ UniToStr3(tmp, sizeof(tmp), a->RecvPacketsUnicast);
+ LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_RECV_UNICASTS"), tmp);
+
+ UniToStr3(tmp, sizeof(tmp), a->SendBytes);
+ LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_SEND_BYTES"), tmp);
+
+ UniToStr3(tmp, sizeof(tmp), a->SendPacketsBroadcast);
+ LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_SEND_BCASTS"), tmp);
+
+ UniToStr3(tmp, sizeof(tmp), a->SendPacketsUnicast);
+ LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_SEND_UNICASTS"), tmp);
+
+ for (i = 0;i < a->NumIpAddress;i++)
+ {
+ UniFormat(tmp2, sizeof(tmp2), _UU("UT_SM_ST_IP"), i + 1);
+ IPToUniStr(tmp, sizeof(tmp), &a->IpAddresses[i]);
+ LvInsertAdd(b, 0, NULL, 2, tmp2, tmp);
+
+ UniFormat(tmp2, sizeof(tmp2), _UU("UT_SM_ST_SUBNET"), i + 1);
+ IPToUniStr(tmp, sizeof(tmp), &a->SubnetMasks[i]);
+ LvInsertAdd(b, 0, NULL, 2, tmp2, tmp);
+ }
+
+ for (i = 0;i < a->NumGateway;i++)
+ {
+ UniFormat(tmp2, sizeof(tmp2), _UU("UT_SM_ST_GATEWAY"), i + 1);
+ IPToUniStr(tmp, sizeof(tmp), &a->Gateways[i]);
+ LvInsertAdd(b, 0, NULL, 2, tmp2, tmp);
+ }
+
+ if (a->UseDhcp)
+ {
+ IPToUniStr(tmp, sizeof(tmp), &a->DhcpServer);
+ LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_DHCP"), tmp);
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), a->DhcpLeaseStart, NULL);
+ LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_DHCP_1"), tmp);
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), a->DhcpLeaseExpires, NULL);
+ LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_DHCP_2"), tmp);
+ }
+
+ if (a->UseWins)
+ {
+ IPToUniStr(tmp, sizeof(tmp), &a->PrimaryWinsServer);
+ LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_WINS_1"), tmp);
+
+ IPToUniStr(tmp, sizeof(tmp), &a->SecondaryWinsServer);
+ LvInsertAdd(b, 0, NULL, 2, _UU("UT_SM_ST_WINS_2"), tmp);
+ }
+
+ LvInsertEnd(b, hWnd, L_STATUS);
+ Enable(hWnd, L_STATUS);
+
+ MsFreeAdapter(a);
+ }
+
+}
+
+static bool g_ut_adapter_list_updating = false;
+
+// Update the adapter list
+void UtSpeedMeterDlgRefreshList(HWND hWnd)
+{
+ wchar_t *old;
+ MS_ADAPTER_LIST *o;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (g_ut_adapter_list_updating)
+ {
+ return;
+ }
+ g_ut_adapter_list_updating = true;
+
+ // Get the current selection
+ old = GetText(hWnd, E_LIST);
+ if (old != NULL)
+ {
+ if (UniStrLen(old) == 0)
+ {
+ Free(old);
+ old = NULL;
+ }
+ }
+
+ o = MsCreateAdapterList();
+ CbReset(hWnd, E_LIST);
+ CbSetHeight(hWnd, E_LIST, 18);
+
+ for (i = 0;i < o->Num;i++)
+ {
+ wchar_t tmp[MAX_SIZE];
+ MS_ADAPTER *a = o->Adapters[i];
+
+ if (a->Info)
+ {
+ StrToUni(tmp, sizeof(tmp), a->Title);
+ CbAddStr(hWnd, E_LIST, tmp, 0);
+ }
+ }
+
+
+ // Re-select the previous selection
+ if (old != NULL)
+ {
+ CbSelectIndex(hWnd, E_LIST, CbFindStr(hWnd, E_LIST, old));
+ Free(old);
+ }
+
+ MsFreeAdapterList(o);
+
+ g_ut_adapter_list_updating = false;
+}
+
+// Speedometer dialog control update
+void UtSpeedMeterDlgUpdate(HWND hWnd)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+}
+
+// Speedometer dialog initialization
+void UtSpeedMeterDlgInit(HWND hWnd)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ LvInitEx(hWnd, L_STATUS, true);
+ LvInsertColumn(hWnd, L_STATUS, 0, _UU("UT_SM_COLUMN_1"), 150);
+ LvInsertColumn(hWnd, L_STATUS, 1, _UU("UT_SM_COLUMN_2"), 290);
+
+ UtSpeedMeterDlgRefreshList(hWnd);
+ selected_adapter = GetTextA(hWnd, E_LIST);
+ UtSpeedMeterDlgRefreshStatus(hWnd);
+ UtSpeedMeterDlgUpdate(hWnd);
+}
+
+// Speedometer dialog
+UINT UtSpeedMeterDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetIcon(hWnd, 0, ICO_NIC_ONLINE);
+ UtSpeedMeterDlgInit(hWnd);
+ SetTimer(hWnd, 1, SPEED_METER_REFRESH_INTERVAL, NULL);
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+ UtSpeedMeterDlgRefreshStatus(hWnd);
+ UtSpeedMeterDlgUpdate(hWnd);
+ SetTimer(hWnd, 1, SPEED_METER_REFRESH_INTERVAL, NULL);
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ if (HIWORD(wParam) == CBN_SELCHANGE) {
+ Free(selected_adapter);
+ selected_adapter = GetTextA(hWnd, E_LIST);
+ UtSpeedMeterDlgUpdate(hWnd);
+ } else {
+ switch (wParam)
+ {
+ case B_REFRESH:
+ UtSpeedMeterDlgRefreshList(hWnd);
+ Free(selected_adapter);
+ selected_adapter = GetTextA(hWnd, E_LIST);
+ UtSpeedMeterDlgUpdate(hWnd);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ }
+ break;
+
+ case WM_CLOSE:
+ Free(selected_adapter);
+ selected_adapter = NULL;
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Speedometer
+void UtSpeedMeter()
+{
+ UtSpeedMeterEx(NULL);
+}
+void UtSpeedMeterEx(void *hWnd)
+{
+ Dialog((HWND)hWnd, D_SPEEDMETER, UtSpeedMeterDlgProc, NULL);
+}
+
+#endif // WIN32
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/UT.h b/src/Cedar/UT.h
new file mode 100644
index 00000000..0c6acafa
--- /dev/null
+++ b/src/Cedar/UT.h
@@ -0,0 +1,112 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// UT.h
+// Header of UT.c
+
+#ifndef UT_H
+#define UT_H
+
+// Constant
+#define SPEED_METER_REFRESH_INTERVAL 500
+
+#ifdef UT_C
+// For internal declaration
+
+// Function prototype
+UINT UtSpeedMeterDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void UtSpeedMeterDlgInit(HWND hWnd);
+void UtSpeedMeterDlgRefreshList(HWND hWnd);
+void UtSpeedMeterDlgRefreshStatus(HWND hWnd);
+void UtSpeedMeterDlgUpdate(HWND hWnd);
+void UtSpeedMeterDlgRefreshStatus(HWND hWnd);
+
+#endif // UT_C
+
+// Function prototype
+void UtSpeedMeter();
+void UtSpeedMeterEx(void *hWnd);
+
+#endif // UT_H
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/UdpAccel.c b/src/Cedar/UdpAccel.c
new file mode 100644
index 00000000..9d0bcd78
--- /dev/null
+++ b/src/Cedar/UdpAccel.c
@@ -0,0 +1,1157 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// UdpAccel.c
+// UDP acceleration function
+
+#include "CedarPch.h"
+
+// Polling process
+void UdpAccelPoll(UDP_ACCEL *a)
+{
+ UCHAR *tmp = a->TmpBuf;
+ IP nat_t_ip;
+ UINT num_ignore_errors = 0;
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ Lock(a->NatT_Lock);
+ {
+ Copy(&nat_t_ip, &a->NatT_IP, sizeof(IP));
+ }
+ Unlock(a->NatT_Lock);
+
+ if (IsZeroIp(&nat_t_ip) == false)
+ {
+ // Release the thread which gets the IP address of the NAT-T server because it is no longer needed
+ if (a->NatT_GetIpThread != NULL)
+ {
+ WaitThread(a->NatT_GetIpThread, INFINITE);
+ ReleaseThread(a->NatT_GetIpThread);
+ a->NatT_GetIpThread = NULL;
+ }
+ }
+
+ // Receive a new UDP packet
+ while (true)
+ {
+ IP src_ip;
+ UINT src_port;
+ UINT ret;
+
+ ret = RecvFrom(a->UdpSock, &src_ip, &src_port, tmp, UDP_ACCELERATION_TMP_BUF_SIZE);
+
+ if (ret != 0 && ret != SOCK_LATER)
+ {
+ if (a->UseUdpIpQuery && a->UdpIpQueryPacketSize >= 8 && CmpIpAddr(&a->UdpIpQueryHost, &src_ip) == 0 &&
+ src_port == a->UdpIpQueryPort)
+ {
+ // Receive a response of the query for IP and port number
+ IP my_ip = {0};
+ UINT myport = 0;
+ BUF *b = MemToBuf(a->UdpIpQueryPacketData, a->UdpIpQueryPacketSize);
+
+
+ FreeBuf(b);
+ }
+ else if (IsZeroIp(&nat_t_ip) == false && CmpIpAddr(&nat_t_ip, &src_ip) == 0 &&
+ src_port == UDP_NAT_T_PORT)
+ {
+ // Receive a response from the NAT-T server
+ IP my_ip;
+ UINT myport;
+
+ if (RUDPParseIPAndPortStr(tmp, ret, &my_ip, &myport))
+ {
+ if (myport >= 1 && myport <= 65535)
+ {
+ if (a->MyPortByNatTServer != myport)
+ {
+ a->MyPortByNatTServer = myport;
+ a->MyPortByNatTServerChanged = true;
+ a->CommToNatT_NumFail = 0;
+
+ Debug("NAT-T: MyPort = %u\n", myport);
+ }
+ }
+ }
+/*
+ BUF *b = NewBuf();
+ PACK *p;
+
+ WriteBuf(b, tmp, ret);
+ SeekBufToBegin(b);
+
+ p = BufToPack(b);
+ if (p != NULL)
+ {
+ if (PackCmpStr(p, "opcode", "query_for_nat_traversal"))
+ {
+ if (PackGetBool(p, "ok"))
+ {
+ if (PackGetInt64(p, "tran_id") == a->NatT_TranId)
+ {
+ UINT myport = PackGetInt(p, "your_port");
+
+ if (myport >= 1 && myport <= 65535)
+ {
+ if (a->MyPortByNatTServer != myport)
+ {
+ a->MyPortByNatTServer = myport;
+ a->MyPortByNatTServerChanged = true;
+
+ Debug("NAT-T: MyPort = %u\n", myport);
+ }
+ }
+ }
+ }
+ }
+
+ FreePack(p);
+ }
+
+ FreeBuf(b);*/
+ }
+ else
+ {
+ BLOCK *b = UdpAccelProcessRecvPacket(a, tmp, ret, &src_ip, src_port);
+
+ //Debug("UDP Recv: %u %u %u\n", ret, (b == NULL ? 0 : b->Size), (b == NULL ? 0 : b->Compressed));
+
+ /*if (b != NULL)
+ {
+ char tmp[MAX_SIZE * 10];
+ BinToStr(tmp, sizeof(tmp), b->Buf, b->Size);
+ Debug("Recv Pkt: %s\n", tmp);
+ }*/
+
+ if (b != NULL)
+ {
+ // Receive a packet
+ InsertQueue(a->RecvBlockQueue, b);
+ }
+ }
+ }
+ else
+ {
+ if (ret == 0)
+ {
+ if (a->UdpSock->IgnoreRecvErr == false)
+ {
+ // Serious UDP reception error occurs
+ a->FatalError = true;
+ break;
+ }
+
+ if ((num_ignore_errors++) >= MAX_NUM_IGNORE_ERRORS)
+ {
+ a->FatalError = true;
+ break;
+ }
+ }
+ else
+ {
+ // SOCK_LATER
+ break;
+ }
+ }
+ }
+
+ // Send a Keep-Alive packet
+ if (a->NextSendKeepAlive == 0 || (a->NextSendKeepAlive <= a->Now) || a->YourPortByNatTServerChanged)
+ {
+ a->YourPortByNatTServerChanged = false;
+
+ if (UdpAccelIsSendReady(a, false))
+ {
+ UINT rand_interval;
+
+ if (a->FastDetect == false)
+ {
+ rand_interval = rand() % (UDP_ACCELERATION_KEEPALIVE_INTERVAL_MAX - UDP_ACCELERATION_KEEPALIVE_INTERVAL_MIN) + UDP_ACCELERATION_KEEPALIVE_INTERVAL_MIN;
+ }
+ else
+ {
+ rand_interval = rand() % (UDP_ACCELERATION_KEEPALIVE_INTERVAL_MAX_FAST - UDP_ACCELERATION_KEEPALIVE_INTERVAL_MIN_FAST) + UDP_ACCELERATION_KEEPALIVE_INTERVAL_MIN_FAST;
+ }
+
+ a->NextSendKeepAlive = a->Now + (UINT64)rand_interval;
+
+ //Debug("UDP KeepAlive\n");
+
+ UdpAccelSend(a, NULL, 0, false, 1000, false);
+ }
+ }
+
+ // Send a NAT-T request packet (Only if the connection by UDP has not be established yet)
+ if (a->NoNatT == false)
+ {
+ // In the usual case
+ if (IsZeroIp(&nat_t_ip) == false)
+ {
+ if (UdpAccelIsSendReady(a, true) == false)
+ {
+ if (a->NextPerformNatTTick == 0 || (a->NextPerformNatTTick <= a->Now))
+ {
+ UINT rand_interval;
+ UCHAR c = 'B';
+
+ a->CommToNatT_NumFail++;
+
+ rand_interval = UDP_NAT_T_INTERVAL_INITIAL * MIN(a->CommToNatT_NumFail, UDP_NAT_T_INTERVAL_FAIL_MAX);
+ //PACK *p = NewPack();
+ //BUF *b;
+
+ if (a->MyPortByNatTServer != 0)
+ {
+ rand_interval = GenRandInterval(UDP_NAT_T_INTERVAL_MIN, UDP_NAT_T_INTERVAL_MAX);
+ }
+
+ a->NextPerformNatTTick = a->Now + (UINT64)rand_interval;
+
+ // Generate the request packet
+ /*PackAddStr(p, "description", UDP_NAT_T_SIGNATURE);
+ PackAddStr(p, "opcode", "query_for_nat_traversal");
+ PackAddInt64(p, "tran_id", a->NatT_TranId);
+ b = PackToBuf(p);
+ FreePack(p);*/
+
+ // Send the request packet
+ SendTo(a->UdpSock, &nat_t_ip, UDP_NAT_T_PORT, &c, 1);
+
+ //FreeBuf(b);
+ }
+ }
+ else
+ {
+ a->NextPerformNatTTick = 0;
+ a->CommToNatT_NumFail = 0;
+ }
+ }
+ }
+ else
+ {
+ // NAT_T is disabled, but there is a reference host (such as VGC)
+ if (a->UseUdpIpQuery)
+ {
+ }
+ }
+}
+
+// Send a packet block
+void UdpAccelSendBlock(UDP_ACCEL *a, BLOCK *b)
+{
+ // Validate arguments
+ if (a == NULL || b == NULL)
+ {
+ return;
+ }
+
+ UdpAccelSend(a, b->Buf, b->Size, b->Compressed, a->MaxUdpPacketSize, b->PriorityQoS);
+}
+
+// Calculate the best MSS
+UINT UdpAccelCalcMss(UDP_ACCEL *a)
+{
+ UINT ret;
+
+ // Validate arguments
+ if (a == NULL)
+ {
+ return 0;
+ }
+
+ ret = MTU_FOR_PPPOE;
+
+ // IPv4
+ if (a->IsIPv6)
+ {
+ ret -= 40;
+ }
+ else
+ {
+ ret -= 20;
+ }
+
+ // UDP
+ ret -= 8;
+
+ if (a->PlainTextMode == false)
+ {
+ // IV
+ ret -= UDP_ACCELERATION_PACKET_IV_SIZE;
+ }
+
+ // Cookie
+ ret -= sizeof(UINT);
+
+ // My Tick
+ ret -= sizeof(UINT64);
+
+ // Your Tick
+ ret -= sizeof(UINT64);
+
+ // Size
+ ret -= sizeof(USHORT);
+
+ // Compress Flag
+ ret -= sizeof(UCHAR);
+
+ if (a->PlainTextMode == false)
+ {
+ // Verify
+ ret -= UDP_ACCELERATION_PACKET_IV_SIZE;
+ }
+
+ // Ethernet header (communication packets)
+ ret -= 14;
+
+ // IPv4 Header (communication packets)
+ ret -= 20;
+
+ // TCP header (communication packet)
+ ret -= 20;
+
+ return ret;
+}
+
+// Send
+void UdpAccelSend(UDP_ACCEL *a, UCHAR *data, UINT data_size, bool compressed, UINT max_size, bool high_priority)
+{
+ UCHAR tmp[UDP_ACCELERATION_TMP_BUF_SIZE];
+ UCHAR *buf;
+ UINT size;
+ UCHAR key[UDP_ACCELERATION_PACKET_KEY_SIZE];
+ UINT64 ui64;
+ USHORT us;
+ UCHAR c;
+ UINT current_size;
+ UINT ui32;
+ bool fatal_error = false;
+ UINT r;
+ // Validate arguments
+ if (a == NULL || (data_size != 0 && data == NULL))
+ {
+ return;
+ }
+ if (max_size == 0)
+ {
+ max_size = INFINITE;
+ }
+
+ buf = tmp;
+ size = 0;
+
+ // IV
+ if (a->PlainTextMode == false)
+ {
+ // IV
+ Copy(buf, a->NextIv, UDP_ACCELERATION_PACKET_IV_SIZE);
+
+ buf += UDP_ACCELERATION_PACKET_IV_SIZE;
+ size += UDP_ACCELERATION_PACKET_IV_SIZE;
+
+ // Calculate the key
+ UdpAccelCalcKey(key, a->MyKey, a->NextIv);
+
+ if (false)
+ {
+ char tmp1[256];
+ char tmp2[256];
+ char tmp3[256];
+ BinToStr(tmp1, sizeof(tmp1), a->MyKey, sizeof(a->MyKey));
+ BinToStr(tmp2, sizeof(tmp2), a->NextIv, UDP_ACCELERATION_PACKET_IV_SIZE);
+ BinToStr(tmp3, sizeof(tmp3), key, sizeof(key));
+ Debug("My Key : %s\n"
+ "IV : %s\n"
+ "Comm Key: %s\n",
+ tmp1, tmp2, tmp3);
+ }
+ }
+
+ // Cookie
+ ui32 = Endian32(a->YourCookie);
+ Copy(buf, &ui32, sizeof(UINT));
+ buf += sizeof(UINT);
+ size += sizeof(UINT);
+
+ // My Tick
+ ui64 = Endian64(a->Now == 0 ? 1ULL : a->Now);
+ Copy(buf, &ui64, sizeof(UINT64));
+ buf += sizeof(UINT64);
+ size += sizeof(UINT64);
+
+ // Your Tick
+ ui64 = Endian64(a->LastRecvYourTick);
+ Copy(buf, &ui64, sizeof(UINT64));
+ buf += sizeof(UINT64);
+ size += sizeof(UINT64);
+
+ // Size
+ us = Endian16(data_size);
+ Copy(buf, &us, sizeof(USHORT));
+ buf += sizeof(USHORT);
+ size += sizeof(USHORT);
+
+ // Compress Flag
+ c = (compressed ? 1 : 0);
+ Copy(buf, &c, sizeof(UCHAR));
+ buf += sizeof(UCHAR);
+ size += sizeof(UCHAR);
+
+ // Data
+ if (data_size >= 1)
+ {
+ Copy(buf, data, data_size);
+ buf += data_size;
+ size += data_size;
+ }
+
+ if (a->PlainTextMode == false)
+ {
+ static UCHAR zero[UDP_ACCELERATION_PACKET_IV_SIZE] = {0};
+ CRYPT *c;
+
+ current_size = UDP_ACCELERATION_PACKET_IV_SIZE + sizeof(UINT) + sizeof(UINT64) * 2 +
+ sizeof(USHORT) + sizeof(UCHAR) + data_size + UDP_ACCELERATION_PACKET_IV_SIZE;
+
+ if (current_size < max_size)
+ {
+ // Padding
+ UCHAR pad[UDP_ACCELERATION_MAX_PADDING_SIZE];
+ UINT pad_size = MIN(max_size - current_size, UDP_ACCELERATION_MAX_PADDING_SIZE);
+ pad_size = rand() % pad_size;
+
+ Zero(pad, sizeof(pad));
+ Copy(buf, pad, pad_size);
+ buf += pad_size;
+ size += pad_size;
+ }
+
+ // Verify
+ Copy(buf, zero, UDP_ACCELERATION_PACKET_IV_SIZE);
+ buf += UDP_ACCELERATION_PACKET_IV_SIZE;
+ size += UDP_ACCELERATION_PACKET_IV_SIZE;
+
+ // Encryption
+ c = NewCrypt(key, UDP_ACCELERATION_PACKET_KEY_SIZE);
+ Encrypt(c, tmp + UDP_ACCELERATION_PACKET_IV_SIZE, tmp + UDP_ACCELERATION_PACKET_IV_SIZE, size - UDP_ACCELERATION_PACKET_IV_SIZE);
+ FreeCrypt(c);
+
+ // Next Iv
+ Copy(a->NextIv, buf - UDP_ACCELERATION_PACKET_IV_SIZE, UDP_ACCELERATION_PACKET_IV_SIZE);
+ }
+
+ // Send
+ SetSockHighPriority(a->UdpSock, high_priority);
+
+ r = SendTo(a->UdpSock, &a->YourIp, a->YourPort, tmp, size);
+ if (r == 0 && a->UdpSock->IgnoreSendErr == false)
+ {
+ fatal_error = true;
+ Debug("Error: SendTo: %r %u %u\n", &a->YourIp, a->YourPort, size);
+ WHERE;
+ }
+
+ if (data_size == 0)
+ {
+ if (UdpAccelIsSendReady(a, true) == false)
+ {
+ if ((a->YourPortByNatTServer != 0) && (a->YourPort != a->YourPortByNatTServer))
+ {
+ r = SendTo(a->UdpSock, &a->YourIp, a->YourPortByNatTServer, tmp, size);
+ if (r == 0 && a->UdpSock->IgnoreSendErr == false)
+ {
+ fatal_error = true;
+ WHERE;
+ }
+ }
+ }
+ }
+
+ if (data_size == 0)
+ {
+ if (IsZeroIP(&a->YourIp2) == false && CmpIpAddr(&a->YourIp, &a->YourIp2) != 0)
+ {
+ if (UdpAccelIsSendReady(a, true) == false)
+ {
+ // When the KeepAlive, if the opponent may be behind a NAT,
+ // send the packet to the IP address of outside of the NAT
+ r = SendTo(a->UdpSock, &a->YourIp2, a->YourPort, tmp, size);
+ if (r == 0 && a->UdpSock->IgnoreSendErr == false)
+ {
+ fatal_error = true;
+ WHERE;
+ }
+
+ if ((a->YourPortByNatTServer != 0) && (a->YourPort != a->YourPortByNatTServer))
+ {
+ r = SendTo(a->UdpSock, &a->YourIp2, a->YourPortByNatTServer, tmp, size);
+ if (r == 0 && a->UdpSock->IgnoreSendErr == false)
+ {
+ fatal_error = true;
+ WHERE;
+ }
+ }
+ }
+ }
+ }
+
+ if (fatal_error)
+ {
+ a->FatalError = true;
+ WHERE;
+ }
+
+ //Debug("UDP Send: %u\n", size);
+}
+
+// Determine whether transmission is possible
+bool UdpAccelIsSendReady(UDP_ACCEL *a, bool check_keepalive)
+{
+ UINT64 timeout_value;
+ // Validate arguments
+ if (a == NULL)
+ {
+ return false;
+ }
+
+ if (a->Inited == false)
+ {
+ return false;
+ }
+
+ if (a->YourPort == 0)
+ {
+ return false;
+ }
+
+ if (IsZeroIp(&a->YourIp))
+ {
+ return false;
+ }
+
+ timeout_value = UDP_ACCELERATION_KEEPALIVE_TIMEOUT;
+
+ if (a->FastDetect)
+ {
+ timeout_value = UDP_ACCELERATION_KEEPALIVE_TIMEOUT_FAST;
+ }
+
+ if (check_keepalive)
+ {
+ if (a->LastRecvTick == 0 || ((a->LastRecvTick + timeout_value) < a->Now))
+ {
+ a->FirstStableReceiveTick = 0;
+ return false;
+ }
+ else
+ {
+ if ((a->FirstStableReceiveTick + (UINT64)UDP_ACCELERATION_REQUIRE_CONTINUOUS) <= a->Now)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+// Process the received packet
+BLOCK *UdpAccelProcessRecvPacket(UDP_ACCEL *a, UCHAR *buf, UINT size, IP *src_ip, UINT src_port)
+{
+ UCHAR key[UDP_ACCELERATION_PACKET_KEY_SIZE];
+ UCHAR *iv;
+ CRYPT *c;
+ UINT64 my_tick, your_tick;
+ UINT inner_size;
+ UCHAR *inner_data = NULL;
+ UINT pad_size;
+ UCHAR *verify;
+ bool compress_flag;
+ BLOCK *b = NULL;
+ UINT cookie;
+ // Validate arguments
+ if (a == NULL || buf == NULL || size == 0 || src_ip == NULL)
+ {
+ return NULL;
+ }
+
+ if (a->PlainTextMode == false)
+ {
+ // IV
+ if (size < UDP_ACCELERATION_PACKET_IV_SIZE)
+ {
+ return NULL;
+ }
+ iv = buf;
+ buf += UDP_ACCELERATION_PACKET_IV_SIZE;
+ size -= UDP_ACCELERATION_PACKET_IV_SIZE;
+
+ // Calculate the key
+ UdpAccelCalcKey(key, a->YourKey, iv);
+
+ if (false)
+ {
+ char tmp1[256];
+ char tmp2[256];
+ char tmp3[256];
+ BinToStr(tmp1, sizeof(tmp1), a->YourKey, sizeof(a->YourKey));
+ BinToStr(tmp2, sizeof(tmp2), iv, UDP_ACCELERATION_PACKET_IV_SIZE);
+ BinToStr(tmp3, sizeof(tmp3), key, sizeof(key));
+ Debug("Your Key: %s\n"
+ "IV : %s\n"
+ "Comm Key: %s\n",
+ tmp1, tmp2, tmp3);
+ }
+
+ // Decryption
+ c = NewCrypt(key, UDP_ACCELERATION_PACKET_KEY_SIZE);
+ Encrypt(c, buf, buf, size);
+ FreeCrypt(c);
+ }
+
+ // Cookie
+ if (size < sizeof(UINT))
+ {
+ return NULL;
+ }
+ cookie = READ_UINT(buf);
+ buf += sizeof(UINT);
+ size -= sizeof(UINT);
+
+ if (cookie != a->MyCookie)
+ {
+ return NULL;
+ }
+
+ // My Tick
+ if (size < sizeof(UINT64))
+ {
+ return NULL;
+ }
+ my_tick = READ_UINT64(buf);
+ buf += sizeof(UINT64);
+ size -= sizeof(UINT64);
+
+ // Your Tick
+ if (size < sizeof(UINT64))
+ {
+ return NULL;
+ }
+ your_tick = READ_UINT64(buf);
+ buf += sizeof(UINT64);
+ size -= sizeof(UINT64);
+
+ // inner_size
+ if (size < sizeof(USHORT))
+ {
+ return NULL;
+ }
+ inner_size = READ_USHORT(buf);
+ buf += sizeof(USHORT);
+ size -= sizeof(USHORT);
+
+ // compress_flag
+ if (size < sizeof(UCHAR))
+ {
+ return NULL;
+ }
+ compress_flag = *((UCHAR *)buf);
+ buf += sizeof(UCHAR);
+ size -= sizeof(UCHAR);
+
+ if (size < inner_size)
+ {
+ return NULL;
+ }
+
+ // inner_data
+ if (inner_size >= 1)
+ {
+ inner_data = buf;
+ buf += inner_size;
+ size -= inner_size;
+ }
+
+ if (a->PlainTextMode == false)
+ {
+ // padding
+ if (size < UDP_ACCELERATION_PACKET_IV_SIZE)
+ {
+ return false;
+ }
+ pad_size = size - UDP_ACCELERATION_PACKET_IV_SIZE;
+ buf += pad_size;
+ size -= pad_size;
+
+ // verify
+ if (size != UDP_ACCELERATION_PACKET_IV_SIZE)
+ {
+ return NULL;
+ }
+
+ verify = buf;
+
+ if (IsZero(verify, UDP_ACCELERATION_PACKET_IV_SIZE) == false)
+ {
+ return NULL;
+ }
+ }
+
+ if (my_tick < a->LastRecvYourTick)
+ {
+ if ((a->LastRecvYourTick - my_tick) >= ((UINT64)UDP_ACCELERATION_WINDOW_SIZE_MSEC))
+ {
+ return NULL;
+ }
+ }
+
+ a->LastRecvMyTick = MAX(a->LastRecvMyTick, your_tick);
+ a->LastRecvYourTick = MAX(a->LastRecvYourTick, my_tick);
+
+ if (inner_size >= 1)
+ {
+ b = NewBlock(Clone(inner_data, inner_size), inner_size, compress_flag ? -1 : 0);
+ }
+
+ if (a->LastSetSrcIpAndPortTick < a->LastRecvYourTick)
+ {
+ a->LastSetSrcIpAndPortTick = a->LastRecvYourTick;
+
+ Copy(&a->YourIp, src_ip, sizeof(IP));
+ a->YourPort = src_port;
+ }
+
+ if (a->LastRecvMyTick != 0)
+ {
+ if ((a->LastRecvMyTick + (UINT64)(UDP_ACCELERATION_WINDOW_SIZE_MSEC)) >= a->Now)
+ {
+ a->LastRecvTick = a->Now;
+
+ a->IsReachedOnce = true;
+
+ if (a->FirstStableReceiveTick == 0)
+ {
+ a->FirstStableReceiveTick = a->Now;
+ }
+ }
+ }
+
+ return b;
+}
+
+// Calculate the key
+void UdpAccelCalcKey(UCHAR *key, UCHAR *common_key, UCHAR *iv)
+{
+ UCHAR tmp[UDP_ACCELERATION_COMMON_KEY_SIZE + UDP_ACCELERATION_PACKET_IV_SIZE];
+ // Validate arguments
+ if (key == NULL || common_key == NULL || iv == NULL)
+ {
+ return;
+ }
+
+ Copy(tmp, common_key, UDP_ACCELERATION_COMMON_KEY_SIZE);
+ Copy(tmp + UDP_ACCELERATION_COMMON_KEY_SIZE, iv, UDP_ACCELERATION_PACKET_IV_SIZE);
+
+ HashSha1(key, tmp, sizeof(tmp));
+}
+
+// Set the current time
+void UdpAccelSetTick(UDP_ACCEL *a, UINT64 tick64)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ a->Now = tick64;
+}
+
+// Initialize the server-side
+bool UdpAccelInitServer(UDP_ACCEL *a, UCHAR *client_key, IP *client_ip, UINT client_port, IP *client_ip_2)
+{
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (a == NULL || client_key == NULL)
+ {
+ return false;
+ }
+
+ IPToStr(tmp, sizeof(tmp), client_ip);
+ Debug("UdpAccelInitServer: client_ip=%s, client_port=%u, server_cookie=%u, client_cookie=%u\n", tmp, client_port,
+ a->MyCookie, a->YourCookie);
+
+ if (IsIP6(client_ip) != a->IsIPv6)
+ {
+ return false;
+ }
+
+ Copy(a->YourKey, client_key, UDP_ACCELERATION_COMMON_KEY_SIZE);
+
+ Copy(&a->YourIp, client_ip, sizeof(IP));
+ Copy(&a->YourIp2, client_ip_2, sizeof(IP));
+ a->YourPort = client_port;
+
+ a->Now = Tick64();
+
+ a->Inited = true;
+
+ return true;
+}
+
+// Initialize the client-side
+bool UdpAccelInitClient(UDP_ACCEL *a, UCHAR *server_key, IP *server_ip, UINT server_port, UINT server_cookie, UINT client_cookie, IP *server_ip_2)
+{
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (a == NULL || server_key == NULL || server_ip == NULL || server_port == 0)
+ {
+ return false;
+ }
+
+ IPToStr(tmp, sizeof(tmp), server_ip);
+ Debug("UdpAccelInitClient: server_ip=%s, server_port=%u, server_cookie=%u, client_cookie=%u\n", tmp, server_port, server_cookie, client_cookie);
+
+ if (IsIP6(server_ip) != a->IsIPv6)
+ {
+ return false;
+ }
+
+ Copy(a->YourKey, server_key, UDP_ACCELERATION_COMMON_KEY_SIZE);
+
+ Copy(&a->YourIp, server_ip, sizeof(IP));
+ Copy(&a->YourIp2, server_ip_2, sizeof(IP));
+ a->YourPort = server_port;
+
+ a->Now = Tick64();
+
+ a->MyCookie = client_cookie;
+ a->YourCookie = server_cookie;
+
+ a->Inited = true;
+
+ return true;
+}
+
+// Create a new UDP acceleration function
+UDP_ACCEL *NewUdpAccel(CEDAR *cedar, IP *ip, bool client_mode, bool random_port, bool no_nat_t)
+{
+ UDP_ACCEL *a;
+ SOCK *s;
+ UINT max_udp_size;
+ bool is_in_cedar_port_list = false;
+
+ if (IsZeroIP(ip))
+ {
+ ip = NULL;
+ }
+
+ if (client_mode || random_port)
+ {
+ // Use a appropriate vacant port number in the case of using random port or client mode
+ s = NewUDPEx3(0, ip);
+ }
+ else
+ {
+ // Specify in the range in the case of server mode
+ UINT i;
+ s = NULL;
+
+ LockList(cedar->UdpPortList);
+ {
+ for (i = UDP_SERVER_PORT_LOWER;i <= UDP_SERVER_PORT_HIGHER;i++)
+ {
+ if (IsIntInList(cedar->UdpPortList, i) == false)
+ {
+ s = NewUDPEx3(i, ip);
+
+ if (s != NULL)
+ {
+ is_in_cedar_port_list = true;
+ break;
+ }
+ }
+ }
+
+ if (s == NULL)
+ {
+ // Leave the port selection to the OS because the available port is not found within the range
+ s = NewUDPEx3(0, ip);
+ }
+
+ if (s != NULL && is_in_cedar_port_list)
+ {
+ AddIntDistinct(cedar->UdpPortList, i);
+ }
+ }
+ UnlockList(cedar->UdpPortList);
+ }
+
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ a = ZeroMalloc(sizeof(UDP_ACCEL));
+
+ a->Cedar = cedar;
+ AddRef(a->Cedar->ref);
+
+ a->NoNatT = no_nat_t;
+
+
+ a->NatT_TranId = Rand64();
+
+ a->CreatedTick = Tick64();
+
+ a->IsInCedarPortList = is_in_cedar_port_list;
+
+ a->ClientMode = client_mode;
+
+ a->Now = Tick64();
+ a->UdpSock = s;
+ Rand(a->MyKey, sizeof(a->MyKey));
+ Rand(a->YourKey, sizeof(a->YourKey));
+
+ Copy(&a->MyIp, ip, sizeof(IP));
+ a->MyPort = s->LocalPort;
+
+ a->IsIPv6 = IsIP6(ip);
+
+ a->RecvBlockQueue = NewQueue();
+
+ Rand(a->NextIv, sizeof(a->NextIv));
+
+ do
+ {
+ a->MyCookie = Rand32();
+ }
+ while (a->MyCookie == 0);
+
+ do
+ {
+ a->YourCookie = Rand32();
+ }
+ while (a->MyCookie == 0 || a->MyCookie == a->YourCookie);
+
+ // Calculate the maximum transmittable UDP packet size
+ max_udp_size = MTU_FOR_PPPOE;
+
+ if (a->IsIPv6 == false)
+ {
+ // IPv4
+ max_udp_size -= 20;
+ }
+ else
+ {
+ // IPv6
+ max_udp_size -= 40;
+ }
+
+ // UDP
+ max_udp_size -= 8;
+
+ a->MaxUdpPacketSize = max_udp_size;
+
+ Debug("Udp Accel My Port = %u\n", a->MyPort);
+
+ // Initialize the NAT-T server IP address acquisition thread
+ a->NatT_Lock = NewLock();
+ a->NatT_HaltEvent = NewEvent();
+
+ if (a->NoNatT == false)
+ {
+ a->NatT_GetIpThread = NewThread(NatT_GetIpThread, a);
+ }
+
+ return a;
+}
+
+// NAT-T server IP address acquisition thread
+void NatT_GetIpThread(THREAD *thread, void *param)
+{
+ UDP_ACCEL *a;
+ char hostname[MAX_SIZE];
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ a = (UDP_ACCEL *)param;
+
+ RUDPGetRegisterHostNameByIP(hostname, sizeof(hostname), NULL);
+
+ while (a->NatT_Halt == false)
+ {
+ IP ip;
+
+ // Get the IP address
+ bool ret = GetIP4Ex(&ip, hostname, 0, &a->NatT_Halt);
+
+ if (ret && (IsZeroIp(&ip) == false))
+ {
+ char tmp[128];
+
+ // Success to get
+ Lock(a->NatT_Lock);
+ {
+ Copy(&a->NatT_IP, &ip, sizeof(IP));
+ }
+ Unlock(a->NatT_Lock);
+
+ IPToStr(tmp, sizeof(tmp), &ip);
+ Debug("NAT-T IP Address Resolved: %s = %s\n", hostname, tmp);
+
+ a->NatT_IP_Changed = true;
+
+ break;
+ }
+
+ // Fail to get
+ Wait(a->NatT_HaltEvent, UDP_NAT_T_GET_IP_INTERVAL);
+ }
+}
+
+// Release the UDP acceleration function
+void FreeUdpAccel(UDP_ACCEL *a)
+{
+ // Validate arguments
+ if (a == NULL)
+ {
+ return;
+ }
+
+ while (true)
+ {
+ BLOCK *b = GetNext(a->RecvBlockQueue);
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ FreeBlock(b);
+ }
+
+ ReleaseQueue(a->RecvBlockQueue);
+
+ ReleaseSock(a->UdpSock);
+
+ if (a->IsInCedarPortList)
+ {
+ LockList(a->Cedar->UdpPortList);
+ {
+ DelInt(a->Cedar->UdpPortList, a->MyPort);
+ }
+ UnlockList(a->Cedar->UdpPortList);
+ }
+
+ // Release of NAT-T related
+ a->NatT_Halt = true;
+ Set(a->NatT_HaltEvent);
+
+ if (a->NatT_GetIpThread != NULL)
+ {
+ WaitThread(a->NatT_GetIpThread, INFINITE);
+ ReleaseThread(a->NatT_GetIpThread);
+ }
+
+ ReleaseEvent(a->NatT_HaltEvent);
+ DeleteLock(a->NatT_Lock);
+
+ ReleaseCedar(a->Cedar);
+
+ Free(a);
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/UdpAccel.h b/src/Cedar/UdpAccel.h
new file mode 100644
index 00000000..472a113d
--- /dev/null
+++ b/src/Cedar/UdpAccel.h
@@ -0,0 +1,195 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// UdpAccel.h
+// Header of UdpAccel.c
+
+#ifndef UDPACCEL_H
+#define UDPACCEL_H
+
+// Constants
+#define UDP_ACCELERATION_COMMON_KEY_SIZE 20 // Common key size
+#define UDP_ACCELERATION_PACKET_KEY_SIZE 20 // Key size for the packet
+#define UDP_ACCELERATION_PACKET_IV_SIZE 20 // IV size for the packet
+#define UDP_ACCELERATION_TMP_BUF_SIZE 2048 // Temporary buffer size
+#define UDP_ACCELERATION_WINDOW_SIZE_MSEC (30 * 1000) // Receive window size (in milliseconds)
+
+#define UDP_ACCELERATION_SUPPORTED_MAX_PAYLOAD_SIZE 1600 // Maximum supported payload size
+#define UDP_ACCELERATION_MAX_PADDING_SIZE 32 // Maximum padding size
+
+#define UDP_ACCELERATION_REQUIRE_CONTINUOUS (10 * 1000) // Not to use if stable communication is not continued at least for this time
+
+// Time constant for Build 8534 or earlier
+#define UDP_ACCELERATION_KEEPALIVE_INTERVAL_MIN (1 * 1000) // Keep Alive Interval (minimum)
+#define UDP_ACCELERATION_KEEPALIVE_INTERVAL_MAX (3 * 1000) // Keep Alive Interval (maximum)
+#define UDP_ACCELERATION_KEEPALIVE_TIMEOUT (9 * 1000) // Time to disconnect time by non-communication
+
+// Time constant for Build 8535 or later
+#define UDP_ACCELERATION_KEEPALIVE_INTERVAL_MIN_FAST (500) // Keep Alive Interval (minimum)
+#define UDP_ACCELERATION_KEEPALIVE_INTERVAL_MAX_FAST (1000) // Keep Alive Interval (maximum)
+#define UDP_ACCELERATION_KEEPALIVE_TIMEOUT_FAST (2100) // Time to disconnect time by non-communication
+
+// Range of port numbers
+#define UDP_SERVER_PORT_LOWER 40000 // Minimum port
+#define UDP_SERVER_PORT_HIGHER 44999 // Maximum port
+
+// NAT-T port signature to be embedded in the Keep Alive of the session
+#define UDP_NAT_T_PORT_SIGNATURE_IN_KEEP_ALIVE "NATT_MY_PORT"
+
+// UDP Acceleration Mode
+struct UDP_ACCEL
+{
+ CEDAR *Cedar; // Cedar
+ bool NoNatT; // Not to communicate with the NAT-T server (To communicate with the query server instead)
+ bool ClientMode; // Whether client mode
+ bool IsInCedarPortList; // Whether included in the port list of the Cedar
+ UINT64 Now; // Current time
+ UCHAR MyKey[UDP_ACCELERATION_COMMON_KEY_SIZE]; // Submit-direction common key
+ UCHAR YourKey[UDP_ACCELERATION_COMMON_KEY_SIZE]; // Receiving-direction common key
+ SOCK *UdpSock; // UDP socket
+ UINT MyPort; // My port number
+ UINT YourPort; // Port number of the other party
+ IP MyIp; // My IP address
+ IP YourIp; // IP address of the other party
+ IP YourIp2; // IP address of the other party (second)
+ bool IsIPv6; // Whether it's an IPv6
+ UCHAR TmpBuf[UDP_ACCELERATION_TMP_BUF_SIZE]; // Temporary buffer
+ UINT64 LastRecvYourTick; // Opponent's tick value of the last reception
+ UINT64 LastRecvMyTick; // My tick value of the last reception
+ QUEUE *RecvBlockQueue; // Reception block queue
+ bool UseHMac; // Flag to use the HMAC
+ bool PlainTextMode; // No encryption
+ UINT64 LastSetSrcIpAndPortTick; // Opponent's tick ??value at the time of storing the IP address and port number of the opponent at the end
+ UINT64 LastRecvTick; // Tick when data has received at the end
+ UINT64 NextSendKeepAlive; // Next time to send a KeepAlive packet
+ UCHAR NextIv[UDP_ACCELERATION_PACKET_IV_SIZE]; // IV to be used next
+ UINT MyCookie; // My cookie
+ UINT YourCookie; // Cookie of the other party
+ bool Inited; // Initialized flag
+ UINT Mss; // Optimal MSS
+ UINT MaxUdpPacketSize; // Get the maximum transmittable UDP size
+ LOCK *NatT_Lock; // Lock the IP address field of NAT-T server
+ IP NatT_IP; // IP address of the NAT-T server
+ THREAD *NatT_GetIpThread; // IP address acquisition thread of NAT-T server
+ bool NatT_Halt; // Halting flag of IP address acquisition thread of NAT-T server
+ EVENT *NatT_HaltEvent; // Halting event of IP address acquisition thread of NAT-T server
+ UINT64 NextPerformNatTTick; // Time to communicate with NAT-T server next time
+ UINT CommToNatT_NumFail; // Number of failures to communicate with NAT-T server
+ UINT MyPortByNatTServer; // Self port number which is received from the NAT-T server
+ bool MyPortByNatTServerChanged; // The self port number which is received from the NAT-T server changes
+ UINT YourPortByNatTServer; // Port number of the opponent that was found via the NAT-T server
+ bool YourPortByNatTServerChanged; // Port number of the opponent that was found via the NAT-T server has been changed
+ bool FatalError; // A fatal error occurred
+ bool NatT_IP_Changed; // IP address of the NAT-T server has changed
+ UINT64 NatT_TranId; // Transaction ID to be exchanged with the NAT-T server
+ bool IsReachedOnce; // It is true if it succeeds in mutual transmission and reception of packets at least once
+ UINT64 CreatedTick; // Object creation time
+ bool FastDetect; // Fast disconnection detection mode
+ UINT64 FirstStableReceiveTick; // Start time of current stable continued receivable period
+ bool UseUdpIpQuery; // Use the self IP address query by UDP
+ IP UdpIpQueryHost; // Host for the self IP address query by UDP
+ UINT UdpIpQueryPort; // Port number for self IP address for query by UDP
+ UCHAR UdpIpQueryPacketData[16]; // Query packet data (final transmission)
+ UINT UdpIpQueryPacketSize; // Query packet data size (final transmission)
+ UCHAR UdpHostUniqueKey[SHA1_SIZE]; // Unique key for UDP self endpoint query
+};
+
+// Function prototype
+UDP_ACCEL *NewUdpAccel(CEDAR *cedar, IP *ip, bool client_mode, bool random_port, bool no_nat_t);
+void FreeUdpAccel(UDP_ACCEL *a);
+bool UdpAccelInitClient(UDP_ACCEL *a, UCHAR *server_key, IP *server_ip, UINT server_port, UINT server_cookie, UINT client_cookie, IP *server_ip_2);
+bool UdpAccelInitServer(UDP_ACCEL *a, UCHAR *client_key, IP *client_ip, UINT client_port, IP *client_ip_2);
+void UdpAccelPoll(UDP_ACCEL *a);
+void UdpAccelSetTick(UDP_ACCEL *a, UINT64 tick64);
+BLOCK *UdpAccelProcessRecvPacket(UDP_ACCEL *a, UCHAR *buf, UINT size, IP *src_ip, UINT src_port);
+void UdpAccelCalcKey(UCHAR *key, UCHAR *common_key, UCHAR *iv);
+bool UdpAccelIsSendReady(UDP_ACCEL *a, bool check_keepalive);
+void UdpAccelSend(UDP_ACCEL *a, UCHAR *data, UINT data_size, bool compressed, UINT max_size, bool high_priority);
+void UdpAccelSendBlock(UDP_ACCEL *a, BLOCK *b);
+UINT UdpAccelCalcMss(UDP_ACCEL *a);
+void NatT_GetIpThread(THREAD *thread, void *param);
+
+#endif // UDPACCEL_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/VG.c b/src/Cedar/VG.c
new file mode 100644
index 00000000..6c7c5638
--- /dev/null
+++ b/src/Cedar/VG.c
@@ -0,0 +1,105 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// VG.c
+// VPN Gate Plugin Main Implementation
+
+#include "CedarPch.h"
+
+
+bool InitVg()
+{
+ return false;
+}
+
+void FreeVg()
+{
+}
+
+void VgUseStaticLink()
+{
+}
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/VG.h b/src/Cedar/VG.h
new file mode 100644
index 00000000..54339232
--- /dev/null
+++ b/src/Cedar/VG.h
@@ -0,0 +1,101 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// VG.h
+// Header for VG.c
+
+#ifndef VG_H
+#define VG_H
+
+#define VG_HUBNAME "VPNGATE"
+
+
+bool InitVg();
+void FreeVg();
+void VgUseStaticLink();
+
+#endif // VG_H
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/VLan.c b/src/Cedar/VLan.c
new file mode 100644
index 00000000..6186e2b6
--- /dev/null
+++ b/src/Cedar/VLan.c
@@ -0,0 +1,108 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// VLan.c
+// Virtual LAN card adapter manipulation library
+
+#include <GlobalConst.h>
+
+#define VLAN_C
+
+#ifdef WIN32
+#define OS_WIN32
+#endif
+
+#ifdef OS_WIN32
+
+// For Win32
+#include "VLanWin32.c"
+
+#else
+
+// For UNIX
+#include "VLanUnix.c"
+
+#endif // OS_WIN32
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/VLan.h b/src/Cedar/VLan.h
new file mode 100644
index 00000000..1c2fdba7
--- /dev/null
+++ b/src/Cedar/VLan.h
@@ -0,0 +1,112 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// VLan.h
+// Header of VLan.c
+
+#ifndef VLAN_H
+#define VLAN_H
+
+// Parameters related to VLAN
+struct VLAN_PARAM
+{
+ UCHAR MacAddress[6];
+ UCHAR Padding[2];
+};
+
+#ifdef OS_WIN32
+
+// For Win32
+#include <Cedar/VLanWin32.h>
+
+#else // OS_WIN32
+
+// For UNIX
+#include <Cedar/VLanUnix.h>
+
+#endif // OS_WIN32
+
+#endif // VLAN_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/VLanUnix.c b/src/Cedar/VLanUnix.c
new file mode 100644
index 00000000..c3e77d0c
--- /dev/null
+++ b/src/Cedar/VLanUnix.c
@@ -0,0 +1,791 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// VLanUnix.c
+// Virtual device driver library for UNIX
+
+#include <GlobalConst.h>
+
+#ifdef VLAN_C
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+
+#ifdef OS_UNIX
+
+static LIST *unix_vlan = NULL;
+
+#ifndef NO_VLAN
+
+// Get the PACKET_ADAPTER
+PACKET_ADAPTER *VLanGetPacketAdapter()
+{
+ PACKET_ADAPTER *pa;
+
+ pa = NewPacketAdapter(VLanPaInit, VLanPaGetCancel,
+ VLanPaGetNextPacket, VLanPaPutPacket, VLanPaFree);
+ if (pa == NULL)
+ {
+ return NULL;
+ }
+
+ return pa;
+}
+
+// PA initialization
+bool VLanPaInit(SESSION *s)
+{
+ VLAN *v;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ // Connect to the driver
+ v = NewVLan(s->ClientOption->DeviceName, NULL);
+ if (v == NULL)
+ {
+ // Failure
+ return false;
+ }
+
+ s->PacketAdapter->Param = v;
+
+ return true;
+}
+
+// Get the cancel object
+CANCEL *VLanPaGetCancel(SESSION *s)
+{
+ VLAN *v;
+ // Validate arguments
+ if ((s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
+ {
+ return NULL;
+ }
+
+ return VLanGetCancel(v);
+}
+
+// Release the packet adapter
+void VLanPaFree(SESSION *s)
+{
+ VLAN *v;
+ // Validate arguments
+ if ((s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
+ {
+ return;
+ }
+
+ // End the virtual LAN card
+ FreeVLan(v);
+
+ s->PacketAdapter->Param = NULL;
+}
+
+// Write a packet
+bool VLanPaPutPacket(SESSION *s, void *data, UINT size)
+{
+ VLAN *v;
+ // Validate arguments
+ if ((s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
+ {
+ return false;
+ }
+
+ return VLanPutPacket(v, data, size);
+}
+
+// Get the next packet
+UINT VLanPaGetNextPacket(SESSION *s, void **data)
+{
+ VLAN *v;
+ UINT size;
+ // Validate arguments
+ if (data == NULL || (s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
+ {
+ return INFINITE;
+ }
+
+ if (VLanGetNextPacket(v, data, &size) == false)
+ {
+ return INFINITE;
+ }
+
+ return size;
+}
+
+// Write a packet to the virtual LAN card
+bool VLanPutPacket(VLAN *v, void *buf, UINT size)
+{
+ UINT ret;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return false;
+ }
+ if (v->Halt)
+ {
+ return false;
+ }
+ if (size > MAX_PACKET_SIZE)
+ {
+ return false;
+ }
+ if (buf == NULL || size == 0)
+ {
+ if (buf != NULL)
+ {
+ Free(buf);
+ }
+ return true;
+ }
+
+ ret = write(v->fd, buf, size);
+
+ if (ret >= 1)
+ {
+ Free(buf);
+ return true;
+ }
+
+ if (errno == EAGAIN || ret == 0)
+ {
+ Free(buf);
+ return true;
+ }
+
+ return false;
+}
+
+// Get the next packet from the virtual LAN card
+bool VLanGetNextPacket(VLAN *v, void **buf, UINT *size)
+{
+ UCHAR tmp[TAP_READ_BUF_SIZE];
+ int ret;
+ // Validate arguments
+ if (v == NULL || buf == NULL || size == 0)
+ {
+ return false;
+ }
+ if (v->Halt)
+ {
+ return false;
+ }
+
+ // Read
+ ret = read(v->fd, tmp, sizeof(tmp));
+
+ if (ret == 0 ||
+ (ret == -1 && errno == EAGAIN))
+ {
+ // No packet
+ *buf = NULL;
+ *size = 0;
+ return true;
+ }
+ else if (ret == -1 || ret > TAP_READ_BUF_SIZE)
+ {
+ // Error
+ return false;
+ }
+ else
+ {
+ // Reading packet success
+ *buf = Malloc(ret);
+ Copy(*buf, tmp, ret);
+ *size = ret;
+ return true;
+ }
+}
+
+// Get the cancel object
+CANCEL *VLanGetCancel(VLAN *v)
+{
+ CANCEL *c;
+ int fd;
+ int yes = 0;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return NULL;
+ }
+
+ c = NewCancel();
+ UnixDeletePipe(c->pipe_read, c->pipe_write);
+ c->pipe_read = c->pipe_write = -1;
+
+ fd = v->fd;
+
+#ifndef UNIX_MACOS
+ UnixSetSocketNonBlockingMode(fd, true);
+#else // UNIX_MACOS
+ UnixSetSocketNonBlockingMode(fd, false);
+#endif // UNIX_MACOS
+
+ c->SpecialFlag = true;
+ c->pipe_read = fd;
+
+ return c;
+}
+
+// Close the Virtual LAN card
+void FreeVLan(VLAN *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ Free(v->InstanceName);
+
+ Free(v);
+}
+
+// Create a tap
+VLAN *NewTap(char *name, char *mac_address)
+{
+ int fd;
+ VLAN *v;
+ // Validate arguments
+ if (name == NULL || mac_address == NULL)
+ {
+ return NULL;
+ }
+
+ fd = UnixCreateTapDeviceEx(name, "tap", mac_address);
+ if (fd == -1)
+ {
+ return NULL;
+ }
+
+ v = ZeroMalloc(sizeof(VLAN));
+ v->Halt = false;
+ v->InstanceName = CopyStr(name);
+ v->fd = fd;
+
+ return v;
+}
+
+// Close the tap
+void FreeTap(VLAN *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ close(v->fd);
+ FreeVLan(v);
+}
+
+// Get the Virtual LAN card list
+VLAN *NewVLan(char *instance_name, VLAN_PARAM *param)
+{
+ int fd;
+ VLAN *v;
+ // Validate arguments
+ if (instance_name == NULL)
+ {
+ return NULL;
+ }
+
+ // Open the tap
+ fd = UnixVLanGet(instance_name);
+ if (fd == -1)
+ {
+ return NULL;
+ }
+
+ v = ZeroMalloc(sizeof(VLAN));
+ v->Halt = false;
+ v->InstanceName = CopyStr(instance_name);
+ v->fd = fd;
+
+ return v;
+}
+
+// Create a tap device
+int UnixCreateTapDeviceEx(char *name, char *prefix, UCHAR *mac_address)
+{
+ int fd;
+ struct ifreq ifr;
+ char eth_name[MAX_SIZE];
+ char instance_name_lower[MAX_SIZE];
+ struct sockaddr sa;
+ char *tap_name = TAP_FILENAME_1;
+ int s;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return -1;
+ }
+
+ // Generate the device name
+ StrCpy(instance_name_lower, sizeof(instance_name_lower), name);
+ Trim(instance_name_lower);
+ StrLower(instance_name_lower);
+ Format(eth_name, sizeof(eth_name), "%s_%s", prefix, instance_name_lower);
+
+ eth_name[15] = 0;
+
+ // Open the tun / tap
+#ifndef UNIX_MACOS
+ if (GetOsInfo()->OsType == OSTYPE_LINUX)
+ {
+ // Linux
+ if (IsFile(TAP_FILENAME_1) == false)
+ {
+ char tmp[MAX_SIZE];
+
+ Format(tmp, sizeof(tmp), "%s c 10 200", TAP_FILENAME_1);
+ Run("mknod", tmp, true, true);
+
+ Format(tmp, sizeof(tmp), "600 %s", TAP_FILENAME_1);
+ Run("chmod", tmp, true, true);
+ }
+ }
+ // Other than MacOS X
+ fd = open(TAP_FILENAME_1, O_RDWR);
+ if (fd == -1)
+ {
+ // Failure
+ fd = open(TAP_FILENAME_2, O_RDWR);
+ if (fd == -1)
+ {
+ return -1;
+ }
+ tap_name = TAP_FILENAME_2;
+ }
+#else // UNIX_MACOS
+ // MacOS X
+ fd = open(TAP_MACOS_FILENAME, O_RDWR);
+ if (fd == -1)
+ {
+ return -1;
+ }
+ tap_name = TAP_MACOS_FILENAME;
+#endif // UNIX_MACOS
+
+#ifdef UNIX_LINUX
+ // Create a tap for Linux
+
+ // Set the device name
+ Zero(&ifr, sizeof(ifr));
+
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), eth_name);
+
+ if (ioctl(fd, TUNSETIFF, &ifr) == -1)
+ {
+ // Failure
+ close(fd);
+ return -1;
+ }
+
+ // MAC address setting
+ s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (s != -1)
+ {
+ if (mac_address != NULL)
+ {
+ Zero(&ifr, sizeof(ifr));
+ StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), eth_name);
+ ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
+ Copy(&ifr.ifr_hwaddr.sa_data, mac_address, 6);
+ ioctl(s, SIOCSIFHWADDR, &ifr);
+ }
+
+ Zero(&ifr, sizeof(ifr));
+ StrCpy(ifr.ifr_name, sizeof(ifr.ifr_name), eth_name);
+ ioctl(s, SIOCGIFFLAGS, &ifr);
+
+ ifr.ifr_flags |= IFF_UP;
+ ioctl(s, SIOCSIFFLAGS, &ifr);
+
+ close(s);
+ }
+
+#else // UNIX_LINUX
+#ifdef UNIX_SOLARIS
+ // Create a tap for Solaris
+ {
+ int ip_fd;
+ int tun_fd;
+ int ppa;
+
+ tun_fd = open(tap_name, O_RDWR);
+ if (tun_fd == -1)
+ {
+ // Failure
+ close(fd);
+ return -1;
+ }
+
+ ip_fd = open("/dev/ip", O_RDWR);
+ if (ip_fd == -1)
+ {
+ // Failure
+ close(tun_fd);
+ close(fd);
+ return -1;
+ }
+
+ ppa = -1;
+ ppa = ioctl(tun_fd, TUNNEWPPA, ppa);
+ if (ppa == -1)
+ {
+ // Failure
+ close(tun_fd);
+ close(fd);
+ close(ip_fd);
+ return -1;
+ }
+
+ if (ioctl(fd, I_PUSH, "ip") < 0)
+ {
+ // Failure
+ close(tun_fd);
+ close(fd);
+ close(ip_fd);
+ return -1;
+ }
+
+ if (ioctl(fd, IF_UNITSEL, (char *)&ppa) < 0)
+ {
+ // Failure
+ close(tun_fd);
+ close(fd);
+ close(ip_fd);
+ return -1;
+ }
+
+ if (ioctl(ip_fd, I_LINK, fd) < 0)
+ {
+ // Failure
+ close(tun_fd);
+ close(fd);
+ close(ip_fd);
+ return -1;
+ }
+
+ close(tun_fd);
+ close(ip_fd);
+ }
+
+#endif // UNIX_SOLARIS
+#endif // UNIX_LINUX
+
+ return fd;
+}
+int UnixCreateTapDevice(char *name, UCHAR *mac_address)
+{
+ return UnixCreateTapDeviceEx(name, "vpn", mac_address);
+}
+
+// Close the tap device
+void UnixCloseTapDevice(int fd)
+{
+ // Validate arguments
+ if (fd == -1)
+ {
+ return;
+ }
+
+ close(fd);
+}
+
+#else // NO_VLAN
+
+void UnixCloseTapDevice(int fd)
+{
+}
+
+int UnixCreateTapDeviceEx(char *name, char *prefix, UCHAR *mac_address)
+{
+ return -1;
+}
+int UnixCreateTapDevice(char *name, UCHAR *mac_address)
+{
+ return -1;
+}
+
+#endif // NO_VLAN
+
+// Comparison of the VLAN list entries
+int UnixCompareVLan(void *p1, void *p2)
+{
+ UNIX_VLAN_LIST *v1, *v2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ v1 = *(UNIX_VLAN_LIST **)p1;
+ v2 = *(UNIX_VLAN_LIST **)p2;
+ if (v1 == NULL || v2 == NULL)
+ {
+ return 0;
+ }
+
+ return StrCmpi(v1->Name, v2->Name);
+}
+
+// Initialize the VLAN list
+void UnixVLanInit()
+{
+ unix_vlan = NewList(UnixCompareVLan);
+}
+
+// Create a VLAN
+bool UnixVLanCreateEx(char *name, char *prefix, UCHAR *mac_address)
+{
+ // Validate arguments
+ char tmp[MAX_SIZE];
+ if (name == NULL)
+ {
+ return false;
+ }
+
+ StrCpy(tmp, sizeof(tmp), name);
+ Trim(tmp);
+ name = tmp;
+
+ LockList(unix_vlan);
+ {
+ UNIX_VLAN_LIST *t, tt;
+ int fd;
+
+ // Check whether a device with the same name exists
+ Zero(&tt, sizeof(tt));
+ StrCpy(tt.Name, sizeof(tt.Name), name);
+
+ t = Search(unix_vlan, &tt);
+ if (t != NULL)
+ {
+ // Already exist
+ UnlockList(unix_vlan);
+ return false;
+ }
+
+ // Create a tap device
+ fd = UnixCreateTapDeviceEx(name, prefix, mac_address);
+ if (fd == -1)
+ {
+ // Failure to create
+ UnlockList(unix_vlan);
+ return false;
+ }
+
+ t = ZeroMalloc(sizeof(UNIX_VLAN_LIST));
+ t->fd = fd;
+ StrCpy(t->Name, sizeof(t->Name), name);
+
+ Insert(unix_vlan, t);
+ }
+ UnlockList(unix_vlan);
+
+ return true;
+}
+bool UnixVLanCreate(char *name, UCHAR *mac_address)
+{
+ return UnixVLanCreateEx(name, "vpn", mac_address);
+}
+
+// Enumerate VLANs
+TOKEN_LIST *UnixVLanEnum()
+{
+ TOKEN_LIST *ret;
+ UINT i;
+ if (unix_vlan == NULL)
+ {
+ return NullToken();
+ }
+
+ ret = ZeroMalloc(sizeof(TOKEN_LIST));
+
+ LockList(unix_vlan);
+ {
+ ret->NumTokens = LIST_NUM(unix_vlan);
+ ret->Token = ZeroMalloc(sizeof(char *) * ret->NumTokens);
+
+ for (i = 0;i < ret->NumTokens;i++)
+ {
+ UNIX_VLAN_LIST *t = LIST_DATA(unix_vlan, i);
+
+ ret->Token[i] = CopyStr(t->Name);
+ }
+ }
+ UnlockList(unix_vlan);
+
+ return ret;
+}
+
+// Delete the VLAN
+void UnixVLanDelete(char *name)
+{
+ // Validate arguments
+ if (name == NULL || unix_vlan == NULL)
+ {
+ return;
+ }
+
+ LockList(unix_vlan);
+ {
+ UINT i;
+ UNIX_VLAN_LIST *t, tt;
+
+ Zero(&tt, sizeof(tt));
+ StrCpy(tt.Name, sizeof(tt.Name), name);
+
+ t = Search(unix_vlan, &tt);
+ if (t != NULL)
+ {
+ UnixCloseTapDevice(t->fd);
+ Delete(unix_vlan, t);
+ Free(t);
+ }
+ }
+ UnlockList(unix_vlan);
+}
+
+// Get the VLAN
+int UnixVLanGet(char *name)
+{
+ int fd = -1;
+ // Validate arguments
+ if (name == NULL || unix_vlan == NULL)
+ {
+ return -1;
+ }
+
+ LockList(unix_vlan);
+ {
+ UINT i;
+ UNIX_VLAN_LIST *t, tt;
+
+ Zero(&tt, sizeof(tt));
+ StrCpy(tt.Name, sizeof(tt.Name), name);
+
+ t = Search(unix_vlan, &tt);
+ if (t != NULL)
+ {
+ fd = t->fd;
+ }
+ }
+ UnlockList(unix_vlan);
+
+ return fd;
+}
+
+// Release the VLAN list
+void UnixVLanFree()
+{
+ UINT i;
+
+ for (i = 0;i < LIST_NUM(unix_vlan);i++)
+ {
+ UNIX_VLAN_LIST *t = LIST_DATA(unix_vlan, i);
+
+ UnixCloseTapDevice(t->fd);
+ Free(t);
+ }
+
+ ReleaseList(unix_vlan);
+ unix_vlan = NULL;
+}
+
+#endif // OS_UNIX
+
+#endif // VLAN_C
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/VLanUnix.h b/src/Cedar/VLanUnix.h
new file mode 100644
index 00000000..90449494
--- /dev/null
+++ b/src/Cedar/VLanUnix.h
@@ -0,0 +1,144 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// VLanUnix.h
+// Header of VLanUnix.c
+
+#ifndef VLANUNIX_H
+#define VLANUNIX_H
+
+// Constant
+#define TAP_READ_BUF_SIZE 1600
+
+#ifndef NO_VLAN
+
+// VLAN structure
+struct VLAN
+{
+ volatile bool Halt; // Halt flag
+ char *InstanceName; // Instance name
+ int fd; // File
+};
+
+// Function prototype
+VLAN *NewVLan(char *instance_name, VLAN_PARAM *param);
+VLAN *NewTap(char *name, char *mac_address);
+void FreeVLan(VLAN *v);
+CANCEL *VLanGetCancel(VLAN *v);
+bool VLanGetNextPacket(VLAN *v, void **buf, UINT *size);
+bool VLanPutPacket(VLAN *v, void *buf, UINT size);
+
+PACKET_ADAPTER *VLanGetPacketAdapter();
+bool VLanPaInit(SESSION *s);
+CANCEL *VLanPaGetCancel(SESSION *s);
+UINT VLanPaGetNextPacket(SESSION *s, void **data);
+bool VLanPaPutPacket(SESSION *s, void *data, UINT size);
+void VLanPaFree(SESSION *s);
+
+#else // NO_VLAN
+
+#define VLanGetPacketAdapter NullGetPacketAdapter
+
+#endif // NO_VLAN
+
+struct UNIX_VLAN_LIST
+{
+ char Name[MAX_SIZE]; // Device name
+ int fd; // fd
+};
+
+int UnixCreateTapDevice(char *name, UCHAR *mac_address);
+int UnixCreateTapDeviceEx(char *name, char *prefix, UCHAR *mac_address);
+void UnixCloseTapDevice(int fd);
+void UnixVLanInit();
+void UnixVLanFree();
+bool UnixVLanCreate(char *name, UCHAR *mac_address);
+bool UnixVLanCreateEx(char *name, char *prefix, UCHAR *mac_address);
+TOKEN_LIST *UnixVLanEnum();
+void UnixVLanDelete(char *name);
+int UnixVLanGet(char *name);
+int UnixCompareVLan(void *p1, void *p2);
+
+#endif // VLANUNIX_H
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/VLanWin32.c b/src/Cedar/VLanWin32.c
new file mode 100644
index 00000000..777c9ca0
--- /dev/null
+++ b/src/Cedar/VLanWin32.c
@@ -0,0 +1,1587 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// VLanWin32.c
+// Virtual device driver library for Win32
+
+#include <GlobalConst.h>
+
+#ifdef VLAN_C
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+
+#ifdef OS_WIN32
+
+typedef DWORD(CALLBACK* OPENVXDHANDLE)(HANDLE);
+
+// Get the version information of Windows
+void Win32GetWinVer(RPC_WINVER *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ Zero(v, sizeof(RPC_WINVER));
+
+ v->IsWindows = true;
+
+ if (OS_IS_WINDOWS_NT(GetOsType()) == false)
+ {
+ // Windows 9x
+ OSVERSIONINFO os;
+ Zero(&os, sizeof(os));
+ os.dwOSVersionInfoSize = sizeof(os);
+ GetVersionEx(&os);
+
+ v->Build = LOWORD(os.dwBuildNumber);
+ v->VerMajor = os.dwMajorVersion;
+ v->VerMinor = os.dwMinorVersion;
+
+ Format(v->Title, sizeof(v->Title), "%s %s",
+ GetOsInfo()->OsProductName,
+ GetOsInfo()->OsVersion);
+ Trim(v->Title);
+ }
+ else
+ {
+ // Windows NT 4.0 SP6 or later
+ OSVERSIONINFOEX os;
+ Zero(&os, sizeof(os));
+ os.dwOSVersionInfoSize = sizeof(os);
+ Win32GetVersionExInternal((LPOSVERSIONINFOA)&os);
+
+ v->IsNT = true;
+ v->Build = os.dwBuildNumber;
+ v->ServicePack = os.wServicePackMajor;
+
+ if (os.wProductType != VER_NT_WORKSTATION)
+ {
+ v->IsServer = true;
+ }
+ v->VerMajor = os.dwMajorVersion;
+ v->VerMinor = os.dwMinorVersion;
+
+ if (GetOsInfo()->OsServicePack == 0)
+ {
+ StrCpy(v->Title, sizeof(v->Title), GetOsInfo()->OsProductName);
+ }
+ else
+ {
+ Format(v->Title, sizeof(v->Title), "%s Service Pack %u",
+ GetOsInfo()->OsProductName,
+ GetOsInfo()->OsServicePack);
+ }
+ Trim(v->Title);
+
+ if (InStr(GetOsInfo()->OsVersion, "rc") ||
+ InStr(GetOsInfo()->OsVersion, "beta"))
+ {
+ v->IsBeta = true;
+ }
+ }
+}
+
+// Release the DHCP addresses of all virtual LAN cards
+void Win32ReleaseAllDhcp9x(bool wait)
+{
+ TOKEN_LIST *t;
+ UINT i;
+
+ t = MsEnumNetworkAdapters(VLAN_ADAPTER_NAME, VLAN_ADAPTER_NAME_OLD);
+ if (t == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ char *name = t->Token[i];
+ UINT id = GetInstanceId(name);
+ if (id != 0)
+ {
+ Win32ReleaseDhcp9x(id, wait);
+ }
+ }
+
+ FreeToken(t);
+}
+
+// Routing table tracking main
+void RouteTrackingMain(SESSION *s)
+{
+ ROUTE_TRACKING *t;
+ UINT64 now;
+ ROUTE_TABLE *table;
+ ROUTE_ENTRY *rs;
+ bool changed = false;
+ bool check = false;
+ bool any_modified = false;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+ if (s->ClientModeAndUseVLan == false)
+ {
+ return;
+ }
+
+ // Get the state
+ t = ((VLAN *)s->PacketAdapter->Param)->RouteState;
+ if (t == NULL)
+ {
+ return;
+ }
+
+ // Current time
+ PROBE_STR("RouteTrackingMain 1");
+ now = Tick64();
+
+ if (t->RouteChange != NULL)
+ {
+ if (t->NextRouteChangeCheckTime == 0 ||
+ t->NextRouteChangeCheckTime <= now)
+ {
+ t->NextRouteChangeCheckTime = now + 1000ULL;
+
+ check = IsRouteChanged(t->RouteChange);
+
+ if (check)
+ {
+ Debug("*** Routing Table Changed ***\n");
+ t->NextTrackingTime = 0;
+ }
+ }
+ }
+ if (t->NextTrackingTime != 0 && t->NextTrackingTime > now)
+ {
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL && s->UdpAccel->NatT_IP_Changed)
+ {
+ // Check always if the IP address of the NAT-T server has changed
+ }
+ else
+ {
+ PROBE_STR("RouteTrackingMain 2");
+ return;
+ }
+ }
+ PROBE_STR("RouteTrackingMain 3");
+
+ if (s->UseUdpAcceleration && s->UdpAccel != NULL)
+ {
+ IP nat_t_ip;
+
+ s->UdpAccel->NatT_IP_Changed = false;
+
+ Zero(&nat_t_ip, sizeof(nat_t_ip));
+
+ Lock(s->UdpAccel->NatT_Lock);
+ {
+ Copy(&nat_t_ip, &s->UdpAccel->NatT_IP, sizeof(IP));
+ }
+ Unlock(s->UdpAccel->NatT_Lock);
+
+ // Add a route to the NAT-T server
+ if (IsZeroIp(&nat_t_ip) == false)
+ {
+ if (t->RouteToNatTServer == NULL)
+ {
+ if (t->RouteToEight != NULL)
+ {
+ ROUTE_ENTRY *e = Clone(t->RouteToEight, sizeof(ROUTE_ENTRY));
+ char ip_str[64];
+ char ip_str2[64];
+
+ Copy(&e->DestIP, &nat_t_ip, sizeof(IP));
+ e->Metric = e->OldIfMetric;
+
+ IPToStr(ip_str, sizeof(ip_str), &e->DestIP);
+ IPToStr(ip_str2, sizeof(ip_str2), &e->GatewayIP);
+
+ t->RouteToNatTServer = e;
+
+ if (AddRouteEntry(t->RouteToNatTServer))
+ {
+ Debug("Adding Static Route to %s via %s metric %u: ok.\n", ip_str, ip_str2, e->Metric);
+ }
+ else
+ {
+ FreeRouteEntry(t->RouteToNatTServer);
+ t->RouteToNatTServer = NULL;
+ }
+ }
+ }
+ }
+ }
+
+ // Get the current routing table
+ table = GetRouteTable();
+ rs = t->RouteToServer;
+ if (table != NULL)
+ {
+ UINT i;
+ bool route_to_server_erased = true;
+ bool is_vlan_want_to_be_default_gateway = false;
+ UINT vlan_default_gatewat_metric = 0;
+ UINT other_if_default_gateway_metric_min = INFINITE;
+
+ // Get whether the routing table have been changed
+ if (t->LastRoutingTableHash != table->HashedValue)
+ {
+ t->LastRoutingTableHash = table->HashedValue;
+ changed = true;
+ }
+
+ //DebugPrintRouteTable(table);
+
+ // Scan the routing table
+ for (i = 0;i < table->NumEntry;i++)
+ {
+ ROUTE_ENTRY *e = table->Entry[i];
+
+ if (rs != NULL)
+ {
+ if (CmpIpAddr(&e->DestIP, &rs->DestIP) == 0 &&
+ CmpIpAddr(&e->DestMask, &rs->DestMask) == 0
+// && CmpIpAddr(&e->GatewayIP, &rs->GatewayIP) == 0
+// && e->InterfaceID == rs->InterfaceID &&
+// e->LocalRouting == rs->LocalRouting &&
+// e->Metric == rs->Metric
+ )
+ {
+ // Routing entry to the server that added at the time of connection is found
+ route_to_server_erased = false;
+ }
+ }
+
+ // Search for the default gateway
+ if (IPToUINT(&e->DestIP) == 0 &&
+ IPToUINT(&e->DestMask) == 0)
+ {
+ Debug("e->InterfaceID = %u, t->VLanInterfaceId = %u\n",
+ e->InterfaceID, t->VLanInterfaceId);
+
+ if (e->InterfaceID == t->VLanInterfaceId)
+ {
+ // The virtual LAN card think that he want to be a default gateway
+ is_vlan_want_to_be_default_gateway = true;
+ vlan_default_gatewat_metric = e->Metric;
+
+ if (vlan_default_gatewat_metric >= 2 &&
+ t->OldDefaultGatewayMetric == (vlan_default_gatewat_metric - 1))
+ {
+ // Restore because the PPP server rewrites
+ // the routing table selfishly
+ DeleteRouteEntry(e);
+ e->Metric--;
+ AddRouteEntry(e);
+ Debug("** Restore metric destroyed by PPP.\n");
+
+ any_modified = true;
+ }
+
+ // Keep this entry
+ if (t->DefaultGatewayByVLan != NULL)
+ {
+ // Delete if there is one added last time
+ FreeRouteEntry(t->DefaultGatewayByVLan);
+ }
+
+ t->DefaultGatewayByVLan = ZeroMalloc(sizeof(ROUTE_ENTRY));
+ Copy(t->DefaultGatewayByVLan, e, sizeof(ROUTE_ENTRY));
+
+ t->OldDefaultGatewayMetric = vlan_default_gatewat_metric;
+ }
+ else
+ {
+ // There are default gateway other than the virtual LAN card
+ // Save the metric value of the default gateway
+ if (other_if_default_gateway_metric_min > e->Metric)
+ {
+ // Ignore the metric value of all PPP connection in the case of Windows Vista
+ if (MsIsVista() == false || e->PPPConnection == false)
+ {
+ other_if_default_gateway_metric_min = e->Metric;
+ }
+ else
+ {
+ // a PPP is used to Connect to the network
+ // in using Windows Vista
+ t->VistaAndUsingPPP = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (t->VistaAndUsingPPP)
+ {
+ if (t->DefaultGatewayByVLan != NULL)
+ {
+ if (is_vlan_want_to_be_default_gateway)
+ {
+ if (t->VistaOldDefaultGatewayByVLan == NULL || Cmp(t->VistaOldDefaultGatewayByVLan, t->DefaultGatewayByVLan, sizeof(ROUTE_ENTRY)) != 0)
+ {
+ ROUTE_ENTRY *e;
+ // Add the route of 0.0.0.0/1 and 128.0.0.0/1
+ // to the system if the virtual LAN card should be
+ // the default gateway in the case of the connection
+ // using PPP in Windows Vista
+
+ if (t->VistaOldDefaultGatewayByVLan != NULL)
+ {
+ FreeRouteEntry(t->VistaOldDefaultGatewayByVLan);
+ }
+
+ if (t->VistaDefaultGateway1 != NULL)
+ {
+ DeleteRouteEntry(t->VistaDefaultGateway1);
+ FreeRouteEntry(t->VistaDefaultGateway1);
+
+ DeleteRouteEntry(t->VistaDefaultGateway2);
+ FreeRouteEntry(t->VistaDefaultGateway2);
+ }
+
+ t->VistaOldDefaultGatewayByVLan = Clone(t->DefaultGatewayByVLan, sizeof(ROUTE_ENTRY));
+
+ e = Clone(t->DefaultGatewayByVLan, sizeof(ROUTE_ENTRY));
+ SetIP(&e->DestIP, 0, 0, 0, 0);
+ SetIP(&e->DestMask, 128, 0, 0, 0);
+ t->VistaDefaultGateway1 = e;
+
+ e = Clone(t->DefaultGatewayByVLan, sizeof(ROUTE_ENTRY));
+ SetIP(&e->DestIP, 128, 0, 0, 0);
+ SetIP(&e->DestMask, 128, 0, 0, 0);
+ t->VistaDefaultGateway2 = e;
+
+ AddRouteEntry(t->VistaDefaultGateway1);
+ AddRouteEntry(t->VistaDefaultGateway2);
+
+ Debug("Vista PPP Fix Route Table Added.\n");
+
+ any_modified = true;
+ }
+ }
+ else
+ {
+ if (t->VistaOldDefaultGatewayByVLan != NULL)
+ {
+ FreeRouteEntry(t->VistaOldDefaultGatewayByVLan);
+ t->VistaOldDefaultGatewayByVLan = NULL;
+ }
+
+ if (t->VistaDefaultGateway1 != NULL)
+ {
+ Debug("Vista PPP Fix Route Table Deleted.\n");
+ DeleteRouteEntry(t->VistaDefaultGateway1);
+ FreeRouteEntry(t->VistaDefaultGateway1);
+
+ DeleteRouteEntry(t->VistaDefaultGateway2);
+ FreeRouteEntry(t->VistaDefaultGateway2);
+
+ any_modified = true;
+
+ t->VistaDefaultGateway1 = t->VistaDefaultGateway2 = NULL;
+ }
+ }
+ }
+ }
+
+ // If the virtual LAN card want to be the default gateway and
+ // there is no LAN card with smaller metric of 0.0.0.0/0 than
+ // the virtual LAN card, delete other default gateway entries
+ // to elect the virtual LAN card as the default gateway
+// Debug("is_vlan_want_to_be_default_gateway = %u, rs = %u, route_to_server_erased = %u, other_if_default_gateway_metric_min = %u, vlan_default_gatewat_metric = %u\n",
+// is_vlan_want_to_be_default_gateway, rs, route_to_server_erased, other_if_default_gateway_metric_min, vlan_default_gatewat_metric);
+ if (is_vlan_want_to_be_default_gateway && (rs != NULL && route_to_server_erased == false) &&
+ other_if_default_gateway_metric_min >= vlan_default_gatewat_metric)
+ {
+ // Scan the routing table again
+ for (i = 0;i < table->NumEntry;i++)
+ {
+ ROUTE_ENTRY *e = table->Entry[i];
+
+ if (e->InterfaceID != t->VLanInterfaceId)
+ {
+ if (IPToUINT(&e->DestIP) == 0 &&
+ IPToUINT(&e->DestMask) == 0)
+ {
+ char str[64];
+ // Default gateway is found
+ ROUTE_ENTRY *r = ZeroMalloc(sizeof(ROUTE_ENTRY));
+
+ Copy(r, e, sizeof(ROUTE_ENTRY));
+
+ // Put in the queue
+ InsertQueue(t->DeletedDefaultGateway, r);
+
+ // Delete this gateway entry once
+ DeleteRouteEntry(e);
+
+ IPToStr(str, sizeof(str), &e->GatewayIP);
+ Debug("Default Gateway %s Deleted.\n", str);
+
+ any_modified = true;
+ }
+ }
+ }
+ }
+
+ if (rs != NULL && route_to_server_erased)
+ {
+ // Physical entry to the server has disappeared
+ Debug("Route to Server entry ERASED !!!\n");
+
+ // Forced disconnection (reconnection enabled)
+ s->RetryFlag = true;
+ s->Halt = true;
+ }
+
+ // Release the routing table
+ FreeRouteTable(table);
+ }
+
+ // Set the time to perform the next track
+ if (t->NextTrackingTimeAdd == 0 || changed)
+ {
+ t->NextTrackingTimeAdd = TRACKING_INTERVAL_INITIAL;
+ }
+ else
+ {
+ UINT64 max_value = TRACKING_INTERVAL_MAX;
+ if (t->RouteChange != NULL)
+ {
+ max_value = TRACKING_INTERVAL_MAX_RC;
+ }
+
+ t->NextTrackingTimeAdd += TRACKING_INTERVAL_ADD;
+
+ if (t->NextTrackingTimeAdd >= max_value)
+ {
+ t->NextTrackingTimeAdd = max_value;
+ }
+ }
+ //Debug("t->NextTrackingTimeAdd = %I64u\n", t->NextTrackingTimeAdd);
+ t->NextTrackingTime = now + t->NextTrackingTimeAdd;
+
+ if (any_modified)
+ {
+ // Clear the DNS cache
+ Win32FlushDnsCache();
+ }
+}
+
+// Start tracking of the routing table
+void RouteTrackingStart(SESSION *s)
+{
+ VLAN *v;
+ ROUTE_TRACKING *t;
+ UINT if_id = 0;
+ ROUTE_ENTRY *e;
+ ROUTE_ENTRY *dns = NULL;
+ ROUTE_ENTRY *route_to_real_server_global = NULL;
+ char tmp[64];
+ UINT exclude_if_id = 0;
+ bool already_exists = false;
+ bool already_exists_by_other_account = false;
+ IP eight;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return;
+ }
+
+ v = (VLAN *)s->PacketAdapter->Param;
+ if (v->RouteState != NULL)
+ {
+ return;
+ }
+
+ // Get the interface ID of the virtual LAN card
+ if_id = GetInstanceId(v->InstanceName);
+ Debug("[InstanceId of %s] = 0x%x\n", v->InstanceName, if_id);
+
+ if (MsIsVista())
+ {
+ // The routing table by the virtual LAN card body should be
+ // excluded explicitly in Windows Vista
+ exclude_if_id = if_id;
+ }
+
+ // Get the route to the server
+ e = GetBestRouteEntryEx(&s->ServerIP, exclude_if_id);
+ if (e == NULL)
+ {
+ // Acquisition failure
+ Debug("Failed to get GetBestRouteEntry().\n");
+ return;
+ }
+ IPToStr(tmp, sizeof(tmp), &e->GatewayIP);
+ Debug("GetBestRouteEntry() Succeed. [Gateway: %s]\n", tmp);
+
+ // Add a route
+ if (MsIsVista())
+ {
+ e->Metric = e->OldIfMetric;
+ }
+ if (AddRouteEntryEx(e, &already_exists) == false)
+ {
+ FreeRouteEntry(e);
+ e = NULL;
+ }
+ Debug("already_exists: %u\n", already_exists);
+
+ if (already_exists)
+ {
+ if (s->Cedar->Client != NULL && s->Account != NULL)
+ {
+ UINT i;
+ ACCOUNT *a;
+ for (i = 0;i < LIST_NUM(s->Cedar->Client->AccountList);i++)
+ {
+ a = LIST_DATA(s->Cedar->Client->AccountList, i);
+ Lock(a->lock);
+ {
+ SESSION *sess = a->ClientSession;
+ if (sess != NULL && sess != s)
+ {
+ VLAN *v = sess->PacketAdapter->Param;
+ if (v != NULL)
+ {
+ ROUTE_TRACKING *tr = v->RouteState;
+ if (tr != NULL && e != NULL)
+ {
+ if (Cmp(tr->RouteToServer, e, sizeof(ROUTE_ENTRY)) == 0)
+ {
+ already_exists_by_other_account = true;
+ }
+ }
+ }
+ }
+ }
+ Unlock(a->lock);
+ }
+ }
+
+ if (already_exists_by_other_account)
+ {
+ Debug("already_exists_by_other_account = %u\n", already_exists_by_other_account);
+ already_exists = false;
+ }
+ }
+
+ // Get the routing table to the DNS server
+ // (If the DNS server is this PC itself, there's no need to get)
+ if (IsZeroIP(&s->DefaultDns) == false)
+ {
+ if (IsMyIPAddress(&s->DefaultDns) == false)
+ {
+ dns = GetBestRouteEntryEx(&s->DefaultDns, exclude_if_id);
+ if (dns == NULL)
+ {
+ // Getting failure
+ Debug("Failed to get GetBestRouteEntry DNS.\n");
+ }
+ else
+ {
+ // Add a route
+ if (MsIsVista())
+ {
+ dns->Metric = dns->OldIfMetric;
+
+ if (AddRouteEntry(dns) == false)
+ {
+ FreeRouteEntry(dns);
+ dns = NULL;
+ }
+ }
+ }
+ }
+ }
+
+ if (s->IsAzureSession && IsZeroIP(&s->AzureRealServerGlobalIp) == false)
+ {
+ // Add also a static route to the real server in the case of via VPN Azure
+ if (IsMyIPAddress(&s->AzureRealServerGlobalIp) == false)
+ {
+ route_to_real_server_global = GetBestRouteEntryEx(&s->AzureRealServerGlobalIp, exclude_if_id);
+
+ if (route_to_real_server_global != NULL)
+ {
+ if (MsIsVista())
+ {
+ route_to_real_server_global->Metric = route_to_real_server_global->OldIfMetric;
+ }
+
+ if (AddRouteEntry(route_to_real_server_global) == false)
+ {
+ FreeRouteEntry(route_to_real_server_global);
+ route_to_real_server_global = NULL;
+ }
+ }
+ }
+ }
+
+ // Initialize
+ if (s->Cedar->Client != NULL && s->Account != NULL)
+ {
+ Lock(s->Account->lock);
+ }
+
+ t = ZeroMalloc(sizeof(ROUTE_TRACKING));
+ v->RouteState = t;
+
+ t->RouteToServerAlreadyExists = already_exists;
+ t->RouteToServer = e;
+ t->RouteToDefaultDns = dns;
+ t->RouteToRealServerGlobal = route_to_real_server_global;
+ t->VLanInterfaceId = if_id;
+ t->NextTrackingTime = 0;
+ t->DeletedDefaultGateway = NewQueue();
+ t->OldDefaultGatewayMetric = 0x7fffffff;
+
+ if (s->Cedar->Client != NULL && s->Account != NULL)
+ {
+ Unlock(s->Account->lock);
+ }
+
+ // Get the route to 8.8.8.8
+ SetIP(&eight, 8, 8, 8, 8);
+ t->RouteToEight = GetBestRouteEntryEx(&eight, exclude_if_id);
+
+ // Get the current default DNS server to detect network changes
+ GetDefaultDns(&t->OldDnsServer);
+
+ // Get as soon as releasing the IP address in the case of using DHCP
+ if (IsNt())
+ {
+ char tmp[MAX_SIZE];
+ MS_ADAPTER *a;
+
+ Format(tmp, sizeof(tmp), VLAN_ADAPTER_NAME_TAG, v->InstanceName);
+ a = MsGetAdapter(tmp);
+
+ if (a != NULL)
+ {
+ if (a->UseDhcp)
+ {
+ bool ret = Win32ReleaseAddressByGuidEx(a->Guid, 100);
+ Debug("*** Win32ReleaseAddressByGuidEx = %u\n", ret);
+
+ ret = Win32RenewAddressByGuidEx(a->Guid, 100);
+ Debug("*** Win32RenewAddressByGuidEx = %u\n", ret);
+ }
+
+ MsFreeAdapter(a);
+ }
+ }
+ else
+ {
+ // For Win9x
+ Win32RenewDhcp9x(if_id);
+ }
+
+ // Clear the DNS cache
+ Win32FlushDnsCache();
+
+ // Detect a change in the routing table (for only supported OS)
+ t->RouteChange = NewRouteChange();
+ Debug("t->RouteChange = 0x%p\n", t->RouteChange);
+}
+
+// End the tracking of the routing table
+void RouteTrackingStop(SESSION *s, ROUTE_TRACKING *t)
+{
+ ROUTE_ENTRY *e;
+ ROUTE_TABLE *table;
+ IP dns_ip;
+ bool network_has_changed = false;
+ bool do_not_delete_routing_entry = false;
+ // Validate arguments
+ if (s == NULL || t == NULL)
+ {
+ return;
+ }
+
+ Zero(&dns_ip, sizeof(dns_ip));
+
+ // Remove the default gateway added by the virtual LAN card
+ if (MsIsVista() == false)
+ {
+ if (t->DefaultGatewayByVLan != NULL)
+ {
+ Debug("Default Gateway by VLAN was deleted.\n");
+ DeleteRouteEntry(t->DefaultGatewayByVLan);
+ }
+
+ if (t->VistaOldDefaultGatewayByVLan != NULL)
+ {
+ FreeRouteEntry(t->VistaOldDefaultGatewayByVLan);
+ }
+ }
+
+ if (t->DefaultGatewayByVLan != NULL)
+ {
+ FreeRouteEntry(t->DefaultGatewayByVLan);
+ t->DefaultGatewayByVLan = NULL;
+ }
+
+ if (t->VistaDefaultGateway1 != NULL)
+ {
+ Debug("Vista PPP Fix Route Table Deleted.\n");
+ DeleteRouteEntry(t->VistaDefaultGateway1);
+ FreeRouteEntry(t->VistaDefaultGateway1);
+
+ DeleteRouteEntry(t->VistaDefaultGateway2);
+ FreeRouteEntry(t->VistaDefaultGateway2);
+ }
+
+ if (MsIsNt() == false)
+ {
+ // Only in the case of Windows 9x, release the DHCP address of the virtual LAN card
+ Win32ReleaseDhcp9x(t->VLanInterfaceId, false);
+ }
+
+ // Clear the DNS cache
+ Win32FlushDnsCache();
+
+ if (s->Cedar->Client != NULL && s->Account != NULL)
+ {
+ UINT i;
+ ACCOUNT *a;
+ for (i = 0;i < LIST_NUM(s->Cedar->Client->AccountList);i++)
+ {
+ a = LIST_DATA(s->Cedar->Client->AccountList, i);
+ Lock(a->lock);
+ {
+ SESSION *sess = a->ClientSession;
+ if (sess != NULL && sess != s)
+ {
+ VLAN *v = sess->PacketAdapter->Param;
+ if (v != NULL)
+ {
+ ROUTE_TRACKING *tr = v->RouteState;
+ if (tr != NULL)
+ {
+ if (Cmp(tr->RouteToServer, t->RouteToServer, sizeof(ROUTE_ENTRY)) == 0)
+ {
+ do_not_delete_routing_entry = true;
+ }
+ }
+ }
+ }
+ }
+ Unlock(a->lock);
+ }
+
+ Lock(s->Account->lock);
+ }
+
+ if (do_not_delete_routing_entry == false)
+ {
+ // Delete the route that is added firstly
+ if (t->RouteToServerAlreadyExists == false)
+ {
+ DeleteRouteEntry(t->RouteToServer);
+ }
+
+ DeleteRouteEntry(t->RouteToDefaultDns);
+
+ DeleteRouteEntry(t->RouteToNatTServer);
+
+ DeleteRouteEntry(t->RouteToRealServerGlobal);
+ }
+
+ FreeRouteEntry(t->RouteToDefaultDns);
+ FreeRouteEntry(t->RouteToServer);
+ FreeRouteEntry(t->RouteToEight);
+ FreeRouteEntry(t->RouteToNatTServer);
+ FreeRouteEntry(t->RouteToRealServerGlobal);
+ t->RouteToDefaultDns = t->RouteToServer = t->RouteToEight =
+ t->RouteToNatTServer = t->RouteToRealServerGlobal = NULL;
+
+ if (s->Cedar->Client != NULL && s->Account != NULL)
+ {
+ Unlock(s->Account->lock);
+ }
+
+#if 0
+ // Get the current DNS server
+ if (GetDefaultDns(&dns_ip))
+ {
+ if (IPToUINT(&t->OldDnsServer) != 0)
+ {
+ if (IPToUINT(&t->OldDnsServer) != IPToUINT(&dns_ip))
+ {
+ char s1[MAX_SIZE], s2[MAX_SIZE];
+ network_has_changed = true;
+ IPToStr(s1, sizeof(s1), &t->OldDnsServer);
+ IPToStr(s2, sizeof(s2), &dns_ip);
+ Debug("Old Dns: %s, New Dns: %s\n",
+ s1, s2);
+ }
+ }
+ }
+
+ if (network_has_changed == false)
+ {
+ Debug("Network: not changed.\n");
+ }
+ else
+ {
+ Debug("Network: Changed.\n");
+ }
+
+#endif
+
+ // Get the current routing table
+ table = GetRouteTable();
+
+ // Restore the routing table which has been removed so far
+ while (e = GetNext(t->DeletedDefaultGateway))
+ {
+ bool restore = true;
+ UINT i;
+ // If the restoring routing entry is a default gateway and
+ // the existing routing table contains another default gateway
+ // on the interface, give up restoring the entry
+ if (IPToUINT(&e->DestIP) == 0 && IPToUINT(&e->DestMask) == 0)
+ {
+ for (i = 0;i < table->NumEntry;i++)
+ {
+ ROUTE_ENTRY *r = table->Entry[i];
+ if (IPToUINT(&r->DestIP) == 0 && IPToUINT(&r->DestMask) == 0)
+ {
+ if (r->InterfaceID == e->InterfaceID)
+ {
+ restore = false;
+ }
+ }
+ }
+ if (network_has_changed)
+ {
+ restore = false;
+ }
+ }
+
+ if (restore)
+ {
+ // Routing table restoration
+ AddRouteEntry(e);
+ }
+
+ // Memory release
+ FreeRouteEntry(e);
+ }
+
+ // Release
+ FreeRouteTable(table);
+ ReleaseQueue(t->DeletedDefaultGateway);
+
+ FreeRouteChange(t->RouteChange);
+
+ Free(t);
+}
+
+// Get the instance ID of the virtual LAN card
+UINT GetInstanceId(char *name)
+{
+ char tmp[MAX_SIZE];
+ UINT id = 0;
+ // Validate arguments
+ if (name == NULL)
+ {
+ return 0;
+ }
+
+ Format(tmp, sizeof(tmp), VLAN_ADAPTER_NAME_TAG, name);
+
+ id = GetVLanInterfaceID(tmp);
+ if (id != 0)
+ {
+ return id;
+ }
+ else
+ {
+ Format(tmp, sizeof(tmp), VLAN_ADAPTER_NAME_TAG_OLD, name);
+
+ id = GetVLanInterfaceID(tmp);
+ return id;
+ }
+}
+
+// Get the instance list of virtual LAN card
+INSTANCE_LIST *GetInstanceList()
+{
+ INSTANCE_LIST *n = ZeroMalloc(sizeof(INSTANCE_LIST));
+
+ // Enumeration
+ char **ss = EnumVLan(VLAN_ADAPTER_NAME);
+
+ if (ss == NULL)
+ {
+ // Failure
+ n->NumInstance = 0;
+ n->InstanceName = Malloc(0);
+ return n;
+ }
+ else
+ {
+ UINT i, num;
+ i = num = 0;
+ while (true)
+ {
+ if (ss[i++] == NULL)
+ {
+ break;
+ }
+ num++;
+ }
+ i = 0;
+ n->NumInstance = num;
+ n->InstanceName = (char **)ZeroMalloc(sizeof(char *) * n->NumInstance);
+ for (i = 0;i < num;i++)
+ {
+ char *s = ss[i] + StrLen(VLAN_ADAPTER_NAME) + StrLen(" - ");
+ if (StrLen(ss[i]) > StrLen(VLAN_ADAPTER_NAME) + StrLen(" - "))
+ {
+ n->InstanceName[i] = CopyStr(s);
+ }
+ }
+ FreeEnumVLan(ss);
+ }
+
+ ss = EnumVLan(VLAN_ADAPTER_NAME_OLD);
+ if (ss != NULL)
+ {
+ UINT i, num, j;
+
+ i = num = 0;
+ while (true)
+ {
+ if (ss[i++] == NULL)
+ {
+ break;
+ }
+ num++;
+ }
+ j = n->NumInstance;
+ n->NumInstance += num;
+ n->InstanceName = (char **)ReAlloc(n->InstanceName, sizeof(char) * n->NumInstance);
+ for (i = 0;i < num;i++)
+ {
+ char *s = ss[i] + StrLen(VLAN_ADAPTER_NAME_OLD) + StrLen(" - ");
+ if (StrLen(ss[i]) > StrLen(VLAN_ADAPTER_NAME_OLD) + StrLen(" - "))
+ {
+ n->InstanceName[j] = CopyStr(s);
+ }
+ j++;
+ }
+ FreeEnumVLan(ss);
+ }
+
+ return n;
+}
+
+// Release the instance list
+void FreeInstanceList(INSTANCE_LIST *n)
+{
+ UINT i;
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < n->NumInstance;i++)
+ {
+ Free(n->InstanceName[i]);
+ }
+ Free(n->InstanceName);
+ Free(n);
+}
+
+// Release the packet adapter
+void VLanPaFree(SESSION *s)
+{
+ VLAN *v;
+ ROUTE_TRACKING *t;
+ // Validate arguments
+ if ((s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
+ {
+ return;
+ }
+
+ // Release the IP address if you are using DHCP
+ if (IsNt())
+ {
+ char tmp[MAX_SIZE];
+ MS_ADAPTER *a;
+
+ Format(tmp, sizeof(tmp), VLAN_ADAPTER_NAME_TAG, v->InstanceName);
+ a = MsGetAdapter(tmp);
+
+ if (a != NULL)
+ {
+ if (a->UseDhcp)
+ {
+ bool ret = Win32ReleaseAddressByGuidEx(a->Guid, 50);
+ Debug("*** Win32ReleaseAddressByGuid = %u\n", ret);
+ }
+
+ MsFreeAdapter(a);
+ }
+ }
+
+ t = v->RouteState;
+ // End the virtual LAN card
+ FreeVLan(v);
+
+ // End the routing table tracking
+ if (s->ClientModeAndUseVLan)
+ {
+ RouteTrackingStop(s, t);
+ }
+ s->PacketAdapter->Param = NULL;
+}
+
+
+// Write a packet
+bool VLanPaPutPacket(SESSION *s, void *data, UINT size)
+{
+ VLAN *v;
+ // Validate arguments
+ if ((s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
+ {
+ return false;
+ }
+
+ return VLanPutPacket(v, data, size);
+}
+
+// Get the next packet
+UINT VLanPaGetNextPacket(SESSION *s, void **data)
+{
+ VLAN *v;
+ UINT size;
+ // Validate arguments
+ if (data == NULL || (s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
+ {
+ return 0;
+ }
+
+ RouteTrackingMain(s);
+
+ if (VLanGetNextPacket(v, data, &size) == false)
+ {
+ return INFINITE;
+ }
+
+ return size;
+}
+
+// Get the cancel object
+CANCEL *VLanPaGetCancel(SESSION *s)
+{
+ VLAN *v;
+ // Validate arguments
+ if ((s == NULL) || ((v = s->PacketAdapter->Param) == NULL))
+ {
+ return NULL;
+ }
+
+ return VLanGetCancel(v);
+}
+
+// Initialize the packet adapter
+bool VLanPaInit(SESSION *s)
+{
+ VLAN *v;
+ // Validate arguments
+ if ((s == NULL)/* || (s->ServerMode != false) || (s->ClientOption == NULL)*/)
+ {
+ return false;
+ }
+
+ // Get the IP address of the DNS server at the time just before the connection
+ if (s->ClientModeAndUseVLan)
+ {
+ Zero(&s->DefaultDns, sizeof(IP));
+ GetDefaultDns(&s->DefaultDns);
+ }
+
+ // Normalize the setting of interface metric of the default gateway
+ if (s->ClientModeAndUseVLan)
+ {
+ if (MsIsVista())
+ {
+ MsNormalizeInterfaceDefaultGatewaySettings(VLAN_ADAPTER_NAME_TAG, s->ClientOption->DeviceName);
+ MsNormalizeInterfaceDefaultGatewaySettings(VLAN_ADAPTER_NAME_TAG_OLD, s->ClientOption->DeviceName);
+ }
+ }
+
+ // Connect to the driver
+ v = NewVLan(s->ClientOption->DeviceName, NULL);
+ if (v == NULL)
+ {
+ // Failure
+ return false;
+ }
+
+ s->PacketAdapter->Param = v;
+
+ // Routing table tracking start
+ if (s->ClientModeAndUseVLan)
+ {
+ RouteTrackingStart(s);
+ }
+
+ return true;
+}
+
+// Get the packet adapter of the VLAN
+PACKET_ADAPTER *VLanGetPacketAdapter()
+{
+ PACKET_ADAPTER *pa;
+
+ pa = NewPacketAdapter(VLanPaInit, VLanPaGetCancel,
+ VLanPaGetNextPacket, VLanPaPutPacket, VLanPaFree);
+ if (pa == NULL)
+ {
+ return NULL;
+ }
+
+ return pa;
+}
+
+
+// Write the next received packet to the driver
+bool VLanPutPacket(VLAN *v, void *buf, UINT size)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return false;
+ }
+ if (v->Halt)
+ {
+ return false;
+ }
+ if (size > MAX_PACKET_SIZE)
+ {
+ return false;
+ }
+
+ // First, examine whether the current buffer is full
+ if ((NEO_NUM_PACKET(v->PutBuffer) >= NEO_MAX_PACKET_EXCHANGE) ||
+ (buf == NULL && NEO_NUM_PACKET(v->PutBuffer) != 0))
+ {
+#ifdef USE_PROBE
+ {
+ char tmp[MAX_SIZE];
+ snprintf(tmp, sizeof(tmp), "VLanPutPacket: NEO_NUM_PACKET(v->PutBuffer) = %u", NEO_NUM_PACKET(v->PutBuffer));
+ PROBE_DATA2(tmp, NULL, 0);
+ }
+#endif // USE_PROBE
+ // Write a packet to the driver
+ if (VLanPutPacketsToDriver(v) == false)
+ {
+ return false;
+ }
+ NEO_NUM_PACKET(v->PutBuffer) = 0;
+ }
+
+ // Add the next packet to the buffer
+ if (buf != NULL)
+ {
+ UINT i = NEO_NUM_PACKET(v->PutBuffer);
+ NEO_NUM_PACKET(v->PutBuffer)++;
+
+ NEO_SIZE_OF_PACKET(v->PutBuffer, i) = size;
+ Copy(NEO_ADDR_OF_PACKET(v->PutBuffer, i), buf, size);
+ Free(buf);
+ }
+
+ return true;
+}
+
+// Read the next sent packet from the driver
+bool VLanGetNextPacket(VLAN *v, void **buf, UINT *size)
+{
+ // Validate arguments
+ if (v == NULL || buf == NULL || size == NULL)
+ {
+ return false;
+ }
+ if (v->Halt)
+ {
+ return false;
+ }
+
+ PROBE_STR("VLanGetNextPacket");
+
+ while (true)
+ {
+ if (v->CurrentPacketCount < NEO_NUM_PACKET(v->GetBuffer))
+ {
+ // There are still packets that have been read already
+ *size = NEO_SIZE_OF_PACKET(v->GetBuffer, v->CurrentPacketCount);
+ *buf = MallocFast(*size);
+ Copy(*buf, NEO_ADDR_OF_PACKET(v->GetBuffer, v->CurrentPacketCount), *size);
+
+ // Increment the packet number
+ v->CurrentPacketCount++;
+
+ return true;
+ }
+ else
+ {
+ // Read the next packet from the driver
+ if (VLanGetPacketsFromDriver(v) == false)
+ {
+ return false;
+ }
+
+ if (NEO_NUM_PACKET(v->GetBuffer) == 0)
+ {
+ // Packet is not received currently
+ *buf = NULL;
+ *size = 0;
+ return true;
+ }
+
+ v->CurrentPacketCount = 0;
+ }
+ }
+}
+
+// Write all the current packets to the driver
+bool VLanPutPacketsToDriver(VLAN *v)
+{
+ DWORD write_size;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return false;
+ }
+ if (v->Halt)
+ {
+ return false;
+ }
+
+ if (v->Win9xMode == false)
+ {
+ // Windows NT
+ PROBE_STR("VLanPutPacketsToDriver: WriteFile");
+ if (WriteFile(v->Handle, v->PutBuffer, NEO_EXCHANGE_BUFFER_SIZE, &write_size,
+ NULL) == false)
+ {
+ v->Halt = true;
+ return false;
+ }
+ PROBE_STR("VLanPutPacketsToDriver: WriteFile Completed.");
+
+ if (write_size != NEO_EXCHANGE_BUFFER_SIZE)
+ {
+ v->Halt = true;
+ return false;
+ }
+ }
+ else
+ {
+ // Windows 9x
+ if (DeviceIoControl(v->Handle, NEO_IOCTL_PUT_PACKET, v->PutBuffer,
+ NEO_EXCHANGE_BUFFER_SIZE, NULL, 0, &write_size, NULL) == false)
+ {
+ v->Halt = true;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Read the next packet from the driver
+bool VLanGetPacketsFromDriver(VLAN *v)
+{
+ DWORD read_size;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return false;
+ }
+ if (v->Halt)
+ {
+ return false;
+ }
+
+ if (v->Win9xMode == false)
+ {
+ // Windows NT
+ PROBE_STR("VLanGetPacketsFromDriver: ReadFile");
+ if (ReadFile(v->Handle, v->GetBuffer, NEO_EXCHANGE_BUFFER_SIZE,
+ &read_size, NULL) == false)
+ {
+ v->Halt = true;
+ return false;
+ }
+ }
+ else
+ {
+ // Windows 9x
+ if (DeviceIoControl(v->Handle, NEO_IOCTL_GET_PACKET, NULL, 0,
+ v->GetBuffer, NEO_EXCHANGE_BUFFER_SIZE, &read_size, NULL) == false)
+ {
+ v->Halt = true;
+ return false;
+ }
+ }
+
+ if (read_size != NEO_EXCHANGE_BUFFER_SIZE)
+ {
+ v->Halt = true;
+ return false;
+ }
+
+ return true;
+}
+
+// Get the cancel object
+CANCEL *VLanGetCancel(VLAN *v)
+{
+ CANCEL *c;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return NULL;
+ }
+
+ // Create a cancel object
+ c = NewCancel();
+ c->SpecialFlag = true;
+ CloseHandle(c->hEvent);
+
+ c->hEvent = v->Event;
+
+ return c;
+}
+
+// Release the VLAN object
+void FreeVLan(VLAN *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ // Close the handle
+ CloseHandle(v->Event);
+ CloseHandle(v->Handle);
+
+ // Memory release
+ Free(v->InstanceName);
+ Free(v->EventNameWin32);
+ Free(v->DeviceNameWin32);
+ Free(v->PutBuffer);
+ Free(v->GetBuffer);
+ Free(v);
+}
+
+// Create a VLAN object
+VLAN *NewVLan(char *instance_name, VLAN_PARAM *param)
+{
+ VLAN *v;
+ HANDLE h = INVALID_HANDLE_VALUE;
+ HANDLE e = INVALID_HANDLE_VALUE;
+ char tmp[MAX_SIZE];
+ char name_upper[MAX_SIZE];
+ // Validate arguments
+ if (instance_name == NULL)
+ {
+ return NULL;
+ }
+
+ v = ZeroMalloc(sizeof(VLAN));
+
+ if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType))
+ {
+ v->Win9xMode = true;
+ }
+
+ // Initialize the name
+ Format(name_upper, sizeof(name_upper), "%s", instance_name);
+ StrUpper(name_upper);
+ v->InstanceName = CopyStr(name_upper);
+ Format(tmp, sizeof(tmp), NDIS_NEO_DEVICE_FILE_NAME, v->InstanceName);
+ v->DeviceNameWin32 = CopyStr(tmp);
+
+ if (v->Win9xMode == false)
+ {
+ Format(tmp, sizeof(tmp), NDIS_NEO_EVENT_NAME_WIN32, v->InstanceName);
+ v->EventNameWin32 = CopyStr(tmp);
+ }
+
+ // Connect to the device
+ h = CreateFile(v->DeviceNameWin32,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ // Connection failure
+ goto CLEANUP;
+ }
+
+ if (v->Win9xMode == false)
+ {
+ // Connect to the event
+ e = OpenEvent(SYNCHRONIZE, FALSE, v->EventNameWin32);
+ if (e == INVALID_HANDLE_VALUE)
+ {
+ // Connection failure
+ goto CLEANUP;
+ }
+ }
+ else
+ {
+ OPENVXDHANDLE OpenVxDHandle;
+ DWORD vxd_handle;
+ UINT bytes_returned;
+
+ OpenVxDHandle = (OPENVXDHANDLE)GetProcAddress(GetModuleHandle("KERNEL32"),
+ "OpenVxDHandle");
+
+ // Deliver to the driver by creating an event
+ e = CreateEvent(NULL, FALSE, FALSE, NULL);
+ vxd_handle = (DWORD)OpenVxDHandle(e);
+
+ DeviceIoControl(h, NEO_IOCTL_SET_EVENT, &vxd_handle, sizeof(DWORD),
+ NULL, 0, &bytes_returned, NULL);
+ }
+
+ v->Event = e;
+ v->Handle = h;
+
+ v->GetBuffer = ZeroMalloc(NEO_EXCHANGE_BUFFER_SIZE);
+ v->PutBuffer = ZeroMalloc(NEO_EXCHANGE_BUFFER_SIZE);
+
+ return v;
+
+CLEANUP:
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(h);
+ }
+ if (e != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(e);
+ }
+
+ Free(v->InstanceName);
+ Free(v->EventNameWin32);
+ Free(v->DeviceNameWin32);
+ Free(v);
+
+ return NULL;
+}
+
+#endif // OS_WIN32
+
+#endif //VLAN_C
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/VLanWin32.h b/src/Cedar/VLanWin32.h
new file mode 100644
index 00000000..c481efd9
--- /dev/null
+++ b/src/Cedar/VLanWin32.h
@@ -0,0 +1,174 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// VLanWin32.h
+// Header of VLanWin32.c
+
+#ifndef VLANWIN32_H
+#define VLANWIN32_H
+
+// Routing table tracking timer
+#define TRACKING_INTERVAL_INITIAL 444 // Initial
+#define TRACKING_INTERVAL_ADD 444 // Adding value
+#define TRACKING_INTERVAL_MAX 12345 // Maximum value
+#define TRACKING_INTERVAL_MAX_RC 87654 // Maximum value (OS which change detection mechanism enabled)
+
+
+typedef void *HANDLE;
+
+// Routing tracking state machine
+struct ROUTE_TRACKING
+{
+ UINT VLanInterfaceId;
+ ROUTE_ENTRY *RouteToServer;
+ bool RouteToServerAlreadyExists;
+ ROUTE_ENTRY *DefaultGatewayByVLan;
+ ROUTE_ENTRY *VistaDefaultGateway1, *VistaDefaultGateway2, *VistaOldDefaultGatewayByVLan;
+ ROUTE_ENTRY *RouteToDefaultDns;
+ ROUTE_ENTRY *RouteToEight;
+ ROUTE_ENTRY *RouteToNatTServer;
+ ROUTE_ENTRY *RouteToRealServerGlobal;
+ UINT64 NextTrackingTime;
+ UINT64 NextTrackingTimeAdd;
+ UINT64 NextRouteChangeCheckTime;
+ UINT LastRoutingTableHash;
+ QUEUE *DeletedDefaultGateway;
+ UINT OldDefaultGatewayMetric;
+ IP OldDnsServer;
+ bool VistaAndUsingPPP;
+ ROUTE_CHANGE *RouteChange;
+};
+
+// VLAN structure
+struct VLAN
+{
+ volatile bool Halt; // Halting flag
+ bool Win9xMode; // Windows 9x
+ char *InstanceName; // Instance name
+ char *DeviceNameWin32; // Win32 device name
+ char *EventNameWin32; // Win32 event name
+ HANDLE Handle; // Device driver file
+ HANDLE Event; // Handle of the event
+ void *GetBuffer; // Sent packet capturing buffer
+ UINT CurrentPacketCount; // Packet number to be read next
+ void *PutBuffer; // Buffer for writing received packet
+ ROUTE_TRACKING *RouteState; // Routing tracking state machine
+};
+
+// Instance list
+struct INSTANCE_LIST
+{
+ UINT NumInstance;
+ char **InstanceName;
+};
+
+
+// Function prototype
+VLAN *NewVLan(char *instance_name, VLAN_PARAM *param);
+void FreeVLan(VLAN *v);
+CANCEL *VLanGetCancel(VLAN *v);
+bool VLanGetNextPacket(VLAN *v, void **buf, UINT *size);
+bool VLanGetPacketsFromDriver(VLAN *v);
+bool VLanPutPacketsToDriver(VLAN *v);
+bool VLanPutPacket(VLAN *v, void *buf, UINT size);
+
+PACKET_ADAPTER *VLanGetPacketAdapter();
+bool VLanPaInit(SESSION *s);
+CANCEL *VLanPaGetCancel(SESSION *s);
+UINT VLanPaGetNextPacket(SESSION *s, void **data);
+bool VLanPaPutPacket(SESSION *s, void *data, UINT size);
+void VLanPaFree(SESSION *s);
+
+INSTANCE_LIST *GetInstanceList();
+void FreeInstanceList(INSTANCE_LIST *n);
+UINT GetInstanceId(char *name);
+
+void RouteTrackingStart(SESSION *s);
+void RouteTrackingStop(SESSION *s, ROUTE_TRACKING *t);
+void RouteTrackingMain(SESSION *s);
+void Win32ReleaseAllDhcp9x(bool wait);
+
+void Win32GetWinVer(RPC_WINVER *v);
+
+#endif // VLANWIN32_H
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Virtual.c b/src/Cedar/Virtual.c
new file mode 100644
index 00000000..ebd32b58
--- /dev/null
+++ b/src/Cedar/Virtual.c
@@ -0,0 +1,10117 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Virtual.c
+// User-mode virtual host program
+
+#include "CedarPch.h"
+
+static UCHAR broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+static char v_vgs_hostname[256] = {0};
+
+static char secure_nat_target_hostname[MAX_SIZE] = {0};
+
+// Specify the destination host name to be used for connectivity testing in SecureNAT
+void NnSetSecureNatTargetHostname(char *name)
+{
+ // Validate arguments
+ if (name == NULL)
+ {
+ return;
+ }
+
+ StrCpy(secure_nat_target_hostname, sizeof(secure_nat_target_hostname), name);
+}
+
+// Delete the oldest NAT session if necessary
+void NnDeleteOldestNatSessionIfNecessary(NATIVE_NAT *t, UINT ip, UINT protocol)
+{
+ UINT current_num;
+ UINT max_sessions = 0;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ if (t->v->HubOption != NULL)
+ {
+ HUB_OPTION *o = t->v->HubOption;
+
+ switch (protocol)
+ {
+ case NAT_TCP:
+ max_sessions = o->SecureNAT_MaxTcpSessionsPerIp;
+ break;
+
+ case NAT_UDP:
+ max_sessions = o->SecureNAT_MaxUdpSessionsPerIp;
+ break;
+
+ case NAT_ICMP:
+ max_sessions = o->SecureNAT_MaxIcmpSessionsPerIp;
+ break;
+ }
+ }
+
+ if (max_sessions == 0)
+ {
+ return;
+ }
+
+ current_num = NnGetNumNatEntriesPerIp(t, ip, protocol);
+
+ if (current_num >= max_sessions)
+ {
+ NnDeleteOldestNatSession(t, ip, protocol);
+ }
+}
+
+// Delete the oldest NAT session
+void NnDeleteOldestNatSession(NATIVE_NAT *t, UINT ip, UINT protocol)
+{
+ NATIVE_NAT_ENTRY *e;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ e = NnGetOldestNatEntryOfIp(t, ip, protocol);
+
+ if (e != NULL)
+ {
+ NnDeleteSession(t, e);
+ }
+}
+
+// Get the oldest NAT session
+NATIVE_NAT_ENTRY *NnGetOldestNatEntryOfIp(NATIVE_NAT *t, UINT ip, UINT protocol)
+{
+ UINT i;
+ NATIVE_NAT_ENTRY *oldest = NULL;
+ UINT64 oldest_tick = 0xFFFFFFFFFFFFFFFFULL;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(t->NatTableForRecv->AllList);i++)
+ {
+ NATIVE_NAT_ENTRY *e = LIST_DATA(t->NatTableForRecv->AllList, i);
+
+ if (e->SrcIp == ip)
+ {
+ if (e->Protocol == protocol)
+ {
+ if (e->LastCommTime <= oldest_tick)
+ {
+ oldest_tick = e->LastCommTime;
+ oldest = e;
+ }
+ }
+ }
+ }
+
+ return oldest;
+}
+
+// Get the number of NAT sessions per IP address
+UINT NnGetNumNatEntriesPerIp(NATIVE_NAT *t, UINT src_ip, UINT protocol)
+{
+ UINT ret = 0;
+ UINT i;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return 0;
+ }
+
+ for (i = 0;i < LIST_NUM(t->NatTableForRecv->AllList);i++)
+ {
+ NATIVE_NAT_ENTRY *e = LIST_DATA(t->NatTableForRecv->AllList, i);
+
+ if (e->SrcIp == src_ip)
+ {
+ if (e->Protocol == protocol)
+ {
+ ret++;
+ }
+ }
+ }
+
+ return ret;
+}
+
+// Delete the old NAT sessions
+void NnDeleteOldSessions(NATIVE_NAT *t)
+{
+ UINT i;
+ LIST *o;
+ UINT64 now;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ o = NULL;
+ now = t->v->Now;
+
+ for (i = 0;i < LIST_NUM(t->NatTableForSend->AllList);i++)
+ {
+ NATIVE_NAT_ENTRY *e = LIST_DATA(t->NatTableForSend->AllList, i);
+ UINT64 timeout;
+
+ if (e->Status == NAT_TCP_CONNECTED || e->Status == NAT_TCP_ESTABLISHED)
+ {
+ timeout = e->LastCommTime + (UINT64)(e->Protocol == NAT_TCP ? t->v->NatTcpTimeout : t->v->NatUdpTimeout);
+ }
+ else
+ {
+ timeout = e->LastCommTime + (UINT64)NN_TIMEOUT_FOR_UNESTBALISHED_TCP;
+ }
+
+ if (timeout < now)
+ {
+ // Time-out occurs
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+
+ Add(o, e);
+ }
+ }
+
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ NATIVE_NAT_ENTRY *e = LIST_DATA(o, i);
+
+ NnDeleteSession(t, e);
+ }
+
+ ReleaseList(o);
+ }
+}
+
+// Delete the NAT entry
+void NnDeleteSession(NATIVE_NAT *t, NATIVE_NAT_ENTRY *e)
+{
+ // Validate arguments
+ if (t == NULL || e == NULL)
+ {
+ return;
+ }
+
+ switch (e->Protocol)
+ {
+ case NAT_TCP:
+ // Send a RST to the client side
+ SendTcp(t->v, e->DestIp, e->DestPort, e->SrcIp, e->SrcPort,
+ e->LastAck, e->LastSeq + (e->Status == NAT_TCP_CONNECTING ? 1 : 0), TCP_RST | TCP_ACK, 0, 0, NULL, 0);
+
+ NLog(t->v, "LH_NAT_TCP_DELETED", e->Id);
+ break;
+
+ case NAT_UDP:
+ NLog(t->v, "LH_NAT_UDP_DELETED", e->Id);
+ break;
+
+ case NAT_ICMP:
+ Debug("NAT ICMP %u Deleted.", e->Id);
+ break;
+ }
+
+ DeleteHash(t->NatTableForSend, e);
+ DeleteHash(t->NatTableForRecv, e);
+
+ Free(e);
+}
+
+// Poll the IP combining object
+void NnPollingIpCombine(NATIVE_NAT *t)
+{
+ LIST *o;
+ UINT i;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ // Discard the old combining object
+ o = NULL;
+ for (i = 0;i < LIST_NUM(t->IpCombine);i++)
+ {
+ IP_COMBINE *c = LIST_DATA(t->IpCombine, i);
+
+ if (c->Expire < t->v->Now)
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+ Add(o, c);
+ }
+ }
+
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IP_COMBINE *c = LIST_DATA(o, i);
+
+ // Remove from the list
+ Delete(t->IpCombine, c);
+
+ // Release the memory
+ NnFreeIpCombine(t, c);
+ }
+ ReleaseList(o);
+ }
+}
+
+// Combine the IP packet received to the IP combining object
+void NnCombineIp(NATIVE_NAT *t, IP_COMBINE *c, UINT offset, void *data, UINT size, bool last_packet, UCHAR *head_ip_header_data, UINT head_ip_header_size)
+{
+ UINT i;
+ IP_PART *p;
+ UINT need_size;
+ UINT data_size_delta;
+ // Validate arguments
+ if (c == NULL || data == NULL)
+ {
+ return;
+ }
+
+ // Check the size and offset
+ if ((offset + size) > 65535)
+ {
+ // Do not process a packet larger than 64Kbytes
+ return;
+ }
+
+ if (last_packet == false && c->Size != 0)
+ {
+ if ((offset + size) > c->Size)
+ {
+ // Do not process a packet larger than the packet size
+ return;
+ }
+ }
+
+ if (head_ip_header_data != NULL && head_ip_header_size >= sizeof(IPV4_HEADER))
+ {
+ if (c->HeadIpHeaderData == NULL)
+ {
+ c->HeadIpHeaderData = Clone(head_ip_header_data, head_ip_header_size);
+ c->HeadIpHeaderDataSize = head_ip_header_size;
+ }
+ }
+
+ need_size = offset + size;
+ data_size_delta = c->DataReserved;
+ // Ensure sufficient if the buffer is insufficient
+ while (c->DataReserved < need_size)
+ {
+ c->DataReserved = c->DataReserved * 4;
+ c->Data = ReAlloc(c->Data, c->DataReserved);
+ }
+ data_size_delta = c->DataReserved - data_size_delta;
+ t->CurrentIpQuota += data_size_delta;
+
+ // Overwrite the data into the buffer
+ Copy(((UCHAR *)c->Data) + offset, data, size);
+
+ if (last_packet)
+ {
+ // If No More Flagment packet arrives, the size of this datagram is finalized
+ c->Size = offset + size;
+ }
+
+ // Check the overlap between the region which is represented by the offset and size of the
+ // existing received list and the region which is represented by the offset and size
+ for (i = 0;i < LIST_NUM(c->IpParts);i++)
+ {
+ UINT moving_size;
+ IP_PART *p = LIST_DATA(c->IpParts, i);
+
+ // Check the overlapping between the existing area and head area
+ if ((p->Offset <= offset) && ((p->Offset + p->Size) > offset))
+ {
+ // Compress behind the offset of this packet since a duplication is
+ // found in the first part with the existing packet and this packet
+
+ if ((offset + size) <= (p->Offset + p->Size))
+ {
+ // This packet is buried in the existing packet
+ size = 0;
+ }
+ else
+ {
+ // Retral region is not overlapped
+ moving_size = p->Offset + p->Size - offset;
+ offset += moving_size;
+ size -= moving_size;
+ }
+ }
+ if ((p->Offset < (offset + size)) && ((p->Offset + p->Size) >= (offset + size)))
+ {
+ // Compress the size of this packet forward because a duplication is
+ // found between the posterior portion the existing packet and this packet
+
+ moving_size = p->Offset + p->Size - offset - size;
+ size -= moving_size;
+ }
+
+ if ((p->Offset >= offset) && ((p->Offset + p->Size) <= (offset + size)))
+ {
+ // This packet was overwritten to completely hunched over a existing packet
+ p->Size = 0;
+ }
+ }
+
+ if (size != 0)
+ {
+ // Register this packet
+ p = ZeroMalloc(sizeof(IP_PART));
+
+ p->Offset = offset;
+ p->Size = size;
+
+ Add(c->IpParts, p);
+ }
+
+ if (c->Size != 0)
+ {
+ // Get the total size of the data portion list already received
+ UINT total_size = 0;
+ UINT i;
+
+ for (i = 0;i < LIST_NUM(c->IpParts);i++)
+ {
+ IP_PART *p = LIST_DATA(c->IpParts, i);
+
+ total_size += p->Size;
+ }
+
+ if (total_size == c->Size)
+ {
+ // Received whole of the IP packet
+ NnIpReceived(t, c->SrcIP, c->DestIP, c->Protocol, c->Data, c->Size, c->Ttl,
+ c->HeadIpHeaderData, c->HeadIpHeaderDataSize, c->MaxL3Size);
+
+ // Release the combining object
+ NnFreeIpCombine(t, c);
+
+ // Remove from the combining object list
+ Delete(t->IpCombine, c);
+ }
+ }
+}
+
+// Release the IP combining object
+void NnFreeIpCombine(NATIVE_NAT *t, IP_COMBINE *c)
+{
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Release the data
+ t->CurrentIpQuota -= c->DataReserved;
+ Free(c->Data);
+
+ // Release the partial list
+ for (i = 0;i < LIST_NUM(c->IpParts);i++)
+ {
+ IP_PART *p = LIST_DATA(c->IpParts, i);
+
+ Free(p);
+ }
+
+ Free(c->HeadIpHeaderData);
+
+ ReleaseList(c->IpParts);
+ Free(c);
+}
+
+// Search the IP combining list
+IP_COMBINE *NnSearchIpCombine(NATIVE_NAT *t, UINT src_ip, UINT dest_ip, USHORT id, UCHAR protocol)
+{
+ IP_COMBINE *c, tt;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ tt.DestIP = dest_ip;
+ tt.SrcIP = src_ip;
+ tt.Id = id;
+ tt.Protocol = protocol;
+
+ c = Search(t->IpCombine, &tt);
+
+ return c;
+}
+
+// Insert by creating a new object to the IP combining list
+IP_COMBINE *NnInsertIpCombine(NATIVE_NAT *t, UINT src_ip, UINT dest_ip, USHORT id, UCHAR protocol, bool mac_broadcast, UCHAR ttl, bool src_is_localmac)
+{
+ IP_COMBINE *c;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ // Examine the quota
+ if ((t->CurrentIpQuota + IP_COMBINE_INITIAL_BUF_SIZE) > IP_COMBINE_WAIT_QUEUE_SIZE_QUOTA)
+ {
+ // IP packet can not be stored any more
+ return NULL;
+ }
+
+ c = ZeroMalloc(sizeof(IP_COMBINE));
+ c->SrcIsLocalMacAddr = src_is_localmac;
+ c->DestIP = dest_ip;
+ c->SrcIP = src_ip;
+ c->Id = id;
+ c->Expire = t->v->Now + (UINT64)IP_COMBINE_TIMEOUT;
+ c->Size = 0;
+ c->IpParts = NewList(NULL);
+ c->Protocol = protocol;
+ c->MacBroadcast = mac_broadcast;
+ c->Ttl = ttl;
+
+ // Secure the memory
+ c->DataReserved = IP_COMBINE_INITIAL_BUF_SIZE;
+ c->Data = Malloc(c->DataReserved);
+ t->CurrentIpQuota += c->DataReserved;
+
+ Insert(t->IpCombine, c);
+
+ return c;
+}
+
+// Initialize the IP combining list
+void NnInitIpCombineList(NATIVE_NAT *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ t->IpCombine = NewList(CompareIpCombine);
+}
+
+// Release the IP combining list
+void NnFreeIpCombineList(NATIVE_NAT *t)
+{
+ UINT i;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(t->IpCombine);i++)
+ {
+ IP_COMBINE *c = LIST_DATA(t->IpCombine, i);
+
+ NnFreeIpCombine(t, c);
+ }
+
+ ReleaseList(t->IpCombine);
+}
+
+// A TCP packet is received
+void NnTcpReceived(NATIVE_NAT *t, UINT src_ip, UINT dest_ip, void *data, UINT size, UCHAR ttl, UINT max_l3_size)
+{
+ TCP_HEADER *tcp;
+ UCHAR *payload;
+ UINT payload_size;
+ UINT tcp_header_size;
+ // Validate arguments
+ if (t == NULL || data == NULL)
+ {
+ return;
+ }
+
+ // TCP header
+ if (size < sizeof(TCP_HEADER))
+ {
+ return;
+ }
+
+ tcp = (TCP_HEADER *)data;
+
+ // Get the TCP header size
+ tcp_header_size = TCP_GET_HEADER_SIZE(tcp) * 4;
+ if (size < tcp_header_size || tcp_header_size < sizeof(TCP_HEADER))
+ {
+ return;
+ }
+
+ // Payload
+ payload = ((UCHAR *)data) + tcp_header_size;
+ payload_size = size - tcp_header_size;
+
+ // Search the port from the NAT table
+ if (true)
+ {
+ NATIVE_NAT_ENTRY tt;
+ NATIVE_NAT_ENTRY *e;
+
+ NnSetNat(&tt, NAT_TCP, 0, 0, src_ip, Endian16(tcp->SrcPort), dest_ip, Endian16(tcp->DstPort));
+
+ e = SearchHash(t->NatTableForRecv, &tt);
+
+ if (e != NULL)
+ {
+ // Last communication time
+ e->LastCommTime = t->v->Now;
+ e->TotalRecv += (UINT64)size;
+
+ // Rewrite the TCP header
+ tcp->Checksum = 0;
+ tcp->DstPort = Endian16(e->SrcPort);
+
+ if (tcp->Flag & TCP_FIN || tcp->Flag & TCP_RST)
+ {
+ // Disconnect
+ e->Status = NAT_TCP_WAIT_DISCONNECT;
+ }
+
+ if (tcp->Flag & TCP_SYN && tcp->Flag & TCP_ACK)
+ {
+ // Connection complete
+ if (e->Status != NAT_TCP_WAIT_DISCONNECT)
+ {
+ e->Status = NAT_TCP_ESTABLISHED;
+ }
+ }
+
+ e->LastSeq = Endian32(tcp->AckNumber);
+ e->LastAck = Endian32(tcp->SeqNumber);
+
+ // Checksum recalculation
+ tcp->Checksum = CalcChecksumForIPv4(src_ip, e->SrcIp, IP_PROTO_TCP, tcp, size, 0);
+
+ // IP transmission
+ SendIp(t->v, e->SrcIp, src_ip, IP_PROTO_TCP, tcp, size);
+ }
+ }
+}
+
+// An ICMP packet has been received
+void NnIcmpReceived(NATIVE_NAT *t, UINT src_ip, UINT dest_ip, void *data, UINT size, UCHAR ttl, UINT max_l3_size)
+{
+ ICMP_HEADER *icmp;
+ // Validate arguments
+ if (t == NULL || data == NULL)
+ {
+ return;
+ }
+ if (ttl == 0)
+ {
+ ttl = 1;
+ }
+
+ // ICMP header
+ if (size < sizeof(ICMP_HEADER))
+ {
+ return;
+ }
+
+ icmp = (ICMP_HEADER *)data;
+
+ if (icmp->Type == ICMP_TYPE_ECHO_RESPONSE)
+ {
+ UCHAR *payload;
+ UINT payload_size;
+ ICMP_ECHO *echo;
+ NATIVE_NAT_ENTRY tt, *e;
+
+ // Echo Response
+ echo = (ICMP_ECHO *)(((UCHAR *)data) + sizeof(ICMP_HEADER));
+
+ if (size < (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO)))
+ {
+ return;
+ }
+
+ payload = ((UCHAR *)data) + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO);
+ payload_size = size - (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
+
+ // Search the NAT
+ NnSetNat(&tt, NAT_ICMP, 0, 0, 0, 0, dest_ip, Endian16(echo->Identifier));
+
+ e = SearchHash(t->NatTableForRecv, &tt);
+
+ if (e != NULL)
+ {
+ // Rewrite the header
+ icmp->Checksum = 0;
+ echo->Identifier = Endian16(e->SrcPort);
+ icmp->Checksum = IpChecksum(icmp, size);
+
+ e->LastCommTime = t->v->Now;
+ e->TotalRecv += (UINT64)size;
+
+ // Transmission
+ SendIpEx(t->v, e->SrcIp, src_ip, IP_PROTO_ICMPV4, icmp, size, MAX(ttl - 1, 1));
+ }
+ }
+ else if (icmp->Type == ICMP_TYPE_ECHO_REQUEST)
+ {
+ UCHAR *payload;
+ UINT payload_size;
+ ICMP_ECHO *echo;
+
+ // Echo Response
+ echo = (ICMP_ECHO *)(((UCHAR *)data) + sizeof(ICMP_HEADER));
+
+ if (size < (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO)))
+ {
+ return;
+ }
+
+ payload = ((UCHAR *)data) + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO);
+ payload_size = size - (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
+
+ if (dest_ip == t->PublicIP)
+ {
+ // Respond as soon as the Echo Request is received at the public side interface
+ ICMP_HEADER *ret_icmp;
+ ICMP_ECHO *ret_echo;
+ UINT ret_size = sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO) + payload_size;
+
+ ret_icmp = ZeroMalloc(ret_size);
+ ret_echo = (ICMP_ECHO *)(((UCHAR *)ret_icmp) + sizeof(ICMP_HEADER));
+
+ ret_icmp->Type = ICMP_TYPE_ECHO_RESPONSE;
+ ret_icmp->Code = icmp->Code;
+
+ ret_echo->Identifier = echo->Identifier;
+ ret_echo->SeqNo = echo->SeqNo;
+
+ Copy((UCHAR *)ret_icmp + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO),
+ payload, payload_size);
+
+ ret_icmp->Checksum = IpChecksum(ret_icmp, ret_size);
+
+ NnIpSendForInternet(t, IP_PROTO_ICMPV4, 0, dest_ip, src_ip, ret_icmp, ret_size, max_l3_size);
+
+ Free(ret_icmp);
+ }
+ }
+ else
+ {
+ if (icmp->Type == ICMP_TYPE_DESTINATION_UNREACHABLE || icmp->Type == ICMP_TYPE_TIME_EXCEEDED)
+ {
+ // Rewrite the Src IP of the IPv4 header of the ICMP response packet
+ if (size >= (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO) + sizeof(IPV4_HEADER)))
+ {
+ IPV4_HEADER *orig_ipv4 = (IPV4_HEADER *)(((UCHAR *)data) + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
+ UINT orig_ipv4_size = size - (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
+
+ UINT orig_ipv4_header_size = GetIpHeaderSize((UCHAR *)orig_ipv4, orig_ipv4_size);
+
+ if (orig_ipv4_header_size >= sizeof(IPV4_HEADER) && orig_ipv4_size >= orig_ipv4_header_size)
+ {
+ if (orig_ipv4->Protocol == IP_PROTO_ICMPV4)
+ {
+ // Search the inner ICMP header
+ UINT inner_icmp_size = orig_ipv4_size - orig_ipv4_header_size;
+
+ if (inner_icmp_size >= (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO)))
+ {
+ ICMP_HEADER *inner_icmp = (ICMP_HEADER *)(((UCHAR *)data) +
+ sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO) + orig_ipv4_header_size);
+
+ if (inner_icmp->Type == ICMP_TYPE_ECHO_REQUEST)
+ {
+ ICMP_ECHO *inner_echo = (ICMP_ECHO *)(((UCHAR *)inner_icmp) + sizeof(ICMP_HEADER));
+ NATIVE_NAT_ENTRY tt, *e;
+
+ // Search for the existing NAT table entry
+ NnSetNat(&tt, NAT_ICMP, 0, 0, 0, 0, orig_ipv4->SrcIP, Endian16(inner_echo->Identifier));
+
+ e = SearchHash(t->NatTableForRecv, &tt);
+
+ if (e != NULL)
+ {
+ e->LastCommTime = t->v->Now;
+
+ // Rewrite the inner IP packet and the ICMP header according to the NAT table
+ inner_echo->Identifier = Endian16(e->SrcPort);
+ inner_icmp->Checksum = 0;
+
+ orig_ipv4->SrcIP = e->SrcIp;
+
+ orig_ipv4->Checksum = 0;
+ orig_ipv4->Checksum = IpChecksum(orig_ipv4, orig_ipv4_header_size);
+
+ // Rewrite the outer ICMP header
+ if (true)
+ {
+ UCHAR *payload;
+ UINT payload_size;
+ ICMP_ECHO *echo;
+
+ // Echo Response
+ echo = (ICMP_ECHO *)(((UCHAR *)data) + sizeof(ICMP_HEADER));
+
+ if (size < (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO)))
+ {
+ return;
+ }
+
+ payload = ((UCHAR *)data) + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO);
+ payload_size = size - (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
+
+ // Rewrite the header
+ icmp->Checksum = 0;
+ echo->Identifier = Endian16(e->SrcPort);
+ icmp->Checksum = IpChecksum(icmp, size);
+
+ // Transmission
+ SendIpEx(t->v, e->SrcIp, src_ip, IP_PROTO_ICMPV4, icmp, size, MAX(ttl - 1, 1));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// An UDP packet has been received
+void NnUdpReceived(NATIVE_NAT *t, UINT src_ip, UINT dest_ip, void *data, UINT size, UCHAR ttl, UINT max_l3_size)
+{
+ UDP_HEADER *udp;
+ UCHAR *payload;
+ UINT payload_size;
+ // Validate arguments
+ if (t == NULL || data == NULL)
+ {
+ return;
+ }
+
+ // UDP header
+ if (size <= sizeof(UDP_HEADER))
+ {
+ return;
+ }
+
+ udp = (UDP_HEADER *)data;
+
+ // Payload
+ payload = ((UCHAR *)data) + sizeof(UDP_HEADER);
+ payload_size = size - sizeof(UDP_HEADER);
+
+ // Inspect the payload size
+ if (payload_size < (Endian16(udp->PacketLength) - sizeof(UDP_HEADER)))
+ {
+ return;
+ }
+
+ // Truncate the payload
+ payload_size = Endian16(udp->PacketLength) - sizeof(UDP_HEADER);
+
+ // Search the port number from the NAT table
+ if (true)
+ {
+ NATIVE_NAT_ENTRY tt;
+ NATIVE_NAT_ENTRY *e;
+
+ NnSetNat(&tt, NAT_UDP, 0, 0, 0, 0, dest_ip, Endian16(udp->DstPort));
+
+ e = SearchHash(t->NatTableForRecv, &tt);
+
+ if (e != NULL)
+ {
+ // Last communication time
+ e->LastCommTime = t->v->Now;
+ e->TotalRecv += (UINT64)payload_size;
+
+ // Deliver to the client by rewriting the port number
+ SendUdp(t->v, e->SrcIp, e->SrcPort, src_ip, Endian16(udp->SrcPort),
+ payload, payload_size);
+ }
+ }
+}
+
+// A combined IP packet is received
+void NnIpReceived(NATIVE_NAT *t, UINT src_ip, UINT dest_ip, UINT protocol, void *data, UINT size,
+ UCHAR ttl, UCHAR *ip_header, UINT ip_header_size, UINT max_l3_size)
+{
+ // Validate arguments
+ if (t == NULL || data == NULL)
+ {
+ return;
+ }
+
+ if (dest_ip != t->PublicIP)
+ {
+ // Destination IP is not a unicast
+ return;
+ }
+
+ switch (protocol)
+ {
+ case IP_PROTO_UDP:
+ // UDP
+ NnUdpReceived(t, src_ip, dest_ip, data, size, ttl, max_l3_size);
+ break;
+
+ case IP_PROTO_TCP:
+ // TCP
+ NnTcpReceived(t, src_ip, dest_ip, data, size, ttl, max_l3_size);
+ break;
+
+ case IP_PROTO_ICMPV4:
+ // ICMP
+ NnIcmpReceived(t, src_ip, dest_ip, data, size, ttl, max_l3_size);
+ break;
+ }
+}
+
+// Received an IP packet
+void NnFragmentedIpReceived(NATIVE_NAT *t, PKT *packet)
+{
+ IPV4_HEADER *ip;
+ void *data;
+ UINT data_size_recved;
+ UINT size;
+ UINT ipv4_header_size;
+ bool last_packet = false;
+ UINT l3_size = 0;
+ UCHAR *head_ip_header_data = NULL;
+ UINT head_ip_header_size = 0;
+ // Validate arguments
+ if (t == NULL || packet == NULL)
+ {
+ return;
+ }
+
+ ip = packet->L3.IPv4Header;
+
+ // Get the size of the IPv4 header
+ ipv4_header_size = IPV4_GET_HEADER_LEN(packet->L3.IPv4Header) * 4;
+ head_ip_header_size = ipv4_header_size;
+
+ // Get the pointer to the data
+ data = ((UCHAR *)packet->L3.PointerL3) + ipv4_header_size;
+
+ // Get the data size
+ size = l3_size = Endian16(ip->TotalLength);
+ if (size <= ipv4_header_size)
+ {
+ // There is no data
+ return;
+ }
+ size -= ipv4_header_size;
+
+ // Get the size of data actually received
+ data_size_recved = packet->PacketSize - (ipv4_header_size + MAC_HEADER_SIZE);
+ if (data_size_recved < size)
+ {
+ // Data insufficient (It may be missing on the way)
+ return;
+ }
+
+ if (IPV4_GET_OFFSET(ip) == 0 && (IPV4_GET_FLAGS(ip) & 0x01) == 0)
+ {
+ // Because this packet has not been fragmented, it can be passed to the upper layer immediately
+ head_ip_header_data = (UCHAR *)packet->L3.IPv4Header;
+ NnIpReceived(t, ip->SrcIP, ip->DstIP, ip->Protocol, data, size, ip->TimeToLive,
+ head_ip_header_data, head_ip_header_size, l3_size);
+ }
+ else
+ {
+ // This packet is necessary to combine because it is fragmented
+ UINT offset = IPV4_GET_OFFSET(ip) * 8;
+ IP_COMBINE *c = NnSearchIpCombine(t, ip->SrcIP, ip->DstIP, Endian16(ip->Identification), ip->Protocol);
+
+ if (offset == 0)
+ {
+ head_ip_header_data = (UCHAR *)packet->L3.IPv4Header;
+ }
+
+ last_packet = ((IPV4_GET_FLAGS(ip) & 0x01) == 0 ? true : false);
+
+ if (c != NULL)
+ {
+ // It is the second or subsequent packet
+ c->MaxL3Size = MAX(c->MaxL3Size, l3_size);
+ NnCombineIp(t, c, offset, data, size, last_packet, head_ip_header_data, head_ip_header_size);
+ }
+ else
+ {
+ // Create a combining object because it is the first packet
+ c = NnInsertIpCombine(
+ t, ip->SrcIP, ip->DstIP, Endian16(ip->Identification), ip->Protocol, packet->BroadcastPacket,
+ ip->TimeToLive, false);
+ c->MaxL3Size = MAX(c->MaxL3Size, l3_size);
+ if (c != NULL)
+ {
+ NnCombineIp(t, c, offset, data, size, last_packet, head_ip_header_data, head_ip_header_size);
+ }
+ }
+ }
+}
+
+// Layer 2 packet processing
+void NnLayer2(NATIVE_NAT *t, PKT *packet)
+{
+ // Validate arguments
+ if (t == NULL || packet == NULL)
+ {
+ return;
+ }
+
+ if (packet->TypeL3 == L3_IPV4)
+ {
+ // IPv4
+ NnFragmentedIpReceived(t, packet);
+ }
+}
+
+// Extract the received packets of native NAT, and deliver it to the VPN client
+void NnPoll(NATIVE_NAT *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ LockQueue(t->RecvQueue);
+ {
+ while (true)
+ {
+ PKT *pkt = GetNext(t->RecvQueue);
+
+ if (pkt == NULL)
+ {
+ break;
+ }
+
+ NnLayer2(t, pkt);
+
+ FreePacketWithData(pkt);
+ }
+ }
+ UnlockQueue(t->RecvQueue);
+
+ if (t->SendStateChanged)
+ {
+ TUBE *halt_tube = NULL;
+
+ Lock(t->Lock);
+ {
+ if (t->HaltTube != NULL)
+ {
+ halt_tube = t->HaltTube;
+
+ AddRef(halt_tube->Ref);
+ }
+ }
+ Unlock(t->Lock);
+
+ if (halt_tube != NULL)
+ {
+ TubeFlushEx(halt_tube, true);
+
+ t->SendStateChanged = false;
+
+ ReleaseTube(halt_tube);
+ }
+ }
+
+ NnPollingIpCombine(t);
+
+ NnDeleteOldSessions(t);
+}
+
+// Send a fragmented IP packet to the Internet
+void NnIpSendFragmentedForInternet(NATIVE_NAT *t, UCHAR ip_protocol, UINT src_ip, UINT dest_ip, USHORT id, USHORT total_size,
+ USHORT offset, void *data, UINT size, UCHAR ttl)
+{
+ UCHAR *buf;
+ IPV4_HEADER *ip;
+ BLOCK *b;
+ // Validate arguments
+ if (t == NULL || data == NULL)
+ {
+ return;
+ }
+
+ // Memory allocation
+ buf = Malloc(size + IP_HEADER_SIZE);
+ ip = (IPV4_HEADER *)&buf[0];
+
+ // IP header construction
+ ip->VersionAndHeaderLength = 0;
+ IPV4_SET_VERSION(ip, 4);
+ IPV4_SET_HEADER_LEN(ip, (IP_HEADER_SIZE / 4));
+ ip->TypeOfService = DEFAULT_IP_TOS;
+ ip->TotalLength = Endian16((USHORT)(size + IP_HEADER_SIZE));
+ ip->Identification = Endian16(id);
+ ip->FlagsAndFlagmentOffset[0] = ip->FlagsAndFlagmentOffset[1] = 0;
+ IPV4_SET_OFFSET(ip, (offset / 8));
+ if ((offset + size) >= total_size)
+ {
+ IPV4_SET_FLAGS(ip, 0x00);
+ }
+ else
+ {
+ IPV4_SET_FLAGS(ip, 0x01);
+ }
+ ip->TimeToLive = (ttl == 0 ? DEFAULT_IP_TTL : ttl);
+ ip->Protocol = ip_protocol;
+ ip->Checksum = 0;
+ ip->SrcIP = src_ip;
+ ip->DstIP = dest_ip;
+
+ // Checksum calculation
+ ip->Checksum = IpChecksum(ip, IP_HEADER_SIZE);
+
+ // Data copy
+ Copy(buf + IP_HEADER_SIZE, data, size);
+
+ // Transmission
+ b = NewBlock(buf, size + IP_HEADER_SIZE, 0);
+
+ LockQueue(t->SendQueue);
+ {
+ if (t->SendQueue->num_item <= NN_MAX_QUEUE_LENGTH)
+ {
+ InsertQueue(t->SendQueue, b);
+
+ t->SendStateChanged = true;
+ }
+ else
+ {
+ FreeBlock(b);
+ }
+ }
+ UnlockQueue(t->SendQueue);
+}
+
+// Send an IP packet to the Internet
+void NnIpSendForInternet(NATIVE_NAT *t, UCHAR ip_protocol, UCHAR ttl, UINT src_ip, UINT dest_ip, void *data, UINT size, UINT max_l3_size)
+{
+ UINT mss = 0;
+ UCHAR *buf;
+ USHORT offset;
+ USHORT id;
+ USHORT total_size;
+ UINT size_of_this_packet;
+ // Validate arguments
+ if (t == NULL || data == NULL)
+ {
+ return;
+ }
+
+ // Maximum segment size
+ if (max_l3_size > IP_HEADER_SIZE)
+ {
+ mss = max_l3_size - IP_HEADER_SIZE;
+ }
+
+ if (mss == 0)
+ {
+ mss = t->v->IpMss;
+ }
+
+ mss = MAX(mss, 1000);
+
+ // Buffer
+ buf = (UCHAR *)data;
+
+ // ID
+ id = (t->NextId++);
+
+ // Total size
+ total_size = (USHORT)size;
+
+ // Start to fragment
+ offset = 0;
+
+ while (true)
+ {
+ bool last_packet = false;
+ // Get the size of this packet
+ size_of_this_packet = MIN((USHORT)mss, (total_size - offset));
+ if ((offset + (USHORT)size_of_this_packet) == total_size)
+ {
+ last_packet = true;
+ }
+
+ // Transmit the fragmented packet
+ NnIpSendFragmentedForInternet(t, ip_protocol, src_ip, dest_ip, id, total_size, offset,
+ buf + offset, size_of_this_packet, ttl);
+ if (last_packet)
+ {
+ break;
+ }
+
+ offset += (USHORT)size_of_this_packet;
+ }
+}
+
+// Communication of ICMP towards the Internet
+void NnIcmpEchoRecvForInternet(VH *v, UINT src_ip, UINT dest_ip, void *data, UINT size, UCHAR ttl, void *icmp_data, UINT icmp_size, UCHAR *ip_header, UINT ip_header_size, UINT max_l3_size)
+{
+ NATIVE_NAT_ENTRY tt;
+ NATIVE_NAT_ENTRY *e;
+ NATIVE_NAT *t;
+ USHORT src_port;
+ ICMP_HEADER *old_icmp_header;
+ ICMP_ECHO *old_icmp_echo;
+ ICMP_HEADER *icmp;
+ ICMP_ECHO *echo;
+ UCHAR *payload_data;
+ UINT payload_size;
+ // Validate arguments
+ if (NnIsActive(v) == false || icmp_data == NULL)
+ {
+ return;
+ }
+
+ t = v->NativeNat;
+
+ old_icmp_header = (ICMP_HEADER *)icmp_data;
+ old_icmp_echo = (ICMP_ECHO *)(((UCHAR *)icmp_data) + sizeof(ICMP_HEADER));
+
+ if (size < (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO)))
+ {
+ return;
+ }
+
+ payload_data = ((UCHAR *)icmp_data) + (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
+ payload_size = icmp_size - (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
+
+ if (dest_ip == v->HostIP)
+ {
+ // Respond because it is addressed to me
+ VirtualIcmpEchoSendResponse(v, dest_ip, src_ip, Endian16(old_icmp_echo->Identifier),
+ Endian16(old_icmp_echo->SeqNo), payload_data, payload_size);
+
+ return;
+ }
+
+ if (ttl <= 1)
+ {
+ // Reply the Time Exceeded immediately for the packet whose TTL is 1
+ UINT reply_size = sizeof(ICMP_HEADER) + 4 + ip_header_size + 8;
+ UCHAR *reply_data = ZeroMalloc(reply_size);
+ ICMP_HEADER *icmp = (ICMP_HEADER *)reply_data;
+ icmp->Type = ICMP_TYPE_TIME_EXCEEDED;
+ icmp->Code = ICMP_CODE_TTL_EXCEEDED_IN_TRANSIT;
+ Copy(reply_data + sizeof(ICMP_HEADER) + 4, ip_header, ip_header_size);
+ Copy(reply_data + sizeof(ICMP_HEADER) + 4 + ip_header_size, icmp_data, MIN(icmp_size, 8));
+
+ icmp->Checksum = IpChecksum(icmp, reply_size);
+
+ SendIp(v, src_ip, v->HostIP, IP_PROTO_ICMPV4, reply_data, reply_size);
+
+ Free(reply_data);
+
+ return;
+ }
+
+ src_port = Endian16(old_icmp_echo->Identifier);
+
+ // Search whether there is an existing session
+ NnSetNat(&tt, NAT_ICMP, src_ip, src_port, 0, 0, 0, 0);
+
+ e = SearchHash(t->NatTableForSend, &tt);
+
+ if (e == NULL)
+ {
+ // Create a new session because there is no existing one
+ UINT public_port;
+
+ if (CanCreateNewNatEntry(v) == false)
+ {
+ // Can not make any more
+ return;
+ }
+
+ NnDeleteOldestNatSessionIfNecessary(t, src_ip, NAT_ICMP);
+
+ // Get a free port
+ public_port = NnMapNewPublicPort(t, NAT_ICMP, 0, 0, t->PublicIP);
+ if (public_port == 0)
+ {
+ // There are no free ports
+ return;
+ }
+
+ e = ZeroMalloc(sizeof(NATIVE_NAT_ENTRY));
+
+ e->Status = NAT_TCP_ESTABLISHED;
+
+ e->HashCodeForSend = INFINITE;
+ e->HashCodeForRecv = INFINITE;
+ e->Id = Inc(v->Counter);
+ e->Protocol = NAT_ICMP;
+ e->SrcIp = src_ip;
+ e->SrcPort = src_port;
+ e->DestIp = 0;
+ e->DestPort = 0;
+ e->PublicIp = t->PublicIP;
+ e->PublicPort = public_port;
+
+ e->CreatedTime = v->Now;
+ e->LastCommTime = v->Now;
+
+ // Add to the list
+ AddHash(t->NatTableForSend, e);
+ AddHash(t->NatTableForRecv, e);
+
+ // Log
+ if (true)
+ {
+ IP ip1, ip2;
+ char s1[MAX_SIZE], s2[MAX_SIZE];
+ UINTToIP(&ip1, src_ip);
+ UINTToIP(&ip2, dest_ip);
+ IPToStr(s1, 0, &ip1);
+ IPToStr(s2, 0, &ip2);
+
+ Debug("ICMP Session %u: %s:0x%x -> %s:0x%x\n", e->Id, s1, src_port, s2, public_port);
+ }
+ }
+
+ // Rebuild the ICMP header
+ icmp = ZeroMalloc(sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO) + payload_size);
+ icmp->Code = old_icmp_header->Code;
+ icmp->Type = old_icmp_header->Type;
+ icmp->Checksum = 0;
+
+ echo = (ICMP_ECHO *)(((UCHAR *)icmp) + sizeof(ICMP_HEADER));
+ echo->SeqNo = old_icmp_echo->SeqNo;
+ echo->Identifier = Endian16(e->PublicPort);
+
+ Copy(((UCHAR *)icmp) + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO), payload_data, payload_size);
+
+ icmp->Checksum = IpChecksum(icmp, sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO) + payload_size);
+
+ e->TotalSent += (UINT64)payload_size;
+ e->LastCommTime = v->Now;
+
+ // Send to the Internet
+ NnIpSendForInternet(t, IP_PROTO_ICMPV4, ttl - 1, e->PublicIp, dest_ip, icmp, sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO) + payload_size, max_l3_size);
+
+ Free(icmp);
+}
+
+// Communication of UDP towards the Internet
+void NnUdpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size, UINT max_l3_size)
+{
+ NATIVE_NAT_ENTRY tt;
+ NATIVE_NAT_ENTRY *e;
+ NATIVE_NAT *t;
+ UDP_HEADER *udp;
+ // Validate arguments
+ if (NnIsActive(v) == false || data == NULL)
+ {
+ return;
+ }
+
+ t = v->NativeNat;
+
+ // Search whether there is an existing session
+ NnSetNat(&tt, NAT_UDP, src_ip, src_port, 0, 0, 0, 0);
+
+ e = SearchHash(t->NatTableForSend, &tt);
+
+ if (e == NULL)
+ {
+ // Create a new session because there is no existing one
+ UINT public_port;
+
+ if (CanCreateNewNatEntry(v) == false)
+ {
+ // Can not make any more
+ return;
+ }
+
+ NnDeleteOldestNatSessionIfNecessary(t, src_ip, NAT_UDP);
+
+ // Get a free port
+ public_port = NnMapNewPublicPort(t, NAT_UDP, 0, 0, t->PublicIP);
+ if (public_port == 0)
+ {
+ // There are no free ports
+ return;
+ }
+
+ e = ZeroMalloc(sizeof(NATIVE_NAT_ENTRY));
+
+ e->Status = NAT_TCP_ESTABLISHED;
+
+ e->HashCodeForSend = INFINITE;
+ e->HashCodeForRecv = INFINITE;
+ e->Id = Inc(v->Counter);
+ e->Protocol = NAT_UDP;
+ e->SrcIp = src_ip;
+ e->SrcPort = src_port;
+ e->DestIp = 0;
+ e->DestPort = 0;
+ e->PublicIp = t->PublicIP;
+ e->PublicPort = public_port;
+
+ e->CreatedTime = v->Now;
+ e->LastCommTime = v->Now;
+
+ // Add to the list
+ AddHash(t->NatTableForSend, e);
+ AddHash(t->NatTableForRecv, e);
+
+ // Log
+ if (true)
+ {
+ IP ip1, ip2;
+ char s1[MAX_SIZE], s2[MAX_SIZE];
+ UINTToIP(&ip1, src_ip);
+ UINTToIP(&ip2, dest_ip);
+ IPToStr(s1, 0, &ip1);
+ IPToStr(s2, 0, &ip2);
+
+ NLog(v, "LH_NAT_UDP_CREATED", e->Id, s1, src_port, s2, dest_port);
+ }
+ }
+
+ // Rebuild the UDP header
+ udp = ZeroMalloc(sizeof(UDP_HEADER) + size);
+
+ udp->SrcPort = Endian16(e->PublicPort);
+ udp->DstPort = Endian16(dest_port);
+ udp->PacketLength = Endian16((USHORT)sizeof(UDP_HEADER) + size);
+
+ Copy(((UCHAR *)udp) + sizeof(UDP_HEADER), data, size);
+
+ udp->Checksum = CalcChecksumForIPv4(e->PublicIp, dest_ip, IP_PROTO_UDP, udp, sizeof(UDP_HEADER) + size, 0);
+
+ e->TotalSent += (UINT64)size;
+ e->LastCommTime = v->Now;
+
+ // Send to the Internet
+ NnIpSendForInternet(t, IP_PROTO_UDP, 127, e->PublicIp, dest_ip, udp, sizeof(UDP_HEADER) + size, max_l3_size);
+
+ Free(udp);
+}
+
+// Communication of TCP towards the Internet
+void NnTcpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, TCP_HEADER *old_tcp, void *data, UINT size, UINT max_l3_size)
+{
+ NATIVE_NAT_ENTRY tt;
+ NATIVE_NAT_ENTRY *e;
+ NATIVE_NAT *t;
+ UINT tcp_header_size;
+ TCP_HEADER *tcp;
+ // Validate arguments
+ if (NnIsActive(v) == false || old_tcp == NULL || data == NULL)
+ {
+ return;
+ }
+
+ t = v->NativeNat;
+
+ // Search whether there is an existing session
+ NnSetNat(&tt, NAT_TCP, src_ip, src_port, dest_ip, dest_port, 0, 0);
+
+ e = SearchHash(t->NatTableForSend, &tt);
+
+ if (e == NULL)
+ {
+ // Create a new session because there is no existing one
+ UINT public_port;
+
+ if (old_tcp->Flag != TCP_SYN)
+ {
+ // If there is no existing session, pass through only for SYN packet
+ return;
+ }
+
+ if (CanCreateNewNatEntry(v) == false)
+ {
+ // Can not make any more
+ return;
+ }
+
+ NnDeleteOldestNatSessionIfNecessary(t, src_ip, NAT_TCP);
+
+ // Get a free port
+ public_port = NnMapNewPublicPort(t, NAT_TCP, dest_ip, dest_port, t->PublicIP);
+ if (public_port == 0)
+ {
+ // There are no free ports
+ return;
+ }
+
+ e = ZeroMalloc(sizeof(NATIVE_NAT_ENTRY));
+
+ e->HashCodeForSend = INFINITE;
+ e->HashCodeForRecv = INFINITE;
+ e->Id = Inc(v->Counter);
+ e->Status = NAT_TCP_CONNECTING;
+ e->Protocol = NAT_TCP;
+ e->SrcIp = src_ip;
+ e->SrcPort = src_port;
+ e->DestIp = dest_ip;
+ e->DestPort = dest_port;
+ e->PublicIp = t->PublicIP;
+ e->PublicPort = public_port;
+
+ e->CreatedTime = v->Now;
+ e->LastCommTime = v->Now;
+
+ // Add to the list
+ AddHash(t->NatTableForSend, e);
+ AddHash(t->NatTableForRecv, e);
+
+ // Log
+ if (true)
+ {
+ IP ip1, ip2;
+ char s1[MAX_SIZE], s2[MAX_SIZE];
+ UINTToIP(&ip1, src_ip);
+ UINTToIP(&ip2, dest_ip);
+ IPToStr(s1, 0, &ip1);
+ IPToStr(s2, 0, &ip2);
+
+ NLog(v, "LH_NAT_TCP_CREATED", e->Id, s1, src_port, s2, dest_port);
+ }
+ }
+
+ // Update the last communication time
+ e->LastCommTime = v->Now;
+
+ e->TotalSent += (UINT64)size;
+
+ tcp_header_size = TCP_GET_HEADER_SIZE(old_tcp) * 4;
+
+ // Create a new TCP packet
+ tcp = ZeroMalloc(tcp_header_size + size);
+
+ // Copy the old TCP header
+ Copy(tcp, old_tcp, tcp_header_size);
+
+ if (tcp->Flag & TCP_RST || tcp->Flag & TCP_FIN)
+ {
+ // Disconnect
+ e->Status = NAT_TCP_WAIT_DISCONNECT;
+ }
+
+ // Rewrite the TCP header
+ tcp->Checksum = 0;
+ tcp->SrcPort = Endian16(e->PublicPort);
+
+ e->LastSeq = Endian32(tcp->SeqNumber);
+ e->LastAck = Endian32(tcp->AckNumber);
+
+ // Payload
+ Copy(((UCHAR *)tcp) + tcp_header_size, data, size);
+
+ // Checksum calculation
+ tcp->Checksum = CalcChecksumForIPv4(e->PublicIp, dest_ip, IP_PROTO_TCP, tcp, tcp_header_size + size, 0);
+
+ // Send to the Internet
+ NnIpSendForInternet(t, IP_PROTO_TCP, 127, e->PublicIp, dest_ip, tcp, tcp_header_size + size, max_l3_size);
+
+ Free(tcp);
+}
+
+// Assign a new public-side port
+UINT NnMapNewPublicPort(NATIVE_NAT *t, UINT protocol, UINT dest_ip, UINT dest_port, UINT public_ip)
+{
+ UINT i;
+ UINT base_port;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return 0;
+ }
+
+ base_port = Rand32() % (65500 - 1025) + 1025;
+
+ for (i = 0;i < (65500 - 1025);i++)
+ {
+ UINT port;
+ NATIVE_NAT_ENTRY tt;
+ NATIVE_NAT *e;
+
+ port = base_port + i;
+ if (port > 65500)
+ {
+ port = port - 65500 + 1025;
+ }
+
+ // Is this port vacant?
+ NnSetNat(&tt, protocol, 0, 0, dest_ip, dest_port, public_ip, port);
+
+ e = SearchHash(t->NatTableForRecv, &tt);
+
+ if (e == NULL)
+ {
+ // Free port is found
+ return port;
+ }
+ }
+
+ return 0;
+}
+
+// Examine whether the native NAT is available
+bool NnIsActive(VH *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return false;
+ }
+
+ if (v->NativeNat == NULL)
+ {
+ return false;
+ }
+
+ if (v->NativeNat->PublicIP == 0)
+ {
+ return false;
+ }
+
+ return v->NativeNat->Active;
+}
+
+// Native NAT main loop
+void NnMainLoop(NATIVE_NAT *t, NATIVE_STACK *a)
+{
+ IPC *ipc;
+ TUBE *tubes[3];
+ UINT num_tubes = 0;
+ UINT64 next_poll_tick = 0;
+ INTERRUPT_MANAGER *interrupt;
+ USHORT dns_src_port = 0;
+ USHORT dns_tran_id = 0;
+ USHORT tcp_src_port = 0;
+ UINT tcp_seq = 0;
+ IP yahoo_ip;
+ bool wait_for_dns = false;
+ UINT64 tcp_last_recv_tick = 0;
+ UINT dhcp_renew_interval;
+ UINT64 next_dhcp_renew_tick = 0;
+ // Validate arguments
+ if (t == NULL || a == NULL)
+ {
+ return;
+ }
+
+ dhcp_renew_interval = a->CurrentDhcpOptionList.LeaseTime;
+
+ if (dhcp_renew_interval == 0)
+ {
+ dhcp_renew_interval = IPC_DHCP_DEFAULT_LEASE;
+ }
+
+ dhcp_renew_interval = MAX(dhcp_renew_interval, IPC_DHCP_MIN_LEASE) / 2;
+
+ interrupt = NewInterruptManager();
+
+ ipc = a->Ipc;
+
+ tubes[num_tubes++] = ipc->Sock->RecvTube;
+ tubes[num_tubes++] = ipc->Sock->SendTube;
+ tubes[num_tubes++] = t->HaltTube;
+
+ Zero(&yahoo_ip, sizeof(yahoo_ip));
+
+ next_poll_tick = Tick64() + (UINT64)NN_POLL_CONNECTIVITY_INTERVAL;
+ AddInterrupt(interrupt, next_poll_tick);
+
+ tcp_last_recv_tick = Tick64();
+ next_dhcp_renew_tick = Tick64() + (UINT64)dhcp_renew_interval;
+ AddInterrupt(interrupt, next_dhcp_renew_tick);
+
+ while (t->Halt == false && t->v->UseNat && ((t->v->HubOption == NULL) || (t->v->HubOption->DisableKernelModeSecureNAT == false)))
+ {
+ UINT64 now = Tick64();
+ bool call_cancel = false;
+ bool state_changed = false;
+ UINT wait_interval;
+
+ IPCFlushArpTable(ipc);
+ call_cancel = false;
+
+LABEL_RESTART:
+ state_changed = false;
+
+ if (next_poll_tick == 0 || next_poll_tick <= now)
+ {
+ BUF *dns_query;
+
+ dns_src_port = NnGenSrcPort();
+ dns_tran_id = Rand16();
+
+ // Start a connectivity check periodically
+ dns_query = NnBuildIpPacket(NnBuildUdpPacket(NnBuildDnsQueryPacket(NN_CHECK_HOSTNAME, dns_tran_id),
+ IPToUINT(&ipc->ClientIPAddress), dns_src_port, IPToUINT(&a->DnsServerIP), 53),
+ IPToUINT(&ipc->ClientIPAddress), IPToUINT(&a->DnsServerIP), IP_PROTO_UDP, 0);
+
+ IPCSendIPv4(ipc, dns_query->Buf, dns_query->Size);
+
+ wait_for_dns = true;
+
+ FreeBuf(dns_query);
+
+ next_poll_tick = now + (UINT64)NN_POLL_CONNECTIVITY_INTERVAL;
+ AddInterrupt(interrupt, next_poll_tick);
+ }
+
+ if (next_dhcp_renew_tick == 0 || next_dhcp_renew_tick <= now)
+ {
+ IP ip;
+
+ UINTToIP(&ip, a->CurrentDhcpOptionList.ServerAddress);
+
+ IPCDhcpRenewIP(ipc, &ip);
+
+ next_dhcp_renew_tick = now + (UINT64)dhcp_renew_interval;
+ AddInterrupt(interrupt, next_dhcp_renew_tick);
+ }
+
+ // Send an IP packet to IPC
+ LockQueue(t->SendQueue);
+ {
+ while (true)
+ {
+ BLOCK *b = GetNext(t->SendQueue);
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ IPCSendIPv4(ipc, b->Buf, b->Size);
+
+ state_changed = true;
+
+ FreeBlock(b);
+ }
+ }
+ UnlockQueue(t->SendQueue);
+
+ // Happy processing
+ IPCProcessL3Events(ipc);
+
+ LockQueue(t->RecvQueue);
+ {
+ while (true)
+ {
+ // Receive an IP packet from IPC
+ BLOCK *b = IPCRecvIPv4(ipc);
+ PKT *pkt;
+
+ if (b == NULL)
+ {
+ // Can not receive any more
+ break;
+ }
+
+ // Parse the packet
+ pkt = ParsePacketIPv4WithDummyMacHeader(b->Buf, b->Size);
+
+ FreeBlock(b);
+
+ if (pkt != NULL)
+ {
+ bool no_store = false;
+
+ // Read the contents of the packet first, to determine whether it is a response for the connectivity test packet
+ if (wait_for_dns)
+ {
+ if (pkt->TypeL3 == L3_IPV4 && pkt->TypeL4 == L4_UDP &&
+ pkt->L3.IPv4Header->SrcIP == IPToUINT(&a->DnsServerIP) &&
+ pkt->L3.IPv4Header->DstIP == IPToUINT(&ipc->ClientIPAddress) &&
+ pkt->L4.UDPHeader->SrcPort == Endian16(53) && pkt->L4.UDPHeader->DstPort == Endian16(dns_src_port))
+ {
+ DNSV4_HEADER *dns_header = (DNSV4_HEADER *)pkt->Payload;
+ if (pkt->PayloadSize >= sizeof(DNSV4_HEADER))
+ {
+ if (dns_header->TransactionId == Endian16(dns_tran_id))
+ {
+ IP ret_ip;
+
+ if (NnParseDnsResponsePacket(pkt->Payload, pkt->PayloadSize, &ret_ip))
+ {
+ BUF *tcp_query;
+
+ Copy(&yahoo_ip, &ret_ip, sizeof(IP));
+
+ //SetIP(&yahoo_ip, 192, 168, 2, 32);
+
+ // DNS response has been received
+ no_store = true;
+
+ tcp_src_port = NnGenSrcPort();
+
+ // Generate a TCP connection attempt packet
+ tcp_seq = Rand32();
+ tcp_query = NnBuildIpPacket(NnBuildTcpPacket(NewBuf(), IPToUINT(&ipc->ClientIPAddress), tcp_src_port,
+ IPToUINT(&yahoo_ip), 80, tcp_seq, 0, TCP_SYN, 8192, 1414),
+ IPToUINT(&ipc->ClientIPAddress), IPToUINT(&yahoo_ip), IP_PROTO_TCP, 0);
+
+ IPCSendIPv4(ipc, tcp_query->Buf, tcp_query->Size);
+
+ FreeBuf(tcp_query);
+
+ wait_for_dns = false;
+ }
+ }
+ }
+ }
+ }
+
+ if (pkt->TypeL3 == L3_IPV4 && pkt->TypeL4 == L4_TCP &&
+ pkt->L3.IPv4Header->SrcIP == IPToUINT(&yahoo_ip) &&
+ pkt->L3.IPv4Header->DstIP == IPToUINT(&ipc->ClientIPAddress) &&
+ pkt->L4.TCPHeader->SrcPort == Endian16(80) && pkt->L4.TCPHeader->DstPort == Endian16(tcp_src_port))
+ {
+ TCP_HEADER *tcp_header = (TCP_HEADER *)pkt->L4.TCPHeader;
+ if ((tcp_header->Flag & TCP_SYN) && (tcp_header->Flag & TCP_ACK))
+ {
+ // There was a TCP response
+ BUF *tcp_query;
+ UINT recv_seq = Endian32(tcp_header->SeqNumber) + 1;
+
+ no_store = true;
+
+ // Send a RST
+ tcp_query = NnBuildIpPacket(NnBuildTcpPacket(NewBuf(), IPToUINT(&ipc->ClientIPAddress), tcp_src_port,
+ IPToUINT(&yahoo_ip), 80, tcp_seq + 1, recv_seq, TCP_RST | TCP_ACK, 8192, 0),
+ IPToUINT(&ipc->ClientIPAddress), IPToUINT(&yahoo_ip), IP_PROTO_TCP, 0);
+
+ IPCSendIPv4(ipc, tcp_query->Buf, tcp_query->Size);
+
+ FreeBuf(tcp_query);
+
+ tcp_last_recv_tick = now;
+ }
+ }
+
+ if (t->RecvQueue->num_item > NN_MAX_QUEUE_LENGTH)
+ {
+ no_store = true;
+ }
+
+ if (no_store == false)
+ {
+ // Put in the queue
+ InsertQueue(t->RecvQueue, pkt);
+ call_cancel = true;
+ state_changed = true;
+ }
+ else
+ {
+ // Release the packet
+ FreePacketWithData(pkt);
+ }
+ }
+ }
+ }
+ UnlockQueue(t->RecvQueue);
+
+ if (state_changed)
+ {
+ goto LABEL_RESTART;
+ }
+
+ if (call_cancel)
+ {
+ CANCEL *c = NULL;
+
+ Lock(t->CancelLock);
+ {
+ c = t->Cancel;
+
+ AddRef(c->ref);
+ }
+ Unlock(t->CancelLock);
+
+ if (c != NULL)
+ {
+ Cancel(c);
+
+ ReleaseCancel(c);
+ }
+ }
+
+ if (IsTubeConnected(ipc->Sock->RecvTube) == false || IsTubeConnected(ipc->Sock->SendTube) == false)
+ {
+ // Disconnected
+ break;
+ }
+
+ if ((tcp_last_recv_tick + (UINT64)NN_POLL_CONNECTIVITY_TIMEOUT) < now)
+ {
+ // Connectivity test has timed out because a certain period of time has elapsed
+ Debug("NN_POLL_CONNECTIVITY_TIMEOUT\n");
+ break;
+ }
+
+ wait_interval = GetNextIntervalForInterrupt(interrupt);
+ wait_interval = MIN(wait_interval, 1234);
+
+ if (wait_interval != 0)
+ {
+ WaitForTubes(tubes, num_tubes, wait_interval);
+ }
+ }
+
+ FreeInterruptManager(interrupt);
+}
+
+// Build an IP packet
+BUF *NnBuildIpPacket(BUF *payload, UINT src_ip, UINT dst_ip, UCHAR protocol, UCHAR ttl)
+{
+ BUF *ret = NewBuf();
+ IPV4_HEADER h;
+
+ if (ttl == 0)
+ {
+ ttl = 127;
+ }
+
+ // IP header
+ Zero(&h, sizeof(h));
+ IPV4_SET_VERSION(&h, 4);
+ IPV4_SET_HEADER_LEN(&h, sizeof(IPV4_HEADER) / 4);
+ h.TotalLength = Endian16((USHORT)sizeof(IPV4_HEADER) + payload->Size);
+ h.Identification = Rand16();
+ h.TimeToLive = ttl;
+ h.Protocol = protocol;
+ h.SrcIP = src_ip;
+ h.DstIP = dst_ip;
+
+ h.Checksum = IpChecksum(&h, sizeof(h));
+
+ WriteBuf(ret, &h, sizeof(h));
+ WriteBufBuf(ret, payload);
+
+ SeekBufToBegin(ret);
+
+ FreeBuf(payload);
+
+ return ret;
+}
+
+// Build an UDP packet
+BUF *NnBuildUdpPacket(BUF *payload, UINT src_ip, USHORT src_port, UINT dst_ip, USHORT dst_port)
+{
+ BUF *ret = NewBuf();
+ BUF *phbuf = NewBuf();
+ UDPV4_PSEUDO_HEADER ph;
+ UDP_HEADER h;
+
+ // UDP pseudo header
+ Zero(&ph, sizeof(ph));
+
+ ph.SrcIP = src_ip;
+ ph.DstIP = dst_ip;
+ ph.SrcPort = Endian16(src_port);
+ ph.DstPort = Endian16(dst_port);
+ ph.Protocol = IP_PROTO_UDP;
+ ph.PacketLength1 = ph.PacketLength2 = Endian16(payload->Size + (USHORT)sizeof(UDP_HEADER));
+
+ WriteBuf(phbuf, &ph, sizeof(ph));
+ WriteBufBuf(phbuf, payload);
+
+ // UDP header
+ Zero(&h, sizeof(h));
+ h.SrcPort = Endian16(src_port);
+ h.DstPort = Endian16(dst_port);
+ h.PacketLength = Endian16(payload->Size + (USHORT)sizeof(UDP_HEADER));
+ h.Checksum = IpChecksum(phbuf->Buf, phbuf->Size);
+
+ WriteBuf(ret, &h, sizeof(h));
+ WriteBuf(ret, payload->Buf, payload->Size);
+
+ SeekBufToBegin(ret);
+
+ FreeBuf(payload);
+ FreeBuf(phbuf);
+
+ return ret;
+}
+
+// Build a TCP packet
+BUF *NnBuildTcpPacket(BUF *payload, UINT src_ip, USHORT src_port, UINT dst_ip, USHORT dst_port, UINT seq, UINT ack, UINT flag, UINT window_size, UINT mss)
+{
+ BUF *ret;
+ IPV4_PSEUDO_HEADER *vh;
+ TCP_HEADER *tcp;
+ static UCHAR tcp_mss_option[] = {0x02, 0x04, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00};
+ UINT header_size = TCP_HEADER_SIZE;
+ UINT total_size;
+
+ // Memory allocation
+ vh = Malloc(sizeof(IPV4_PSEUDO_HEADER) + TCP_HEADER_SIZE + payload->Size + 32);
+ tcp = (TCP_HEADER *)(((UCHAR *)vh) + sizeof(IPV4_PSEUDO_HEADER));
+
+ if (mss != 0)
+ {
+ USHORT *mss_size;
+ mss_size = (USHORT *)(&tcp_mss_option[2]);
+ *mss_size = Endian16((USHORT)mss);
+ header_size += sizeof(tcp_mss_option);
+ }
+
+ total_size = header_size + payload->Size;
+
+ // Pseudo header generation
+ vh->SrcIP = src_ip;
+ vh->DstIP = dst_ip;
+ vh->Reserved = 0;
+ vh->Protocol = IP_PROTO_TCP;
+ vh->PacketLength = Endian16((USHORT)total_size);
+
+ // TCP header generation
+ tcp->SrcPort = Endian16((USHORT)src_port);
+ tcp->DstPort = Endian16((USHORT)dst_port);
+ tcp->SeqNumber = Endian32(seq);
+ tcp->AckNumber = Endian32(ack);
+ tcp->HeaderSizeAndReserved = 0;
+ TCP_SET_HEADER_SIZE(tcp, (UCHAR)(header_size / 4));
+ tcp->Flag = (UCHAR)flag;
+ tcp->WindowSize = Endian16((USHORT)window_size);
+ tcp->Checksum = 0;
+ tcp->UrgentPointer = 0;
+
+ // Copy the option values
+ if (mss != 0)
+ {
+ Copy(((UCHAR *)tcp) + TCP_HEADER_SIZE, tcp_mss_option, sizeof(tcp_mss_option));
+ }
+
+ // Data copy
+ Copy(((UCHAR *)tcp) + header_size, payload->Buf, payload->Size);
+
+ // Checksum calculation
+ tcp->Checksum = IpChecksum(vh, total_size + 12);
+
+ ret = NewBufFromMemory(tcp, total_size);
+
+ Free(vh);
+
+ FreeBuf(payload);
+
+ return ret;
+}
+
+// Build a DNS query packet
+BUF *NnBuildDnsQueryPacket(char *hostname, USHORT tran_id)
+{
+ BUF *buf = NewBuf();
+ DNSV4_HEADER header;
+
+ Zero(&header, sizeof(header));
+
+ header.TransactionId = Endian16(tran_id);
+ header.Flag1 = 0x01;
+ header.Flag2 = 0x00;
+ header.NumQuery = Endian16(1);
+
+ WriteBuf(buf, &header, sizeof(header));
+
+ BuildDnsQueryPacket(buf, hostname, false);
+
+ SeekBufToBegin(buf);
+
+ return buf;
+}
+
+// Read a DNS record
+BUF *NnReadDnsRecord(BUF *buf, bool answer, USHORT *ret_type, USHORT *ret_class)
+{
+ USHORT type;
+ USHORT clas;
+ UINT ttl;
+ BUF *ret = NULL;
+ // Validate arguments
+ if (buf == NULL)
+ {
+ return NULL;
+ }
+
+ // Read the DNS label
+ if (NnReadDnsLabel(buf) == false)
+ {
+ return false;
+ }
+
+ // Type and Class
+ if (ReadBuf(buf, &type, sizeof(USHORT)) != sizeof(USHORT))
+ {
+ return false;
+ }
+
+ if (ret_type != NULL)
+ {
+ *ret_type = Endian16(type);
+ }
+
+ if (ReadBuf(buf, &clas, sizeof(USHORT)) != sizeof(USHORT))
+ {
+ return false;
+ }
+
+ if (ret_class != NULL)
+ {
+ *ret_class = Endian16(clas);
+ }
+
+ if (answer)
+ {
+ USHORT data_len;
+ UCHAR *data;
+
+ // TTL
+ if (ReadBuf(buf, &ttl, sizeof(UINT)) != sizeof(UINT))
+ {
+ return false;
+ }
+
+ // data_len
+ if (ReadBuf(buf, &data_len, sizeof(USHORT)) != sizeof(USHORT))
+ {
+ return false;
+ }
+
+ data_len = Endian16(data_len);
+
+ // data
+ data = Malloc(data_len);
+ if (ReadBuf(buf, data, data_len) != data_len)
+ {
+ return false;
+ }
+
+ ret = NewBufFromMemory(data, data_len);
+
+ Free(data);
+ }
+ else
+ {
+ ret = NewBuf();
+ }
+
+ return ret;
+}
+
+// Read the DNS label
+bool NnReadDnsLabel(BUF *buf)
+{
+ UCHAR c;
+ UCHAR tmp[256];
+ // Validate arguments
+ if (buf == NULL)
+ {
+ return false;
+ }
+
+LABEL_START:
+
+ if (ReadBuf(buf, &c, 1) != 1)
+ {
+ return false;
+ }
+
+ if (c == 0)
+ {
+ return true;
+ }
+
+ if (c & 0xC0)
+ {
+ // Compression label
+ if (ReadBuf(buf, &c, 1) != 1)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ else
+ {
+ // Usual label
+ if (ReadBuf(buf, tmp, c) != c)
+ {
+ return false;
+ }
+ else
+ {
+ goto LABEL_START;
+ }
+ }
+
+}
+
+// Parse the DNS response packet
+bool NnParseDnsResponsePacket(UCHAR *data, UINT size, IP *ret_ip)
+{
+ BUF *buf = NewBufFromMemory(data, size);
+ bool ret = false;
+ DNSV4_HEADER h;
+
+ if (ReadBuf(buf, &h, sizeof(h)) == sizeof(h))
+ {
+ UINT num_questions = Endian16(h.NumQuery);
+ UINT num_answers = Endian16(h.AnswerRRs);
+ UINT i;
+
+ for (i = 0;i < num_questions;i++)
+ {
+ BUF *r = NnReadDnsRecord(buf, false, NULL, NULL);
+
+ if (r != NULL)
+ {
+ FreeBuf(r);
+ }
+ else
+ {
+ goto LABEL_CLEANUP;
+ }
+ }
+
+ for (i = 0;i < num_answers;i++)
+ {
+ USHORT tp, cl;
+ BUF *r = NnReadDnsRecord(buf, true, &tp, &cl);
+
+ if (r != NULL)
+ {
+ if (tp == 0x0001 && cl == 0x0001 && r->Size == 4)
+ {
+ ret = true;
+
+ if (ret_ip != NULL)
+ {
+ Zero(ret_ip, sizeof(IP));
+
+ Copy(ret_ip->addr, r->Buf, 4);
+ }
+ }
+
+ FreeBuf(r);
+ }
+ else
+ {
+ goto LABEL_CLEANUP;
+ }
+ }
+ }
+
+LABEL_CLEANUP:
+ FreeBuf(buf);
+
+ return ret;
+}
+
+// Test the connectivity of the stack to the Internet
+bool NnTestConnectivity(NATIVE_STACK *a, TUBE *halt_tube)
+{
+ BUF *dns_query;
+ bool ok = false;
+ USHORT dns_tran_id = Rand16();
+ UINT64 next_send_tick = 0;
+ UINT64 giveup_time;
+ IPC *ipc;
+ UINT src_port = NnGenSrcPort();
+ INTERRUPT_MANAGER *interrupt;
+ TUBE *tubes[3];
+ UINT num_tubes = 0;
+ IP yahoo_ip;
+ // Validate arguments
+ if (a == NULL)
+ {
+ return false;
+ }
+
+ ipc = a->Ipc;
+ interrupt = NewInterruptManager();
+
+ tubes[num_tubes++] = ipc->Sock->RecvTube;
+ tubes[num_tubes++] = ipc->Sock->SendTube;
+
+ if (halt_tube != NULL)
+ {
+ tubes[num_tubes++] = halt_tube;
+ }
+
+ Zero(&yahoo_ip, sizeof(yahoo_ip));
+
+ // Try to get an IP address of www.yahoo.com
+ dns_query = NnBuildIpPacket(NnBuildUdpPacket(NnBuildDnsQueryPacket(NN_CHECK_HOSTNAME, dns_tran_id),
+ IPToUINT(&ipc->ClientIPAddress), src_port, IPToUINT(&a->DnsServerIP), 53),
+ IPToUINT(&ipc->ClientIPAddress), IPToUINT(&a->DnsServerIP), IP_PROTO_UDP, 0);
+
+ giveup_time = Tick64() + NN_CHECK_CONNECTIVITY_TIMEOUT;
+ AddInterrupt(interrupt, giveup_time);
+ while (true)
+ {
+ UINT64 now = Tick64();
+
+ IPCFlushArpTable(a->Ipc);
+
+ if (now >= giveup_time)
+ {
+ break;
+ }
+
+ // Send a packet periodically
+ if (next_send_tick == 0 || next_send_tick <= now)
+ {
+ next_send_tick = now + (UINT64)NN_CHECK_CONNECTIVITY_INTERVAL;
+
+ AddInterrupt(interrupt, next_send_tick);
+
+ IPCSendIPv4(ipc, dns_query->Buf, dns_query->Size);
+ }
+
+ // Happy processing
+ IPCProcessL3Events(ipc);
+
+ while (true)
+ {
+ // Receive a packet
+ BLOCK *b = IPCRecvIPv4(ipc);
+ PKT *pkt;
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ // Parse the packet
+ pkt = ParsePacketIPv4WithDummyMacHeader(b->Buf, b->Size);
+
+ if (pkt != NULL)
+ {
+ if (pkt->TypeL3 == L3_IPV4 && pkt->TypeL4 == L4_UDP &&
+ pkt->L3.IPv4Header->SrcIP == IPToUINT(&a->DnsServerIP) &&
+ pkt->L3.IPv4Header->DstIP == IPToUINT(&ipc->ClientIPAddress) &&
+ pkt->L4.UDPHeader->SrcPort == Endian16(53) && pkt->L4.UDPHeader->DstPort == Endian16(src_port))
+ {
+ DNSV4_HEADER *dns_header = (DNSV4_HEADER *)pkt->Payload;
+ if (pkt->PayloadSize >= sizeof(DNSV4_HEADER))
+ {
+ if (dns_header->TransactionId == Endian16(dns_tran_id))
+ {
+ IP ret_ip;
+
+ if (NnParseDnsResponsePacket(pkt->Payload, pkt->PayloadSize, &ret_ip))
+ {
+ Copy(&yahoo_ip, &ret_ip, sizeof(IP));
+ }
+ }
+ }
+ }
+ }
+
+ FreePacketWithData(pkt);
+ FreeBlock(b);
+ }
+
+ if ((halt_tube != NULL && IsTubeConnected(halt_tube) == false) ||
+ IsTubeConnected(ipc->Sock->SendTube) == false || IsTubeConnected(ipc->Sock->RecvTube) == false)
+ {
+ // Disconnected
+ break;
+ }
+
+ if (IsZeroIP(&yahoo_ip) == false)
+ {
+ // There is a response
+ break;
+ }
+
+ // Keep the CPU waiting
+ WaitForTubes(tubes, num_tubes, GetNextIntervalForInterrupt(interrupt));
+ }
+
+ FreeBuf(dns_query);
+
+ if (IsZeroIP(&yahoo_ip) == false)
+ {
+ BUF *tcp_query;
+ UINT seq = Rand32();
+ bool tcp_get_response = false;
+ UINT recv_seq = 0;
+
+ // Since the IP address of www.yahoo.com has gotten, try to connect by TCP
+ giveup_time = Tick64() + NN_CHECK_CONNECTIVITY_TIMEOUT;
+ AddInterrupt(interrupt, giveup_time);
+
+ // Generate a TCP packet
+ tcp_query = NnBuildIpPacket(NnBuildTcpPacket(NewBuf(), IPToUINT(&ipc->ClientIPAddress), src_port,
+ IPToUINT(&yahoo_ip), 80, seq, 0, TCP_SYN, 8192, 1414),
+ IPToUINT(&ipc->ClientIPAddress), IPToUINT(&yahoo_ip), IP_PROTO_TCP, 0);
+
+ Debug("Test TCP to %r\n", &yahoo_ip);
+
+ next_send_tick = 0;
+
+ while (true)
+ {
+ UINT64 now = Tick64();
+
+ IPCFlushArpTable(a->Ipc);
+
+ if (now >= giveup_time)
+ {
+ break;
+ }
+
+ // Send the packet periodically
+ if (next_send_tick == 0 || next_send_tick <= now)
+ {
+ next_send_tick = now + (UINT64)NN_CHECK_CONNECTIVITY_INTERVAL;
+
+ AddInterrupt(interrupt, next_send_tick);
+
+ IPCSendIPv4(ipc, tcp_query->Buf, tcp_query->Size);
+ }
+
+ // Happy procedure
+ IPCProcessL3Events(ipc);
+
+ while (true)
+ {
+ // Receive a packet
+ BLOCK *b = IPCRecvIPv4(ipc);
+ PKT *pkt;
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ // Parse the packet
+ pkt = ParsePacketIPv4WithDummyMacHeader(b->Buf, b->Size);
+
+ if (pkt != NULL)
+ {
+ if (pkt->TypeL3 == L3_IPV4 && pkt->TypeL4 == L4_TCP &&
+ pkt->L3.IPv4Header->SrcIP == IPToUINT(&yahoo_ip) &&
+ pkt->L3.IPv4Header->DstIP == IPToUINT(&ipc->ClientIPAddress) &&
+ pkt->L4.TCPHeader->SrcPort == Endian16(80) && pkt->L4.TCPHeader->DstPort == Endian16(src_port))
+ {
+ TCP_HEADER *tcp_header = (TCP_HEADER *)pkt->L4.TCPHeader;
+ if ((tcp_header->Flag & TCP_SYN) && (tcp_header->Flag & TCP_ACK))
+ {
+ // There was a TCP response
+ tcp_get_response = true;
+ recv_seq = Endian32(tcp_header->SeqNumber);
+ }
+ }
+ }
+
+ FreePacketWithData(pkt);
+ FreeBlock(b);
+ }
+
+ if ((halt_tube != NULL && IsTubeConnected(halt_tube) == false) ||
+ IsTubeConnected(ipc->Sock->SendTube) == false || IsTubeConnected(ipc->Sock->RecvTube) == false)
+ {
+ // Disconnected
+ break;
+ }
+
+ if (tcp_get_response)
+ {
+ WHERE;
+ break;
+ }
+
+ // Keep the CPU waiting
+ WaitForTubes(tubes, num_tubes, GetNextIntervalForInterrupt(interrupt));
+ }
+
+ FreeBuf(tcp_query);
+
+ // Send a RST
+ if (recv_seq != 0)
+ {
+ recv_seq++;
+ }
+
+ tcp_query = NnBuildIpPacket(NnBuildTcpPacket(NewBuf(), IPToUINT(&ipc->ClientIPAddress), src_port,
+ IPToUINT(&yahoo_ip), 80, seq + 1, recv_seq, TCP_RST | TCP_ACK, 8192, 0),
+ IPToUINT(&ipc->ClientIPAddress), IPToUINT(&yahoo_ip), IP_PROTO_TCP, 0);
+
+ IPCSendIPv4(ipc, tcp_query->Buf, tcp_query->Size);
+
+ FreeBuf(tcp_query);
+
+ SleepThread(100);
+
+ if (tcp_get_response)
+ {
+ ok = true;
+ }
+ }
+
+ FreeInterruptManager(interrupt);
+
+ return ok;
+}
+
+// Generate source port number by a random number
+UINT NnGenSrcPort()
+{
+ return 1025 + Rand32() % (65500 - 1025);
+}
+
+// Get a next good interface for the native NAT
+NATIVE_STACK *NnGetNextInterface(NATIVE_NAT *t)
+{
+ NATIVE_STACK *ret = NULL;
+ UINT current_hash;
+ TOKEN_LIST *device_list;
+ UINT i;
+ char tmp[MAX_SIZE];
+ char *dev_name;
+ UINT current_ip_hash;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return NULL;
+ }
+
+ t->NextWaitTimeForRetry = NN_NEXT_WAIT_TIME_FOR_DEVICE_ENUM * MIN((t->FailedCount + 1), NN_NEXT_WAIT_TIME_MAX_FAIL_COUNT);
+
+ // Get the device list
+ device_list = GetEthList();
+
+ if (device_list == NULL || device_list->NumTokens == 0)
+ {
+ // Device list acquisition failure (Or no device acquired as a result)
+ FreeToken(device_list);
+ t->FailedCount++;
+ return NULL;
+ }
+
+ current_hash = GetEthDeviceHash();
+ current_ip_hash = GetHostIPAddressHash32();
+
+ if (t->LastInterfaceDeviceHash != current_hash || t->LastHostAddressHash != current_ip_hash)
+ {
+ // Device list is altered from the previous search
+ t->LastInterfaceIndex = INFINITE;
+ t->FailedCount = 0;
+ }
+
+ t->LastInterfaceDeviceHash = current_hash;
+ t->LastHostAddressHash = current_ip_hash;
+
+ if (t->LastInterfaceIndex == INFINITE)
+ {
+ i = 0;
+ }
+ else
+ {
+ i = t->LastInterfaceIndex + 1;
+ if (i >= device_list->NumTokens)
+ {
+ i = 0;
+ }
+ }
+
+ if ((i + 1) == device_list->NumTokens)
+ {
+ // Searched to the end
+ t->LastInterfaceIndex = INFINITE;
+
+ // Increase the number of search failures by one
+ t->FailedCount++;
+ }
+ else
+ {
+ // It is not the end yet
+ t->LastInterfaceIndex = i;
+ t->NextWaitTimeForRetry = 0;
+ }
+
+ dev_name = device_list->Token[i];
+
+ if (IsInLinesFile(NN_NO_NATIVE_NAT_FILENAME, dev_name, true) == false)
+ {
+ // Try to open the device
+ BinToStr(tmp, sizeof(tmp), t->v->MacAddress, 6);
+ ret = NewNativeStack(NULL, dev_name, tmp);
+
+ if (ret != NULL)
+ {
+ // Test whether an IP address can be obtained from a DHCP server
+ DHCP_OPTION_LIST opt;
+
+ Copy(t->CurrentMacAddress, ret->Ipc->MacAddress, 6);
+
+ Zero(&opt, sizeof(opt));
+
+ BinToStr(tmp, sizeof(tmp), ret->MacAddress, 6);
+ Format(ret->Ipc->ClientHostname, sizeof(ret->Ipc->ClientHostname), NN_HOSTNAME_FORMAT, tmp);
+ StrLower(ret->Ipc->ClientHostname);
+
+ Debug("IPCDhcpAllocateIP for %s\n", ret->DeviceName);
+ if (IPCDhcpAllocateIP(ret->Ipc, &opt, t->HaltTube2))
+ {
+ char client_ip[64];
+ char dhcp_ip[64];
+ char client_mask[64];
+ char gateway_ip[64];
+
+ IP ip;
+ IP subnet;
+ IP gw;
+
+ IPToStr32(client_ip, sizeof(client_ip), opt.ClientAddress);
+ IPToStr32(client_mask, sizeof(client_mask), opt.SubnetMask);
+ IPToStr32(dhcp_ip, sizeof(dhcp_ip), opt.ServerAddress);
+ IPToStr32(gateway_ip, sizeof(gateway_ip), opt.Gateway);
+
+ Debug("DHCP: client_ip=%s, client_mask=%s, dhcp_ip=%s, gateway_ip=%s\n",
+ client_ip, client_mask, dhcp_ip, gateway_ip);
+
+ Copy(&ret->CurrentDhcpOptionList, &opt, sizeof(DHCP_OPTION_LIST));
+
+ // IP parameter settings
+ UINTToIP(&ip, opt.ClientAddress);
+ UINTToIP(&subnet, opt.SubnetMask);
+ UINTToIP(&gw, opt.Gateway);
+
+ IPCSetIPv4Parameters(ret->Ipc, &ip, &subnet, &gw);
+
+ // Determine the DNS server to use
+ UINTToIP(&ret->DnsServerIP, opt.DnsServer);
+ if (IsZeroIP(&ret->DnsServerIP))
+ {
+ // Use 8.8.8.8 instead If the DNS is not assigned from the DHCP server
+ SetIP(&ret->DnsServerIP, 8, 8, 8, 8);
+ }
+
+ // Connectivity test
+ // (always fail if the default gateway is not set)
+ if (opt.Gateway != 0 &&
+ NnTestConnectivity(ret, t->HaltTube2))
+ {
+ // Reset the number of search failures
+ t->FailedCount = 0;
+ Debug("Connectivity OK.\n");
+ }
+ else
+ {
+ Debug("Connectivity Failed.\n");
+ FreeNativeStack(ret);
+ ret = NULL;
+ }
+ }
+ else
+ {
+ Debug("DHCP Failed.\n");
+ FreeNativeStack(ret);
+ ret = NULL;
+
+ Zero(t->CurrentMacAddress, sizeof(t->CurrentMacAddress));
+ }
+ }
+ }
+
+ FreeToken(device_list);
+
+ return ret;
+}
+
+// Native NAT thread
+void NativeNatThread(THREAD *thread, void *param)
+{
+ NATIVE_NAT *t = (NATIVE_NAT *)param;
+ void *wait_handle = InitWaitUntilHostIPAddressChanged();
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ while (t->Halt == false)
+ {
+ NATIVE_STACK *a;
+
+ while (t->v->UseNat == false || (t->v->HubOption != NULL && t->v->HubOption->DisableKernelModeSecureNAT))
+ {
+ if (t->Halt)
+ {
+ break;
+ }
+
+ // If the NAT is disabled, wait until it becomes enabled
+ Wait(t->HaltEvent, 1234);
+ }
+
+ if (t->Halt)
+ {
+ break;
+ }
+
+ // Get a next good native NAT stack
+ Debug("NnGetNextInterface Start.\n");
+
+ NnClearQueue(t);
+
+ a = NnGetNextInterface(t);
+
+ if (a != NULL)
+ {
+ char macstr[64];
+ // Acquisition success
+ Debug("NnGetNextInterface Ok: %s\n", a->DeviceName);
+
+ Lock(t->Lock);
+ {
+ if (a->Sock1 != NULL)
+ {
+ t->HaltTube = a->Sock2->RecvTube;
+
+ if (t->HaltTube != NULL)
+ {
+ AddRef(t->HaltTube->Ref);
+ }
+ }
+ }
+ Unlock(t->Lock);
+
+ NnClearQueue(t);
+
+ t->PublicIP = IPToUINT(&a->Ipc->ClientIPAddress);
+ t->Active = true;
+
+
+ Debug("NnMainLoop Start.\n");
+ MacToStr(macstr, sizeof(macstr), a->Ipc->MacAddress);
+ NLog(t->v, "LH_KERNEL_MODE_START", a->DeviceName,
+ &a->Ipc->ClientIPAddress, &a->Ipc->SubnetMask, &a->Ipc->DefaultGateway, &a->Ipc->BroadcastAddress,
+ macstr, &a->CurrentDhcpOptionList.ServerAddress, &a->DnsServerIP);
+ NnMainLoop(t, a);
+ Debug("NnMainLoop End.\n");
+
+ t->Active = false;
+ t->PublicIP = 0;
+
+
+ NnClearQueue(t);
+
+ // Close the stack
+ Lock(t->Lock);
+ {
+ if (t->HaltTube != NULL)
+ {
+ ReleaseTube(t->HaltTube);
+ t->HaltTube = NULL;
+ }
+ }
+ Unlock(t->Lock);
+ FreeNativeStack(a);
+
+ Zero(t->CurrentMacAddress, 6);
+ }
+ else
+ {
+ Debug("NnGetNextInterface Failed.\n");
+ }
+
+ // Wait for a certain period of time
+ if (t->NextWaitTimeForRetry != 0)
+ {
+ WaitUntilHostIPAddressChanged(wait_handle, t->HaltEvent, t->NextWaitTimeForRetry, 1000);
+ }
+ }
+
+ FreeWaitUntilHostIPAddressChanged(wait_handle);
+}
+
+// Erase the contents of the queue for transmission and reception
+void NnClearQueue(NATIVE_NAT *t)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ LockQueue(t->SendQueue);
+ {
+ while (true)
+ {
+ BLOCK *b = GetNext(t->SendQueue);
+
+ if (b == NULL)
+ {
+ break;
+ }
+
+ FreeBlock(b);
+ }
+ }
+ UnlockQueue(t->SendQueue);
+
+ LockQueue(t->RecvQueue);
+ {
+ while (true)
+ {
+ PKT *p = GetNext(t->RecvQueue);
+
+ if (p == NULL)
+ {
+ break;
+ }
+
+ FreePacketWithData(p);
+ }
+ }
+ UnlockQueue(t->RecvQueue);
+}
+
+// Structure setting function to search for native NAT
+void NnSetNat(NATIVE_NAT_ENTRY *e, UINT protocol, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT pub_ip, UINT pub_port)
+{
+ // Validate arguments
+ if (e == NULL)
+ {
+ return;
+ }
+
+ Zero(e, sizeof(NATIVE_NAT_ENTRY));
+
+ e->Protocol = protocol;
+ e->SrcIp = src_ip;
+ e->SrcPort = src_port;
+ e->DestIp = dest_ip;
+ e->DestPort = dest_port;
+ e->PublicIp = pub_ip;
+ e->PublicPort = pub_port;
+ e->HashCodeForSend = e->HashCodeForRecv = INFINITE;
+}
+
+// Get the hash code of the native NAT table (receiving direction)
+UINT GetHashNativeNatTableForRecv(void *p)
+{
+ UINT r;
+ NATIVE_NAT_ENTRY *e = (NATIVE_NAT_ENTRY *)p;
+ if (e == NULL)
+ {
+ return 0;
+ }
+
+ if (e->HashCodeForRecv != INFINITE)
+ {
+ return e->HashCodeForRecv;
+ }
+
+ r = 0;
+
+ r += e->Protocol;
+ r += e->PublicIp;
+ r += e->PublicPort;
+
+ if (e->Protocol == NAT_TCP)
+ {
+ r += e->DestIp;
+ r += e->DestPort;
+ }
+
+ e->HashCodeForRecv = r;
+
+ return r;
+}
+
+// Comparison function of native NAT table (receiving direction)
+int CmpNativeNatTableForRecv(void *p1, void *p2)
+{
+ int r;
+ NATIVE_NAT_ENTRY *e1, *e2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ e1 = *(NATIVE_NAT_ENTRY **)p1;
+ e2 = *(NATIVE_NAT_ENTRY **)p2;
+ if (e1 == NULL || e2 == NULL)
+ {
+ return 0;
+ }
+
+ r = COMPARE_RET(e1->Protocol, e2->Protocol);
+ if (r != 0)
+ {
+ return r;
+ }
+
+ r = COMPARE_RET(e1->PublicIp, e2->PublicIp);
+ if (r != 0)
+ {
+ return r;
+ }
+
+ r = COMPARE_RET(e1->PublicPort, e2->PublicPort);
+ if (r != 0)
+ {
+ return r;
+ }
+
+ if (e1->Protocol == NAT_TCP)
+ {
+ r = COMPARE_RET(e1->DestIp, e2->DestIp);
+ if (r != 0)
+ {
+ return r;
+ }
+
+ r = COMPARE_RET(e1->DestPort, e2->DestPort);
+ if (r != 0)
+ {
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+// Get the hash code of the native NAT table (transmit direction)
+UINT GetHashNativeNatTableForSend(void *p)
+{
+ UINT r;
+ NATIVE_NAT_ENTRY *e = (NATIVE_NAT_ENTRY *)p;
+ if (e == NULL)
+ {
+ return 0;
+ }
+
+ if (e->HashCodeForSend != INFINITE)
+ {
+ return e->HashCodeForSend;
+ }
+
+ r = 0;
+
+ r += e->Protocol;
+ r += e->SrcIp;
+ r += e->SrcPort;
+
+ if (e->Protocol == NAT_TCP)
+ {
+ r += e->DestIp;
+ r += e->DestPort;
+ }
+
+ e->HashCodeForSend = r;
+
+ return r;
+}
+
+// Comparison function of native NAT table (transmit direction)
+int CmpNativeNatTableForSend(void *p1, void *p2)
+{
+ int r;
+ NATIVE_NAT_ENTRY *e1, *e2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ e1 = *(NATIVE_NAT_ENTRY **)p1;
+ e2 = *(NATIVE_NAT_ENTRY **)p2;
+ if (e1 == NULL || e2 == NULL)
+ {
+ return 0;
+ }
+
+ r = COMPARE_RET(e1->Protocol, e2->Protocol);
+ if (r != 0)
+ {
+ return r;
+ }
+
+ r = COMPARE_RET(e1->SrcIp, e2->SrcIp);
+ if (r != 0)
+ {
+ return r;
+ }
+
+ r = COMPARE_RET(e1->SrcPort, e2->SrcPort);
+ if (r != 0)
+ {
+ return r;
+ }
+
+ if (e1->Protocol == NAT_TCP)
+ {
+ r = COMPARE_RET(e1->DestIp, e2->DestIp);
+ if (r != 0)
+ {
+ return r;
+ }
+
+ r = COMPARE_RET(e1->DestPort, e2->DestPort);
+ if (r != 0)
+ {
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+// Start the native NAT
+NATIVE_NAT *NewNativeNat(VH *v)
+{
+ NATIVE_NAT *t;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return NULL;
+ }
+
+ t = ZeroMalloc(sizeof(NATIVE_NAT));
+
+ t->v = v;
+
+ t->Cancel = v->Cancel;
+ AddRef(t->Cancel->ref);
+
+ // Data structure initialization
+ t->LastInterfaceIndex = INFINITE;
+ t->SendQueue = NewQueue();
+ t->RecvQueue = NewQueue();
+ NnInitIpCombineList(t);
+
+ t->Lock = NewLock();
+
+ t->CancelLock = NewLock();
+
+ t->HaltEvent = NewEvent();
+
+ NewTubePair(&t->HaltTube2, &t->HaltTube3, 0);
+
+ // Create a NAT table
+ t->NatTableForSend = NewHashList(GetHashNativeNatTableForSend, CmpNativeNatTableForSend, 11, true);
+ t->NatTableForRecv = NewHashList(GetHashNativeNatTableForRecv, CmpNativeNatTableForRecv, 11, true);
+
+ t->Thread = NewThread(NativeNatThread, t);
+
+ return t;
+}
+
+// Stop the native NAT
+void FreeNativeNat(NATIVE_NAT *t)
+{
+ TUBE *tube;
+ UINT i;
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ t->Halt = true;
+
+ Lock(t->Lock);
+ {
+ tube = t->HaltTube;
+
+ if (tube != NULL)
+ {
+ AddRef(tube->Ref);
+ }
+ }
+ Unlock(t->Lock);
+
+ if (tube != NULL)
+ {
+ TubeFlushEx(tube, true);
+
+ SleepThread(100);
+
+ TubeDisconnect(tube);
+
+ ReleaseTube(tube);
+ }
+
+ TubeDisconnect(t->HaltTube2);
+ TubeDisconnect(t->HaltTube3);
+
+ Set(t->HaltEvent);
+
+ WaitThread(t->Thread, INFINITE);
+
+ ReleaseThread(t->Thread);
+
+ DeleteLock(t->Lock);
+
+ DeleteLock(t->CancelLock);
+
+ ReleaseEvent(t->HaltEvent);
+
+ ReleaseTube(t->HaltTube2);
+ ReleaseTube(t->HaltTube3);
+
+ NnClearQueue(t);
+
+ ReleaseQueue(t->RecvQueue);
+ ReleaseQueue(t->SendQueue);
+
+ ReleaseCancel(t->Cancel);
+
+ // Release the NAT table
+ for (i = 0;i < LIST_NUM(t->NatTableForSend->AllList);i++)
+ {
+ NATIVE_NAT_ENTRY *e = LIST_DATA(t->NatTableForSend->AllList, i);
+
+ Free(e);
+ }
+
+ ReleaseHashList(t->NatTableForSend);
+ ReleaseHashList(t->NatTableForRecv);
+
+ NnFreeIpCombineList(t);
+
+ Free(t);
+}
+
+// Take the log of Virtual Host
+void VLog(VH *v, char *str)
+{
+ // Not take!!
+ return;
+}
+
+// Disconnect the NAT entry immediately
+void DisconnectNatEntryNow(VH *v, NAT_ENTRY *e)
+{
+ // Validate arguments
+ if (v == NULL || e == NULL)
+ {
+ return;
+ }
+
+ if (e->DisconnectNow == false)
+ {
+ e->DisconnectNow = true;
+
+ SetSockEvent(v->SockEvent);
+ }
+}
+
+// Get the NAT entry with specified source IP address and the oldest last communication time
+NAT_ENTRY *GetOldestNatEntryOfIp(VH *v, UINT ip, UINT protocol)
+{
+ UINT i;
+ NAT_ENTRY *oldest = NULL;
+ UINT64 oldest_tick = 0xFFFFFFFFFFFFFFFFULL;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(v->NatTable);i++)
+ {
+ NAT_ENTRY *e = LIST_DATA(v->NatTable, i);
+
+ if (e->DisconnectNow == false)
+ {
+ if (e->SrcIp == ip)
+ {
+ if (e->Protocol == protocol)
+ {
+ if (protocol != NAT_TCP || e->TcpStatus != NAT_TCP_CONNECTING)
+ {
+ if (e->LastCommTime <= oldest_tick)
+ {
+ oldest_tick = e->LastCommTime;
+ oldest = e;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return oldest;
+}
+
+// Get the number of current NAT entries per IP address
+UINT GetNumNatEntriesPerIp(VH *v, UINT ip, UINT protocol, bool tcp_syn_sent)
+{
+ UINT ret = 0;
+ UINT i;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return 0;
+ }
+
+ for (i = 0;i < LIST_NUM(v->NatTable);i++)
+ {
+ NAT_ENTRY *e = LIST_DATA(v->NatTable, i);
+
+ if (e->DisconnectNow == false)
+ {
+ if (e->SrcIp == ip)
+ {
+ if (e->Protocol == protocol)
+ {
+ bool ok = false;
+
+ if (protocol == NAT_TCP)
+ {
+ if (tcp_syn_sent)
+ {
+ if (e->TcpStatus == NAT_TCP_CONNECTING)
+ {
+ ok = true;
+ }
+ }
+ else
+ {
+ if (e->TcpStatus != NAT_TCP_CONNECTING)
+ {
+ ok = true;
+ }
+ }
+ }
+ else
+ {
+ ok = true;
+ }
+
+ if (ok)
+ {
+ ret++;
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+// Check whether the NAT is available
+bool CanCreateNewNatEntry(VH *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return false;
+ }
+
+ if (v->UseNat == false)
+ {
+ // NAT stopped
+ return false;
+ }
+
+ if (NnIsActive(v) && v->NativeNat != NULL && v->NativeNat->NatTableForRecv != NULL)
+ {
+ if (v->NativeNat->NatTableForRecv->AllList->num_item > NAT_MAX_SESSIONS_KERNEL)
+ {
+ // Number of sessions exceeded (kernel mode)
+ return false;
+ }
+ }
+ else
+ {
+ if (v->NatTable->num_item > NAT_MAX_SESSIONS)
+ {
+ // Number of sessions exceeded (user mode)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Set a pointer to the Virtual HUB options
+void NatSetHubOption(VH *v, HUB_OPTION *o)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ v->HubOption = o;
+}
+
+// Get a pointer to the Virtual HUB options
+HUB_OPTION *NatGetHubOption(VH *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return NULL;
+ }
+
+ return v->HubOption;
+}
+
+// The main function of NAT processing thread
+void NatThreadMain(VH *v)
+{
+ bool halt_flag;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ v->TmpBuf = Malloc(NAT_TMPBUF_SIZE);
+
+ while (true)
+ {
+ // Wait until the next event is set
+ WaitSockEvent(v->SockEvent, SELECT_TIME);
+
+ halt_flag = false;
+
+ LockVirtual(v);
+ {
+ // Process on all NAT sessions
+ UINT i, num;
+
+ v->Now = Tick64();
+ v->NatDoCancelFlag = false;
+
+LIST_ELEMENT_DELETED:
+ num = LIST_NUM(v->NatTable);
+ for (i = 0;i < num;i++)
+ {
+ NAT_ENTRY *n = LIST_DATA(v->NatTable, i);
+
+ switch (n->Protocol)
+ {
+ case NAT_TCP: // TCP
+ if (NatTransactTcp(v, n) == false)
+ {
+ goto LIST_ELEMENT_DELETED;
+ }
+ break;
+
+ case NAT_UDP: // UDP
+ if (NatTransactUdp(v, n) == false)
+ {
+ goto LIST_ELEMENT_DELETED;
+ }
+ break;
+
+ case NAT_ICMP: // ICMP
+ if (NatTransactIcmp(v, n) == false)
+ {
+ goto LIST_ELEMENT_DELETED;
+ }
+ break;
+
+ case NAT_DNS: // DNS
+ if (NatTransactDns(v, n) == false)
+ {
+ goto LIST_ELEMENT_DELETED;
+ }
+ break;
+ }
+ }
+
+ if (v->NatDoCancelFlag)
+ {
+ // Hit the cancel of the parent thread
+ Cancel(v->Cancel);
+ }
+
+ // Halting flag check
+ if (v->HaltNat)
+ {
+ halt_flag = true;
+ }
+ }
+ UnlockVirtual(v);
+
+ if (halt_flag)
+ {
+ // Terminate the thread by disconnecting all entries forcibly
+ LockVirtual(v);
+ {
+ UINT num = LIST_NUM(v->NatTable);
+ NAT_ENTRY **nn = ToArray(v->NatTable);
+ UINT i;
+
+ for (i = 0;i < num;i++)
+ {
+ NAT_ENTRY *n = nn[i];
+ n->DisconnectNow = true;
+
+ switch (n->Protocol)
+ {
+ case NAT_TCP: // TCP
+ NatTransactTcp(v, n);
+ break;
+
+ case NAT_UDP: // UDP
+ NatTransactUdp(v, n);
+ break;
+
+ case NAT_ICMP: // ICMP
+ NatTransactIcmp(v, n);
+ break;
+
+ case NAT_DNS: // DNS
+ NatTransactDns(v, n);
+ break;
+ }
+ }
+
+ Free(nn);
+ }
+ UnlockVirtual(v);
+ break;
+ }
+ }
+
+ Free(v->TmpBuf);
+}
+
+// DNS: Thread to get the IP address
+void NatGetIPThread(THREAD *t, void *param)
+{
+ NAT_DNS_QUERY *q;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ q = (NAT_DNS_QUERY *)param;
+ AddWaitThread(t);
+
+ q->Ok = GetIP(&q->Ip, q->Hostname);
+
+ DelWaitThread(t);
+
+ if (Release(q->ref) == 0)
+ {
+ Free(q);
+ }
+}
+
+// DNS: Get an IP address from host name
+bool NatGetIP(IP *ip, char *hostname)
+{
+ TOKEN_LIST *t;
+ bool ret = false;
+ // Validate arguments
+ if (ip == NULL || hostname == NULL)
+ {
+ return false;
+ }
+
+ t = ParseToken(hostname, ".");
+ if (t == NULL)
+ {
+ return false;
+ }
+ if (t->NumTokens == 0)
+ {
+ FreeToken(t);
+ return false;
+ }
+
+ if (t->NumTokens == 1)
+ {
+ ret = GetIP(ip, hostname);
+ }
+ else
+ {
+ char *hostname2 = t->Token[0];
+ NAT_DNS_QUERY *q1, *q2;
+ THREAD *t1, *t2;
+
+ q1 = ZeroMalloc(sizeof(NAT_DNS_QUERY));
+ q2 = ZeroMalloc(sizeof(NAT_DNS_QUERY));
+ q1->ref = NewRef();
+ q2->ref = NewRef();
+ AddRef(q1->ref);
+ AddRef(q2->ref);
+ StrCpy(q1->Hostname, sizeof(q1->Hostname), hostname);
+ StrCpy(q2->Hostname, sizeof(q2->Hostname), hostname2);
+
+ t1 = NewThread(NatGetIPThread, q1);
+ t2 = NewThread(NatGetIPThread, q2);
+
+ WaitThread(t1, NAT_DNS_QUERY_TIMEOUT);
+
+ if (q1->Ok)
+ {
+ ret = true;
+ Copy(ip, &q1->Ip, sizeof(IP));
+ }
+ else
+ {
+ WaitThread(t2, NAT_DNS_QUERY_TIMEOUT);
+ if (q1->Ok)
+ {
+ ret = true;
+ Copy(ip, &q1->Ip, sizeof(IP));
+ }
+ else if (q2->Ok)
+ {
+ ret = true;
+ Copy(ip, &q2->Ip, sizeof(IP));
+ }
+ }
+
+ ReleaseThread(t1);
+ ReleaseThread(t2);
+
+ if (Release(q1->ref) == 0)
+ {
+ Free(q1);
+ }
+ if (Release(q2->ref) == 0)
+ {
+ Free(q2);
+ }
+ }
+
+ FreeToken(t);
+
+ return ret;
+}
+
+// DNS query function
+void NatDnsThread(THREAD *t, void *param)
+{
+ NAT_ENTRY *n;
+ IP ip;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+ n = (NAT_ENTRY *)param;
+
+ // Notify the initialization completion
+ NoticeThreadInit(t);
+
+ // Run processing
+ if (EndWith(n->DnsTargetHostName, ".in-addr.arpa") == false)
+ {
+ // Forward resolution
+ if (NatGetIP(&ip, n->DnsTargetHostName))
+ {
+ // Forward resolution success
+ Copy(&n->DnsResponseIp, &ip, sizeof(IP));
+ n->DnsOk = true;
+ }
+ }
+ else
+ {
+ // Reverse resolution
+ IP ip;
+ n->DnsGetIpFromHost = true; // Set the reverse resolution flag
+ // Convert a *.in-addr.arpa string to an IP address
+ if (ArpaToIP(&ip, n->DnsTargetHostName))
+ {
+ // Reverse resolution process
+ char tmp[256];
+ if (GetHostName(tmp, sizeof(tmp), &ip))
+ {
+ // Reverse resolution success
+ n->DnsResponseHostName = CopyStr(tmp);
+ n->DnsOk = true;
+ }
+ }
+ }
+
+ // Notify the results
+ n->DnsFinished = true;
+
+ SetSockEvent(n->v->SockEvent);
+}
+
+// Convert a reverse resolution address to an IP address
+bool ArpaToIP(IP *ip, char *str)
+{
+ TOKEN_LIST *token;
+ bool ret = false;
+ // Validate arguments
+ if (ip == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ // Token conversion
+ token = ParseToken(str, ".");
+ if (token->NumTokens == 6)
+ {
+ // Convert the token [0, 1, 2, 3] to IP
+ UINT i;
+ Zero(ip, sizeof(IP));
+ for (i = 0;i < 4;i++)
+ {
+ ip->addr[i] = (UCHAR)ToInt(token->Token[3 - i]);
+ }
+ ret = true;
+ }
+
+ FreeToken(token);
+
+ if (IPToUINT(ip) == 0)
+ {
+ ret = false;
+ }
+
+ return ret;
+}
+
+// Handle a DNS entry
+bool NatTransactDns(VH *v, NAT_ENTRY *n)
+{
+ // Validate arguments
+ if (v == NULL || n == NULL)
+ {
+ return true;
+ }
+
+ if (n->DisconnectNow)
+ {
+ goto DISCONNECT;
+ }
+
+ if (n->DnsThread == NULL && n->DnsFinished == false)
+ {
+ // Create a thread
+ THREAD *t = NewThread(NatDnsThread, (void *)n);
+ WaitThreadInit(t);
+ n->DnsThread = t;
+ }
+ else
+ {
+ // Wait for the result
+ if (n->DnsFinished)
+ {
+ // Results have been received
+ WaitThread(n->DnsThread, INFINITE);
+ ReleaseThread(n->DnsThread);
+ n->DnsThread = NULL;
+ // Notify to the main thread
+ v->NatDoCancelFlag = true;
+ }
+ }
+
+ return true;
+
+DISCONNECT:
+
+ // Releasing process
+ if (n->DnsThread != NULL)
+ {
+ WaitThread(n->DnsThread, INFINITE);
+ ReleaseThread(n->DnsThread);
+ n->DnsThread = NULL;
+ }
+
+ if (n->DnsTargetHostName != NULL)
+ {
+ Free(n->DnsTargetHostName);
+ n->DnsTargetHostName = NULL;
+ }
+
+ if (n->DnsResponseHostName != NULL)
+ {
+ Free(n->DnsResponseHostName);
+ n->DnsResponseHostName = NULL;
+ }
+
+ DeleteLock(n->lock);
+ Delete(v->NatTable, n);
+ Free(n);
+
+ return false;
+}
+
+// ICMP thread procedure
+void NatIcmpThreadProc(THREAD *thread, void *param)
+{
+ NAT_ENTRY *n;
+ ICMP_RESULT *ret = NULL;
+ USHORT src_id = 0, src_seqno = 0;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ n = (NAT_ENTRY *)param;
+
+ if (n->IcmpQueryBlock)
+ {
+ UCHAR *data = n->IcmpQueryBlock->Buf;
+ UINT size = n->IcmpQueryBlock->Size;
+
+ if (size >= (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO)))
+ {
+ ICMP_HEADER *icmp = (ICMP_HEADER *)data;
+ ICMP_ECHO *echo = (ICMP_ECHO *)(data + sizeof(ICMP_HEADER));
+
+ if (icmp->Type == ICMP_TYPE_ECHO_REQUEST && icmp->Code == 0)
+ {
+ UCHAR *icmp_payload = data + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO);
+ UINT icmp_payload_size = size - sizeof(ICMP_HEADER) - sizeof(ICMP_ECHO);
+ IP dest_ip;
+
+ src_id = Endian16(echo->Identifier);
+ src_seqno = Endian16(echo->SeqNo);
+
+ UINTToIP(&dest_ip, n->DestIp);
+
+ // Send a query by using the ICMP API
+ ret = IcmpApiEchoSend(&dest_ip, n->IcmpQueryBlock->Ttl,
+ icmp_payload, icmp_payload_size, NAT_ICMP_TIMEOUT_WITH_API);
+ }
+ }
+ }
+
+ if (ret != NULL && ret->Timeout == false)
+ {
+ // Convert to an IPv4 + ICMP packet since the result of ICMP API was obtained
+ IPV4_HEADER ipv4;
+ ICMP_HEADER icmp;
+ ICMP_ECHO echo;
+ BUF *buf = NewBuf();
+
+ // IPv4 header
+ Zero(&ipv4, sizeof(ipv4));
+ IPV4_SET_VERSION(&ipv4, 4);
+ IPV4_SET_HEADER_LEN(&ipv4, sizeof(IPV4_HEADER) / 4);
+ ipv4.TimeToLive = ret->Ttl;
+ ipv4.Protocol = IP_PROTO_ICMPV4;
+ ipv4.SrcIP = IPToUINT(&ret->IpAddress);
+ ipv4.DstIP = 0x01010101;
+
+
+ // ICMP header
+ Zero(&icmp, sizeof(icmp));
+ Zero(&echo, sizeof(echo));
+
+ if (ret->Ok)
+ {
+ // Normal response
+ echo.Identifier = Endian16(src_id);
+ echo.SeqNo = Endian16(src_seqno);
+
+ ipv4.TotalLength = Endian16((USHORT)(sizeof(ipv4) + sizeof(icmp) + sizeof(echo) + ret->DataSize));
+
+ WriteBuf(buf, &ipv4, sizeof(ipv4));
+ WriteBuf(buf, &icmp, sizeof(icmp));
+ WriteBuf(buf, &echo, sizeof(echo));
+ WriteBuf(buf, ret->Data, ret->DataSize);
+ }
+ else
+ {
+ // Error reply
+ icmp.Type = ret->Type;
+ icmp.Code = ret->Code;
+ echo.Identifier = Endian16(src_id);
+ echo.SeqNo = Endian16(src_seqno);
+
+ ipv4.TotalLength = Endian16((USHORT)(sizeof(ipv4) + sizeof(icmp) + sizeof(echo) + n->IcmpOriginalCopySize));
+
+ WriteBuf(buf, &ipv4, sizeof(ipv4));
+ WriteBuf(buf, &icmp, sizeof(icmp));
+ WriteBuf(buf, &echo, sizeof(echo));
+
+ // Copy of the original packet to be included in the response packet
+ WriteBuf(buf, n->IcmpOriginalCopy, n->IcmpOriginalCopySize);
+ }
+
+ n->IcmpResponseBlock = NewBlock(Clone(buf->Buf, buf->Size), buf->Size, 0);
+ n->IcmpResponseBlock->Ttl = ret->Ttl;
+
+ FreeBuf(buf);
+ }
+ IcmpApiFreeResult(ret);
+
+ // Inform the completion of the processing
+ n->IcmpTaskFinished = true;
+ SetSockEvent(n->v->SockEvent);
+}
+
+// Process ICMP entry
+bool NatTransactIcmp(VH *v, NAT_ENTRY *n)
+{
+ void *buf;
+ UINT recv_size;
+ BLOCK *block;
+ UINT dest_port = n->DestPort;
+ IP dest_ip;
+ UINT num_ignore_errors = 0;
+ // Validate arguments
+ if (v == NULL || n == NULL)
+ {
+ return true;
+ }
+
+ if (n->DisconnectNow)
+ {
+ goto DISCONNECT;
+ }
+
+ if (v->IcmpRawSocketOk)
+ {
+ // Environment that the Raw sockets are available
+ if (n->UdpSocketCreated == false)
+ {
+ // Create a UDP socket
+ n->Sock = NewUDP(MAKE_SPECIAL_PORT(IP_PROTO_ICMPV4));
+ if (n->Sock == NULL)
+ {
+ // Socket creation failure
+ goto DISCONNECT;
+ }
+ else
+ {
+ n->PublicIp = IPToUINT(&n->Sock->LocalIP);
+ n->PublicPort = n->Sock->LocalPort;
+
+ JoinSockToSockEvent(n->Sock, v->SockEvent);
+ n->UdpSocketCreated = true;
+ }
+ }
+ }
+ else
+ {
+ // Create a thread for using ICMP API if Raw sockets are not available
+ if (n->IcmpThread == NULL)
+ {
+ if (n->UdpSendQueue->num_item >= 1)
+ {
+ // Since UdpSendQueue contains only 1 query, get a first query
+ // and create a thread and pass the query to the thread
+ BLOCK *block = GetNext(n->UdpSendQueue);
+
+ n->IcmpQueryBlock = block;
+
+ n->IcmpThread = NewThread(NatIcmpThreadProc, n);
+ }
+ }
+
+ if (n->IcmpTaskFinished)
+ {
+ if (n->IcmpResponseBlock != NULL)
+ {
+ // Because there was a response from the thread that calls ICMP API, pass this result to the stack
+ block = n->IcmpResponseBlock;
+ n->IcmpResponseBlock = NULL;
+ InsertQueue(n->UdpRecvQueue, block);
+ v->NatDoCancelFlag = true;
+ n->LastCommTime = v->Now;
+ }
+ else
+ {
+ // Disconnect immediately when it fails
+ goto DISCONNECT;
+ }
+ }
+
+ // Examine whether this session timed-out
+ if ((n->LastCommTime + (UINT64)NAT_ICMP_TIMEOUT_WITH_API) < v->Now || n->LastCommTime > v->Now)
+ {
+ // Time-out
+ goto DISCONNECT;
+ }
+
+ return true;
+ }
+
+ // Following are processed only for if the raw sockets are available
+ buf = v->TmpBuf;
+ UINTToIP(&dest_ip, n->DestIp);
+
+ // Try to receive data from the UDP socket
+ while (true)
+ {
+ IP src_ip;
+ UINT src_port;
+ recv_size = RecvFrom(n->Sock, &src_ip, &src_port, buf, 65536);
+
+ if (recv_size == SOCK_LATER)
+ {
+ // Packet has not arrived
+ break;
+ }
+ else if (recv_size == 0)
+ {
+ Debug("ICMP ERROR\n");
+ // Error?
+ if (n->Sock->IgnoreRecvErr == false)
+ {
+ // A fatal error occurred
+ goto DISCONNECT;
+ }
+ else
+ {
+ if ((num_ignore_errors++) >= MAX_NUM_IGNORE_ERRORS)
+ {
+ goto DISCONNECT;
+ }
+ }
+ }
+ else
+ {
+ // Analyze the arriving packet
+ ICMP_RESULT *ret = IcmpParseResult(&dest_ip, n->SrcPort, 0, buf, recv_size);
+
+ if (ret != NULL)
+ {
+ if ((ret->Ok && CmpIpAddr(&ret->IpAddress, &dest_ip) == 0) ||
+ (ret->DataSize >= sizeof(IPV4_HEADER) && ((IPV4_HEADER *)ret->Data)->DstIP == n->DestIp))
+ {
+ // Insert to the queue
+ void *data = Malloc(recv_size);
+ Copy(data, buf, recv_size);
+ block = NewBlock(data, recv_size, 0);
+ InsertQueue(n->UdpRecvQueue, block);
+ v->NatDoCancelFlag = true;
+ n->LastCommTime = v->Now;
+ }
+
+ IcmpFreeResult(ret);
+ }
+ }
+ }
+
+ // Try to send data to the UDP socket
+ while (block = GetNext(n->UdpSendQueue))
+ {
+ // Assemble the Echo header and ICMP header
+ UINT send_size;
+
+ SetTtl(n->Sock, block->Ttl);
+ send_size = SendTo(n->Sock, &dest_ip, dest_port, block->Buf, block->Size);
+
+ FreeBlock(block);
+ if (send_size == 0)
+ {
+ Debug("ICMP ERROR\n");
+ // Determine whether a fatal error
+ if (n->Sock->IgnoreSendErr == false)
+ {
+ // A fatal error occurred
+ goto DISCONNECT;
+ }
+ }
+ else
+ {
+ n->LastCommTime = v->Now;
+ }
+ }
+
+ // Examine whether this session timed-out
+ if ((n->LastCommTime + (UINT64)NAT_ICMP_TIMEOUT) < v->Now || n->LastCommTime > v->Now)
+ {
+ // Time-out
+ goto DISCONNECT;
+ }
+
+ return true;
+
+DISCONNECT:
+ // Disconnect this session
+ if (n->UdpSocketCreated)
+ {
+ // Close the socket
+ Disconnect(n->Sock);
+ ReleaseSock(n->Sock);
+ n->Sock = NULL;
+ }
+
+ // Terminate if the thread has been created
+ if (n->IcmpThread != NULL)
+ {
+ WaitThread(n->IcmpThread, INFINITE);
+ ReleaseThread(n->IcmpThread);
+ n->IcmpThread = NULL;
+ }
+
+ // Delete the entry
+ DeleteNatIcmp(v, n);
+
+ return false;
+}
+
+// Process the UDP entry
+bool NatTransactUdp(VH *v, NAT_ENTRY *n)
+{
+ void *buf;
+ UINT recv_size;
+ BLOCK *block;
+ UINT dest_port = n->DestPort;
+ IP dest_ip;
+ UINT num_ignore_errors;
+ // Validate arguments
+ if (v == NULL || n == NULL)
+ {
+ return true;
+ }
+
+ if (n->DisconnectNow)
+ {
+ goto DISCONNECT;
+ }
+
+ if (n->UdpSocketCreated == false)
+ {
+ // Create a UDP socket
+ n->Sock = NewUDP(0);
+ if (n->Sock == NULL)
+ {
+ // Socket creation failure
+ goto DISCONNECT;
+ }
+ else
+ {
+ n->PublicIp = IPToUINT(&n->Sock->LocalIP);
+ n->PublicPort = n->Sock->LocalPort;
+
+ JoinSockToSockEvent(n->Sock, v->SockEvent);
+ n->UdpSocketCreated = true;
+ }
+ }
+
+ buf = v->TmpBuf;
+ if (n->ProxyDns == false)
+ {
+ UINTToIP(&dest_ip, n->DestIp);
+ }
+ else
+ {
+ UINTToIP(&dest_ip, n->DestIpProxy);
+ }
+
+ num_ignore_errors = 0;
+
+ // Try to receive data from the UDP socket
+ while (true)
+ {
+ IP src_ip;
+ UINT src_port;
+ recv_size = RecvFrom(n->Sock, &src_ip, &src_port, buf, 65536);
+
+ if (recv_size == SOCK_LATER)
+ {
+ // Packet has not arrived
+ break;
+ }
+ else if (recv_size == 0)
+ {
+ // Error?
+ if (n->Sock->IgnoreRecvErr == false)
+ {
+ // A fatal error occurred
+ goto DISCONNECT;
+ }
+ else
+ {
+ if ((num_ignore_errors++) > MAX_NUM_IGNORE_ERRORS)
+ {
+ goto DISCONNECT;
+ }
+ }
+ }
+ else
+ {
+ // Packet arrives. Check the source IP
+ if (IPToUINT(&src_ip) == n->DestIp || n->DestIp == 0xFFFFFFFF || (IPToUINT(&src_ip) == n->DestIpProxy && n->ProxyDns) && src_port == n->DestPort)
+ {
+ // Insert to the queue
+ void *data = Malloc(recv_size);
+ Copy(data, buf, recv_size);
+ block = NewBlock(data, recv_size, 0);
+
+ if (block != NULL)
+ {
+ if (src_port == SPECIAL_UDP_PORT_WSD || src_port == SPECIAL_UDP_PORT_SSDP)
+ {
+ // Make believe there is a response from the host really in the case of WSD packet
+ block->Param1 = IPToUINT(&src_ip);
+ }
+ }
+
+ InsertQueue(n->UdpRecvQueue, block);
+ v->NatDoCancelFlag = true;
+ n->LastCommTime = v->Now;
+ }
+ }
+ }
+
+ // Try to send data to the UDP socket
+ while (block = GetNext(n->UdpSendQueue))
+ {
+ UINT send_size;
+ bool is_nbtdgm = false;
+ LIST *local_ip_list = NULL;
+
+ if (dest_port == SPECIAL_UDP_PORT_NBTDGM)
+ {
+ // Determine whether NetBIOS Datagram packet
+ NBTDG_HEADER *nh = (NBTDG_HEADER *)block->Buf;
+
+ if (nh != NULL && block->Size >= sizeof(NBTDG_HEADER))
+ {
+ if (nh->SrcIP == n->SrcIp && Endian16(nh->SrcPort) == n->SrcPort)
+ {
+ local_ip_list = GetHostIPAddressList();
+
+ if (local_ip_list != NULL)
+ {
+ is_nbtdgm = true;
+ }
+ }
+ }
+ }
+
+ if (is_nbtdgm == false)
+ {
+ // Normal UDP packet
+ send_size = SendTo(n->Sock, &dest_ip, dest_port, block->Buf, block->Size);
+ }
+ else
+ {
+ // IP address and port number is embedded in the NetBIOS Datagram Packet.
+ // Transfer by rewriting it properly
+ UINT i;
+
+ for (i = 0;i < LIST_NUM(local_ip_list);i++)
+ {
+ IP *my_ip = LIST_DATA(local_ip_list, i);
+
+ if (IsIP4(my_ip) && IsZeroIp(my_ip) == false && IsLocalHostIP(my_ip) == false)
+ {
+ NBTDG_HEADER *nh = (NBTDG_HEADER *)block->Buf;
+
+ nh->SrcIP = IPToUINT(my_ip);
+ nh->SrcPort = Endian16(n->PublicPort);
+
+ send_size = SendTo(n->Sock, &dest_ip, dest_port, block->Buf, block->Size);
+ }
+ }
+ }
+
+ if (local_ip_list != NULL)
+ {
+ FreeHostIPAddressList(local_ip_list);
+ }
+
+ FreeBlock(block);
+ if (send_size == 0)
+ {
+ // Determining whether a fatal error
+ if (n->Sock->IgnoreSendErr == false)
+ {
+ // A fatal error occurred
+ goto DISCONNECT;
+ }
+ }
+ else
+ {
+ n->LastCommTime = v->Now;
+ }
+ }
+
+ // Examine whether this session timed-out
+ if ((n->LastCommTime + (UINT64)v->NatUdpTimeout) < v->Now || n->LastCommTime > v->Now)
+ {
+ // Time-out
+ goto DISCONNECT;
+ }
+
+ return true;
+
+DISCONNECT:
+ // Disconnect this session
+ if (n->UdpSocketCreated)
+ {
+ // Close the socket
+ Disconnect(n->Sock);
+ ReleaseSock(n->Sock);
+ n->Sock = NULL;
+ }
+
+ // Delete the entry
+ DeleteNatUdp(v, n);
+
+ return false;
+}
+
+// Thread to make a connection to the TCP host
+void NatTcpConnectThread(THREAD *t, void *p)
+{
+ NAT_ENTRY *n = (NAT_ENTRY *)p;
+ IP ip;
+ char hostname[MAX_SIZE];
+ UINT port_number;
+ SOCK *sock;
+ SOCK_EVENT *e;
+ // Validate arguments
+ if (n == NULL || t == NULL)
+ {
+ return;
+ }
+
+ UINTToIP(&ip, n->DestIp);
+ IPToStr(hostname, sizeof(hostname), &ip);
+ port_number = n->DestPort;
+ e = n->v->SockEvent;
+ AddRef(e->ref);
+
+ // Notify the initialization completion
+ NoticeThreadInit(t);
+
+ // Attempt to connect to the TCP host
+ Debug("NatTcpConnect Connecting to %s:%u\n", hostname, port_number);
+ sock = ConnectEx3(hostname, port_number, 0, &n->NatTcpCancelFlag, NULL, NULL, false, false, true);
+ if (sock == NULL)
+ {
+ // Connection failure
+ n->TcpMakeConnectionFailed = true;
+ }
+ else
+ {
+ // Successful connection
+ n->TcpMakeConnectionSucceed = true;
+ }
+ n->Sock = sock;
+ JoinSockToSockEvent(sock, e);
+ SetSockEvent(e);
+
+ ReleaseSockEvent(e);
+}
+
+// Create a thread for trying to connect to the TCP host
+void CreateNatTcpConnectThread(VH *v, NAT_ENTRY *n)
+{
+ // Validate arguments
+ if (v == NULL || n == NULL)
+ {
+ return;
+ }
+
+ // Create a thread
+ n->NatTcpConnectThread = NewThread(NatTcpConnectThread, (void *)n);
+
+ // Wait for a thread initialization completion
+ WaitThreadInit(n->NatTcpConnectThread);
+}
+
+// Handle the TCP entry
+bool NatTransactTcp(VH *v, NAT_ENTRY *n)
+{
+ char str[MAX_SIZE];
+ bool timeouted = false;
+ // Validate arguments
+ if (v == NULL || n == NULL)
+ {
+ return false;
+ }
+
+ if (n->DisconnectNow)
+ {
+ goto DISCONNECT;
+ }
+
+ // Process by state of the TCP
+ switch (n->TcpStatus)
+ {
+ case NAT_TCP_CONNECTING: // Waiting for connection
+ if (n->NatTcpConnectThread == NULL)
+ {
+ // Start a connection by creating a connection thread
+ CreateNatTcpConnectThread(v, n);
+ }
+ else
+ {
+ // Wait for the result of the connection thread that has already started
+ if (n->TcpMakeConnectionFailed || n->TcpMakeConnectionSucceed)
+ {
+ // Use the results because operation thread has already finished
+ WaitThread(n->NatTcpConnectThread, INFINITE);
+ ReleaseThread(n->NatTcpConnectThread);
+ n->NatTcpConnectThread = NULL;
+
+ if (n->TcpMakeConnectionSucceed)
+ {
+ // Connection is successful, and a Sock was created
+ n->TcpStatus = NAT_TCP_CONNECTED;
+ IPToStr32(str, sizeof(str), n->DestIp);
+ NLog(v, "LH_NAT_TCP_SUCCEED", n->Id, n->Sock->RemoteHostname, str, n->DestPort);
+ }
+ else
+ {
+ // Failed to connect
+ n->TcpStatus = NAT_TCP_SEND_RESET;
+ IPToStr32(str, sizeof(str), n->DestIp);
+ NLog(v, "LH_NAT_TCP_FAILED", n->Id, str, n->DestPort);
+ }
+ v->NatDoCancelFlag = true;
+ }
+ }
+ break;
+
+ case NAT_TCP_CONNECTED: // TCP socket connection completed. Negotiating with the client host
+ break;
+
+ case NAT_TCP_SEND_RESET: // TCP communication disconnection: Send a RST to the client host
+ break;
+
+ case NAT_TCP_ESTABLISHED: // TCP connection established
+ {
+ UINT old_send_fifo_size = 0;
+
+ // Transmit to the socket if there is data in the receive buffer
+ while (n->RecvFifo->size > 0)
+ {
+ UINT sent_size = Send(n->Sock, ((UCHAR *)n->RecvFifo->p) + n->RecvFifo->pos,
+ n->RecvFifo->size, false);
+ if (sent_size == 0)
+ {
+ // Communication has been disconnected
+ n->TcpFinished = true;
+ v->NatDoCancelFlag = true;
+ break;
+ }
+ else if (sent_size == SOCK_LATER)
+ {
+ // Blocking
+ break;
+ }
+ else
+ {
+ // Successful transmission
+ ReadFifo(n->RecvFifo, NULL, sent_size);
+ n->SendAckNext = true;
+ }
+ }
+
+ old_send_fifo_size = FifoSize(n->SendFifo);
+
+ // Write to the transmission buffer by obtaining data from the socket
+ while (true)
+ {
+ void *buf = (void *)v->TmpBuf;
+ UINT want_to_recv_size = 0;
+ UINT recv_size;
+ // Calculate the size of wanting to receive
+ if (n->SendFifo->size < NAT_SEND_BUF_SIZE)
+ {
+ // Still can receive
+ want_to_recv_size = MIN(NAT_SEND_BUF_SIZE - n->SendFifo->size, NAT_TMPBUF_SIZE);
+ }
+ if (want_to_recv_size == 0)
+ {
+ SetNoNeedToRead(n->Sock);
+ break;
+ }
+ recv_size = Recv(n->Sock, buf, want_to_recv_size, false);
+ if (recv_size == 0)
+ {
+ // Communication has been disconnected
+ n->TcpFinished = true;
+ v->NatDoCancelFlag = true;
+ break;
+ }
+ else if (recv_size == SOCK_LATER)
+ {
+ // Blocking
+ break;
+ }
+ else
+ {
+ // Successful reception
+ WriteFifo(n->SendFifo, buf, recv_size);
+ v->NatDoCancelFlag = true;
+ }
+ }
+
+ if (old_send_fifo_size == 0 && FifoSize(n->SendFifo) != 0)
+ {
+ // Reset the time data for timeout when the data is newly queued
+ // in the empty transmission buffer in the transmission process
+ n->TcpLastRecvAckTime = v->Now;
+ }
+
+ // Raise a transmission time-out if a certain period of time elapsed
+ // after receiving the last ACK, and the transmission buffer is not
+ // empty, and the reception window size of other party is not 0
+ if ((n->TcpLastRecvAckTime + (UINT64)VIRTUAL_TCP_SEND_TIMEOUT) < v->Now)
+ {
+ if (FifoSize(n->SendFifo) != 0 && n->TcpSendWindowSize != 0)
+ {
+ timeouted = true;
+ }
+ }
+ }
+ break;
+
+ }
+
+ // Timeout Detection
+ if ((n->LastCommTime + (UINT64)v->NatTcpTimeout) < v->Now || n->LastCommTime > v->Now)
+ {
+ timeouted = true;
+ }
+
+ if (timeouted)
+ {
+ // Time-out occurs, the session close
+ n->TcpStatus = NAT_TCP_SEND_RESET;
+ v->NatDoCancelFlag = true;
+ }
+
+ return true;
+
+DISCONNECT: // Disconnect and session disposal
+ DeleteNatTcp(v, n);
+
+ return false;
+}
+
+// Delete the entry of TCP NAT
+void DeleteNatTcp(VH *v, NAT_ENTRY *n)
+{
+ // Validate arguments
+ if (v == NULL || n == NULL)
+ {
+ return;
+ }
+
+ NLog(v, "LH_NAT_TCP_DELETED", n->Id);
+
+ // Shutdown of connection thread
+ if (n->NatTcpConnectThread != NULL)
+ {
+ n->NatTcpCancelFlag = true;
+
+ WaitThread(n->NatTcpConnectThread, INFINITE);
+ ReleaseThread(n->NatTcpConnectThread);
+ n->NatTcpConnectThread = NULL;
+ }
+ if (n->Sock != NULL)
+ {
+ // Disconnect the socket
+ Disconnect(n->Sock);
+ ReleaseSock(n->Sock);
+ n->Sock = NULL;
+ }
+
+ // Release the window memory
+ if (n->TcpRecvWindow != NULL)
+ {
+ ReleaseFifo(n->TcpRecvWindow);
+ n->TcpRecvWindow = NULL;
+ }
+
+ // Release the window reception list
+ if (n->TcpRecvList != NULL)
+ {
+ UINT i;
+ for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
+ {
+ IP_PART *p = LIST_DATA(n->TcpRecvList, i);
+ Free(p);
+ }
+ ReleaseList(n->TcpRecvList);
+ n->TcpRecvList = NULL;
+ }
+
+ // FIFO release
+ ReleaseFifo(n->SendFifo);
+ ReleaseFifo(n->RecvFifo);
+
+ // Delete from the NAT entry
+ Delete(v->NatTable, n);
+
+ DeleteLock(n->lock);
+
+ // Release the memory
+ Free(n);
+
+ Debug("NAT_ENTRY: DeleteNatTcp\n");
+}
+
+// NAT processing thread
+void NatThread(THREAD *t, void *param)
+{
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Notify the initialization completion
+ NoticeThreadInit(t);
+
+ NatThreadMain((VH *)param);
+}
+
+// Send a beacon packet
+void SendBeacon(VH *v)
+{
+ UINT dest_ip;
+ ARPV4_HEADER arp;
+ static char beacon_str[] =
+ "SecureNAT Virtual TCP/IP Stack Beacon";
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ // Send an UDP
+ dest_ip = (v->HostIP & v->HostMask) | (~v->HostMask);
+ SendUdp(v, dest_ip, 7, v->HostIP, 7, beacon_str, sizeof(beacon_str));
+
+ // Build the ARP header
+ arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+ arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
+ arp.HardwareSize = 6;
+ arp.ProtocolSize = 4;
+ arp.Operation = Endian16(ARP_OPERATION_RESPONSE);
+ Copy(arp.SrcAddress, v->MacAddress, 6);
+ arp.SrcIP = v->HostIP;
+ arp.TargetAddress[0] =
+ arp.TargetAddress[1] =
+ arp.TargetAddress[2] =
+ arp.TargetAddress[3] =
+ arp.TargetAddress[4] =
+ arp.TargetAddress[5] = 0xff;
+ arp.TargetIP = dest_ip;
+
+ // Transmission
+ VirtualLayer2Send(v, broadcast, v->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
+}
+
+// Send a TCP packet
+void SendTcp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT seq, UINT ack, UINT flag, UINT window_size, UINT mss, void *data, UINT size)
+{
+ static UCHAR tcp_mss_option[] = {0x02, 0x04, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00};
+ IPV4_PSEUDO_HEADER *vh;
+ TCP_HEADER *tcp;
+ UINT header_size = TCP_HEADER_SIZE;
+ UINT total_size;
+ // Validate arguments
+ if (v == NULL || (size != 0 && data == NULL))
+ {
+ return;
+ }
+
+ // Memory allocation
+ vh = Malloc(sizeof(IPV4_PSEUDO_HEADER) + TCP_HEADER_SIZE + size + 32);
+ tcp = (TCP_HEADER *)(((UCHAR *)vh) + sizeof(IPV4_PSEUDO_HEADER));
+
+ if (mss != 0)
+ {
+ USHORT *mss_size;
+ mss_size = (USHORT *)(&tcp_mss_option[2]);
+ *mss_size = Endian16((USHORT)mss);
+ header_size += sizeof(tcp_mss_option);
+ }
+
+ total_size = header_size + size;
+ if (total_size > 65536)
+ {
+ // Packet is too long
+ Free(vh);
+ return;
+ }
+
+ // Pseudo header generation
+ vh->SrcIP = src_ip;
+ vh->DstIP = dest_ip;
+ vh->Reserved = 0;
+ vh->Protocol = IP_PROTO_TCP;
+ vh->PacketLength = Endian16((USHORT)total_size);
+
+ // TCP header generation
+ tcp->SrcPort = Endian16((USHORT)src_port);
+ tcp->DstPort = Endian16((USHORT)dest_port);
+ tcp->SeqNumber = Endian32(seq);
+ tcp->AckNumber = Endian32(ack);
+ tcp->HeaderSizeAndReserved = 0;
+ TCP_SET_HEADER_SIZE(tcp, (UCHAR)(header_size / 4));
+ tcp->Flag = (UCHAR)flag;
+ tcp->WindowSize = Endian16((USHORT)window_size);
+ tcp->Checksum = 0;
+ tcp->UrgentPointer = 0;
+
+ // Copy the option values
+ if (mss != 0)
+ {
+ Copy(((UCHAR *)tcp) + TCP_HEADER_SIZE, tcp_mss_option, sizeof(tcp_mss_option));
+ }
+
+ // Data copy
+ Copy(((UCHAR *)tcp) + header_size, data, size);
+
+ // Checksum calculation
+ tcp->Checksum = IpChecksum(vh, total_size + 12);
+
+ // Submit as an IP packet
+ SendIp(v, dest_ip, src_ip, IP_PROTO_TCP, tcp, total_size);
+
+ // Release the memory
+ Free(vh);
+}
+
+// Polling process of TCP
+void PollingNatTcp(VH *v, NAT_ENTRY *n)
+{
+ // Validate arguments
+ if (v == NULL || n == NULL)
+ {
+ return;
+ }
+
+ switch (n->TcpStatus)
+ {
+ case NAT_TCP_CONNECTING: // Socket connecting: nothing to do
+ break;
+
+ case NAT_TCP_CONNECTED: // The socket connected: process SYN + ACK, ACK
+ if ((n->LastSynAckSentTime > v->Now) || n->LastSynAckSentTime == 0 || ((n->LastSynAckSentTime + (UINT64)(NAT_TCP_SYNACK_SEND_TIMEOUT * (UINT64)(n->SynAckSentCount + 1)) <= v->Now)))
+ {
+ n->LastSynAckSentTime = v->Now;
+ // Send a SYN + ACK
+ SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
+ (UINT)(n->SendSeqInit + n->SendSeq),
+ (UINT)(n->RecvSeqInit + n->RecvSeq),
+ TCP_SYN | TCP_ACK, n->TcpRecvWindowSize,
+ v->TcpMss, NULL, 0);
+ n->SynAckSentCount++;
+ }
+ break;
+
+ case NAT_TCP_SEND_RESET: // Reset the connection
+ // Send a RST
+ if (n->TcpFinished == false)
+ {
+ SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
+ (UINT)(n->SendSeq + n->SendSeqInit),
+ (UINT)(n->SendSeq + n->SendSeqInit),
+ TCP_RST, 0,
+ 0, NULL, 0);
+ // Disconnect
+ n->TcpStatus = NAT_TCP_WAIT_DISCONNECT;
+ n->DisconnectNow = true;
+ }
+ else
+ {
+ // Send FINs for NAT_FIN_SEND_MAX_COUNT times
+ if (n->FinSentTime == 0 || (n->FinSentTime > v->Now) || (n->FinSentTime + NAT_FIN_SEND_INTERVAL * (n->FinSentCount + 1)) < v->Now)
+ {
+ SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
+ (UINT)(n->SendSeq + n->SendSeqInit),
+ (UINT)(n->RecvSeq + n->RecvSeqInit),
+ TCP_ACK | TCP_FIN, 0,
+ 0, NULL, 0);
+ n->FinSentTime = v->Now;
+ n->FinSentCount++;
+ if (n->FinSentCount >= NAT_FIN_SEND_MAX_COUNT)
+ {
+ n->TcpFinished = false;
+ }
+ }
+ }
+ break;
+
+ case NAT_TCP_ESTABLISHED: // Connection established
+ {
+ UINT send_data_size;
+ UINT current_pointer;
+ UINT notice_window_size_value = 0;
+ UINT buf_free_bytes = 0;
+ // Determine the value of the window size to be notified
+ if (FifoSize(n->RecvFifo) < NAT_RECV_BUF_SIZE)
+ {
+ buf_free_bytes = NAT_RECV_BUF_SIZE - FifoSize(n->RecvFifo);
+ }
+ notice_window_size_value = MIN(n->TcpRecvWindowSize, buf_free_bytes);
+ if (n->LastSentKeepAliveTime == 0 ||
+ (n->LastSentKeepAliveTime + (UINT64)NAT_ACK_KEEPALIVE_SPAN) < v->Now ||
+ (n->LastSentKeepAliveTime > v->Now))
+ {
+ if (n->LastSentKeepAliveTime != 0)
+ {
+ // Send an ACK packet for Keep-Alive
+ SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
+ (UINT)(n->SendSeqInit + n->SendSeq),
+ (UINT)(n->RecvSeqInit + n->RecvSeq) - 1,
+ TCP_ACK,
+ notice_window_size_value,
+ 0,
+ NULL,
+ 0);
+ }
+ n->LastSentKeepAliveTime = v->Now;
+ }
+ if (n->TcpLastSentTime == 0 ||
+ (n->TcpLastSentTime > v->Now) ||
+ ((n->TcpLastSentTime + (UINT64)n->TcpSendTimeoutSpan) < v->Now) ||
+ n->SendAckNext)
+ {
+ // If there is data to send, send the data
+ // Calculate the segment size to be transmitted
+ send_data_size = n->TcpSendWindowSize;
+ if (send_data_size > (n->TcpSendCWnd * n->TcpSendMaxSegmentSize))
+ {
+ // Apply the cwnd value
+ send_data_size = n->TcpSendCWnd * n->TcpSendMaxSegmentSize;
+ }
+ if (send_data_size > n->SendFifo->size)
+ {
+ // Can not be sent over the data that is currently held
+ send_data_size = n->SendFifo->size;
+ }
+ if (send_data_size >= 1)
+ {
+ // Transmit the fragmented segments
+ current_pointer = 0;
+ while (send_data_size > 0)
+ {
+ UINT send_segment_size = MIN(n->TcpSendMaxSegmentSize, send_data_size);
+ void *send_segment = (void *)(((UCHAR *)n->SendFifo->p) + n->SendFifo->pos + current_pointer);
+ SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
+ (UINT)(n->SendSeqInit + n->SendSeq + (UINT64)current_pointer),
+ (UINT)(n->RecvSeqInit + n->RecvSeq),
+ TCP_ACK | TCP_PSH,
+ notice_window_size_value,
+ 0,
+ send_segment,
+ send_segment_size);
+ current_pointer += send_segment_size;
+ send_data_size -= send_segment_size;
+ }
+ // Record the transmission time
+ n->TcpLastSentTime = v->Now;
+ // Record the stream size to be transmitted this time
+ n->SendMissionSize = current_pointer;
+ n->CurrentSendingMission = true;
+ // RTT measurement
+ if (n->CalcRTTStartTime == 0)
+ {
+ n->CalcRTTStartTime = v->Now;
+ n->CalcRTTStartValue = n->SendSeq + current_pointer - 1;
+ }
+ if (n->RetransmissionUsedFlag == false)
+ {
+ n->RetransmissionUsedFlag = true;
+ }
+ else
+ {
+ // Congestion is detected
+ if (n->TcpSendCWnd > 2)
+ {
+ n->TcpSendCWnd--;
+ }
+ }
+ }
+ else if (n->SendAckNext)
+ {
+ // Send only an ACK
+ SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
+ (UINT)(n->SendSeqInit + n->SendSeq),
+ (UINT)(n->RecvSeqInit + n->RecvSeq),
+ TCP_ACK,
+ notice_window_size_value,
+ 0,
+ NULL,
+ 0);
+ }
+ n->SendAckNext = false;
+ }
+ if (n->TcpFinished)
+ {
+ // Disconnect if all data transmission has completed
+ if (n->SendFifo->size == 0)
+ {
+ n->TcpStatus = NAT_TCP_SEND_RESET;
+ }
+ }
+ }
+ break;
+ }
+}
+
+// Reception of TCP packets addressed to the Internet
+void TcpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, TCP_HEADER *tcp, void *data, UINT size, UINT max_l3_size)
+{
+ NAT_ENTRY *n, t;
+ UINT seq, ack;
+ UINT64 seq64 = 0, ack64 = 0;
+ // Validate arguments
+ if (v == NULL || tcp == NULL || data == NULL)
+ {
+ return;
+ }
+
+ if (NnIsActive(v))
+ {
+ NnTcpRecvForInternet(v, src_ip, src_port, dest_ip, dest_port, tcp, data, size, max_l3_size);
+ return;
+ }
+
+ seq = Endian32(tcp->SeqNumber);
+ ack = Endian32(tcp->AckNumber);
+
+ if (v->HubOption != NULL && v->HubOption->DisableUserModeSecureNAT)
+ {
+ // Disable User-mode NAT
+ SendTcp(v, dest_ip, dest_port, src_ip, src_port,
+ 0, seq + 1, TCP_RST | TCP_ACK, 0, 0, NULL, 0);
+ return;
+ }
+
+ // Search for a session for this packet from the NAT table
+ SetNat(&t, NAT_TCP, src_ip, src_port, dest_ip, dest_port, 0, 0);
+ n = SearchNat(v, &t);
+
+ if (n == NULL)
+ {
+ // There is no existing session
+ // Allow through only SYN packet
+ if ((tcp->Flag & TCP_SYN) && ((tcp->Flag & TCP_ACK) == false))
+ {
+ TCP_OPTION o;
+ // Create a new session
+ n = CreateNatTcp(v, src_ip, src_port, dest_ip, dest_port);
+ if (n == NULL)
+ {
+ // Return the RST if it was not possible to create
+ SendTcp(v, dest_ip, dest_port, src_ip, src_port,
+ 0, seq + 1, TCP_RST | TCP_ACK, 0, 0, NULL, 0);
+ return;
+ }
+
+ // Get the options
+ ParseTcpOption(&o, ((UCHAR *)tcp) + TCP_HEADER_SIZE, TCP_GET_HEADER_SIZE(tcp) * 4 - TCP_HEADER_SIZE);
+ if (o.MaxSegmentSize == 0)
+ {
+ o.MaxSegmentSize = v->TcpMss;
+ }
+
+ Debug("TCP SYN: MSS=%u, WS=%u\n", o.MaxSegmentSize, o.WindowScaling);
+
+ // Initial sequence number
+ n->RecvSeqInit = (UINT64)Endian32(tcp->SeqNumber);
+ n->RecvSeq = 1;
+
+ n->TcpSendMaxSegmentSize = o.MaxSegmentSize;
+ n->TcpRecvWindowSize = NAT_TCP_RECV_WINDOW_SIZE;
+ n->TcpSendWindowSize = (UINT)Endian16(tcp->WindowSize);
+ if (o.WindowScaling != 0)
+ {
+ if (o.WindowScaling > 14)
+ {
+ o.WindowScaling = 14;
+ }
+ n->TcpSendWindowSize = (n->TcpSendWindowSize << o.WindowScaling);
+ }
+ }
+ }
+
+ if (n == NULL)
+ {
+ // Return a RST since a packet which is not registered in the NAT entry arrived
+ SendTcp(v, dest_ip, dest_port, src_ip, src_port,
+ ack, ack, TCP_RST, 0, 0, NULL, 0);
+ return;
+ }
+
+ n->TcpLastRecvAckTime = v->Now;
+
+ switch (n->TcpStatus)
+ {
+ case NAT_TCP_SEND_RESET: // Disconnect the connection by sending a RST
+ break;
+
+ case NAT_TCP_CONNECTED: // Socket connection completion: SYN + ACK, ACK processing
+ if ((tcp->Flag & TCP_ACK) && ((tcp->Flag & TCP_SYN) == false))
+ {
+ if (seq == (UINT)(n->RecvSeqInit + n->RecvSeq) &&
+ ack == (UINT)(n->SendSeqInit + n->SendSeq + 1))
+ {
+ // Handshake complete since the ACK packet came back
+ n->SendSeq++; // SYN packet consumes the seq by 1
+ Debug("TCP Connection Established.\n");
+ n->TcpStatus = NAT_TCP_ESTABLISHED;
+ // Initialize the congestion window size
+ n->TcpSendCWnd = 1;
+ n->LastCommTime = v->Now;
+ }
+ else
+ {
+ goto TCP_RESET;
+ }
+ }
+ else if (tcp->Flag & TCP_RST)
+ {
+TCP_RESET:
+ // Receive a RST
+ Debug("TCP Connection Reseted.\n");
+ n->TcpStatus = NAT_TCP_SEND_RESET;
+ }
+ break;
+
+ case NAT_TCP_ESTABLISHED: // Connection established
+ if (tcp->Flag & TCP_FIN)
+ {
+ // Complete the connection
+ n->TcpFinished = true;
+ }
+ if (tcp->Flag & TCP_RST)
+ {
+ // Receive a RST
+ goto TCP_RESET;
+ }
+ else if (tcp->Flag & TCP_ACK)
+ {
+ TCP_OPTION opt;
+ n->LastCommTime = v->Now;
+ // Get the options, such as window size
+ n->TcpSendWindowSize = Endian16(tcp->WindowSize);
+ ParseTcpOption(&opt, ((UCHAR *)tcp) + TCP_HEADER_SIZE, TCP_GET_HEADER_SIZE(tcp) * 4 - TCP_HEADER_SIZE);
+ if (opt.WindowScaling != 0)
+ {
+ if (opt.WindowScaling > 14)
+ {
+ opt.WindowScaling = 14;
+ }
+ n->TcpSendWindowSize = (n->TcpSendWindowSize << opt.WindowScaling);
+ }
+ // First, process the received ACK
+ // Store the end position of the stream that has received the acknowledgment to ack64
+ ack64 = n->SendSeq + (UINT64)ack - (n->SendSeqInit + n->SendSeq) % X32;
+ if ((n->SendSeqInit + n->SendSeq) % X32 > ack)
+ {
+ if (((n->SendSeqInit + n->SendSeq) % X32 - ack) >= 0x80000000)
+ {
+ ack64 = n->SendSeq + (UINT64)ack + X32 - (n->SendSeqInit + n->SendSeq) % X32;
+ }
+ }
+ if (ack64 > n->SendSeq)
+ {
+ // Reception of 1 byte or more seems to have been completed by the client
+ UINT slide_offset = (UINT)(ack64 - n->SendSeq); // Sliding size of the window
+ if (slide_offset == 0 || slide_offset > n->TcpSendWindowSize || slide_offset > n->SendFifo->size)
+ {
+ // Ignore because the offset value of acknowledgment is
+ // larger than the size that should have been sent so far
+ }
+ else
+ {
+ // RTT measurement
+ if (n->CalcRTTStartTime != 0)
+ {
+ if (n->CalcRTTStartValue < ack64)
+ {
+ UINT time_span;
+ if (v->Now > n->CalcRTTStartTime)
+ {
+ time_span = (UINT)(v->Now - n->CalcRTTStartTime);
+ }
+ else
+ {
+ time_span = 100;
+ }
+ n->CalcRTTStartTime = 0;
+
+ // Smoothing
+ n->CurrentRTT =
+ (UINT)
+ (
+ ((UINT64)n->CurrentRTT * (UINT64)9 +
+ (UINT64)time_span * (UINT64)1) / (UINT64)10
+ );
+ n->TcpSendTimeoutSpan = n->CurrentRTT * 2;
+ }
+ }
+ // Reduce the transmission size
+ n->SendMissionSize -= slide_offset;
+ if (n->SendMissionSize == 0)
+ {
+ // Try to increase the transmission segment size because
+ // all segments to be sent this time have been sent
+ if (n->TcpSendCWnd < 65536)
+ {
+ n->TcpSendCWnd++;
+ }
+ n->CurrentSendingMission = false;
+ n->TcpLastSentTime = 0;
+ n->RetransmissionUsedFlag = false;
+ }
+ // Slide the buffer
+ n->SendSeq += slide_offset;
+ ReadFifo(n->SendFifo, NULL, slide_offset);
+ // Send further by the size of confirmed transmission completion by the ACK this time
+ if (n->SendMissionSize != 0 && false)
+ {
+ UINT notice_window_size_value = 0;
+ UINT send_data_size;
+ UINT buf_free_bytes;
+ UINT send_offset = n->SendMissionSize;
+ // Determine the value of the window size to be notified
+ if (FifoSize(n->RecvFifo) < NAT_RECV_BUF_SIZE)
+ {
+ buf_free_bytes = NAT_RECV_BUF_SIZE - FifoSize(n->RecvFifo);
+ }
+ notice_window_size_value = MIN(n->TcpRecvWindowSize, buf_free_bytes);
+ // Calculate the segment size to be transmitted
+ send_data_size = n->TcpSendWindowSize;
+ if (send_data_size > (n->TcpSendCWnd * n->TcpSendMaxSegmentSize))
+ {
+ // Apply the cwnd value
+ send_data_size = n->TcpSendCWnd * n->TcpSendMaxSegmentSize;
+ }
+ if (n->SendFifo->size > send_offset)
+ {
+ send_data_size = MIN(send_data_size, n->SendFifo->size - send_offset);
+ send_data_size = MIN(send_data_size, slide_offset);
+ }
+ else
+ {
+ send_data_size = 0;
+ }
+ if (send_data_size >= 1)
+ {
+ // Transmit the fragmented segments
+ UINT current_pointer = 0;
+ while (send_data_size > 0)
+ {
+ UINT send_segment_size = MIN(n->TcpSendMaxSegmentSize, send_data_size);
+ void *send_segment = (void *)((
+ (UCHAR *)n->SendFifo->p) + n->SendFifo->pos +
+ current_pointer + send_offset);
+
+ SendTcp(v, n->DestIp, n->DestPort, n->SrcIp, n->SrcPort,
+ (UINT)(n->SendSeqInit + n->SendSeq + (UINT64)current_pointer
+ + (UINT)send_offset),
+ (UINT)(n->RecvSeqInit + n->RecvSeq),
+ TCP_ACK | TCP_PSH,
+ notice_window_size_value,
+ 0,
+ send_segment,
+ send_segment_size);
+ current_pointer += send_segment_size;
+ send_data_size -= send_segment_size;
+ }
+ n->SendMissionSize += current_pointer;
+ n->CurrentSendingMission = true;
+ n->TcpLastSentTime = v->Now;
+ // RTT measurement
+ if (n->CalcRTTStartTime == 0)
+ {
+ n->CalcRTTStartTime = v->Now;
+ n->CalcRTTStartValue = n->SendSeq + current_pointer - 1;
+ }
+ }
+ }
+ // Event occurs
+ SetSockEvent(v->SockEvent);
+ }
+ }
+ // Next, receive the data
+ seq64 = n->RecvSeq + (UINT64)seq - (n->RecvSeqInit + n->RecvSeq) % X32;
+ if ((n->RecvSeqInit + n->RecvSeq) % X32 > seq)
+ {
+ if (((n->RecvSeqInit + n->RecvSeq) % X32 - ack) >= 0x80000000)
+ {
+ seq64 = n->RecvSeq + (UINT64)seq + X32 - (n->RecvSeqInit + n->RecvSeq) % X32;
+ }
+ }
+ // Position of the starting point of the data from the client is in the seq64 at this time
+ if (seq64 >= n->RecvSeq && (seq64 + size) <= (n->RecvSeq + n->TcpRecvWindowSize))
+ {
+ if (size >= 1)
+ {
+ // One or more bytes of data has been received within the receive window
+ UINT offset = (UINT)(seq64 - n->RecvSeq);
+ UINT i;
+ IP_PART *me;
+ if (n->TcpRecvWindow == NULL)
+ {
+ n->TcpRecvWindow = NewFifo();
+ }
+ if (n->TcpRecvList == NULL)
+ {
+ n->TcpRecvList = NewListFast(NULL);
+ }
+ // Add to the list by overwriting arriving packets to the buffer
+ if (FifoSize(n->TcpRecvWindow) < (offset + size))
+ {
+ // Buffer size expansion
+ WriteFifo(n->TcpRecvWindow, NULL, offset + size - FifoSize(n->TcpRecvWindow));
+ }
+ Copy(((UCHAR *)n->TcpRecvWindow->p) + n->TcpRecvWindow->pos +
+ offset, data, size);
+ me = ZeroMalloc(sizeof(IP_PART));
+ me->Offset = offset;
+ me->Size = size;
+ for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
+ {
+ IP_PART *p = LIST_DATA(n->TcpRecvList, i);
+ // If there are overlapped region, remove these
+ if (p->Size != 0)
+ {
+ if (me->Offset <= p->Offset && (me->Offset + me->Size) >= (p->Offset + p->Size))
+ {
+ // This packet completely overwrite the existing packet
+ p->Size = 0;
+ }
+ else if (me->Offset >= p->Offset && (me->Offset + me->Size) <= (p->Offset + p->Size))
+ {
+ // Existing packet completely override this packet
+ me->Size = 0;
+ }
+ else if (me->Offset > p->Offset && me->Offset < (p->Offset + p->Size) &&
+ (me->Offset + me->Size) > (p->Offset + p->Size))
+ {
+ // Partially overlapped
+ p->Size -= p->Offset + p->Size - me->Offset;
+ }
+ else if (me->Offset < p->Offset && (me->Offset + size) > p->Offset && (me->Offset + size) < (p->Offset + p->Size))
+ {
+ // Partially overlapped
+ me->Size -= me->Offset + me->Size - p->Offset;
+ }
+ }
+ }
+ if (me->Size == 0)
+ {
+ Free(me);
+ }
+ else
+ {
+ Add(n->TcpRecvList, me);
+ }
+KILL_NULL_FIRST:
+ // Remove all blank items from reception list
+ for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
+ {
+ IP_PART *p = LIST_DATA(n->TcpRecvList, i);
+ if (p->Size == 0)
+ {
+ Delete(n->TcpRecvList, p);
+ Free(p);
+ goto KILL_NULL_FIRST;
+ }
+ }
+SCAN_FIRST:
+ // Extract if there is something starting at offset 0 in the received list
+ for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
+ {
+ IP_PART *p = LIST_DATA(n->TcpRecvList, i);
+ UINT sz;
+ if (p->Offset == 0)
+ {
+ // Since a data block starts with 0 is found,
+ // slide it left by that amount and write the buffer
+ // for extracting data to the FIFO
+ sz = p->Size;
+ WriteFifo(n->RecvFifo, ((UCHAR *)n->TcpRecvWindow->p) + n->TcpRecvWindow->pos, sz);
+ // Release from the list
+ Delete(n->TcpRecvList, p);
+ Free(p);
+ ReadFifo(n->TcpRecvWindow, NULL, sz);
+ // Slide all the items to the left
+ for (i = 0;i < LIST_NUM(n->TcpRecvList);i++)
+ {
+ p = LIST_DATA(n->TcpRecvList, i);
+ p->Offset -= sz;
+ }
+ // Update the parameters of the TCB
+ n->RecvSeq += (UINT64)sz;
+ SetSockEvent(v->SockEvent);
+ n->SendAckNext = true;
+ // Re-scan from the beginning
+ goto SCAN_FIRST;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ SetSockEvent(v->SockEvent);
+}
+
+// Parse the TCP options
+void ParseTcpOption(TCP_OPTION *o, void *data, UINT size)
+{
+ UCHAR *buf = (UCHAR *)data;
+ UINT i;
+ UINT value_size = 0;
+ UINT value_id = 0;
+ UCHAR value[128];
+ // Validate arguments
+ if (o == NULL || data == NULL)
+ {
+ return;
+ }
+
+ Zero(o, sizeof(TCP_OPTION));
+
+ for (i = 0;i < size;i++)
+ {
+ if (buf[i] == 0)
+ {
+ return;
+ }
+ if (buf[i] != 1)
+ {
+ value_id = buf[i];
+ i++;
+ if (i >= size)
+ {
+ return;
+ }
+ value_size = buf[i];
+ if (value_size <= 1 || value_size > sizeof(value))
+ {
+ return;
+ }
+ i++;
+ if (i >= size)
+ {
+ return;
+ }
+ value_size -= 2;
+ Copy(value, &buf[i], value_size);
+ i += value_size;
+ if (i >= size)
+ {
+ return;
+ }
+ switch (value_id)
+ {
+ case 2: // MSS
+ if (value_size == 2)
+ {
+ USHORT *mss = (USHORT *)value;
+ o->MaxSegmentSize = Endian16(*mss);
+ }
+ break;
+
+ case 3: // WSS
+ if (value_size == 1)
+ {
+ UCHAR *wss = (UCHAR *)value;
+ o->WindowScaling = Endian16(*wss);
+ }
+ break;
+
+ }
+ }
+ }
+
+}
+
+// Create a new NAT TCP session
+NAT_ENTRY *CreateNatTcp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port)
+{
+ NAT_ENTRY *n;
+ HUB_OPTION *o;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return NULL;
+ }
+
+ if (CanCreateNewNatEntry(v) == false)
+ {
+ return NULL;
+ }
+
+ o = NatGetHubOption(v);
+
+ // Fail immediately if the connection with SYN_SENT are too many
+ if (o != NULL && o->SecureNAT_MaxTcpSynSentPerIp != 0)
+ {
+ if (GetNumNatEntriesPerIp(v, src_ip, NAT_TCP, true) >= o->SecureNAT_MaxTcpSynSentPerIp)
+ {
+ return NULL;
+ }
+ }
+
+ // If the connections other than SYN_SENT are too many, delete old ones
+ if (o != NULL && o->SecureNAT_MaxTcpSessionsPerIp != 0)
+ {
+ if (GetNumNatEntriesPerIp(v, src_ip, NAT_TCP, false) >= o->SecureNAT_MaxTcpSessionsPerIp)
+ {
+ NAT_ENTRY *oldest = GetOldestNatEntryOfIp(v, src_ip, NAT_TCP);
+
+ if (oldest != NULL)
+ {
+ DisconnectNatEntryNow(v, oldest);
+ }
+ }
+ }
+
+ // Create a NAT entry
+ n = ZeroMalloc(sizeof(NAT_ENTRY));
+ n->Id = Inc(v->Counter);
+ n->v = v;
+ n->lock = NewLock();
+ n->Protocol = NAT_TCP;
+ n->SrcIp = src_ip;
+ n->SrcPort = src_port;
+ n->DestIp = dest_ip;
+ n->DestPort = dest_port;
+ n->CreatedTime = n->LastCommTime = v->Now;
+ n->TcpLastRecvAckTime = v->Now;
+ n->Sock = NULL;
+ n->DisconnectNow = false;
+ n->TcpSendMaxSegmentSize = n->TcpRecvMaxSegmentSize = v->TcpMss;
+
+ n->SendFifo = NewFifo();
+ n->RecvFifo = NewFifo();
+
+ n->TcpStatus = NAT_TCP_CONNECTING;
+
+ n->SendSeqInit = Rand32();
+ n->CurrentRTT = NAT_INITIAL_RTT_VALUE;
+ n->TcpSendTimeoutSpan = n->CurrentRTT * 2;
+
+ // Add to the NAT table
+ Add(v->NatTable, n);
+
+
+#if 1
+ {
+ IP ip1, ip2;
+ char s1[MAX_SIZE], s2[MAX_SIZE];
+ UINTToIP(&ip1, src_ip);
+ UINTToIP(&ip2, dest_ip);
+ IPToStr(s1, 0, &ip1);
+ IPToStr(s2, 0, &ip2);
+ Debug("NAT_ENTRY: CreateNatTcp %s %u -> %s %u\n", s1, src_port, s2, dest_port);
+
+ NLog(v, "LH_NAT_TCP_CREATED", n->Id, s1, src_port, s2, dest_port);
+ }
+#endif
+
+ return n;
+}
+
+// Received TCP packets from the virtual network
+void VirtualTcpReceived(VH *v, UINT src_ip, UINT dest_ip, void *data, UINT size, UINT max_l3_size)
+{
+ TCP_HEADER *tcp;
+ UINT src_port, dest_port;
+ UINT header_size, buf_size;
+ void *buf;
+ IP ip1, ip2;
+ // Validate arguments
+ if (v == NULL || data == NULL)
+ {
+ return;
+ }
+
+ // Get the header
+ if (size < TCP_HEADER_SIZE)
+ {
+ // Size is too small
+ return;
+ }
+ tcp = (TCP_HEADER *)data;
+ src_port = Endian16(tcp->SrcPort);
+ dest_port = Endian16(tcp->DstPort);
+ if (src_port == 0 || dest_port == 0)
+ {
+ // Port number is invalid
+ return;
+ }
+ if (src_ip == dest_ip || src_ip == 0 || src_ip == 0xffffffff || dest_ip == 0 || dest_ip == 0xffffffff)
+ {
+ // IP address is invalid
+ return;
+ }
+ UINTToIP(&ip1, src_ip);
+ UINTToIP(&ip2, dest_ip);
+ if (ip1.addr[0] == 127 || ip2.addr[0] == 127)
+ {
+ // Loopback IP address can not be specified
+ return;
+ }
+ if (IsInNetwork(dest_ip, v->HostIP, v->HostMask))
+ {
+ // Ignore the packets toward the network of the virtual LAN side
+ return;
+ }
+ // Get the header size
+ header_size = TCP_GET_HEADER_SIZE(tcp) * 4;
+ if (size < header_size)
+ {
+ // Header size is invalid
+ return;
+ }
+ // Get the address and size of the buffer
+ buf_size = size - header_size;
+ buf = (void *)(((UCHAR *)data) + header_size);
+
+ TcpRecvForInternet(v, src_ip, src_port, dest_ip, dest_port, tcp, buf, buf_size, max_l3_size);
+}
+
+// NAT ICMP polling
+void PollingNatIcmp(VH *v, NAT_ENTRY *n)
+{
+ // Validate arguments
+ if (v == NULL || n == NULL)
+ {
+ return;
+ }
+
+ // Process if there are any packets in the receive queue
+ if (n->UdpRecvQueue->num_item != 0)
+ {
+ BLOCK *block;
+
+ // Send all ICMP packets to the virtual network
+ while (block = GetNext(n->UdpRecvQueue))
+ {
+ // Rewrite the destination IP address of the returned packet to the IP address of the client
+ UCHAR *data;
+ UINT size;
+
+ data = (UCHAR *)block->Buf;
+ size = block->Size;
+
+ if (size >= sizeof(IPV4_HEADER))
+ {
+ IPV4_HEADER *ipv4 = (IPV4_HEADER *)data;
+ UINT ipv4_header_size = GetIpHeaderSize((UCHAR *)ipv4, size);
+
+ if (ipv4_header_size >= sizeof(IPV4_HEADER) && (Endian16(ipv4->TotalLength) >= ipv4_header_size))
+ {
+ UCHAR *ipv4_payload = data + ipv4_header_size;
+ UINT ipv4_payload_size = Endian16(ipv4->TotalLength) - ipv4_header_size;
+
+ if (ipv4_payload_size >= sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO))
+ {
+ ICMP_HEADER *icmp = (ICMP_HEADER *)(data + ipv4_header_size);
+ UINT icmp_size = ipv4_payload_size;
+
+ if (icmp->Type == ICMP_TYPE_DESTINATION_UNREACHABLE || icmp->Type == ICMP_TYPE_TIME_EXCEEDED)
+ {
+ // Rewrite the Src IP of the IPv4 header of the ICMP response packet
+ if (icmp_size >= (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO) + sizeof(IPV4_HEADER)))
+ {
+ IPV4_HEADER *orig_ipv4 = (IPV4_HEADER *)(data + ipv4_header_size + sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
+ UINT orig_ipv4_size = icmp_size - (sizeof(ICMP_HEADER) + sizeof(ICMP_ECHO));
+
+ UINT orig_ipv4_header_size = GetIpHeaderSize((UCHAR *)orig_ipv4, orig_ipv4_size);
+
+ if (orig_ipv4_header_size >= sizeof(IPV4_HEADER))
+ {
+ orig_ipv4->SrcIP = n->SrcIp;
+ orig_ipv4->Checksum = 0;
+ orig_ipv4->Checksum = IpChecksum(orig_ipv4, orig_ipv4_header_size);
+ }
+ }
+ }
+
+ // Recalculate the checksum of ICMP
+ icmp->Checksum = IpChecksum(icmp, icmp_size);
+
+ SendIpEx(v, n->SrcIp, ipv4->SrcIP, ipv4->Protocol, ipv4_payload, ipv4_payload_size,
+ MAX(ipv4->TimeToLive - 1, 1));
+ }
+ }
+ }
+
+ FreeBlock(block);
+ }
+
+ if (v->IcmpRawSocketOk == false)
+ {
+ // Release the NAT entry as soon as the results is received in the case of using ICMP API
+ n->DisconnectNow = true;
+ }
+ }
+}
+
+// NAT UDP polling
+void PoolingNatUdp(VH *v, NAT_ENTRY *n)
+{
+ // Validate arguments
+ if (v == NULL || n == NULL)
+ {
+ return;
+ }
+
+ // Process if there are any packets in the receive queue
+ if (n->UdpRecvQueue->num_item != 0)
+ {
+ BLOCK *block;
+
+ // Send all UDP packets to the virtual network
+ while (block = GetNext(n->UdpRecvQueue))
+ {
+ UINT src_ip = n->DestIp;
+
+ if (src_ip == 0xFFFFFFFF)
+ {
+ src_ip = v->HostIP;
+ }
+
+ if (block->Param1 != 0)
+ {
+ src_ip = block->Param1;
+ }
+
+ SendUdp(v, n->SrcIp, n->SrcPort, src_ip, n->DestPort,
+ block->Buf, block->Size);
+
+ FreeBlock(block);
+ }
+ }
+}
+
+// NAT polling
+void PoolingNat(VH *v)
+{
+ UINT i;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ if (NnIsActive(v))
+ {
+ // Poll whether the packet comes from native NAT
+ NnPoll(v->NativeNat);
+ }
+
+ // Process by scanning the all NAT entries
+ for (i = 0;i < LIST_NUM(v->NatTable);i++)
+ {
+ NAT_ENTRY *n = LIST_DATA(v->NatTable, i);
+
+ switch (n->Protocol)
+ {
+ case NAT_TCP:
+ PollingNatTcp(v, n);
+ break;
+
+ case NAT_UDP:
+ PoolingNatUdp(v, n);
+ break;
+
+ case NAT_ICMP:
+ PollingNatIcmp(v, n);
+ break;
+
+ case NAT_DNS:
+ PollingNatDns(v, n);
+ break;
+ }
+ }
+}
+
+// Comparison function of the NAT table entry
+int CompareNat(void *p1, void *p2)
+{
+ NAT_ENTRY *n1, *n2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ n1 = *(NAT_ENTRY **)p1;
+ n2 = *(NAT_ENTRY **)p2;
+ if (n1 == n2)
+ {
+ return 0;
+ }
+
+ if (n1->SrcIp > n2->SrcIp) return 1;
+ else if (n1->SrcIp < n2->SrcIp) return -1;
+ else if (n1->DestIp > n2->DestIp) return 1;
+ else if (n1->DestIp < n2->DestIp) return -1;
+ else if (n1->SrcPort > n2->SrcPort) return 1;
+ else if (n1->SrcPort < n2->SrcPort) return -1;
+ else if (n1->DestPort > n2->DestPort) return 1;
+ else if (n1->DestPort < n2->DestPort) return -1;
+ else if (n1->Protocol > n2->Protocol) return 1;
+ else if (n1->Protocol < n2->Protocol) return -1;
+ else return 0;
+}
+
+// Configure the NAT structure
+void SetNat(NAT_ENTRY *n, UINT protocol, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT public_ip, UINT public_port)
+{
+ // Validate arguments
+ if (n == NULL)
+ {
+ return;
+ }
+
+ n->Protocol = protocol;
+ n->SrcIp = src_ip;
+ n->SrcPort = src_port;
+ n->DestIp = dest_ip;
+ n->DestPort = dest_port;
+ n->PublicIp = public_ip;
+ n->PublicPort = public_port;
+}
+
+// Initialize the NAT
+void InitNat(VH *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ // Create a NAT table
+ v->NatTable = NewList(CompareNat);
+
+ // Create a socket event
+ v->SockEvent = NewSockEvent();
+
+ // Create the NAT thread
+ v->HaltNat = false;
+ v->NatThread = NewThread(NatThread, (void *)v);
+ WaitThreadInit(v->NatThread);
+
+ if (IsEthSupported())
+ {
+ // Start a native NAT if access to the layer 2 Ethernet is supported
+ v->NativeNat = NewNativeNat(v);
+ }
+}
+
+// Release the NAT
+void FreeNat(VH *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ // Stop the native NAT
+ if (v->NativeNat != NULL)
+ {
+ FreeNativeNat(v->NativeNat);
+ v->NativeNat = NULL;
+ }
+
+ // Stop the NAT thread
+ v->HaltNat = true;
+ SetSockEvent(v->SockEvent);
+ WaitThread(v->NatThread, INFINITE);
+ ReleaseThread(v->NatThread);
+ v->NatThread = NULL;
+ ReleaseSockEvent(v->SockEvent);
+ v->SockEvent = NULL;
+
+ // Release the NAT table
+ ReleaseList(v->NatTable);
+}
+
+// Search the NAT table
+NAT_ENTRY *SearchNat(VH *v, NAT_ENTRY *target)
+{
+ NAT_ENTRY *n;
+ // Validate arguments
+ if (v == NULL || target == NULL)
+ {
+ return NULL;
+ }
+
+ // Binary search
+ n = (NAT_ENTRY *)Search(v->NatTable, target);
+
+ return n;
+}
+
+// Delete the UDP NAT entry
+void DeleteNatUdp(VH *v, NAT_ENTRY *n)
+{
+ BLOCK *block;
+ // Validate arguments
+ if (v == NULL || n == NULL)
+ {
+ return;
+ }
+
+ NLog(v, "LH_NAT_UDP_DELETED", n->Id);
+
+ // Release all queues
+ while (block = GetNext(n->UdpRecvQueue))
+ {
+ FreeBlock(block);
+ }
+ ReleaseQueue(n->UdpRecvQueue);
+ while (block = GetNext(n->UdpSendQueue))
+ {
+ FreeBlock(block);
+ }
+ ReleaseQueue(n->UdpSendQueue);
+
+ // Release the socket
+ if (n->Sock != NULL)
+ {
+ Disconnect(n->Sock);
+ ReleaseSock(n->Sock);
+ n->Sock = NULL;
+ }
+
+ DeleteLock(n->lock);
+
+ // Remove from the table
+ Delete(v->NatTable, n);
+
+ // Release the memory
+ Free(n);
+
+ Debug("NAT: DeleteNatUdp\n");
+
+}
+
+// Delete the ICMP NAT entry
+void DeleteNatIcmp(VH *v, NAT_ENTRY *n)
+{
+ BLOCK *block;
+ // Validate arguments
+ if (v == NULL || n == NULL)
+ {
+ return;
+ }
+
+ //NLog(v, "LH_NAT_ICMP_DELETED", n->Id);
+
+ // Release all queues
+ while (block = GetNext(n->UdpRecvQueue))
+ {
+ FreeBlock(block);
+ }
+ ReleaseQueue(n->UdpRecvQueue);
+ while (block = GetNext(n->UdpSendQueue))
+ {
+ FreeBlock(block);
+ }
+ ReleaseQueue(n->UdpSendQueue);
+
+ if (n->IcmpQueryBlock != NULL)
+ {
+ FreeBlock(n->IcmpQueryBlock);
+ }
+
+ if (n->IcmpResponseBlock != NULL)
+ {
+ FreeBlock(n->IcmpResponseBlock);
+ }
+
+ if (n->IcmpOriginalCopy != NULL)
+ {
+ Free(n->IcmpOriginalCopy);
+ }
+
+ // Release the socket
+ if (n->Sock != NULL)
+ {
+ Disconnect(n->Sock);
+ ReleaseSock(n->Sock);
+ n->Sock = NULL;
+ }
+
+ DeleteLock(n->lock);
+
+ // Remove from the table
+ Delete(v->NatTable, n);
+
+ // Release the memory
+ Free(n);
+
+ Debug("NAT: DeleteNatIcmp\n");
+
+}
+
+// Create a NAT ICMP entry
+NAT_ENTRY *CreateNatIcmp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UCHAR *original_copy, UINT original_copy_size)
+{
+ NAT_ENTRY *n;
+ HUB_OPTION *o;
+ // Validate arguments
+ if (v == NULL || original_copy == NULL || original_copy_size == 0)
+ {
+ return NULL;
+ }
+
+ if (CanCreateNewNatEntry(v) == false)
+ {
+ return NULL;
+ }
+
+ o = NatGetHubOption(v);
+ if (o != NULL && o->SecureNAT_MaxIcmpSessionsPerIp != 0)
+ {
+ if (GetNumNatEntriesPerIp(v, src_ip, NAT_ICMP, false) >= o->SecureNAT_MaxIcmpSessionsPerIp)
+ {
+ NAT_ENTRY *oldest = GetOldestNatEntryOfIp(v, src_ip, NAT_ICMP);
+
+ if (oldest != NULL)
+ {
+ DisconnectNatEntryNow(v, oldest);
+ }
+ }
+ }
+
+ n = ZeroMalloc(sizeof(NAT_ENTRY));
+ n->Id = Inc(v->Counter);
+ n->v = v;
+ n->lock = NewLock();
+ n->Protocol = NAT_ICMP;
+ n->SrcIp = src_ip;
+ n->SrcPort = src_port;
+ n->DestIp = dest_ip;
+ n->DestPort = dest_port;
+
+ n->CreatedTime = n->LastCommTime = v->Now;
+
+ n->UdpSendQueue = NewQueue();
+ n->UdpRecvQueue = NewQueue();
+
+ n->UdpSocketCreated = false;
+
+ n->IcmpOriginalCopy = Clone(original_copy, original_copy_size);
+ n->IcmpOriginalCopySize = original_copy_size;
+
+ SetSockEvent(v->SockEvent);
+
+#if 1
+ {
+ IP ip1, ip2;
+ char s1[MAX_SIZE], s2[MAX_SIZE];
+ UINTToIP(&ip1, src_ip);
+ UINTToIP(&ip2, dest_ip);
+ IPToStr(s1, 0, &ip1);
+ IPToStr(s2, 0, &ip2);
+ Debug("NAT_ENTRY: CreateNatIcmp %s %u -> %s %u\n", s1, src_port, s2, dest_port);
+
+ //NLog(v, "LH_NAT_ICMP_CREATED", n->Id, s1, s2, src_port);
+ }
+#endif
+
+ Add(v->NatTable, n);
+
+ return n;
+}
+
+// Create a NAT UDP entry
+NAT_ENTRY *CreateNatUdp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT dns_proxy_ip)
+{
+ NAT_ENTRY *n;
+ HUB_OPTION *o;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return NULL;
+ }
+
+ if (CanCreateNewNatEntry(v) == false)
+ {
+ return NULL;
+ }
+
+ o = NatGetHubOption(v);
+ if (o != NULL && o->SecureNAT_MaxTcpSessionsPerIp != 0)
+ {
+ if (GetNumNatEntriesPerIp(v, src_ip, NAT_UDP, false) >= o->SecureNAT_MaxUdpSessionsPerIp)
+ {
+ NAT_ENTRY *oldest = GetOldestNatEntryOfIp(v, src_ip, NAT_UDP);
+
+ if (oldest != NULL)
+ {
+ DisconnectNatEntryNow(v, oldest);
+ }
+ }
+ }
+
+ n = ZeroMalloc(sizeof(NAT_ENTRY));
+ n->Id = Inc(v->Counter);
+ n->v = v;
+ n->lock = NewLock();
+ n->Protocol = NAT_UDP;
+ n->SrcIp = src_ip;
+ n->SrcPort = src_port;
+ n->DestIp = dest_ip;
+ n->DestPort = dest_port;
+
+ if (dns_proxy_ip != 0)
+ {
+ n->ProxyDns = true;
+ n->DestIpProxy = dns_proxy_ip;
+ }
+
+ n->CreatedTime = n->LastCommTime = v->Now;
+
+ n->UdpSendQueue = NewQueue();
+ n->UdpRecvQueue = NewQueue();
+
+ n->UdpSocketCreated = false;
+
+ SetSockEvent(v->SockEvent);
+
+#if 1
+ {
+ IP ip1, ip2;
+ char s1[MAX_SIZE], s2[MAX_SIZE];
+ UINTToIP(&ip1, src_ip);
+ UINTToIP(&ip2, dest_ip);
+ IPToStr(s1, 0, &ip1);
+ IPToStr(s2, 0, &ip2);
+ Debug("NAT_ENTRY: CreateNatUdp %s %u -> %s %u\n", s1, src_port, s2, dest_port);
+
+ NLog(v, "LH_NAT_UDP_CREATED", n->Id, s1, src_port, s2, dest_port);
+ }
+#endif
+
+ Add(v->NatTable, n);
+
+ return n;
+}
+
+// Ignore for NetBIOS name registration packet
+bool IsNetbiosRegistrationPacket(UCHAR *buf, UINT size)
+{
+ // Validate arguments
+ if (buf == NULL || size == 0)
+ {
+ return false;
+ }
+
+ if (size >= 4)
+ {
+ USHORT us = *((USHORT *)(buf + 2));
+
+ us = Endian16(us);
+
+ if (((us & 0x7800) >> 11) == 5)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Generate the encoded NetBIOS name
+void EncodeNetBiosName(UCHAR *dst, char *src)
+{
+ char tmp[17];
+ UINT i;
+ UINT copy_len;
+ UINT wp;
+ // Validate arguments
+ if (dst == NULL || src == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < 16;i++)
+ {
+ tmp[i] = ' ';
+ }
+ tmp[16] = 0;
+
+ copy_len = StrLen(src);
+ if (copy_len > 16)
+ {
+ copy_len = 16;
+ }
+
+ Copy(tmp, src, StrLen(src));
+
+ wp = 0;
+
+ tmp[15] = 0;
+
+ for (i = 0;i < 16;i++)
+ {
+ char c = tmp[i];
+ char *s = CharToNetBiosStr(c);
+
+ dst[wp++] = s[0];
+ dst[wp++] = s[1];
+ }
+}
+
+// Convert the string to NetBIOS characters
+char *CharToNetBiosStr(char c)
+{
+ c = ToUpper(c);
+
+ switch (c)
+ {
+ case '\0': return "AA";
+ case 'A': return "EB";
+ case 'B': return "EC";
+ case 'C': return "ED";
+ case 'D': return "EE";
+ case 'E': return "EF";
+ case 'F': return "EG";
+ case 'G': return "EH";
+ case 'H': return "EI";
+ case 'I': return "EJ";
+ case 'J': return "EK";
+ case 'K': return "EL";
+ case 'L': return "EM";
+ case 'M': return "EN";
+ case 'N': return "EO";
+ case 'O': return "EP";
+ case 'P': return "FA";
+ case 'Q': return "FB";
+ case 'R': return "FC";
+ case 'S': return "FD";
+ case 'T': return "FE";
+ case 'U': return "FF";
+ case 'V': return "FG";
+ case 'W': return "FH";
+ case 'X': return "FI";
+ case 'Y': return "FJ";
+ case 'Z': return "FK";
+ case '0': return "DA";
+ case '1': return "DB";
+ case '2': return "DC";
+ case '3': return "DD";
+ case '4': return "DE";
+ case '5': return "DF";
+ case '6': return "DG";
+ case '7': return "DH";
+ case '8': return "DI";
+ case '9': return "DJ";
+ case ' ': return "CA";
+ case '!': return "CB";
+ case '\"': return "CC";
+ case '#': return "CD";
+ case '$': return "CE";
+ case '%': return "CF";
+ case '&': return "CG";
+ case '\'': return "CH";
+ case '(': return "CI";
+ case ')': return "CJ";
+ case '*': return "CK";
+ case '+': return "CL";
+ case ',': return "CM";
+ case '-': return "CN";
+ case '.': return "CO";
+ case '=': return "DN";
+ case ':': return "DK";
+ case ';': return "DL";
+ case '@': return "EA";
+ case '^': return "FO";
+ case '_': return "FP";
+ case '{': return "HL";
+ case '}': return "HN";
+ case '~': return "HO";
+ }
+
+ return "CA";
+}
+
+// Process if a NetBIOS name resolution packet for the my host name
+bool ProcessNetBiosNameQueryPacketForMyself(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
+{
+ BUF *rb;
+ USHORT tran_id;
+ USHORT flags;
+ USHORT num_query;
+ USHORT zero1, zero2, zero3;
+ UCHAR name_size;
+ UCHAR encoded_name[32];
+ UCHAR node_type;
+ USHORT type, classid;
+ UCHAR my_pc_encoded_name[32];
+ bool ret = false;
+ // Validate arguments
+ if (v == NULL || data == NULL)
+ {
+ return false;
+ }
+
+ rb = NewBufFromMemory(data, size);
+
+ ReadBuf(rb, &tran_id, sizeof(USHORT));
+
+ ReadBuf(rb, &flags, sizeof(USHORT));
+ flags = Endian16(flags);
+
+ ReadBuf(rb, &num_query, sizeof(USHORT));
+ num_query = Endian16(num_query);
+
+ ReadBuf(rb, &zero1, sizeof(USHORT));
+ ReadBuf(rb, &zero2, sizeof(USHORT));
+ ReadBuf(rb, &zero3, sizeof(USHORT));
+
+ ReadBuf(rb, &name_size, 1);
+
+ ReadBuf(rb, encoded_name, 32);
+
+ ReadBuf(rb, &node_type, 1);
+
+ ReadBuf(rb, &type, sizeof(USHORT));
+ type = Endian16(type);
+
+ if (ReadBuf(rb, &classid, sizeof(USHORT)) == sizeof(USHORT))
+ {
+ classid = Endian16(classid);
+
+ if (((flags >> 11) & 0x0F) == 0 &&
+ num_query == 1 && name_size == 0x20 &&
+ zero1 == 0 && zero2 == 0 && zero3 == 0 && node_type == 0 && type == 0x0020 && classid == 0x0001)
+ {
+ char my_pcname[MAX_SIZE];
+
+ // Get the encoded name of this PC
+ Zero(my_pcname, sizeof(my_pcname));
+ GetMachineHostName(my_pcname, sizeof(my_pcname));
+
+ EncodeNetBiosName(my_pc_encoded_name, my_pcname);
+
+ if (Cmp(my_pc_encoded_name, encoded_name, 30) == 0)
+ {
+ // Assemble the response packet since the name resolution packet which targets this PC name received
+ BUF *sb = NewBuf();
+ USHORT us;
+ UINT ui;
+ LIST *ip_list;
+ BUF *ip_list_buf;
+ bool found = false;
+
+ WriteBuf(sb, &tran_id, sizeof(USHORT));
+
+ flags = Endian16(0x8500);
+ WriteBuf(sb, &flags, sizeof(USHORT));
+
+ num_query = 0;
+ WriteBuf(sb, &num_query, sizeof(USHORT));
+
+ us = Endian16(1);
+ WriteBuf(sb, &us, sizeof(USHORT));
+
+ us = 0;
+ WriteBuf(sb, &us, sizeof(USHORT));
+ WriteBuf(sb, &us, sizeof(USHORT));
+
+ name_size = 0x20;
+ WriteBuf(sb, &name_size, 1);
+
+ WriteBuf(sb, encoded_name, 32);
+
+ node_type = 0;
+ WriteBuf(sb, &node_type, 1);
+
+ type = Endian16(type);
+ classid = Endian16(classid);
+
+ WriteBuf(sb, &type, sizeof(USHORT));
+ WriteBuf(sb, &classid, sizeof(USHORT));
+
+ ui = Endian32((UINT)(Tick64() / 1000ULL));
+ WriteBuf(sb, &ui, sizeof(UINT));
+
+ ip_list_buf = NewBuf();
+
+ ip_list = GetHostIPAddressList();
+ if (ip_list != NULL)
+ {
+ UINT i;
+
+ // Return only private IP if there is a private IP
+ for (i = 0;i < LIST_NUM(ip_list);i++)
+ {
+ IP *ip = LIST_DATA(ip_list, i);
+
+ if (IsIP4(ip) && IsLocalHostIP4(ip) == false && IsZeroIp(ip) == false)
+ {
+ if (IsIPPrivate(ip))
+ {
+ USHORT flags = Endian16(0x4000);
+ UINT ip_uint = IPToUINT(ip);
+
+ WriteBuf(ip_list_buf, &flags, sizeof(USHORT));
+ WriteBuf(ip_list_buf, &ip_uint, sizeof(UINT));
+
+ found = true;
+ }
+ }
+ }
+
+ if (found == false)
+ {
+ // Return all IP if no private IP are found
+ for (i = 0;i < LIST_NUM(ip_list);i++)
+ {
+ IP *ip = LIST_DATA(ip_list, i);
+
+ if (IsIP4(ip) && IsLocalHostIP4(ip) == false && IsZeroIp(ip) == false)
+ {
+ USHORT flags = Endian16(0x4000);
+ UINT ip_uint = IPToUINT(ip);
+
+ WriteBuf(ip_list_buf, &flags, sizeof(USHORT));
+ WriteBuf(ip_list_buf, &ip_uint, sizeof(UINT));
+
+ found = true;
+ }
+ }
+ }
+
+ FreeHostIPAddressList(ip_list);
+ }
+
+ us = Endian16(ip_list_buf->Size);
+ WriteBuf(sb, &us, sizeof(USHORT));
+
+ WriteBufBuf(sb, ip_list_buf);
+
+ SendUdp(v, src_ip, src_port, v->HostIP, dest_port, sb->Buf, sb->Size);
+
+ FreeBuf(ip_list_buf);
+
+ FreeBuf(sb);
+
+ WHERE;
+ }
+ }
+ }
+
+ FreeBuf(rb);
+
+ return ret;
+}
+
+// Process the NetBIOS broadcast packet
+void UdpRecvForNetBiosBroadcast(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size, bool dns_proxy, bool unicast)
+{
+ // Validate arguments
+ if (data == NULL || v == NULL)
+ {
+ return;
+ }
+
+ // Ignore for NetBIOS name registration packet
+ if (IsNetbiosRegistrationPacket(data, size) == false)
+ {
+ if (unicast == false)
+ {
+ dest_ip = 0xFFFFFFFF;
+ }
+
+ if (ProcessNetBiosNameQueryPacketForMyself(v, src_ip, src_port, dest_ip, dest_port, data, size) == false)
+ {
+ UdpRecvForInternet(v, src_ip, src_port, dest_ip, dest_port, data, size, false);
+ }
+ }
+}
+
+// Process the UDP packet to the Internet
+void UdpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size, bool dns_proxy)
+{
+ NAT_ENTRY *n, t;
+ BLOCK *block;
+ void *buf;
+ UINT dns_ip = 0;
+ // Validate arguments
+ if (data == NULL || v == NULL)
+ {
+ return;
+ }
+
+ if (dns_proxy)
+ {
+ // Get the DNS server of the proxy to connect to
+ IP ip;
+ char tmp[MAX_SIZE];
+ if (GetDefaultDns(&ip) == false)
+ {
+ // Failure
+ Debug("Failed to GetDefaultDns()\n");
+ return;
+ }
+ dns_ip = IPToUINT(&ip);
+ IPToStr(tmp, sizeof(tmp), &ip);
+ Debug("Redirect to DNS Server %s\n", tmp);
+ }
+
+ // Examine whether the NAT entry for this packet has already been created
+ SetNat(&t, NAT_UDP, src_ip, src_port, dest_ip, dest_port, 0, 0);
+ n = SearchNat(v, &t);
+
+ if (n == NULL)
+ {
+ // Create a NAT entry because it is the first packet
+ n = CreateNatUdp(v, src_ip, src_port, dest_ip, dest_port, dns_proxy ? dns_ip : 0);
+ if (n == NULL)
+ {
+ // Entry creation failed
+ return;
+ }
+
+ if (dns_proxy)
+ {
+ n->ProxyDns = true;
+ n->DestIpProxy = dns_ip;
+ }
+ }
+
+ // Set the event by inserting the packet into the queue
+ buf = Malloc(size);
+ Copy(buf, data, size);
+ block = NewBlock(buf, size, 0);
+ InsertQueue(n->UdpSendQueue, block);
+
+ SetSockEvent(v->SockEvent);
+}
+
+// Attempt to interpret the DNS packet
+bool ParseDnsPacket(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
+{
+ return ParseDnsPacketEx(v, src_ip, src_port, dest_ip, dest_port, data, size, NULL);
+}
+bool ParseDnsPacketEx(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size, DNS_PARSED_PACKET *parsed_result)
+{
+ DNSV4_HEADER *dns;
+ NAT_ENTRY *nat;
+ UINT transaction_id;
+ void *query_data;
+ UINT query_data_size;
+ char hostname[256];
+ // Validate arguments
+ if (v == NULL || data == NULL || size == 0)
+ {
+ return false;
+ }
+
+ // Check the header size
+ if (size < sizeof(DNSV4_HEADER))
+ {
+ // Undersize
+ return false;
+ }
+
+ // DNS header acquisition
+ dns = (DNSV4_HEADER *)data;
+ transaction_id = Endian16(dns->TransactionId);
+ if ((dns->Flag1 & 78) != 0 || (dns->Flag1 & 0x80) != 0)
+ {
+ // Illegal opcode
+ return false;
+ }
+ if (Endian16(dns->NumQuery) != 1)
+ {
+ // Number of queries is invalid
+ return false;
+ }
+
+ query_data = ((UCHAR *)dns) + sizeof(DNSV4_HEADER);
+ query_data_size = size - sizeof(DNSV4_HEADER);
+
+ // Interpret the query
+ if (ParseDnsQuery(hostname, sizeof(hostname), query_data, query_data_size) == false)
+ {
+ // Interpretation fails
+ return false;
+ }
+
+ if (parsed_result != NULL)
+ {
+ // Only analyse without processing
+ Zero(parsed_result, sizeof(DNS_PARSED_PACKET));
+ StrCpy(parsed_result->Hostname, sizeof(parsed_result->Hostname), hostname);
+ parsed_result->TransactionId = transaction_id;
+
+ return true;
+ }
+
+ // Create a DNS entry
+ nat = CreateNatDns(v, src_ip, src_port, dest_ip, dest_port, transaction_id,
+ false, hostname);
+
+ if (nat == false)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Send the NAT DNS response packet
+void SendNatDnsResponse(VH *v, NAT_ENTRY *n)
+{
+ BUF *b;
+ UINT dns_header_size;
+ DNSV4_HEADER *dns;
+ UINT src_ip;
+ // Validate arguments
+ if (n == NULL || v == NULL)
+ {
+ return;
+ }
+
+ // Generate the data
+ b = NewBuf();
+
+ // Add a Query
+ if (n->DnsGetIpFromHost == false)
+ {
+ BuildDnsQueryPacket(b, n->DnsTargetHostName, false);
+ }
+ else
+ {
+ BuildDnsQueryPacket(b, n->DnsTargetHostName, true);
+ }
+
+ // Add a Response
+ if (n->DnsOk)
+ {
+ if (n->DnsGetIpFromHost == false)
+ {
+ BuildDnsResponsePacketA(b, &n->DnsResponseIp);
+ }
+ else
+ {
+ BuildDnsResponsePacketPtr(b, n->DnsResponseHostName);
+ }
+ }
+
+ // Generate a DNS header
+ dns_header_size = sizeof(DNSV4_HEADER) + b->Size;
+
+ dns = ZeroMalloc(dns_header_size);
+ dns->TransactionId = Endian16((USHORT)n->DnsTransactionId);
+
+ // Generate a response flag
+ if (n->DnsOk)
+ {
+ dns->Flag1 = 0x85;
+ dns->Flag2 = 0x80;
+ }
+ else
+ {
+ dns->Flag1 = 0x85;
+ dns->Flag2 = 0x83;
+ }
+
+ dns->NumQuery = Endian16(1);
+ dns->AnswerRRs = Endian16(n->DnsOk != false ? 1 : 0);
+ dns->AuthorityRRs = 0;
+ dns->AdditionalRRs = 0;
+
+ // Settings, such as the source IP address
+ src_ip = n->DestIp;
+ if (src_ip == Endian32(SPECIAL_IPV4_ADDR_LLMNR_DEST) && n->DestPort == SPECIAL_UDP_PORT_LLMNR)
+ {
+ // Make a unicast response in the case of LLMNR packet
+ src_ip = v->HostIP;
+
+ dns->Flag1 = 0x84;
+ dns->Flag2 = 0x00;
+ }
+
+ // Copy data
+ Copy(((UCHAR *)dns) + sizeof(DNSV4_HEADER), b->Buf, b->Size);
+
+ // Send this packet
+ SendUdp(v, n->SrcIp, n->SrcPort, src_ip, n->DestPort, dns, dns_header_size);
+
+ // Release the memory
+ Free(dns);
+ FreeBuf(b);
+}
+
+// Generate a DNS response packet (host name)
+void BuildDnsResponsePacketPtr(BUF *b, char *hostname)
+{
+ USHORT magic;
+ USHORT type, clas;
+ UINT ttl;
+ USHORT len;
+ BUF *c;
+ // Validate arguments
+ if (b == NULL || hostname == NULL)
+ {
+ return;
+ }
+
+ magic = Endian16(0xc00c);
+ type = Endian16(0x000c);
+ clas = Endian16(0x0001);
+ ttl = Endian32(NAT_DNS_RESPONSE_TTL);
+
+ c = BuildDnsHostName(hostname);
+ if (c == NULL)
+ {
+ return;
+ }
+ len = Endian16((USHORT)c->Size);
+
+ WriteBuf(b, &magic, 2);
+ WriteBuf(b, &type, 2);
+ WriteBuf(b, &clas, 2);
+ WriteBuf(b, &ttl, 4);
+ WriteBuf(b, &len, 2);
+ WriteBuf(b, c->Buf, c->Size);
+ FreeBuf(c);
+}
+
+// Generate a DNS response packet (host IP address)
+void BuildDnsResponsePacketA(BUF *b, IP *ip)
+{
+ UINT ip_addr;
+ USHORT magic;
+ USHORT type, clas;
+ UINT ttl;
+ USHORT len;
+ // Validate arguments
+ if (b == NULL || ip == NULL)
+ {
+ return;
+ }
+
+ ip_addr = IPToUINT(ip);
+ magic = Endian16(0xc00c);
+ type = Endian16(0x0001);
+ clas = Endian16(0x0001);
+ ttl = Endian32(NAT_DNS_RESPONSE_TTL);
+ len = Endian16((USHORT)sizeof(ttl));
+
+ WriteBuf(b, &magic, sizeof(magic));
+ WriteBuf(b, &type, sizeof(type));
+ WriteBuf(b, &clas, sizeof(clas));
+ WriteBuf(b, &ttl, sizeof(ttl));
+ WriteBuf(b, &len, sizeof(len));
+ WriteBuf(b, &ip_addr, sizeof(ip_addr));
+}
+
+// Generate a DNS query data packet
+void BuildDnsQueryPacket(BUF *b, char *hostname, bool ptr)
+{
+ USHORT val;
+ BUF *c;
+ // Validate arguments
+ if (b == NULL || hostname == NULL)
+ {
+ return;
+ }
+
+ // Convert the host name to a buffer
+ c = BuildDnsHostName(hostname);
+ if (c == NULL)
+ {
+ return;
+ }
+
+ WriteBuf(b, c->Buf, c->Size);
+ FreeBuf(c);
+
+ // Type and class
+ if (ptr == false)
+ {
+ val = Endian16(0x0001);
+ }
+ else
+ {
+ val = Endian16(0x000c);
+ }
+ WriteBuf(b, &val, 2);
+
+ val = Endian16(0x0001);
+ WriteBuf(b, &val, 2);
+}
+
+// Generate a DNS host name buffer
+BUF *BuildDnsHostName(char *hostname)
+{
+ UINT i;
+ UCHAR size;
+ TOKEN_LIST *token;
+ BUF *b;
+ // Validate arguments
+ if (hostname == NULL)
+ {
+ return NULL;
+ }
+
+ // Split the host name into tokens
+ token = ParseToken(hostname, ".");
+ if (token == NULL)
+ {
+ return NULL;
+ }
+
+ b = NewBuf();
+
+ // Add a host string
+ for (i = 0;i < token->NumTokens;i++)
+ {
+ size = (UCHAR)StrLen(token->Token[i]);
+ WriteBuf(b, &size, 1);
+ WriteBuf(b, token->Token[i], size);
+ }
+
+ // NULL character
+ size = 0;
+ WriteBuf(b, &size, 1);
+
+ SeekBuf(b, 0, 0);
+
+ FreeToken(token);
+
+ return b;
+}
+
+// Process the NAT DNS entry
+void PollingNatDns(VH *v, NAT_ENTRY *n)
+{
+ // Validate arguments
+ if (v == NULL || n == NULL)
+ {
+ return;
+ }
+
+ if (n->DnsFinished)
+ {
+ if (n->DnsPollingFlag == false)
+ {
+ n->DnsPollingFlag = true;
+ // Process has been completed
+ SendNatDnsResponse(v, n);
+
+ // Terminating
+ n->DisconnectNow = true;
+ }
+ }
+}
+
+// Create a NAT DNS entry
+NAT_ENTRY *CreateNatDns(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port,
+ UINT transaction_id, bool dns_get_ip_from_host, char *dns_target_host_name)
+{
+ NAT_ENTRY *n;
+ HUB_OPTION *o;
+ // Validate arguments
+ if (v == NULL || dns_target_host_name == NULL)
+ {
+ return NULL;
+ }
+
+ if (CanCreateNewNatEntry(v) == false)
+ {
+ return NULL;
+ }
+
+ o = NatGetHubOption(v);
+ if (o != NULL && o->SecureNAT_MaxDnsSessionsPerIp != 0)
+ {
+ if (GetNumNatEntriesPerIp(v, src_ip, NAT_DNS, false) >= o->SecureNAT_MaxDnsSessionsPerIp)
+ {
+ NAT_ENTRY *oldest = GetOldestNatEntryOfIp(v, src_ip, NAT_DNS);
+
+ if (oldest != NULL)
+ {
+ DisconnectNatEntryNow(v, oldest);
+ }
+ }
+ }
+
+ n = ZeroMalloc(sizeof(NAT_ENTRY));
+ n->Id = Inc(v->Counter);
+ n->v = v;
+ n->lock = NewLock();
+ n->Protocol = NAT_DNS;
+ n->SrcIp = src_ip;
+ n->SrcPort = src_port;
+ n->DestIp = dest_ip;
+ n->DestPort = dest_port;
+ n->DnsTransactionId = transaction_id;
+ n->CreatedTime = n->LastCommTime = v->Now;
+ n->DisconnectNow = false;
+
+ n->DnsGetIpFromHost = false;
+ n->DnsTargetHostName = CopyStr(dns_target_host_name);
+
+ Add(v->NatTable, n);
+
+#if 1
+ {
+ IP ip1, ip2;
+ char s1[MAX_SIZE], s2[MAX_SIZE];
+ UINTToIP(&ip1, src_ip);
+ UINTToIP(&ip2, dest_ip);
+ IPToStr(s1, 0, &ip1);
+ IPToStr(s2, 0, &ip2);
+ Debug("NAT_ENTRY: CreateNatDns %s %u -> %s %u\n", s1, src_port, s2, dest_port);
+ }
+#endif
+
+
+ return n;
+}
+
+// Get the next byte
+UCHAR GetNextByte(BUF *b)
+{
+ UCHAR c = 0;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return 0;
+ }
+
+ if (ReadBuf(b, &c, 1) != 1)
+ {
+ return 0;
+ }
+
+ return c;
+}
+
+// Interpret the DNS query
+bool ParseDnsQuery(char *name, UINT name_size, void *data, UINT data_size)
+{
+ BUF *b;
+ char tmp[257];
+ bool ok = true;
+ USHORT val;
+ // Validate arguments
+ if (name == NULL || data == NULL || data_size == 0)
+ {
+ return false;
+ }
+ StrCpy(name, name_size, "");
+
+ b = NewBuf();
+ WriteBuf(b, data, data_size);
+ SeekBuf(b, 0, 0);
+
+ while (true)
+ {
+ UINT next_len = (UINT)GetNextByte(b);
+ if (next_len > 0)
+ {
+ // Read only the specified length
+ Zero(tmp, sizeof(tmp));
+ if (ReadBuf(b, tmp, next_len) != next_len)
+ {
+ ok = false;
+ break;
+ }
+ // Append
+ if (StrLen(name) != 0)
+ {
+ StrCat(name, name_size, ".");
+ }
+ StrCat(name, name_size, tmp);
+ }
+ else
+ {
+ // Read all
+ break;
+ }
+ }
+
+ if (ReadBuf(b, &val, sizeof(val)) != sizeof(val))
+ {
+ ok = false;
+ }
+ else
+ {
+ if (Endian16(val) != 0x01 && Endian16(val) != 0x0c)
+ {
+ ok = false;
+ }
+ }
+
+ if (ReadBuf(b, &val, sizeof(val)) != sizeof(val))
+ {
+ ok = false;
+ }
+ else
+ {
+ if (Endian16(val) != 0x01)
+ {
+ ok = false;
+ }
+ }
+
+ FreeBuf(b);
+
+ if (ok == false || StrLen(name) == 0)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+// Set the VGS host name
+void SetDnsProxyVgsHostname(char *hostname)
+{
+ // Validate arguments
+ if (hostname == NULL)
+ {
+ return;
+ }
+
+ StrCpy(v_vgs_hostname, sizeof(v_vgs_hostname), hostname);
+}
+
+// Operate as a DNS proxy
+void DnsProxy(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
+{
+ // Validate arguments
+ if (v == NULL || data == NULL || size == 0)
+ {
+ return;
+ }
+
+ if (dest_port == SPECIAL_UDP_PORT_LLMNR)
+ {
+ // Process by analyzing the DNS query in the case of LLMNR
+ ParseDnsPacket(v, src_ip, src_port, dest_ip, dest_port, data, size);
+ }
+ else
+ {
+ // Forward the packet as it is in the case of a normal DNS packet
+ if (IsEmptyStr(v_vgs_hostname) == false)
+ {
+ // Response by proxy in the case of trying to get the IP of the VGS
+ DNS_PARSED_PACKET p;
+
+ Zero(&p, sizeof(p));
+ if (ParseDnsPacketEx(v, src_ip, src_port, dest_ip, dest_port, data, size, &p))
+ {
+ if (StrCmpi(p.Hostname, "254.254.211.10.in-addr.arpa") == 0)
+ {
+ NAT_ENTRY n;
+
+ Zero(&n, sizeof(n));
+ n.DnsTargetHostName = p.Hostname;
+ n.DnsGetIpFromHost = true;
+ n.DnsResponseHostName = v_vgs_hostname;
+ n.DnsTransactionId = p.TransactionId;
+ n.DnsOk = true;
+ n.DestIp = dest_ip;
+ n.SrcIp = src_ip;
+ n.DestPort = dest_port;
+ n.SrcPort = src_port;
+
+ SendNatDnsResponse(v, &n);
+ return;
+ }
+ }
+ }
+
+ UdpRecvForInternet(v, src_ip, src_port, dest_ip, dest_port, data, size, true);
+ }
+}
+
+// Process the LLMNR query
+void UdpRecvLlmnr(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
+{
+ // Validate arguments
+ if (data == NULL || v == NULL)
+ {
+ return;
+ }
+
+ if (dest_port == SPECIAL_UDP_PORT_LLMNR)
+ {
+ // DNS proxy start
+ DnsProxy(v, src_ip, src_port, dest_ip, dest_port, data, size);
+ }
+}
+
+// Process the UDP packet to the virtual host
+void UdpRecvForMe(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
+{
+ // Validate arguments
+ if (data == NULL || v == NULL)
+ {
+ return;
+ }
+
+ if (dest_port == NAT_DNS_PROXY_PORT)
+ {
+ // DNS proxy start
+ DnsProxy(v, src_ip, src_port, dest_ip, dest_port, data, size);
+ }
+}
+
+// Process the UDP broadcast packet
+void UdpRecvForBroadcast(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size)
+{
+ // Validate arguments
+ if (data == NULL || v == NULL)
+ {
+ return;
+ }
+}
+
+// An UDP packet has been received
+void VirtualUdpReceived(VH *v, UINT src_ip, UINT dest_ip, void *data, UINT size, bool mac_broadcast, bool is_localmac, UINT max_l3_size)
+{
+ UDP_HEADER *udp;
+ UINT packet_length;
+ void *buf;
+ UINT buf_size;
+ UINT src_port, dest_port;
+ // Validate arguments
+ if (v == NULL || data == NULL)
+ {
+ return;
+ }
+
+ // Check the header
+ udp = (UDP_HEADER *)data;
+ if (size < UDP_HEADER_SIZE)
+ {
+ return;
+ }
+ packet_length = Endian16(udp->PacketLength);
+ if (packet_length != size)
+ {
+ return;
+ }
+ buf = ((UCHAR *)data) + UDP_HEADER_SIZE;
+ buf_size = size - UDP_HEADER_SIZE;
+ src_port = Endian16(udp->SrcPort);
+ dest_port = Endian16(udp->DstPort);
+ // Check the port number
+ if (dest_port == 0)
+ {
+ // Port number is invalid
+ return;
+ }
+
+ // Determine whether it's broadcast packet or packet addressed to myself
+ if (dest_ip == v->HostIP)
+ {
+ // IP packet addressed to myself has arrived
+ UdpRecvForMe(v, src_ip, src_port, dest_ip, dest_port, buf, buf_size);
+ }
+ else if ((mac_broadcast || dest_ip == Endian32(0xE00000FC)) && dest_port == SPECIAL_UDP_PORT_LLMNR)
+ {
+ if (is_localmac == false)
+ {
+ // Packet addressed to 224.0.0.252 (LLMNR) arrives
+ UdpRecvLlmnr(v, src_ip, src_port, dest_ip, dest_port, buf, buf_size);
+ }
+ }
+ else if (mac_broadcast && (dest_port == SPECIAL_UDP_PORT_WSD || dest_port == SPECIAL_UDP_PORT_SSDP))
+ {
+ if (is_localmac == false)
+ {
+ // WS-Discovery packet arrives
+ UdpRecvForInternet(v, src_ip, src_port, 0xFFFFFFFF, dest_port, buf, buf_size, false);
+ }
+ }
+ else if (mac_broadcast && (dest_port == SPECIAL_UDP_PORT_NBTDGM || dest_port == SPECIAL_UDP_PORT_NBTNS))
+ {
+ if (is_localmac == false)
+ {
+ // NetBIOS Broadcast packet arrived
+ UdpRecvForNetBiosBroadcast(v, src_ip, src_port, dest_ip, dest_port, buf, buf_size, false, false);
+ }
+ }
+ else if (mac_broadcast || dest_ip == 0xffffffff || dest_ip == GetBroadcastAddress(v->HostIP, v->HostMask))
+ {
+ if (is_localmac == false)
+ {
+ // Broadcast packet arrived
+ UdpRecvForBroadcast(v, src_ip, src_port, dest_ip, dest_port, buf, buf_size);
+ }
+ }
+ else if (IsInNetwork(dest_ip, v->HostIP, v->HostMask) == false)
+ {
+ // Packets to other than local address (that is on the Internet) has been received
+ if (NnIsActive(v) == false)
+ {
+ if (v->HubOption != NULL && v->HubOption->DisableUserModeSecureNAT)
+ {
+ // User-mode NAT is disabled
+ return;
+ }
+
+ // User-mode NAT
+ UdpRecvForInternet(v, src_ip, src_port, dest_ip, dest_port, buf, buf_size, false);
+ }
+ else
+ {
+ // Kernel-mode NAT
+ NnUdpRecvForInternet(v, src_ip, src_port, dest_ip, dest_port, buf, buf_size, max_l3_size);
+ }
+ }
+ else
+ {
+ // Local address has arrived. Ignore it
+ }
+}
+
+// Determine the network address of the subnet to which the specified IP address belongs
+UINT GetNetworkAddress(UINT addr, UINT mask)
+{
+ return (addr & mask);
+}
+
+// Determine the broadcast address of the subnet to which the specified IP address belongs
+UINT GetBroadcastAddress(UINT addr, UINT mask)
+{
+ return ((addr & mask) | (~mask));
+}
+void GetBroadcastAddress4(IP *dst, IP *addr, IP *mask)
+{
+ // Validate arguments
+ if (dst == NULL || IsIP4(addr) == false || IsIP4(mask) == false)
+ {
+ Zero(dst, sizeof(IP));
+ return;
+ }
+
+ UINTToIP(dst, GetBroadcastAddress(IPToUINT(addr), IPToUINT(mask)));
+}
+
+// Determine whether the specified IP address belongs to the sub-network that is
+// represented by a another specified network address and a subnet mask
+bool IsInNetwork(UINT uni_addr, UINT network_addr, UINT mask)
+{
+ if (GetNetworkAddress(uni_addr, mask) == GetNetworkAddress(network_addr, mask))
+ {
+ return true;
+ }
+ return false;
+}
+
+// Send an UDP packet
+void SendUdp(VH *v, UINT dest_ip, UINT dest_port, UINT src_ip, UINT src_port, void *data, UINT size)
+{
+ UDPV4_PSEUDO_HEADER *vh;
+ UDP_HEADER *udp;
+ UINT udp_packet_length = UDP_HEADER_SIZE + size;
+ USHORT checksum;
+ // Validate arguments
+ if (v == NULL || data == NULL)
+ {
+ return;
+ }
+ if (udp_packet_length > 65536)
+ {
+ return;
+ }
+
+ // Generate a virtual header
+ vh = Malloc(sizeof(UDPV4_PSEUDO_HEADER) + size);
+ udp = (UDP_HEADER *)(((UCHAR *)vh) + 12);
+
+ vh->SrcIP = src_ip;
+ vh->DstIP = dest_ip;
+ vh->Reserved = 0;
+ vh->Protocol = IP_PROTO_UDP;
+ vh->PacketLength1 = Endian16((USHORT)udp_packet_length);
+ udp->SrcPort = Endian16((USHORT)src_port);
+ udp->DstPort = Endian16((USHORT)dest_port);
+ udp->PacketLength = Endian16((USHORT)udp_packet_length);
+ udp->Checksum = 0;
+
+ // Copy data
+ Copy(((UCHAR *)udp) + UDP_HEADER_SIZE, data, size);
+
+ // Calculate the checksum
+ checksum = IpChecksum(vh, udp_packet_length + 12);
+ if (checksum == 0x0000)
+ {
+ checksum = 0xffff;
+ }
+ udp->Checksum = checksum;
+
+ // Send a packet
+ SendIp(v, dest_ip, src_ip, IP_PROTO_UDP, udp, udp_packet_length);
+
+ // Release the memory
+ Free(vh);
+}
+
+// Poll the IP combining object
+void PollingIpCombine(VH *v)
+{
+ LIST *o;
+ UINT i;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ // Discard the old combining object
+ o = NULL;
+ for (i = 0;i < LIST_NUM(v->IpCombine);i++)
+ {
+ IP_COMBINE *c = LIST_DATA(v->IpCombine, i);
+
+ if (c->Expire < v->Now)
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+ Add(o, c);
+ }
+ }
+
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IP_COMBINE *c = LIST_DATA(o, i);
+
+ // Remove from the list
+ Delete(v->IpCombine, c);
+
+ // Release the memory
+ FreeIpCombine(v, c);
+ }
+ ReleaseList(o);
+ }
+}
+
+// Send an ICMP packet
+void VirtualIcmpSend(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size)
+{
+ ICMP_HEADER *icmp;
+ void *data_buf;
+ // Validate arguments
+ if (v == NULL || data == NULL)
+ {
+ return;
+ }
+
+ // Build the header
+ icmp = ZeroMalloc(sizeof(ICMP_HEADER) + size);
+ // Data copy
+ data_buf = ((UCHAR *)icmp) + sizeof(ICMP_HEADER);
+ Copy(data_buf, data, size);
+ // Other
+ icmp->Checksum = 0;
+ icmp->Code = 0;
+ icmp->Type = ICMP_TYPE_ECHO_RESPONSE;
+ // Checksum
+ icmp->Checksum = IpChecksum(icmp, sizeof(ICMP_HEADER) + size);
+
+ // IP packet transmission
+ SendIp(v, dst_ip, src_ip, IP_PROTO_ICMPV4, icmp, sizeof(ICMP_HEADER) + size);
+
+ // Release the memory
+ Free(icmp);
+}
+
+// Send the ICMP Echo Response packet
+void VirtualIcmpEchoSendResponse(VH *v, UINT src_ip, UINT dst_ip, USHORT id, USHORT seq_no, void *data, UINT size)
+{
+ ICMP_ECHO *e;
+ // Validate arguments
+ if (v == NULL || data == NULL)
+ {
+ return;
+ }
+
+ // Build the header
+ e = ZeroMalloc(sizeof(ICMP_ECHO) + size);
+ e->Identifier = Endian16(id);
+ e->SeqNo = Endian16(seq_no);
+
+ // Data copy
+ Copy(((UCHAR *)e) + sizeof(ICMP_ECHO), data, size);
+
+ // Send an ICMP
+ VirtualIcmpSend(v, src_ip, dst_ip, e, sizeof(ICMP_ECHO) + size);
+
+ // Release the memory
+ Free(e);
+}
+
+// Treat the ICMP Echo Request packet with a Raw Socket
+void VirtualIcmpEchoRequestReceivedRaw(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size, UCHAR ttl, void *icmp_data, UINT icmp_size, UCHAR *ip_header, UINT ip_header_size)
+{
+ ICMP_ECHO *echo;
+ UINT data_size;
+ void *data_buf;
+ USHORT id, seq_no;
+ void *buf;
+ BLOCK *block;
+ // Validate arguments
+ if (v == NULL || data == NULL || icmp_data == NULL || ip_header == NULL)
+ {
+ return;
+ }
+ if (ttl == 0)
+ {
+ ttl = 1;
+ }
+
+ echo = (ICMP_ECHO *)data;
+
+ // Echo size check
+ if (size < sizeof(ICMP_ECHO))
+ {
+ // Insufficient data
+ return;
+ }
+
+ id = Endian16(echo->Identifier);
+ seq_no = Endian16(echo->SeqNo);
+
+ // Data size
+ data_size = size - sizeof(ICMP_ECHO);
+
+ // Data body
+ data_buf = ((UCHAR *)data) + sizeof(ICMP_ECHO);
+
+ if (dst_ip == v->HostIP)
+ {
+ // Respond because it is addressed to me
+ VirtualIcmpEchoSendResponse(v, v->HostIP, src_ip, id, seq_no, data_buf, data_size);
+ }
+ else if (IsInNetwork(dst_ip, v->HostIP, v->HostMask) == false)
+ {
+ NAT_ENTRY *n = NULL, t;
+ // Process by creating a NAT entry because it is addressed to the Internet
+
+ if (ttl <= 1)
+ {
+ // Reply the Time Exceeded immediately for the packet whose TTL is 1
+ UINT reply_size = sizeof(ICMP_HEADER) + 4 + ip_header_size + 8;
+ UCHAR *reply_data = ZeroMalloc(reply_size);
+ ICMP_HEADER *icmp = (ICMP_HEADER *)reply_data;
+ icmp->Type = ICMP_TYPE_TIME_EXCEEDED;
+ icmp->Code = ICMP_CODE_TTL_EXCEEDED_IN_TRANSIT;
+ Copy(reply_data + sizeof(ICMP_HEADER) + 4, ip_header, ip_header_size);
+ Copy(reply_data + sizeof(ICMP_HEADER) + 4 + ip_header_size, icmp_data, MIN(icmp_size, 8));
+
+ icmp->Checksum = IpChecksum(icmp, reply_size);
+
+ SendIp(v, src_ip, v->HostIP, IP_PROTO_ICMPV4, reply_data, reply_size);
+
+ Free(reply_data);
+ }
+ else
+ {
+ SetNat(&t, NAT_ICMP, src_ip, id, dst_ip, id, 0, 0);
+
+ if (v->IcmpRawSocketOk)
+ {
+ // Examine whether a NAT entry for this packet has already been created
+ n = SearchNat(v, &t);
+ }
+
+ if (n == NULL)
+ {
+ // Create a NAT entry because it is the first packet
+ n = CreateNatIcmp(v, src_ip, id, dst_ip, id, (UCHAR *)ip_header, ip_header_size + 8);
+
+ if (n == NULL)
+ {
+ // Entry creation failed
+ return;
+ }
+ }
+
+ // Set the event by inserting the packet into the queue
+ buf = Malloc(icmp_size);
+ Copy(buf, icmp_data, icmp_size);
+ block = NewBlock(buf, icmp_size, 0);
+ block->Ttl = MAKESURE(ttl - 1, 1, 255);
+ InsertQueue(n->UdpSendQueue, block);
+
+ SetSockEvent(v->SockEvent);
+ }
+ }
+}
+
+// Receive an ICMP Echo Request packet
+void VirtualIcmpEchoRequestReceived(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size, UCHAR ttl, void *icmp_data, UINT icmp_size, UCHAR *ip_header, UINT ip_header_size, UINT max_l3_size)
+{
+ ICMP_ECHO *echo;
+ UINT data_size;
+ void *data_buf;
+ USHORT id, seq_no;
+ // Validate arguments
+ if (v == NULL || data == NULL || icmp_data == NULL)
+ {
+ return;
+ }
+
+ if (NnIsActive(v))
+ {
+ // Process by the Native NAT
+ NnIcmpEchoRecvForInternet(v, src_ip, dst_ip, data, size, ttl, icmp_data, icmp_size,
+ ip_header, ip_header_size, max_l3_size);
+ return;
+ }
+
+ if (v->HubOption != NULL && v->HubOption->DisableUserModeSecureNAT)
+ {
+ // User-mode NAT is disabled
+ return;
+ }
+
+ if (v->IcmpRawSocketOk || v->IcmpApiOk)
+ {
+ // Process in the Raw Socket
+ VirtualIcmpEchoRequestReceivedRaw(v, src_ip, dst_ip, data, size, ttl, icmp_data, icmp_size,
+ ip_header, ip_header_size);
+ return;
+ }
+
+ // Returns the fake ICMP forcibly if any of Native NAT or Raw Socket can not be used
+
+ echo = (ICMP_ECHO *)data;
+
+ // Echo size check
+ if (size < sizeof(ICMP_ECHO))
+ {
+ // Insufficient data
+ return;
+ }
+
+ id = Endian16(echo->Identifier);
+ seq_no = Endian16(echo->SeqNo);
+
+ // Data size
+ data_size = size - sizeof(ICMP_ECHO);
+
+ // Data body
+ data_buf = ((UCHAR *)data) + sizeof(ICMP_ECHO);
+
+ // Return the ICMP Echo Response
+ VirtualIcmpEchoSendResponse(v, dst_ip, src_ip, id, seq_no, data_buf, data_size);
+}
+
+// An ICMP packet has been received
+void VirtualIcmpReceived(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size, UCHAR ttl, UCHAR *ip_header, UINT ip_header_size, UINT max_l3_size)
+{
+ ICMP_HEADER *icmp;
+ UINT msg_size;
+ USHORT checksum_calc, checksum_original;
+ // Validate arguments
+ if (v == NULL || data == NULL)
+ {
+ return;
+ }
+
+ // Size check
+ if (size < sizeof(ICMP_HEADER))
+ {
+ return;
+ }
+
+ // ICMP header
+ icmp = (ICMP_HEADER *)data;
+
+ // Get the ICMP message size
+ msg_size = size - sizeof(ICMP_HEADER);
+
+ // Check the checksum of the ICMP header
+ checksum_original = icmp->Checksum;
+ icmp->Checksum = 0;
+ checksum_calc = IpChecksum(data, size);
+ icmp->Checksum = checksum_original;
+
+ if (checksum_calc != checksum_original)
+ {
+ // Checksum is invalid
+ Debug("ICMP CheckSum Failed.\n");
+ return;
+ }
+
+ // Identified by the opcode
+ switch (icmp->Type)
+ {
+ case ICMP_TYPE_ECHO_REQUEST: // ICMP Echo request
+ VirtualIcmpEchoRequestReceived(v, src_ip, dst_ip, ((UCHAR *)data) + sizeof(ICMP_HEADER), msg_size, ttl,
+ icmp, size, ip_header, ip_header_size, max_l3_size);
+ break;
+
+ case ICMP_TYPE_ECHO_RESPONSE: // ICMP Echo response
+ // Do Nothing
+ break;
+ }
+}
+
+// Received an IP packet
+void IpReceived(VH *v, UINT src_ip, UINT dest_ip, UINT protocol, void *data, UINT size, bool mac_broadcast, UCHAR ttl, UCHAR *ip_header, UINT ip_header_size, bool is_local_mac, UINT max_l3_size)
+{
+ // Validate arguments
+ if (v == NULL || data == NULL)
+ {
+ return;
+ }
+
+ // Deliver the data to the supported high-level protocol
+ switch (protocol)
+ {
+ case IP_PROTO_ICMPV4: // ICMPv4
+ if (mac_broadcast == false)
+ {
+ VirtualIcmpReceived(v, src_ip, dest_ip, data, size, ttl, ip_header, ip_header_size, max_l3_size);
+ }
+ break;
+
+ case IP_PROTO_TCP: // TCP
+ if (mac_broadcast == false)
+ {
+ VirtualTcpReceived(v, src_ip, dest_ip, data, size, max_l3_size);
+ }
+ break;
+
+ case IP_PROTO_UDP: // UDP
+ VirtualUdpReceived(v, src_ip, dest_ip, data, size, mac_broadcast, is_local_mac, max_l3_size);
+ break;
+ }
+}
+
+// Combine the IP packet received to the IP combining object
+void CombineIp(VH *v, IP_COMBINE *c, UINT offset, void *data, UINT size, bool last_packet, UCHAR *head_ip_header_data, UINT head_ip_header_size)
+{
+ UINT i;
+ IP_PART *p;
+ UINT need_size;
+ UINT data_size_delta;
+ // Validate arguments
+ if (c == NULL || data == NULL)
+ {
+ return;
+ }
+
+ // Check the size and offset
+ if ((offset + size) > 65535)
+ {
+ // Do not process packet larger than 64Kbytes
+ return;
+ }
+
+ if (last_packet == false && c->Size != 0)
+ {
+ if ((offset + size) > c->Size)
+ {
+ // Do not process the packet larger than the packet size
+ return;
+ }
+ }
+
+ if (head_ip_header_data != NULL && head_ip_header_size >= sizeof(IPV4_HEADER))
+ {
+ if (c->HeadIpHeaderData == NULL)
+ {
+ c->HeadIpHeaderData = Clone(head_ip_header_data, head_ip_header_size);
+ c->HeadIpHeaderDataSize = head_ip_header_size;
+ }
+ }
+
+ need_size = offset + size;
+ data_size_delta = c->DataReserved;
+ // Ensure sufficient if the buffer is insufficient
+ while (c->DataReserved < need_size)
+ {
+ c->DataReserved = c->DataReserved * 4;
+ c->Data = ReAlloc(c->Data, c->DataReserved);
+ }
+ data_size_delta = c->DataReserved - data_size_delta;
+ v->CurrentIpQuota += data_size_delta;
+
+ // Overwrite the data into the buffer
+ Copy(((UCHAR *)c->Data) + offset, data, size);
+
+ if (last_packet)
+ {
+ // If No More Flagment packet arrives, the size of this datagram is finalized
+ c->Size = offset + size;
+ }
+
+ // Check the overlap between the region which is represented by the offset and size of the
+ // existing received list and the region which is represented by the offset and size
+ for (i = 0;i < LIST_NUM(c->IpParts);i++)
+ {
+ UINT moving_size;
+ IP_PART *p = LIST_DATA(c->IpParts, i);
+
+ // Check the overlapping between the existing area and head area
+ if ((p->Offset <= offset) && ((p->Offset + p->Size) > offset))
+ {
+ // Compress behind the offset of this packet since a duplication is
+ // found in the first part with the existing packet and this packet
+
+ if ((offset + size) <= (p->Offset + p->Size))
+ {
+ // This packet is buried in the existing packet
+ size = 0;
+ }
+ else
+ {
+ // Retral region is not overlapped
+ moving_size = p->Offset + p->Size - offset;
+ offset += moving_size;
+ size -= moving_size;
+ }
+ }
+ if ((p->Offset < (offset + size)) && ((p->Offset + p->Size) >= (offset + size)))
+ {
+ // Compress the size of this packet forward because a duplication is
+ // found between the posterior portion the existing packet and this packet
+
+ moving_size = p->Offset + p->Size - offset - size;
+ size -= moving_size;
+ }
+
+ if ((p->Offset >= offset) && ((p->Offset + p->Size) <= (offset + size)))
+ {
+ // This packet was overwritten to completely cover an existing packet
+ p->Size = 0;
+ }
+ }
+
+ if (size != 0)
+ {
+ // Register this packet
+ p = ZeroMalloc(sizeof(IP_PART));
+
+ p->Offset = offset;
+ p->Size = size;
+
+ Add(c->IpParts, p);
+ }
+
+ if (c->Size != 0)
+ {
+ // Get the total size of the data portion list already received
+ UINT total_size = 0;
+ UINT i;
+
+ for (i = 0;i < LIST_NUM(c->IpParts);i++)
+ {
+ IP_PART *p = LIST_DATA(c->IpParts, i);
+
+ total_size += p->Size;
+ }
+
+ if (total_size == c->Size)
+ {
+ // Received all of the IP packet
+ IpReceived(v, c->SrcIP, c->DestIP, c->Protocol, c->Data, c->Size, c->MacBroadcast, c->Ttl,
+ c->HeadIpHeaderData, c->HeadIpHeaderDataSize, c->SrcIsLocalMacAddr, c->MaxL3Size);
+
+ // Release the combining object
+ FreeIpCombine(v, c);
+
+ // Remove from the combining object list
+ Delete(v->IpCombine, c);
+ }
+ }
+}
+
+// Release the IP combining object
+void FreeIpCombine(VH *v, IP_COMBINE *c)
+{
+ UINT i;
+ // Validate arguments
+ if (c == NULL)
+ {
+ return;
+ }
+
+ // Release the data
+ v->CurrentIpQuota -= c->DataReserved;
+ Free(c->Data);
+
+ // Release the partial list
+ for (i = 0;i < LIST_NUM(c->IpParts);i++)
+ {
+ IP_PART *p = LIST_DATA(c->IpParts, i);
+
+ Free(p);
+ }
+
+ Free(c->HeadIpHeaderData);
+
+ ReleaseList(c->IpParts);
+ Free(c);
+}
+
+// Search the IP combining list
+IP_COMBINE *SearchIpCombine(VH *v, UINT src_ip, UINT dest_ip, USHORT id, UCHAR protocol)
+{
+ IP_COMBINE *c, t;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return NULL;
+ }
+
+ t.DestIP = dest_ip;
+ t.SrcIP = src_ip;
+ t.Id = id;
+ t.Protocol = protocol;
+
+ c = Search(v->IpCombine, &t);
+
+ return c;
+}
+
+// Insert by creating a new object to the IP combining list
+IP_COMBINE *InsertIpCombine(VH *v, UINT src_ip, UINT dest_ip, USHORT id, UCHAR protocol, bool mac_broadcast, UCHAR ttl, bool src_is_localmac)
+{
+ IP_COMBINE *c;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return NULL;
+ }
+
+ // Examine the quota
+ if ((v->CurrentIpQuota + IP_COMBINE_INITIAL_BUF_SIZE) > IP_COMBINE_WAIT_QUEUE_SIZE_QUOTA)
+ {
+ // IP packet can not be stored any more
+ return NULL;
+ }
+
+ c = ZeroMalloc(sizeof(IP_COMBINE));
+ c->SrcIsLocalMacAddr = src_is_localmac;
+ c->DestIP = dest_ip;
+ c->SrcIP = src_ip;
+ c->Id = id;
+ c->Expire = v->Now + (UINT64)IP_COMBINE_TIMEOUT;
+ c->Size = 0;
+ c->IpParts = NewList(NULL);
+ c->Protocol = protocol;
+ c->MacBroadcast = mac_broadcast;
+ c->Ttl = ttl;
+
+ // Secure the memory
+ c->DataReserved = IP_COMBINE_INITIAL_BUF_SIZE;
+ c->Data = Malloc(c->DataReserved);
+ v->CurrentIpQuota += c->DataReserved;
+
+ Insert(v->IpCombine, c);
+
+ return c;
+}
+
+// Initialize the IP combining list
+void InitIpCombineList(VH *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ v->IpCombine = NewList(CompareIpCombine);
+}
+
+// Release the IP combining list
+void FreeIpCombineList(VH *v)
+{
+ UINT i;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(v->IpCombine);i++)
+ {
+ IP_COMBINE *c = LIST_DATA(v->IpCombine, i);
+
+ FreeIpCombine(v, c);
+ }
+
+ ReleaseList(v->IpCombine);
+}
+
+// Comparison of IP combining list entry
+int CompareIpCombine(void *p1, void *p2)
+{
+ IP_COMBINE *c1, *c2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ c1 = *(IP_COMBINE **)p1;
+ c2 = *(IP_COMBINE **)p2;
+ if (c1 == NULL || c2 == NULL)
+ {
+ return 0;
+ }
+ if (c1->Id > c2->Id)
+ {
+ return 1;
+ }
+ else if (c1->Id < c2->Id)
+ {
+ return -1;
+ }
+ else if (c1->DestIP > c2->DestIP)
+ {
+ return 1;
+ }
+ else if (c1->DestIP < c2->DestIP)
+ {
+ return -1;
+ }
+ else if (c1->SrcIP > c2->SrcIP)
+ {
+ return 1;
+ }
+ else if (c1->SrcIP < c2->SrcIP)
+ {
+ return -1;
+ }
+ else if (c1->Protocol > c2->Protocol)
+ {
+ return 1;
+ }
+ else if (c1->Protocol < c2->Protocol)
+ {
+ return -1;
+ }
+ return 0;
+}
+
+// Received an IP packet
+void VirtualIpReceived(VH *v, PKT *packet)
+{
+ IPV4_HEADER *ip;
+ void *data;
+ UINT data_size_recved;
+ UINT size;
+ UINT ipv4_header_size;
+ bool last_packet;
+ UCHAR *head_ip_header_data = NULL;
+ UINT head_ip_header_size = 0;
+ bool is_local_mac = false;
+ UINT ip_l3_size;
+ // Validate arguments
+ if (v == NULL || packet == NULL)
+ {
+ return;
+ }
+
+ ip = packet->L3.IPv4Header;
+
+ if (packet->BroadcastPacket)
+ {
+ is_local_mac = IsMacAddressLocalFast(packet->MacAddressSrc);
+ }
+
+ // Get the size of the IPv4 header
+ ipv4_header_size = IPV4_GET_HEADER_LEN(packet->L3.IPv4Header) * 4;
+ head_ip_header_size = ipv4_header_size;
+
+ // Calculate the checksum of the IPv4 header
+ if (IpCheckChecksum(ip) == false)
+ {
+ return;
+ }
+
+ // Get a pointer to the data
+ data = ((UCHAR *)packet->L3.PointerL3) + ipv4_header_size;
+
+ // Register to the ARP table
+ ArpIpWasKnown(v, packet->L3.IPv4Header->SrcIP, packet->MacAddressSrc);
+
+ // Get the data size
+ size = ip_l3_size = Endian16(ip->TotalLength);
+ if (size <= ipv4_header_size)
+ {
+ // There is no data
+ return;
+ }
+ size -= ipv4_header_size;
+
+ // Get the size of data actually received
+ data_size_recved = packet->PacketSize - (ipv4_header_size + MAC_HEADER_SIZE);
+ if (data_size_recved < size)
+ {
+ // Data insufficient (It may be missing on the way)
+ return;
+ }
+
+ if (IPV4_GET_OFFSET(ip) == 0 && (IPV4_GET_FLAGS(ip) & 0x01) == 0)
+ {
+ // Because this packet has not been fragmented, it can be delivered to the upper layer immediately
+ head_ip_header_data = (UCHAR *)packet->L3.IPv4Header;
+ IpReceived(v, ip->SrcIP, ip->DstIP, ip->Protocol, data, size, packet->BroadcastPacket, ip->TimeToLive,
+ head_ip_header_data, head_ip_header_size, is_local_mac, ip_l3_size);
+ }
+ else
+ {
+ // This packet is necessary to combine because it is fragmented
+ UINT offset = IPV4_GET_OFFSET(ip) * 8;
+ IP_COMBINE *c = SearchIpCombine(v, ip->SrcIP, ip->DstIP, Endian16(ip->Identification), ip->Protocol);
+
+ if (offset == 0)
+ {
+ head_ip_header_data = (UCHAR *)packet->L3.IPv4Header;
+ }
+
+ last_packet = ((IPV4_GET_FLAGS(ip) & 0x01) == 0 ? true : false);
+
+ if (c != NULL)
+ {
+ // It is the second or subsequent packet
+ c->MaxL3Size = MAX(c->MaxL3Size, ip_l3_size);
+ CombineIp(v, c, offset, data, size, last_packet, head_ip_header_data, head_ip_header_size);
+ }
+ else
+ {
+ // Create a combining object because it is the first packet
+ c = InsertIpCombine(
+ v, ip->SrcIP, ip->DstIP, Endian16(ip->Identification), ip->Protocol, packet->BroadcastPacket,
+ ip->TimeToLive, is_local_mac);
+ if (c != NULL)
+ {
+ c->MaxL3Size = ip_l3_size;
+
+ CombineIp(v, c, offset, data, size, last_packet, head_ip_header_data, head_ip_header_size);
+ }
+ }
+ }
+}
+
+// Send the waiting IP packets from the specified IP address
+void SendWaitingIp(VH *v, UCHAR *mac, UINT dest_ip)
+{
+ UINT i;
+ LIST *o = NULL;
+ // Validate arguments
+ if (v == NULL || mac == NULL)
+ {
+ return;
+ }
+
+ // Get a target list
+ for (i = 0;i < LIST_NUM(v->IpWaitTable);i++)
+ {
+ IP_WAIT *w = LIST_DATA(v->IpWaitTable, i);
+
+ if (w->DestIP == dest_ip)
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+ Add(o, w);
+ }
+ }
+
+ // Send the target packets at once
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IP_WAIT *w = LIST_DATA(o, i);
+
+ // Transmission processing
+ VirtualIpSend(v, mac, w->Data, w->Size);
+
+ // Remove from the list
+ Delete(v->IpWaitTable, w);
+
+ // Release the memory
+ Free(w->Data);
+ Free(w);
+ }
+
+ ReleaseList(o);
+ }
+}
+
+// Remove the old IP waiting table entries
+void DeleteOldIpWaitTable(VH *v)
+{
+ UINT i;
+ LIST *o = NULL;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ // Get the deleting list
+ for (i = 0;i < LIST_NUM(v->IpWaitTable);i++)
+ {
+ IP_WAIT *w = LIST_DATA(v->IpWaitTable, i);
+
+ if (w->Expire < v->Now)
+ {
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+ Add(o, w);
+ }
+ }
+
+ // Delete all at once
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ IP_WAIT *w = LIST_DATA(o, i);
+
+ // Remove from the list
+ Delete(v->IpWaitTable, w);
+
+ // Release the memory
+ Free(w->Data);
+ Free(w);
+ }
+ ReleaseList(o);
+ }
+}
+
+// Poll the IP waiting table
+void PollingIpWaitTable(VH *v)
+{
+ // Delete the old table entries
+ DeleteOldIpWaitTable(v);
+}
+
+// Insert the IP packet to the IP waiting table
+void InsertIpWaitTable(VH *v, UINT dest_ip, UINT src_ip, void *data, UINT size)
+{
+ IP_WAIT *w;
+ // Validate arguments
+ if (v == NULL || data == NULL || size == 0)
+ {
+ return;
+ }
+
+ w = ZeroMalloc(sizeof(IP_WAIT));
+ w->Data = data;
+ w->Size = size;
+ w->SrcIP = src_ip;
+ w->DestIP = dest_ip;
+ w->Expire = v->Now + (UINT64)IP_WAIT_FOR_ARP_TIMEOUT;
+
+ Add(v->IpWaitTable, w);
+}
+
+// Initialize the IP waiting table
+void InitIpWaitTable(VH *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ v->IpWaitTable = NewList(NULL);
+}
+
+// Release the IP waiting table
+void FreeIpWaitTable(VH *v)
+{
+ UINT i;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(v->IpWaitTable);i++)
+ {
+ IP_WAIT *w = LIST_DATA(v->IpWaitTable, i);
+
+ Free(w->Data);
+ Free(w);
+ }
+
+ ReleaseList(v->IpWaitTable);
+}
+
+// MAC address for the IP address is found because something such as an ARP Response arrives
+void ArpIpWasKnown(VH *v, UINT ip, UCHAR *mac)
+{
+ // Validate arguments
+ if (v == NULL || mac == NULL)
+ {
+ return;
+ }
+
+ // If there is a query for this IP address in the ARP queue, delete it
+ DeleteArpWaitTable(v, ip);
+
+ // Update or register in the ARP table
+ InsertArpTable(v, mac, ip);
+
+ // Send the IP packets waiting in the IP waiting list
+ SendWaitingIp(v, mac, ip);
+}
+
+// Re-issue ARPs by checking the ARP waiting list
+void PollingArpWaitTable(VH *v)
+{
+ UINT i;
+ LIST *o;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ // Initialize the deletion list
+ o = NULL;
+
+ // Scan whole ARP waiting list
+ for (i = 0;i < LIST_NUM(v->ArpWaitTable);i++)
+ {
+ ARP_WAIT *w = LIST_DATA(v->ArpWaitTable, i);
+
+ if (w->GiveupTime < v->Now || (w->GiveupTime - 100 * 1000) > v->Now)
+ {
+ // Give up the sending of ARP
+ if (o == NULL)
+ {
+ o = NewListFast(NULL);
+ }
+ Add(o, w);
+ }
+ else
+ {
+ if (w->TimeoutTime < v->Now)
+ {
+ // Send an ARP again
+ VirtualArpSendRequest(v, w->IpAddress);
+
+ // Set the next timeout time
+ w->TimeoutTime = v->Now + (UINT64)w->NextTimeoutTimeValue;
+ // Increase the ARP transmission interval of the second and subsequent
+ w->NextTimeoutTimeValue = w->NextTimeoutTimeValue + ARP_REQUEST_TIMEOUT;
+ }
+ }
+ }
+
+ // Remove if there is a ARP waiting record to be deleted
+ if (o != NULL)
+ {
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ ARP_WAIT *w = LIST_DATA(o, i);
+
+ DeleteArpWaitTable(v, w->IpAddress);
+ }
+ ReleaseList(o);
+ }
+}
+
+// Issue an ARP
+void SendArp(VH *v, UINT ip)
+{
+ ARP_WAIT *w;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ // Examine whether the destination IP address has been registered in the ARP waiting list first
+ w = SearchArpWaitTable(v, ip);
+ if (w != NULL)
+ {
+ // Do not do anything because it is already registered
+ return;
+ }
+
+ // Send an ARP packet first
+ VirtualArpSendRequest(v, ip);
+
+ // Register in the ARP waiting list
+ w = ZeroMalloc(sizeof(ARP_WAIT));
+ w->GiveupTime = v->Now + (UINT64)ARP_REQUEST_GIVEUP;
+ w->TimeoutTime = v->Now + (UINT64)ARP_REQUEST_TIMEOUT;
+ w->NextTimeoutTimeValue = ARP_REQUEST_TIMEOUT;
+ w->IpAddress = ip;
+
+ InsertArpWaitTable(v, w);
+}
+
+// Delete the ARP waiting table
+void DeleteArpWaitTable(VH *v, UINT ip)
+{
+ ARP_WAIT *w;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ w = SearchArpWaitTable(v, ip);
+ if (w == NULL)
+ {
+ return;
+ }
+ Delete(v->ArpWaitTable, w);
+
+ Free(w);
+}
+
+// Search the ARP waiting table
+ARP_WAIT *SearchArpWaitTable(VH *v, UINT ip)
+{
+ ARP_WAIT *w, t;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return NULL;
+ }
+
+ t.IpAddress = ip;
+ w = Search(v->ArpWaitTable, &t);
+
+ return w;
+}
+
+// Register in the ARP waiting table
+void InsertArpWaitTable(VH *v, ARP_WAIT *w)
+{
+ // Validate arguments
+ if (v == NULL || w == NULL)
+ {
+ return;
+ }
+
+ Add(v->ArpWaitTable, w);
+}
+
+// Initialize the ARP waiting table
+void InitArpWaitTable(VH *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ v->ArpWaitTable = NewList(CompareArpWaitTable);
+}
+
+// Release the ARP waiting table
+void FreeArpWaitTable(VH *v)
+{
+ UINT i;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(v->ArpWaitTable);i++)
+ {
+ ARP_WAIT *w = LIST_DATA(v->ArpWaitTable, i);
+
+ Free(w);
+ }
+
+ ReleaseList(v->ArpWaitTable);
+}
+
+// Check whether the MAC address is valid
+bool IsMacInvalid(UCHAR *mac)
+{
+ UINT i;
+ // Validate arguments
+ if (mac == NULL)
+ {
+ return false;
+ }
+
+ for (i = 0;i < 6;i++)
+ {
+ if (mac[i] != 0x00)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Check whether the MAC address is a broadcast address
+bool IsMacBroadcast(UCHAR *mac)
+{
+ UINT i;
+ // Validate arguments
+ if (mac == NULL)
+ {
+ return false;
+ }
+
+ for (i = 0;i < 6;i++)
+ {
+ if (mac[i] != 0xff)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Insert an entry in the ARP table
+void InsertArpTable(VH *v, UCHAR *mac, UINT ip)
+{
+ ARP_ENTRY *e, t;
+ // Validate arguments
+ if (v == NULL || mac == NULL || ip == 0 || ip == 0xffffffff || IsMacBroadcast(mac) || IsMacInvalid(mac))
+ {
+ return;
+ }
+
+ // Check whether the same IP address is not already registered
+ t.IpAddress = ip;
+ e = Search(v->ArpTable, &t);
+ if (e != NULL)
+ {
+ // Override this simply because it was registered
+ if (Cmp(e->MacAddress, mac, 6) != 0)
+ {
+ e->Created = v->Now;
+ Copy(e->MacAddress, mac, 6);
+ }
+ e->Expire = v->Now + (UINT64)ARP_ENTRY_EXPIRES;
+ }
+ else
+ {
+ // Create a new entry
+ e = ZeroMalloc(sizeof(ARP_ENTRY));
+
+ e->Created = v->Now;
+ e->Expire = v->Now + (UINT64)ARP_ENTRY_EXPIRES;
+ Copy(e->MacAddress, mac, 6);
+ e->IpAddress = ip;
+
+ Add(v->ArpTable, e);
+ }
+}
+
+// Poll the ARP table
+void PollingArpTable(VH *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ if (v->Now > v->NextArpTablePolling)
+ {
+ v->NextArpTablePolling = v->Now + (UINT64)ARP_ENTRY_POLLING_TIME;
+ RefreshArpTable(v);
+ }
+}
+
+// Remove the old ARP entries
+void RefreshArpTable(VH *v)
+{
+ UINT i;
+ LIST *o;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ o = NewListFast(NULL);
+ for (i = 0;i < LIST_NUM(v->ArpTable);i++)
+ {
+ ARP_ENTRY *e = LIST_DATA(v->ArpTable, i);
+
+ // Check for expired
+ if (e->Expire < v->Now)
+ {
+ // Expired
+ Add(o, e);
+ }
+ }
+
+ // Remove expired entries at once
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ ARP_ENTRY *e = LIST_DATA(o, i);
+
+ Delete(v->ArpTable, e);
+ Free(e);
+ }
+
+ ReleaseList(o);
+}
+
+// Search the ARP table
+ARP_ENTRY *SearchArpTable(VH *v, UINT ip)
+{
+ ARP_ENTRY *e, t;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return NULL;
+ }
+
+ t.IpAddress = ip;
+ e = Search(v->ArpTable, &t);
+
+ return e;
+}
+
+// Initialize the ARP table
+void InitArpTable(VH *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ v->ArpTable = NewList(CompareArpTable);
+}
+
+// Release the ARP table
+void FreeArpTable(VH *v)
+{
+ UINT i;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ // Delete all entries
+ for (i = 0;i < LIST_NUM(v->ArpTable);i++)
+ {
+ ARP_ENTRY *e = LIST_DATA(v->ArpTable, i);
+ Free(e);
+ }
+ ReleaseList(v->ArpTable);
+}
+
+// Comparison of the ARP waiting table entry
+int CompareArpWaitTable(void *p1, void *p2)
+{
+ ARP_WAIT *e1, *e2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ e1 = *(ARP_WAIT **)p1;
+ e2 = *(ARP_WAIT **)p2;
+ if (e1 == NULL || e2 == NULL)
+ {
+ return 0;
+ }
+
+ if (e1->IpAddress > e2->IpAddress)
+ {
+ return 1;
+ }
+ else if (e1->IpAddress < e2->IpAddress)
+ {
+ return -1;
+ }
+ return 0;
+}
+
+// Comparison of the ARP table entry
+int CompareArpTable(void *p1, void *p2)
+{
+ ARP_ENTRY *e1, *e2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ e1 = *(ARP_ENTRY **)p1;
+ e2 = *(ARP_ENTRY **)p2;
+ if (e1 == NULL || e2 == NULL)
+ {
+ return 0;
+ }
+
+ if (e1->IpAddress > e2->IpAddress)
+ {
+ return 1;
+ }
+ else if (e1->IpAddress < e2->IpAddress)
+ {
+ return -1;
+ }
+ return 0;
+}
+
+// Initialize the virtual host
+bool VirtualInit(VH *v)
+{
+ // Initialize the log
+ v->Logger = NULL;
+
+ LockVirtual(v);
+ {
+ // Initialize
+ v->Cancel = NewCancel();
+ v->SendQueue = NewQueue();
+ }
+ UnlockVirtual(v);
+
+ // Counter reset
+ v->Counter->c = 0;
+ v->DhcpId = 0;
+
+ // Initialize the ARP table
+ InitArpTable(v);
+
+ // Initialize the ARP waiting table
+ InitArpWaitTable(v);
+
+ // Initialize the IP waiting table
+ InitIpWaitTable(v);
+
+ // Initialize the IP combining list
+ InitIpCombineList(v);
+
+ // Initialize the NAT
+ InitNat(v);
+
+ // Initialize the DHCP server
+ InitDhcpServer(v);
+
+ // Other initialization
+ v->flag1 = false;
+ v->NextArpTablePolling = Tick64() + (UINT64)ARP_ENTRY_POLLING_TIME;
+ v->CurrentIpQuota = 0;
+ v->Active = true;
+
+ return true;
+}
+bool VirtualPaInit(SESSION *s)
+{
+ VH *v;
+ // Validate arguments
+ if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
+ {
+ return false;
+ }
+
+ return VirtualInit(v);
+}
+
+// Get the cancel object of the virtual host
+CANCEL *VirtualPaGetCancel(SESSION *s)
+{
+ VH *v;
+ // Validate arguments
+ if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
+ {
+ return NULL;
+ }
+
+ AddRef(v->Cancel->ref);
+ return v->Cancel;
+}
+
+// Get the next packet from the virtual host
+UINT VirtualGetNextPacket(VH *v, void **data)
+{
+ UINT ret = 0;
+
+START:
+ // Examine the transmission queue
+ LockQueue(v->SendQueue);
+ {
+ BLOCK *block = GetNext(v->SendQueue);
+
+ if (block != NULL)
+ {
+ // There is a packet
+ ret = block->Size;
+ *data = block->Buf;
+ // Discard the structure
+ Free(block);
+ }
+ }
+ UnlockQueue(v->SendQueue);
+
+ if (ret == 0)
+ {
+ LockVirtual(v);
+ {
+ v->Now = Tick64();
+ // Polling process
+ VirtualPolling(v);
+ }
+ UnlockVirtual(v);
+ if (v->SendQueue->num_item != 0)
+ {
+ goto START;
+ }
+ }
+
+ return ret;
+}
+UINT VirtualPaGetNextPacket(SESSION *s, void **data)
+{
+ VH *v;
+ // Validate arguments
+ if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
+ {
+ return INFINITE;
+ }
+
+ return VirtualGetNextPacket(v, data);
+}
+
+// Polling process (Always called once in a SessionMain loop)
+void VirtualPolling(VH *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ // DHCP polling
+ PollingDhcpServer(v);
+
+ // NAT polling
+ PoolingNat(v);
+
+ // Clear the old ARP table entries
+ PollingArpTable(v);
+
+ // Poll the ARP waiting list
+ PollingArpWaitTable(v);
+
+ // Poll the IP waiting list
+ PollingIpWaitTable(v);
+
+ // Poll the IP combining list
+ PollingIpCombine(v);
+
+ // Beacon transmission procedure
+ PollingBeacon(v);
+}
+
+// Beacon transmission procedure
+void PollingBeacon(VH *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ if (v->LastSendBeacon == 0 ||
+ ((v->LastSendBeacon + BEACON_SEND_INTERVAL) <= Tick64()))
+ {
+ v->LastSendBeacon = Tick64();
+
+ SendBeacon(v);
+ }
+}
+
+// Send a Layer-2 packet
+void VirtualLayer2Send(VH *v, UCHAR *dest_mac, UCHAR *src_mac, USHORT protocol, void *data, UINT size)
+{
+ MAC_HEADER *mac_header;
+ UCHAR *buf;
+ BLOCK *block;
+ // Validate arguments
+ if (v == NULL || dest_mac == NULL || src_mac == NULL || data == NULL || size > (MAX_PACKET_SIZE - sizeof(MAC_HEADER)))
+ {
+ return;
+ }
+
+ // Create buffer
+ buf = Malloc(MAC_HEADER_SIZE + size);
+
+ // MAC header
+ mac_header = (MAC_HEADER *)&buf[0];
+ Copy(mac_header->DestAddress, dest_mac, 6);
+ Copy(mac_header->SrcAddress, src_mac, 6);
+ mac_header->Protocol = Endian16(protocol);
+
+ // Copy data
+ Copy(&buf[sizeof(MAC_HEADER)], data, size);
+
+ // Size
+ size += sizeof(MAC_HEADER);
+
+ // Generate the packet
+ block = NewBlock(buf, size, 0);
+
+ // Insert into the queue
+ LockQueue(v->SendQueue);
+ {
+ InsertQueue(v->SendQueue, block);
+ }
+ UnlockQueue(v->SendQueue);
+
+ // Cancel
+ Cancel(v->Cancel);
+}
+
+// Send an IP packet (with automatic fragmentation)
+void SendIp(VH *v, UINT dest_ip, UINT src_ip, UCHAR protocol, void *data, UINT size)
+{
+ SendIpEx(v, dest_ip, src_ip, protocol, data, size, 0);
+}
+void SendIpEx(VH *v, UINT dest_ip, UINT src_ip, UCHAR protocol, void *data, UINT size, UCHAR ttl)
+{
+ UINT mss;
+ UCHAR *buf;
+ USHORT offset;
+ USHORT id;
+ USHORT total_size;
+ UINT size_of_this_packet;
+ // Validate arguments
+ if (v == NULL || data == NULL || size == 0 || size > MAX_IP_DATA_SIZE_TOTAL)
+ {
+ return;
+ }
+
+ // Maximum segment size
+ mss = v->IpMss;
+
+ // Buffer
+ buf = (UCHAR *)data;
+
+ // ID
+ id = (v->NextId++);
+
+ // Total size
+ total_size = (USHORT)size;
+
+ // Start to split
+ offset = 0;
+
+ while (true)
+ {
+ bool last_packet = false;
+ // Gets the size of this packet
+ size_of_this_packet = MIN((USHORT)mss, (total_size - offset));
+ if ((offset + (USHORT)size_of_this_packet) == total_size)
+ {
+ last_packet = true;
+ }
+
+ // Transmit the fragmented packet
+ SendFragmentedIp(v, dest_ip, src_ip, id,
+ total_size, offset, protocol, buf + offset, size_of_this_packet, NULL, ttl);
+ if (last_packet)
+ {
+ break;
+ }
+
+ offset += (USHORT)size_of_this_packet;
+ }
+}
+
+// Reserve to send the fragmented IP packet
+void SendFragmentedIp(VH *v, UINT dest_ip, UINT src_ip, USHORT id, USHORT total_size, USHORT offset, UCHAR protocol, void *data, UINT size, UCHAR *dest_mac, UCHAR ttl)
+{
+ UCHAR *buf;
+ IPV4_HEADER *ip;
+ ARP_ENTRY *arp;
+ // Validate arguments
+ if (v == NULL || data == NULL || size == 0)
+ {
+ return;
+ }
+
+ // Memory allocation
+ buf = Malloc(size + IP_HEADER_SIZE);
+ ip = (IPV4_HEADER *)&buf[0];
+
+ // IP header construction
+ ip->VersionAndHeaderLength = 0;
+ IPV4_SET_VERSION(ip, 4);
+ IPV4_SET_HEADER_LEN(ip, (IP_HEADER_SIZE / 4));
+ ip->TypeOfService = DEFAULT_IP_TOS;
+ ip->TotalLength = Endian16((USHORT)(size + IP_HEADER_SIZE));
+ ip->Identification = Endian16(id);
+ ip->FlagsAndFlagmentOffset[0] = ip->FlagsAndFlagmentOffset[1] = 0;
+ IPV4_SET_OFFSET(ip, (offset / 8));
+ if ((offset + size) >= total_size)
+ {
+ IPV4_SET_FLAGS(ip, 0x00);
+ }
+ else
+ {
+ IPV4_SET_FLAGS(ip, 0x01);
+ }
+ ip->TimeToLive = (ttl == 0 ? DEFAULT_IP_TTL : ttl);
+ ip->Protocol = protocol;
+ ip->Checksum = 0;
+ ip->SrcIP = src_ip;
+ ip->DstIP = dest_ip;
+
+ // Checksum calculation
+ ip->Checksum = IpChecksum(ip, IP_HEADER_SIZE);
+
+ // Data copy
+ Copy(buf + IP_HEADER_SIZE, data, size);
+
+ if (dest_mac == NULL)
+ {
+ if (ip->DstIP == 0xffffffff ||
+ (IsInNetwork(ip->DstIP, v->HostIP, v->HostMask) && (ip->DstIP & (~v->HostMask)) == (~v->HostMask)))
+ {
+ // Broadcast address
+ dest_mac = broadcast;
+ }
+ else
+ {
+ // Send an ARP query if the destination MAC address is unknown
+ arp = SearchArpTable(v, dest_ip);
+ if (arp != NULL)
+ {
+ dest_mac = arp->MacAddress;
+ }
+ }
+ }
+ if (dest_mac != NULL)
+ {
+ // Send the packet immediately
+ VirtualIpSend(v, dest_mac, buf, size + IP_HEADER_SIZE);
+
+ // Packet data may be released
+ Free(buf);
+ }
+ else
+ {
+ // Because this packet still can not be transferred, add it to the IP waiting table
+ InsertIpWaitTable(v, dest_ip, src_ip, buf, size + IP_HEADER_SIZE);
+
+ // Issue an ARP
+ SendArp(v, dest_ip);
+ }
+}
+
+// Send an IP packet (fragmented)
+void VirtualIpSend(VH *v, UCHAR *dest_mac, void *data, UINT size)
+{
+ // Validate arguments
+ if (v == NULL || dest_mac == NULL || data == NULL || size == 0)
+ {
+ return;
+ }
+
+ // Transmission
+ VirtualLayer2Send(v, dest_mac, v->MacAddress, MAC_PROTO_IPV4, data, size);
+}
+
+// Send an ARP request packet
+void VirtualArpSendRequest(VH *v, UINT dest_ip)
+{
+ ARPV4_HEADER arp;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ // Build the ARP header
+ arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+ arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
+ arp.HardwareSize = 6;
+ arp.ProtocolSize = 4;
+ arp.Operation = Endian16(ARP_OPERATION_REQUEST);
+ Copy(arp.SrcAddress, v->MacAddress, 6);
+ arp.SrcIP = v->HostIP;
+ Zero(&arp.TargetAddress, 6);
+ arp.TargetIP = dest_ip;
+
+ // Transmission
+ VirtualLayer2Send(v, broadcast, v->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(arp));
+}
+
+// Send an ARP response packet
+void VirtualArpSendResponse(VH *v, UCHAR *dest_mac, UINT dest_ip, UINT src_ip)
+{
+ ARPV4_HEADER arp;
+ // Validate arguments
+ if (v == NULL || dest_mac == NULL)
+ {
+ return;
+ }
+
+ // Build the ARP header
+ arp.HardwareType = Endian16(ARP_HARDWARE_TYPE_ETHERNET);
+ arp.ProtocolType = Endian16(MAC_PROTO_IPV4);
+ arp.HardwareSize = 6;
+ arp.ProtocolSize = 4;
+ arp.Operation = Endian16(ARP_OPERATION_RESPONSE);
+ Copy(arp.SrcAddress, v->MacAddress, 6);
+ Copy(arp.TargetAddress, dest_mac, 6);
+ arp.SrcIP = src_ip;
+ arp.TargetIP = dest_ip;
+
+ // Transmission
+ VirtualLayer2Send(v, dest_mac, v->MacAddress, MAC_PROTO_ARPV4, &arp, sizeof(ARPV4_HEADER));
+}
+
+// An ARP request packet was received
+void VirtualArpResponseRequest(VH *v, PKT *packet)
+{
+ ARPV4_HEADER *arp;
+ // Validate arguments
+ if (v == NULL || packet == NULL)
+ {
+ return;
+ }
+
+ arp = packet->L3.ARPv4Header;
+
+ // Memory the information of the host IP address and the MAC address of the other party
+ ArpIpWasKnown(v, arp->SrcIP, arp->SrcAddress);
+
+ // Search whether it matches with the IP address of this host
+ if (v->HostIP == arp->TargetIP)
+ {
+ // Respond since the match
+ VirtualArpSendResponse(v, arp->SrcAddress, arp->SrcIP, v->HostIP);
+ return;
+ }
+ // Do nothing if it doesn't match
+}
+
+// An ARP response packet is received
+void VirtualArpResponseReceived(VH *v, PKT *packet)
+{
+ ARPV4_HEADER *arp;
+ // Validate arguments
+ if (v == NULL || packet == NULL)
+ {
+ return;
+ }
+
+ arp = packet->L3.ARPv4Header;
+
+ // Regard this information as known information
+ ArpIpWasKnown(v, arp->SrcIP, arp->SrcAddress);
+}
+
+// Received an ARP packet
+void VirtualArpReceived(VH *v, PKT *packet)
+{
+ ARPV4_HEADER *arp;
+ // Validate arguments
+ if (v == NULL || packet == NULL)
+ {
+ return;
+ }
+
+ arp = packet->L3.ARPv4Header;
+
+ if (Endian16(arp->HardwareType) != ARP_HARDWARE_TYPE_ETHERNET)
+ {
+ // Ignore if hardware type is other than Ethernet
+ return;
+ }
+ if (Endian16(arp->ProtocolType) != MAC_PROTO_IPV4)
+ {
+ // Ignore if the protocol type is a non-IPv4
+ return;
+ }
+ if (arp->HardwareSize != 6 || arp->ProtocolSize != 4)
+ {
+ // Ignore because the size of protocol address or hardware address is invalid
+ return;
+ }
+ // Check the source MAC address
+ if (Cmp(arp->SrcAddress, packet->MacAddressSrc, 6) != 0)
+ {
+ // MAC address in the MAC header and the MAC address of the ARP packet are different
+ return;
+ }
+
+ switch (Endian16(arp->Operation))
+ {
+ case ARP_OPERATION_REQUEST: // ARP request
+ VirtualArpResponseRequest(v, packet);
+ break;
+
+ case ARP_OPERATION_RESPONSE: // ARP response
+ VirtualArpResponseReceived(v, packet);
+ break;
+ }
+}
+
+// Release the DHCP server
+void FreeDhcpServer(VH *v)
+{
+ UINT i;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ // Remove the all lease entries
+ for (i = 0;i < LIST_NUM(v->DhcpLeaseList);i++)
+ {
+ DHCP_LEASE *d = LIST_DATA(v->DhcpLeaseList, i);
+ FreeDhcpLease(d);
+ }
+
+ ReleaseList(v->DhcpLeaseList);
+ v->DhcpLeaseList = NULL;
+}
+
+// Initialize the DHCP server
+void InitDhcpServer(VH *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ // Create a list
+ v->DhcpLeaseList = NewList(CompareDhcpLeaseList);
+}
+
+// Search for a DHCP lease item by the IP address
+DHCP_LEASE *SearchDhcpLeaseByIp(VH *v, UINT ip)
+{
+ UINT i;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(v->DhcpLeaseList);i++)
+ {
+ DHCP_LEASE *d = LIST_DATA(v->DhcpLeaseList, i);
+ if (d->IpAddress == ip)
+ {
+ return d;
+ }
+ }
+
+ return NULL;
+}
+
+// Search for a DHCP lease item by the MAC address
+DHCP_LEASE *SearchDhcpLeaseByMac(VH *v, UCHAR *mac)
+{
+ DHCP_LEASE *d, t;
+ // Validate arguments
+ if (v == NULL || mac == NULL)
+ {
+ return NULL;
+ }
+
+ Copy(&t.MacAddress, mac, 6);
+ d = Search(v->DhcpLeaseList, &t);
+
+ return d;
+}
+
+// Release the DHCP lease item
+void FreeDhcpLease(DHCP_LEASE *d)
+{
+ // Validate arguments
+ if (d == NULL)
+ {
+ return;
+ }
+
+ Free(d->Hostname);
+ Free(d);
+}
+
+// Create a DHCP lease item
+DHCP_LEASE *NewDhcpLease(UINT expire, UCHAR *mac_address, UINT ip, UINT mask, char *hostname)
+{
+ DHCP_LEASE *d;
+ // Validate arguments
+ if (mac_address == NULL || hostname == NULL)
+ {
+ return NULL;
+ }
+
+ d = ZeroMalloc(sizeof(DHCP_LEASE));
+ d->LeasedTime = (UINT64)Tick64();
+ if (expire == INFINITE)
+ {
+ d->ExpireTime = INFINITE;
+ }
+ else
+ {
+ d->ExpireTime = d->LeasedTime + (UINT64)expire;
+ }
+ d->IpAddress = ip;
+ d->Mask = mask;
+ d->Hostname = CopyStr(hostname);
+ Copy(d->MacAddress, mac_address, 6);
+
+
+ return d;
+}
+
+// Comparison of the items in the DHCP list
+int CompareDhcpLeaseList(void *p1, void *p2)
+{
+ DHCP_LEASE *d1, *d2;
+ // Validate arguments
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ d1 = *(DHCP_LEASE **)p1;
+ d2 = *(DHCP_LEASE **)p2;
+ if (d1 == NULL || d2 == NULL)
+ {
+ return 0;
+ }
+
+ return Cmp(d1->MacAddress, d2->MacAddress, 6);
+}
+
+// Poll the DHCP server
+void PollingDhcpServer(VH *v)
+{
+ UINT i;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ if (v->LastDhcpPolling != 0)
+ {
+ if ((v->LastDhcpPolling + (UINT64)DHCP_POLLING_INTERVAL) > v->Now &&
+ v->LastDhcpPolling < v->Now)
+ {
+ return;
+ }
+ }
+ v->LastDhcpPolling = v->Now;
+
+ // Remove expired entries
+FIRST_LIST:
+ for (i = 0;i < LIST_NUM(v->DhcpLeaseList);i++)
+ {
+ DHCP_LEASE *d = LIST_DATA(v->DhcpLeaseList, i);
+
+ if (d->ExpireTime < v->Now)
+ {
+ FreeDhcpLease(d);
+ Delete(v->DhcpLeaseList, d);
+ goto FIRST_LIST;
+ }
+ }
+}
+
+// Correspond to the DHCP REQUEST
+UINT ServeDhcpRequest(VH *v, UCHAR *mac, UINT request_ip)
+{
+ UINT ret;
+ // Validate arguments
+ if (v == NULL || mac == NULL)
+ {
+ return 0;
+ }
+
+ ret = ServeDhcpDiscover(v, mac, request_ip);
+ if (ret != request_ip)
+ {
+ if (request_ip != 0)
+ {
+ // Raise an error if the requested IP address cannot to be assigned
+ return 0;
+ }
+ }
+
+ return ret;
+}
+
+// Correspond to the DHCP DISCOVER
+UINT ServeDhcpDiscover(VH *v, UCHAR *mac, UINT request_ip)
+{
+ UINT ret = 0;
+ // Validate arguments
+ if (v == NULL || mac == NULL)
+ {
+ return 0;
+ }
+
+ if (request_ip != 0)
+ {
+ // IP address is specified
+ DHCP_LEASE *d = SearchDhcpLeaseByIp(v, request_ip);
+ if (d != NULL)
+ {
+ // If an entry for the same IP address already exists,
+ // check whether it is a request from the same MAC address
+ if (Cmp(mac, d->MacAddress, 6) == 0)
+ {
+ // Examine whether the specified IP address is within the range of assignment
+ if (Endian32(v->DhcpIpStart) <= Endian32(request_ip) &&
+ Endian32(request_ip) <= Endian32(v->DhcpIpEnd))
+ {
+ // Accept if within the range
+ ret = request_ip;
+ }
+ }
+ }
+ else
+ {
+ // Examine whether the specified IP address is within the range of assignment
+ if (Endian32(v->DhcpIpStart) <= Endian32(request_ip) &&
+ Endian32(request_ip) <= Endian32(v->DhcpIpEnd))
+ {
+ // Accept if within the range
+ ret = request_ip;
+ }
+ else
+ {
+ // Propose an IP in the range since it's a Discover although It is out of range
+ }
+ }
+ }
+
+ if (ret == 0)
+ {
+ // If there is any entry with the same MAC address
+ // that are already registered, use it with priority
+ DHCP_LEASE *d = SearchDhcpLeaseByMac(v, mac);
+ if (d != NULL)
+ {
+ // Examine whether the found IP address is in the allocation region
+ if (Endian32(v->DhcpIpStart) <= Endian32(d->IpAddress) &&
+ Endian32(d->IpAddress) <= Endian32(v->DhcpIpEnd))
+ {
+ // Use the IP address if it's found within the range
+ ret = d->IpAddress;
+ }
+ }
+ }
+
+ if (ret == 0)
+ {
+ // Take an appropriate IP addresses that can be assigned newly
+ ret = GetFreeDhcpIpAddress(v);
+ }
+
+ return ret;
+}
+
+// Take an appropriate IP addresses that can be assigned newly
+UINT GetFreeDhcpIpAddress(VH *v)
+{
+ UINT ip_start, ip_end;
+ UINT i;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return 0;
+ }
+
+ ip_start = Endian32(v->DhcpIpStart);
+ ip_end = Endian32(v->DhcpIpEnd);
+
+ for (i = ip_start; i <= ip_end;i++)
+ {
+ UINT ip = Endian32(i);
+ if (SearchDhcpLeaseByIp(v, ip) == NULL)
+ {
+ // A free IP address is found
+ return ip;
+ }
+ }
+
+ // There is no free address
+ return 0;
+}
+
+// Virtual DHCP Server
+void VirtualDhcpServer(VH *v, PKT *p)
+{
+ DHCPV4_HEADER *dhcp;
+ UCHAR *data;
+ UINT size;
+ UINT dhcp_header_size;
+ UINT dhcp_data_offset;
+ UINT tran_id;
+ UINT magic_cookie = Endian32(DHCP_MAGIC_COOKIE);
+ bool ok;
+ DHCP_OPTION_LIST *opt;
+ // Validate arguments
+ if (v == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (v->NativeNat != NULL)
+ {
+ if (Cmp(p->MacAddressSrc, v->NativeNat->CurrentMacAddress, 6) == 0)
+ {
+ // DHCP server is kept from responding for the native NAT interface
+ // ** Not be needed to return yet **
+ //return;
+ }
+ }
+
+ dhcp = p->L7.DHCPv4Header;
+
+ tran_id = Endian32(dhcp->TransactionId);
+
+ // Get the DHCP data and size
+ dhcp_header_size = sizeof(DHCPV4_HEADER);
+ dhcp_data_offset = (UINT)(((UCHAR *)p->L7.DHCPv4Header) - ((UCHAR *)p->MacHeader) + dhcp_header_size);
+ data = ((UCHAR *)dhcp) + dhcp_header_size;
+ size = p->PacketSize - dhcp_data_offset;
+ if (dhcp_header_size < 5)
+ {
+ // Data size is invalid
+ return;
+ }
+
+ // Search for Magic Cookie
+ ok = false;
+ while (size >= 5)
+ {
+ if (Cmp(data, &magic_cookie, sizeof(magic_cookie)) == 0)
+ {
+ // Found
+ data += 4;
+ size -= 4;
+ ok = true;
+ break;
+ }
+ data++;
+ size--;
+ }
+
+ if (ok == false)
+ {
+ // The packet is invalid
+ return;
+ }
+
+ // Parse DHCP options list
+ opt = ParseDhcpOptionList(data, size);
+ if (opt == NULL)
+ {
+ // The packet is invalid
+ return;
+ }
+
+ if (StartWith(opt->Hostname, NN_HOSTNAME_STARTWITH))
+ {
+ Free(opt);
+ return;
+ }
+
+ if (dhcp->OpCode == 1 && (opt->Opcode == DHCP_DISCOVER || opt->Opcode == DHCP_REQUEST || opt->Opcode == DHCP_INFORM))
+ {
+ // Operate as the server
+ UINT ip = 0;
+
+ if (opt->RequestedIp == 0)
+ {
+ opt->RequestedIp = p->L3.IPv4Header->SrcIP;
+ }
+ if (opt->Opcode == DHCP_DISCOVER)
+ {
+ // Return an IP address that can be used
+ ip = ServeDhcpDiscover(v, p->MacAddressSrc, opt->RequestedIp);
+ }
+ else if (opt->Opcode == DHCP_REQUEST)
+ {
+ // Determine the IP address
+ ip = ServeDhcpRequest(v, p->MacAddressSrc, opt->RequestedIp);
+ }
+
+ if (ip != 0 || opt->Opcode == DHCP_INFORM)
+ {
+ // Respond if there is providable IP address
+
+ if (opt->Opcode == DHCP_REQUEST)
+ {
+ DHCP_LEASE *d;
+ char mac[MAX_SIZE];
+ char str[MAX_SIZE];
+ // Remove old records with the same IP address
+ d = SearchDhcpLeaseByIp(v, ip);
+ if (d != NULL)
+ {
+ FreeDhcpLease(d);
+ Delete(v->DhcpLeaseList, d);
+ }
+
+ // Create a new entry
+ d = NewDhcpLease(v->DhcpExpire, p->MacAddressSrc,
+ ip, v->DhcpMask,
+ opt->Hostname);
+ d->Id = ++v->DhcpId;
+ Add(v->DhcpLeaseList, d);
+ MacToStr(mac, sizeof(mac), d->MacAddress);
+
+ IPToStr32(str, sizeof(str), d->IpAddress);
+
+ NLog(v, "LH_NAT_DHCP_CREATED", d->Id, mac, str, d->Hostname, v->DhcpExpire / 1000);
+ }
+
+ // Respond
+ if (true)
+ {
+ DHCP_OPTION_LIST ret;
+ LIST *o;
+ Zero(&ret, sizeof(ret));
+
+ ret.Opcode = (opt->Opcode == DHCP_DISCOVER ? DHCP_OFFER : DHCP_ACK);
+ ret.ServerAddress = v->HostIP;
+ if (v->DhcpExpire == INFINITE)
+ {
+ ret.LeaseTime = INFINITE;
+ }
+ else
+ {
+ ret.LeaseTime = Endian32(v->DhcpExpire / 1000);
+ }
+
+ if (opt->Opcode == DHCP_INFORM)
+ {
+ ret.LeaseTime = 0;
+ }
+
+ StrCpy(ret.DomainName, sizeof(ret.DomainName), v->DhcpDomain);
+ ret.SubnetMask = v->DhcpMask;
+ ret.DnsServer = v->DhcpDns;
+ ret.DnsServer2 = v->DhcpDns2;
+ ret.Gateway = v->DhcpGateway;
+
+ if (opt->Opcode != DHCP_INFORM)
+ {
+ char client_mac[MAX_SIZE];
+ char client_ip[64];
+ IP ips;
+ BinToStr(client_mac, sizeof(client_mac), p->MacAddressSrc, 6);
+ UINTToIP(&ips, ip);
+ IPToStr(client_ip, sizeof(client_ip), &ips);
+ Debug("DHCP %s : %s given %s\n",
+ ret.Opcode == DHCP_OFFER ? "DHCP_OFFER" : "DHCP_ACK",
+ client_mac, client_ip);
+ }
+
+ // Build a DHCP option
+ o = BuildDhcpOption(&ret);
+ if (o != NULL)
+ {
+ BUF *b = BuildDhcpOptionsBuf(o);
+ if (b != NULL)
+ {
+ UINT dest_ip = p->L3.IPv4Header->SrcIP;
+ if (dest_ip == 0)
+ {
+ dest_ip = 0xffffffff;
+ }
+ // Transmission
+ VirtualDhcpSend(v, tran_id, dest_ip, Endian16(p->L4.UDPHeader->SrcPort),
+ ip, dhcp->ClientMacAddress, b, dhcp->HardwareType, dhcp->HardwareAddressSize);
+
+ // Release the memory
+ FreeBuf(b);
+ }
+ FreeDhcpOptions(o);
+ }
+ }
+ }
+ else
+ {
+ // There is no IP address that can be provided
+ DHCP_OPTION_LIST ret;
+ LIST *o;
+ Zero(&ret, sizeof(ret));
+
+ ret.Opcode = DHCP_NACK;
+ ret.ServerAddress = v->HostIP;
+ StrCpy(ret.DomainName, sizeof(ret.DomainName), v->DhcpDomain);
+ ret.SubnetMask = v->DhcpMask;
+
+ // Build the DHCP option
+ o = BuildDhcpOption(&ret);
+ if (o != NULL)
+ {
+ BUF *b = BuildDhcpOptionsBuf(o);
+ if (b != NULL)
+ {
+ UINT dest_ip = p->L3.IPv4Header->SrcIP;
+ if (dest_ip == 0)
+ {
+ dest_ip = 0xffffffff;
+ }
+ // Transmission
+ VirtualDhcpSend(v, tran_id, dest_ip, Endian16(p->L4.UDPHeader->SrcPort),
+ ip, dhcp->ClientMacAddress, b, dhcp->HardwareType, dhcp->HardwareAddressSize);
+
+ // Release the memory
+ FreeBuf(b);
+ }
+ FreeDhcpOptions(o);
+ }
+ }
+ }
+
+ // Release the memory
+ Free(opt);
+}
+
+// Submit the DHCP response packet
+void VirtualDhcpSend(VH *v, UINT tran_id, UINT dest_ip, UINT dest_port,
+ UINT new_ip, UCHAR *client_mac, BUF *b, UINT hw_type, UINT hw_addr_size)
+{
+ UINT blank_size = 128 + 64;
+ UINT dhcp_packet_size;
+ UINT magic = Endian32(DHCP_MAGIC_COOKIE);
+ DHCPV4_HEADER *dhcp;
+ void *magic_cookie_addr;
+ void *buffer_addr;
+ // Validate arguments
+ if (v == NULL || b == NULL)
+ {
+ return;
+ }
+
+ // Calculate the DHCP packet size
+ dhcp_packet_size = blank_size + sizeof(DHCPV4_HEADER) + sizeof(magic) + b->Size;
+
+ if (dhcp_packet_size < DHCP_MIN_SIZE)
+ {
+ // Padding
+ dhcp_packet_size = DHCP_MIN_SIZE;
+ }
+
+ // Create a header
+ dhcp = ZeroMalloc(dhcp_packet_size);
+
+ dhcp->OpCode = 2;
+ dhcp->HardwareType = hw_type;
+ dhcp->HardwareAddressSize = hw_addr_size;
+ dhcp->Hops = 0;
+ dhcp->TransactionId = Endian32(tran_id);
+ dhcp->Seconds = 0;
+ dhcp->Flags = 0;
+ dhcp->YourIP = new_ip;
+ dhcp->ServerIP = v->HostIP;
+ Copy(dhcp->ClientMacAddress, client_mac, 6);
+
+ // Calculate the address
+ magic_cookie_addr = (((UCHAR *)dhcp) + sizeof(DHCPV4_HEADER) + blank_size);
+ buffer_addr = ((UCHAR *)magic_cookie_addr) + sizeof(magic);
+
+ // Magic Cookie
+ Copy(magic_cookie_addr, &magic, sizeof(magic));
+
+ // Buffer
+ Copy(buffer_addr, b->Buf, b->Size);
+
+ // Transmission
+ SendUdp(v, dest_ip, dest_port, v->HostIP, NAT_DHCP_SERVER_PORT, dhcp, dhcp_packet_size);
+
+ Free(dhcp);
+}
+
+// Virtual host: Process the Layer2
+void VirtualLayer2(VH *v, PKT *packet)
+{
+ bool ok;
+ // Validate arguments
+ if (packet == NULL || v == NULL)
+ {
+ return;
+ }
+
+ // Packet filter
+ if (VirtualLayer2Filter(v, packet) == false)
+ {
+ // Packet was ignored
+ return;
+ }
+
+ ok = false;
+ if (packet->TypeL3 == L3_IPV4 && packet->TypeL4 == L4_UDP && packet->TypeL7 == L7_DHCPV4)
+ {
+ if (v->UseDhcp)
+ {
+ // A special treatment on the DHCP packet
+ if (packet->BroadcastPacket || Cmp(packet->MacAddressDest, v->MacAddress, 6) == 0)
+ {
+ // Virtual DHCP server processing
+ VirtualDhcpServer(v, packet);
+ ok = true;
+ }
+ }
+ }
+
+ if (ok == false)
+ {
+ // The process for each supported protocol
+ switch (packet->TypeL3)
+ {
+ case L3_ARPV4: // ARPv4
+ VirtualArpReceived(v, packet);
+ break;
+
+ case L3_IPV4: // IPv4
+ VirtualIpReceived(v, packet);
+ break;
+ }
+ }
+}
+
+// Packet filter (Blocking packets to other than me)
+bool VirtualLayer2Filter(VH *v, PKT *packet)
+{
+ // Validate arguments
+ if (v == NULL || packet == NULL)
+ {
+ return false;
+ }
+
+ // Pass through if broadcast packet
+ if (packet->BroadcastPacket)
+ {
+ return true;
+ }
+
+ // Ignore if the sender of the packet is myself
+ if (Cmp(packet->MacAddressSrc, v->MacAddress, 6) == 0)
+ {
+ return false;
+ }
+ // Pass through in the case of a packet addressed to me
+ if (Cmp(packet->MacAddressDest, v->MacAddress, 6) == 0)
+ {
+ return true;
+ }
+
+ // Discard if the other packets
+ return false;
+}
+
+// The virtual host is made to receive a packet
+bool VirtualPutPacket(VH *v, void *data, UINT size)
+{
+ if (data == NULL)
+ {
+ // Flush
+ v->flag1 = false;
+
+ if (v->NativeNat != NULL)
+ {
+ if (v->NativeNat->SendStateChanged)
+ {
+ TUBE *halt_tube = NULL;
+
+ Lock(v->NativeNat->Lock);
+ {
+ if (v->NativeNat->HaltTube != NULL)
+ {
+ halt_tube = v->NativeNat->HaltTube;
+
+ AddRef(halt_tube->Ref);
+ }
+ }
+ Unlock(v->NativeNat->Lock);
+
+ if (halt_tube != NULL)
+ {
+ TubeFlushEx(halt_tube, true);
+
+ v->NativeNat->SendStateChanged = false;
+
+ ReleaseTube(halt_tube);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Interpret the received packet
+ PKT *packet = ParsePacket(data, size);
+
+ if (v->flag1 == false)
+ {
+ v->flag1 = true;
+ v->Now = Tick64();
+ }
+
+ // Lock the entire virtual machine in here
+ LockVirtual(v);
+ {
+ if (packet != NULL)
+ {
+ // Process the Layer-2
+ VirtualLayer2(v, packet);
+
+ // Release the packet structure
+ FreePacket(packet);
+ }
+ }
+ UnlockVirtual(v);
+
+ Free(data);
+ }
+
+ return true;
+}
+bool VirtualPaPutPacket(SESSION *s, void *data, UINT size)
+{
+ VH *v;
+ // Validate arguments
+ if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
+ {
+ return false;
+ }
+
+ return VirtualPutPacket(v, data, size);
+}
+
+// Get the options for the virtual host
+void GetVirtualHostOption(VH *v, VH_OPTION *o)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ LockVirtual(v);
+ {
+ Zero(o, sizeof(VH_OPTION));
+
+ // MAC address
+ Copy(o->MacAddress, v->MacAddress, 6);
+
+ // Host information
+ UINTToIP(&o->Ip, v->HostIP);
+ UINTToIP(&o->Mask, v->HostMask);
+
+ o->Mtu = v->Mtu;
+
+ // NAT timeout information
+ o->NatTcpTimeout = v->NatTcpTimeout / 1000;
+ o->NatUdpTimeout = v->NatUdpTimeout / 1000;
+
+ // NAT using flag
+ o->UseNat = v->UseNat;
+
+ // DHCP using flag
+ o->UseDhcp = v->UseDhcp;
+
+ // IP address range for DHCP distribution
+ UINTToIP(&o->DhcpLeaseIPStart, v->DhcpIpStart);
+ UINTToIP(&o->DhcpLeaseIPEnd, v->DhcpIpEnd);
+
+ // Subnet mask
+ UINTToIP(&o->DhcpSubnetMask, v->DhcpMask);
+
+ // Expiration date
+ if (v->DhcpExpire != INFINITE)
+ {
+ o->DhcpExpireTimeSpan = v->DhcpExpire / 1000;
+ }
+ else
+ {
+ o->DhcpExpireTimeSpan = INFINITE;
+ }
+
+ // Gateway address
+ UINTToIP(&o->DhcpGatewayAddress, v->DhcpGateway);
+
+ // DNS server address
+ UINTToIP(&o->DhcpDnsServerAddress, v->DhcpDns);
+ UINTToIP(&o->DhcpDnsServerAddress2, v->DhcpDns2);
+
+ // Domain name
+ StrCpy(o->DhcpDomainName, sizeof(o->DhcpDomainName), v->DhcpDomain);
+
+ // Save a log
+ o->SaveLog = v->SaveLog;
+ }
+ UnlockVirtual(v);
+}
+
+// Set the option to the virtual host
+void SetVirtualHostOption(VH *v, VH_OPTION *vo)
+{
+ UINT i;
+ // Validate arguments
+ if (v == NULL || vo == NULL)
+ {
+ return;
+ }
+
+ LockVirtual(v);
+ {
+ // Set the MAC address
+ for (i = 0;i < 6;i++)
+ {
+ if (vo->MacAddress[i] != 0)
+ {
+ Copy(v->MacAddress, vo->MacAddress, 6);
+ break;
+ }
+ }
+
+ // Set the host information list
+ v->HostIP = IPToUINT(&vo->Ip);
+ v->HostMask = IPToUINT(&vo->Mask);
+
+ // Set the MTU, MMS
+ v->Mtu = MIN(vo->Mtu, MAX_L3_DATA_SIZE);
+ if (v->Mtu == 0)
+ {
+ v->Mtu = MAX_L3_DATA_SIZE;
+ }
+ v->Mtu = MAX(v->Mtu, TCP_HEADER_SIZE + IP_HEADER_SIZE + MAC_HEADER_SIZE + 8);
+ v->IpMss = ((v->Mtu - IP_HEADER_SIZE) / 8) * 8;
+ v->TcpMss = ((v->IpMss - TCP_HEADER_SIZE) / 8) * 8;
+ v->UdpMss = ((v->IpMss - UDP_HEADER_SIZE) / 8) * 8;
+
+ if (vo->NatTcpTimeout != 0)
+ {
+ v->NatTcpTimeout = MIN(vo->NatTcpTimeout, 4000000) * 1000;
+ }
+ if (vo->NatUdpTimeout != 0)
+ {
+ v->NatUdpTimeout = MIN(vo->NatUdpTimeout, 4000000) * 1000;
+ }
+ v->NatTcpTimeout = MAKESURE(v->NatTcpTimeout, NAT_TCP_MIN_TIMEOUT, NAT_TCP_MAX_TIMEOUT);
+ v->NatUdpTimeout = MAKESURE(v->NatUdpTimeout, NAT_UDP_MIN_TIMEOUT, NAT_UDP_MAX_TIMEOUT);
+ Debug("Timeout: %d , %d\n", v->NatTcpTimeout, v->NatUdpTimeout);
+
+ // NAT using flag
+ v->UseNat = vo->UseNat;
+
+ // DHCP using flag
+ v->UseDhcp = vo->UseDhcp;
+
+ // Expiration date
+ if (vo->DhcpExpireTimeSpan == 0 || vo->DhcpExpireTimeSpan == INFINITE)
+ {
+ v->DhcpExpire = INFINITE;
+ }
+ else
+ {
+ v->DhcpExpire = MAKESURE(DHCP_MIN_EXPIRE_TIMESPAN,
+ MIN(vo->DhcpExpireTimeSpan * 1000, 2000000000),
+ INFINITE);
+ }
+
+ // Address range to be distributed
+ v->DhcpIpStart = IPToUINT(&vo->DhcpLeaseIPStart);
+ v->DhcpIpEnd = IPToUINT(&vo->DhcpLeaseIPEnd);
+ if (Endian32(v->DhcpIpEnd) < Endian32(v->DhcpIpStart))
+ {
+ v->DhcpIpEnd = v->DhcpIpStart;
+ }
+
+ // Subnet mask
+ v->DhcpMask = IPToUINT(&vo->DhcpSubnetMask);
+
+ // Gateway address
+ v->DhcpGateway = IPToUINT(&vo->DhcpGatewayAddress);
+
+ // DNS server address
+ v->DhcpDns = IPToUINT(&vo->DhcpDnsServerAddress);
+ v->DhcpDns2 = IPToUINT(&vo->DhcpDnsServerAddress2);
+
+ // Domain name
+ StrCpy(v->DhcpDomain, sizeof(v->DhcpDomain), vo->DhcpDomainName);
+
+ // Save a log
+ v->SaveLog = vo->SaveLog;
+ }
+ UnlockVirtual(v);
+}
+
+// Release the virtual host
+void Virtual_Free(VH *v)
+{
+ // Release the DHCP server
+ FreeDhcpServer(v);
+
+ // NAT release
+ FreeNat(v);
+
+ LockVirtual(v);
+ {
+ // Release the IP combining list
+ FreeIpCombineList(v);
+
+ // Release the IP waiting table
+ FreeIpWaitTable(v);
+
+ // Release the ARP waiting table
+ FreeArpWaitTable(v);
+
+ // Release the ARP table
+ FreeArpTable(v);
+
+ // Release the transmission queue
+ LockQueue(v->SendQueue);
+ {
+ BLOCK *block;
+
+ // Release all queues
+ while (block = GetNext(v->SendQueue))
+ {
+ FreeBlock(block);
+ }
+ }
+ UnlockQueue(v->SendQueue);
+ ReleaseQueue(v->SendQueue);
+ v->SendQueue = NULL;
+
+ // Release the cancel object
+ ReleaseCancel(v->Cancel);
+
+ v->Active = false;
+ }
+ UnlockVirtual(v);
+
+ // Release the logger
+ FreeLog(v->Logger);
+}
+void VirtualPaFree(SESSION *s)
+{
+ VH *v;
+ // Validate arguments
+ if (s == NULL || (v = (VH *)s->PacketAdapter->Param) == NULL)
+ {
+ return;
+ }
+
+ Virtual_Free(v);
+}
+
+// Release the virtual host
+void ReleaseVirtual(VH *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ if (Release(v->ref) == 0)
+ {
+ CleanupVirtual(v);
+ }
+}
+
+// Lock the virtual host
+void LockVirtual(VH *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ Lock(v->lock);
+}
+
+// Unlock the virtual host
+void UnlockVirtual(VH *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ Unlock(v->lock);
+}
+
+// Cleanup the virtual host
+void CleanupVirtual(VH *v)
+{
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ if (v->Session != NULL)
+ {
+ ReleaseSession(v->Session);
+ }
+
+ DeleteCounter(v->Counter);
+ DeleteLock(v->lock);
+
+ Free(v);
+}
+
+// Stop the virtual host
+void StopVirtualHost(VH *v)
+{
+ SESSION *s;
+ // Validate arguments
+ if (v == NULL)
+ {
+ return;
+ }
+
+ // Get the session corresponding to the virtual host
+ LockVirtual(v);
+ {
+ s = v->Session;
+ if (s != NULL)
+ {
+ AddRef(s->ref);
+ }
+ }
+ UnlockVirtual(v);
+
+ if (s == NULL)
+ {
+ // This session is already stopped
+ return;
+ }
+
+ // Stop Session
+ StopSession(s);
+
+ ReleaseSession(s);
+}
+
+// Create a new virtual host
+VH *NewVirtualHost(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, VH_OPTION *vh_option)
+{
+ return NewVirtualHostEx(cedar, option, auth, vh_option, NULL);
+}
+VH *NewVirtualHostEx(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, VH_OPTION *vh_option, NAT *nat)
+{
+ VH *v;
+ SOCK *s;
+ // Validate arguments
+ if (vh_option == NULL)
+ {
+ return NULL;
+ }
+
+ // Create a VH
+ v = ZeroMalloc(sizeof(VH));
+ v->ref = NewRef();
+ v->lock = NewLock();
+ v->Counter = NewCounter();
+
+ v->nat = nat;
+
+ // Examine whether ICMP Raw Socket can be created
+ s = NewUDP4(MAKE_SPECIAL_PORT(IP_PROTO_ICMPV4), NULL);
+ if (s != NULL)
+ {
+ if (s->IsTtlSupported)
+ {
+ v->IcmpRawSocketOk = true;
+ }
+
+ ReleaseSock(s);
+ }
+
+ if (v->IcmpRawSocketOk == false)
+ {
+ if (IsIcmpApiSupported())
+ {
+ v->IcmpApiOk = true;
+ }
+ }
+
+ // Set the options
+ SetVirtualHostOption(v, vh_option);
+
+ return v;
+}
+
+// Generate a random MAC address
+void GenMacAddress(UCHAR *mac)
+{
+ UCHAR rand_data[32];
+ UINT64 now;
+ BUF *b;
+ UCHAR hash[SHA1_SIZE];
+ // Validate arguments
+ if (mac == NULL)
+ {
+ return;
+ }
+
+ // Get the current time
+ now = SystemTime64();
+
+ // Generate a random number
+ Rand(rand_data, sizeof(rand_data));
+
+ // Add to the buffer
+ b = NewBuf();
+ WriteBuf(b, &now, sizeof(now));
+ WriteBuf(b, rand_data, sizeof(rand_data));
+
+ // Hash
+ Hash(hash, b->Buf, b->Size, true);
+
+ // Generate a MAC address
+ mac[0] = 0x00;
+ mac[1] = 0xAC; // AC hurray
+ mac[2] = hash[0];
+ mac[3] = hash[1];
+ mac[4] = hash[2];
+ mac[5] = hash[3];
+
+ FreeBuf(b);
+}
+
+// Get a packet of virtual host adapter
+PACKET_ADAPTER *VirtualGetPacketAdapter()
+{
+ return NewPacketAdapter(VirtualPaInit, VirtualPaGetCancel,
+ VirtualPaGetNextPacket, VirtualPaPutPacket, VirtualPaFree);
+}
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Virtual.h b/src/Cedar/Virtual.h
new file mode 100644
index 00000000..ff7be8a8
--- /dev/null
+++ b/src/Cedar/Virtual.h
@@ -0,0 +1,659 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Virtual.h
+// Header of Virtual.c
+
+#ifndef VIRTUAL_H
+#define VIRTUAL_H
+
+
+#define VIRTUAL_TCP_SEND_TIMEOUT (21 * 1000)
+
+#define NN_NEXT_WAIT_TIME_FOR_DEVICE_ENUM (60 * 1000)
+#define NN_NEXT_WAIT_TIME_MAX_FAIL_COUNT 15
+
+#define NN_HOSTNAME_FORMAT "securenat_%s"
+#define NN_HOSTNAME_STARTWITH "securenat_"
+#define NN_CHECK_CONNECTIVITY_TIMEOUT (5 * 1000)
+#define NN_CHECK_CONNECTIVITY_INTERVAL (1 * 1000)
+
+#define NN_POLL_CONNECTIVITY_TIMEOUT (4 * 60 * 1000 + 10)
+#define NN_POLL_CONNECTIVITY_INTERVAL (1 * 60 * 1000)
+
+#define NN_MAX_QUEUE_LENGTH 10000
+#define NN_NO_NATIVE_NAT_FILENAME L"@no_native_nat_niclist.txt"
+
+#define NN_TIMEOUT_FOR_UNESTBALISHED_TCP (10 * 1000) // Time-out period of a TCP connection incomplete session
+
+// Destination host name of the connectivity test for the Internet
+// (Access the www.yahoo.com. Access the www.baidu.com from China. I am sorry.)
+#define NN_CHECK_HOSTNAME (IsEmptyStr(secure_nat_target_hostname) ? (IsUseAlternativeHostname() ? "www.baidu.com" : "www.yahoo.com") : secure_nat_target_hostname)
+
+
+// Native NAT entry
+struct NATIVE_NAT_ENTRY
+{
+ UINT Id; // ID
+ UINT Status; // Status
+ UINT Protocol; // Protocol
+ UINT SrcIp; // Source IP address
+ UINT SrcPort; // Source port number
+ UINT DestIp; // Destination IP address
+ UINT DestPort; // Destination port number
+ UINT PublicIp; // Public IP address
+ UINT PublicPort; // Public port number
+ UINT64 CreatedTime; // Connection time
+ UINT64 LastCommTime; // Last communication time
+ UINT64 TotalSent; // Total number of bytes sent
+ UINT64 TotalRecv; // Total number of bytes received
+ UINT LastSeq; // Last sequence number
+ UINT LastAck; // Last acknowledgment number
+ UINT HashCodeForSend; // Cached hash code (transmit direction)
+ UINT HashCodeForRecv; // Cached hash code (receive direction)
+};
+
+// Native NAT
+struct NATIVE_NAT
+{
+ struct VH *v; // Virtual machine
+ bool Active; // Whether currently available
+ THREAD *Thread; // Main thread
+ bool Halt; // Halting flag
+ TUBE *HaltTube; // Tube to be disconnected in order to stop
+ TUBE *HaltTube2; // Tube 2 to be disconnected in order to stop
+ TUBE *HaltTube3; // Tube 3 to be disconnected in order to stop
+ LOCK *Lock; // Lock
+ EVENT *HaltEvent; // Halting event
+ UINT LastInterfaceIndex; // Index number of the interface that is used for attempting last
+ UINT LastInterfaceDeviceHash; // Hash value of the device list at the time of the last attempted
+ UINT NextWaitTimeForRetry; // Time for waiting next time for the device list enumeration
+ UINT FailedCount; // The number of failed searching for the interface
+ UINT LastHostAddressHash; // Hash of the last host IP address
+ DHCP_OPTION_LIST CurrentDhcpOptions; // Current DHCP options
+ QUEUE *SendQueue; // Transmission queue
+ QUEUE *RecvQueue; // Reception queue
+ CANCEL *Cancel; // Cancel object (Hit if there is a received packet)
+ LOCK *CancelLock; // Lock of the cancel object
+ HASH_LIST *NatTableForSend; // Native NAT table (for transmission)
+ HASH_LIST *NatTableForRecv; // Native NAT table (for reception)
+ UINT PublicIP; // Public IP
+ USHORT NextId; // Next IP packet ID
+ bool SendStateChanged; // Transmission state changed
+ LIST *IpCombine; // IP combining list
+ UINT CurrentIpQuota; // Current IP combining quota
+ UCHAR CurrentMacAddress[6]; // Current MAC address
+};
+
+// ARP entry
+struct ARP_ENTRY
+{
+ UINT IpAddress; // IP address
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2];
+ UINT64 Created; // Creation date and time
+ UINT64 Expire; // Expiration date
+};
+
+// ARP waiting list
+struct ARP_WAIT
+{
+ UINT IpAddress; // IP address trying to solve
+ UINT NextTimeoutTimeValue; // Next time before timing out
+ UINT64 TimeoutTime; // Current Time-out of transmission
+ UINT64 GiveupTime; // Time to give up the transmission
+};
+
+// IP waiting list
+struct IP_WAIT
+{
+ UINT DestIP; // Destination IP address
+ UINT SrcIP; // Source IP address
+ UINT64 Expire; // Storage life
+ void *Data; // Data
+ UINT Size; // Size
+};
+
+// IP partial list
+struct IP_PART
+{
+ UINT Offset; // Offset
+ UINT Size; // Size
+};
+
+// IP restore list
+struct IP_COMBINE
+{
+ UINT DestIP; // Destination IP address
+ UINT SrcIP; // Source IP address
+ USHORT Id; // IP packet ID
+ UCHAR Ttl; // TTL
+ UINT64 Expire; // Storage life
+ void *Data; // Packet data
+ UINT DataReserved; // Area reserved for data
+ UINT Size; // Packet size (Total)
+ LIST *IpParts; // IP partial list
+ UCHAR Protocol; // Protocol number
+ bool MacBroadcast; // Broadcast packets at the MAC level
+ UCHAR *HeadIpHeaderData; // Data of the IP header of the top
+ UINT HeadIpHeaderDataSize; // Data size of the IP header of the top
+ bool SrcIsLocalMacAddr; // Source MAC address is on the same machine
+ UINT MaxL3Size; // Largest L3 size
+};
+
+#define IP_COMBINE_INITIAL_BUF_SIZE (MAX_IP_DATA_SIZE) // Initial buffer size
+
+// NAT session table
+struct NAT_ENTRY
+{
+ // TCP | UDP common items
+ struct VH *v; // Virtual machine
+ UINT Id; // ID
+ LOCK *lock; // Lock
+ UINT Protocol; // Protocol
+ UINT SrcIp; // Source IP address
+ UINT SrcPort; // Source port number
+ UINT DestIp; // Destination IP address
+ UINT DestPort; // Destination port number
+ UINT PublicIp; // Public IP address
+ UINT PublicPort; // Public port number
+ UINT64 CreatedTime; // Connection time
+ UINT64 LastCommTime; // Last communication time
+ SOCK *Sock; // Socket
+ bool DisconnectNow; // Flag to stop immediately
+ UINT tag1;
+ bool ProxyDns; // DNS proxy
+ UINT DestIpProxy; // Proxy DNS address
+
+ // ICMP NAT item (only for the calling ICMP API mode)
+ THREAD *IcmpThread; // ICMP query thread
+ BLOCK *IcmpQueryBlock; // Block that contains the ICMP query
+ BLOCK *IcmpResponseBlock; // Block that contains ICMP result
+ bool IcmpTaskFinished; // Flag indicating that the processing of ICMP has been completed
+ UCHAR *IcmpOriginalCopy; // Copy of the original ICMP packet
+ UINT IcmpOriginalCopySize; // The size of the copy of original ICMP packet
+
+ // DNS NAT item
+ THREAD *DnsThread; // DNS query thread
+ bool DnsGetIpFromHost; // Reverse resolution flag
+ char *DnsTargetHostName; // Target host name
+ IP DnsResponseIp; // Response IP address
+ char *DnsResponseHostName; // Response host name
+ UINT DnsTransactionId; // DNS transaction ID
+ bool DnsFinished; // DNS query completion flag
+ bool DnsOk; // DNS success flag
+ bool DnsPollingFlag; // DNS polling completion flag
+
+ // UDP item
+ QUEUE *UdpSendQueue; // UDP send queue
+ QUEUE *UdpRecvQueue; // UDP receive queue
+ bool UdpSocketCreated; // Whether an UDP socket was created
+
+ // TCP items
+ FIFO *SendFifo; // Transmission FIFO
+ FIFO *RecvFifo; // Receive FIFO
+ UINT TcpStatus; // TCP state
+ bool NatTcpCancelFlag; // TCP connection cancel flag
+ THREAD *NatTcpConnectThread; // TCP socket connection thread
+ bool TcpMakeConnectionFailed; // Failed to connect with connection thread
+ bool TcpMakeConnectionSucceed; // Successfully connected by the connection thread
+ UINT TcpSendMaxSegmentSize; // Maximum transmission segment size
+ UINT TcpRecvMaxSegmentSize; // Maximum reception segment size
+ UINT64 LastSynAckSentTime; // Time which the SYN+ACK was sent last
+ UINT SynAckSentCount; // SYN + ACK transmission times
+ UINT TcpSendWindowSize; // Transmission window size
+ UINT TcpSendCWnd; // Transmission congestion window size (/mss)
+ UINT TcpRecvWindowSize; // Receive window size
+ UINT TcpSendTimeoutSpan; // Transmission time-out period
+ UINT64 TcpLastSentTime; // Time for the last transmitted over TCP
+ UINT64 LastSentKeepAliveTime; // Time which the keep-alive ACK was sent last
+ FIFO *TcpRecvWindow; // TCP receive window
+ LIST *TcpRecvList; // TCP reception list
+ bool SendAckNext; // Send an ACK at the time of the next transmission
+ UINT LastSentWindowSize; // My window size that sent the last
+ UINT64 TcpLastRecvAckTime; // Time that the other party has received the last data in TCP
+
+ UINT64 SendSeqInit; // Initial send sequence number
+ UINT64 SendSeq; // Send sequence number
+ UINT64 RecvSeqInit; // Initial receive sequence number
+ UINT64 RecvSeq; // Receive sequence number
+
+ bool CurrentSendingMission; // Burst transmission ongoing
+ UINT SendMissionSize; // Transmission size of this time
+ bool RetransmissionUsedFlag; // Retransmission using record flag
+
+ UINT CurrentRTT; // Current RTT value
+ UINT64 CalcRTTStartTime; // RTT measurement start time
+ UINT64 CalcRTTStartValue; // RTT measurement start value
+
+ bool TcpFinished; // Data communication end flag of TCP
+ UINT64 FinSentTime; // Time which the FIN was sent last
+ UINT FinSentCount; // Number of FIN transmissions
+};
+
+
+// TCP options
+struct TCP_OPTION
+{
+ UINT MaxSegmentSize; // Maximum segment size
+ UINT WindowScaling; // Window scaling
+};
+
+// Virtual host structure
+struct VH
+{
+ REF *ref; // Reference counter
+ LOCK *lock; // Lock
+ SESSION *Session; // Session
+ CANCEL *Cancel; // Cancel object
+ QUEUE *SendQueue; // Transmission queue
+ bool Active; // Active flag
+ volatile bool HaltNat; // NAT halting flag
+ LIST *ArpTable; // ARP table
+ LIST *ArpWaitTable; // ARP waiting table
+ LIST *IpWaitTable; // IP waiting table
+ LIST *IpCombine; // IP combining table
+ UINT64 Now; // Current time
+ UINT64 NextArpTablePolling; // Next time to poll the ARP table
+ UINT Mtu; // MTU value
+ UINT IpMss; // Maximum IP data size
+ UINT TcpMss; // TCP maximum data size
+ UINT UdpMss; // UDP maximum data size
+ bool flag1; // Flag 1
+ bool flag2; // Flag 2
+ USHORT NextId; // ID of the IP packet
+ UINT CurrentIpQuota; // IP packet memory quota
+ LIST *NatTable; // NAT table
+ SOCK_EVENT *SockEvent; // Socket event
+ THREAD *NatThread; // NAT thread
+ void *TmpBuf; // Buffer that can be used temporarily
+ bool NatDoCancelFlag; // Flag of whether to hit the cancel
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2];
+ UINT HostIP; // Host IP
+ UINT HostMask; // Host subnet mask
+ UINT NatTcpTimeout; // NAT TCP timeout in seconds
+ UINT NatUdpTimeout; // NAT UDP timeout in seconds
+ bool UseNat; // NAT use flag
+ bool UseDhcp; // DHCP using flag
+ UINT DhcpIpStart; // Distribution start address
+ UINT DhcpIpEnd; // Distribution end address
+ UINT DhcpMask; // Subnet mask
+ UINT DhcpExpire; // Address distribution expiration date
+ UINT DhcpGateway; // Gateway address
+ UINT DhcpDns; // DNS server address 1
+ UINT DhcpDns2; // DNS server address 2
+ char DhcpDomain[MAX_HOST_NAME_LEN + 1]; // Assigned domain name
+ LIST *DhcpLeaseList; // DHCP lease list
+ UINT64 LastDhcpPolling; // Time which the DHCP list polled last
+ bool SaveLog; // Save a log
+ COUNTER *Counter; // Session counter
+ UINT DhcpId; // DHCP ID
+ UINT64 LastSendBeacon; // Time which the beacon has been sent last
+ LOG *Logger; // Logger
+ NAT *nat; // A reference to the NAT object
+ bool IcmpRawSocketOk; // ICMP RAW SOCKET is available
+ bool IcmpApiOk; // ICMP API is available
+ HUB_OPTION *HubOption; // Pointer to the Virtual HUB options
+
+ NATIVE_NAT *NativeNat; // Native NAT
+};
+
+// Virtual host option
+struct VH_OPTION
+{
+ char HubName[MAX_HUBNAME_LEN + 1]; // Target Virtual HUB name
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2];
+ IP Ip; // IP address
+ IP Mask; // Subnet mask
+ bool UseNat; // Use flag of NAT function
+ UINT Mtu; // MTU value
+ UINT NatTcpTimeout; // NAT TCP timeout in seconds
+ UINT NatUdpTimeout; // NAT UDP timeout in seconds
+ bool UseDhcp; // Using flag of DHCP function
+ IP DhcpLeaseIPStart; // Start of IP address range for DHCP distribution
+ IP DhcpLeaseIPEnd; // End of IP address range for DHCP distribution
+ IP DhcpSubnetMask; // DHCP subnet mask
+ UINT DhcpExpireTimeSpan; // DHCP expiration date
+ IP DhcpGatewayAddress; // Assigned gateway address
+ IP DhcpDnsServerAddress; // Assigned DNS server address 1
+ IP DhcpDnsServerAddress2; // Assigned DNS server address 2
+ char DhcpDomainName[MAX_HOST_NAME_LEN + 1]; // Assigned domain name
+ bool SaveLog; // Save a log
+};
+
+// DHCP lease entry
+struct DHCP_LEASE
+{
+ UINT Id; // ID
+ UINT64 LeasedTime; // Leased time
+ UINT64 ExpireTime; // Expiration date
+ UCHAR MacAddress[6]; // MAC address
+ UCHAR Padding[2]; // Padding
+ UINT IpAddress; // IP address
+ UINT Mask; // Subnet mask
+ char *Hostname; // Host name
+};
+
+// DNS query
+typedef struct NAT_DNS_QUERY
+{
+ REF *ref; // Reference counter
+ char Hostname[256]; // Host name
+ bool Ok; // Result success flag
+ IP Ip; // Result IP address
+} NAT_DNS_QUERY;
+
+// Parsed DNS query
+struct DNS_PARSED_PACKET
+{
+ UINT TransactionId;
+ char Hostname[128];
+};
+
+
+// Virtual LAN card of the virtual host
+PACKET_ADAPTER *VirtualGetPacketAdapter();
+bool VirtualPaInit(SESSION *s);
+CANCEL *VirtualPaGetCancel(SESSION *s);
+UINT VirtualPaGetNextPacket(SESSION *s, void **data);
+bool VirtualPaPutPacket(SESSION *s, void *data, UINT size);
+void VirtualPaFree(SESSION *s);
+
+bool VirtualInit(VH *v);
+UINT VirtualGetNextPacket(VH *v, void **data);
+bool VirtualPutPacket(VH *v, void *data, UINT size);
+void Virtual_Free(VH *v);
+
+VH *NewVirtualHost(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, VH_OPTION *vh_option);
+VH *NewVirtualHostEx(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *auth, VH_OPTION *vh_option, NAT *nat);
+void LockVirtual(VH *v);
+void UnlockVirtual(VH *v);
+void ReleaseVirtual(VH *v);
+void CleanupVirtual(VH *v);
+void StopVirtualHost(VH *v);
+void SetVirtualHostOption(VH *v, VH_OPTION *vo);
+void GenMacAddress(UCHAR *mac);
+void GetVirtualHostOption(VH *v, VH_OPTION *o);
+
+void VirtualLayer2(VH *v, PKT *packet);
+bool VirtualLayer2Filter(VH *v, PKT *packet);
+void VirtualArpReceived(VH *v, PKT *packet);
+void VirtualArpResponseRequest(VH *v, PKT *packet);
+void VirtualArpResponseReceived(VH *v, PKT *packet);
+void VirtualArpSendResponse(VH *v, UCHAR *dest_mac, UINT dest_ip, UINT src_ip);
+void VirtualArpSendRequest(VH *v, UINT dest_ip);
+void VirtualIpSend(VH *v, UCHAR *dest_mac, void *data, UINT size);
+void VirtualLayer2Send(VH *v, UCHAR *dest_mac, UCHAR *src_mac, USHORT protocol, void *data, UINT size);
+void VirtualPolling(VH *v);
+void InitArpTable(VH *v);
+void FreeArpTable(VH *v);
+int CompareArpTable(void *p1, void *p2);
+ARP_ENTRY *SearchArpTable(VH *v, UINT ip);
+void RefreshArpTable(VH *v);
+void PollingArpTable(VH *v);
+void InsertArpTable(VH *v, UCHAR *mac, UINT ip);
+bool IsMacBroadcast(UCHAR *mac);
+bool IsMacInvalid(UCHAR *mac);
+void InitArpWaitTable(VH *v);
+void FreeArpWaitTable(VH *v);
+int CompareArpWaitTable(void *p1, void *p2);
+ARP_WAIT *SearchArpWaitTable(VH *v, UINT ip);
+void DeleteArpWaitTable(VH *v, UINT ip);
+void SendArp(VH *v, UINT ip);
+void InsertArpWaitTable(VH *v, ARP_WAIT *w);
+void PollingArpWaitTable(VH *v);
+void ArpIpWasKnown(VH *v, UINT ip, UCHAR *mac);
+void InitIpWaitTable(VH *v);
+void FreeIpWaitTable(VH *v);
+void InsertIpWaitTable(VH *v, UINT dest_ip, UINT src_ip, void *data, UINT size);
+void SendFragmentedIp(VH *v, UINT dest_ip, UINT src_ip, USHORT id, USHORT total_size, USHORT offset, UCHAR protocol, void *data, UINT size, UCHAR *dest_mac, UCHAR ttl);
+void SendIp(VH *v, UINT dest_ip, UINT src_ip, UCHAR protocol, void *data, UINT size);
+void SendIpEx(VH *v, UINT dest_ip, UINT src_ip, UCHAR protocol, void *data, UINT size, UCHAR ttl);
+void PollingIpWaitTable(VH *v);
+void DeleteOldIpWaitTable(VH *v);
+void SendWaitingIp(VH *v, UCHAR *mac, UINT dest_ip);
+void VirtualIpReceived(VH *v, PKT *packet);
+void InitIpCombineList(VH *v);
+void FreeIpCombineList(VH *v);
+int CompareIpCombine(void *p1, void *p2);
+void CombineIp(VH *v, IP_COMBINE *c, UINT offset, void *data, UINT size, bool last_packet, UCHAR *head_ip_header_data, UINT head_ip_header_size);
+void IpReceived(VH *v, UINT src_ip, UINT dest_ip, UINT protocol, void *data, UINT size, bool mac_broadcast, UCHAR ttl, UCHAR *ip_header, UINT ip_header_size, bool is_local_mac, UINT max_l3_size);
+void FreeIpCombine(VH *v, IP_COMBINE *c);
+void PollingIpCombine(VH *v);
+IP_COMBINE *InsertIpCombine(VH *v, UINT src_ip, UINT dest_ip, USHORT id, UCHAR protocol, bool mac_broadcast, UCHAR ttl, bool src_is_localmac);
+IP_COMBINE *SearchIpCombine(VH *v, UINT src_ip, UINT dest_ip, USHORT id, UCHAR protocol);
+void VirtualIcmpReceived(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size, UCHAR ttl, UCHAR *ip_header, UINT ip_header_size, UINT max_l3_size);
+void VirtualIcmpEchoRequestReceived(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size, UCHAR ttl, void *icmp_data, UINT icmp_size, UCHAR *ip_header, UINT ip_header_size, UINT max_l3_size);
+void VirtualIcmpEchoRequestReceivedRaw(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size, UCHAR ttl, void *icmp_data, UINT icmp_size, UCHAR *ip_header, UINT ip_header_size);
+void VirtualIcmpEchoSendResponse(VH *v, UINT src_ip, UINT dst_ip, USHORT id, USHORT seq_no, void *data, UINT size);
+void VirtualIcmpSend(VH *v, UINT src_ip, UINT dst_ip, void *data, UINT size);
+void VirtualUdpReceived(VH *v, UINT src_ip, UINT dest_ip, void *data, UINT size, bool mac_broadcast, bool is_localmac, UINT max_l3_size);
+void SendUdp(VH *v, UINT dest_ip, UINT dest_port, UINT src_ip, UINT src_port, void *data, UINT size);
+UINT GetNetworkAddress(UINT addr, UINT mask);
+UINT GetBroadcastAddress(UINT addr, UINT mask);
+void GetBroadcastAddress4(IP *dst, IP *addr, IP *mask);
+bool IsInNetwork(UINT uni_addr, UINT network_addr, UINT mask);
+void UdpRecvForMe(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size);
+void UdpRecvLlmnr(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size);
+void UdpRecvForBroadcast(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size);
+void UdpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size, bool dns_proxy);
+void UdpRecvForNetBiosBroadcast(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size, bool dns_proxy, bool unicast);
+bool IsNetbiosRegistrationPacket(UCHAR *buf, UINT size);
+bool ProcessNetBiosNameQueryPacketForMyself(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size);
+void EncodeNetBiosName(UCHAR *dst, char *src);
+char *CharToNetBiosStr(char c);
+void InitNat(VH *v);
+void FreeNat(VH *v);
+int CompareNat(void *p1, void *p2);
+NAT_ENTRY *SearchNat(VH *v, NAT_ENTRY *target);
+void SetNat(NAT_ENTRY *n, UINT protocol, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT public_ip, UINT public_port);
+void DeleteNatTcp(VH *v, NAT_ENTRY *n);
+void DeleteNatUdp(VH *v, NAT_ENTRY *n);
+void DeleteNatIcmp(VH *v, NAT_ENTRY *n);
+NAT_ENTRY *CreateNatUdp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT dns_proxy_ip);
+NAT_ENTRY *CreateNatIcmp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UCHAR *original_copy, UINT original_copy_size);
+void NatThread(THREAD *t, void *param);
+void NatThreadMain(VH *v);
+bool NatTransactUdp(VH *v, NAT_ENTRY *n);
+bool NatTransactIcmp(VH *v, NAT_ENTRY *n);
+void NatIcmpThreadProc(THREAD *thread, void *param);
+void PoolingNat(VH *v);
+void PoolingNatUdp(VH *v, NAT_ENTRY *n);
+void PollingNatIcmp(VH *v, NAT_ENTRY *n);
+void VirtualTcpReceived(VH *v, UINT src_ip, UINT dest_ip, void *data, UINT size, UINT max_l3_size);
+void TcpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, TCP_HEADER *tcp, void *data, UINT size, UINT max_l3_size);
+NAT_ENTRY *CreateNatTcp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port);
+bool NatTransactTcp(VH *v, NAT_ENTRY *n);
+void CreateNatTcpConnectThread(VH *v, NAT_ENTRY *n);
+void NatTcpConnectThread(THREAD *t, void *p);
+void PollingNatTcp(VH *v, NAT_ENTRY *n);
+void ParseTcpOption(TCP_OPTION *o, void *data, UINT size);
+void SendTcp(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT seq, UINT ack, UINT flag, UINT window_size, UINT mss, void *data, UINT size);
+void DnsProxy(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size);
+bool ParseDnsPacket(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size);
+bool ParseDnsPacketEx(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size, DNS_PARSED_PACKET *parsed_result);
+bool ParseDnsQuery(char *name, UINT name_size, void *data, UINT data_size);
+void SetDnsProxyVgsHostname(char *hostname);
+UCHAR GetNextByte(BUF *b);
+bool NatTransactDns(VH *v, NAT_ENTRY *n);
+void NatDnsThread(THREAD *t, void *param);
+bool NatGetIP(IP *ip, char *hostname);
+void NatGetIPThread(THREAD *t, void *param);
+NAT_ENTRY *CreateNatDns(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port,
+ UINT transaction_id, bool dns_get_ip_from_host, char *dns_target_host_name);
+void PollingNatDns(VH *v, NAT_ENTRY *n);
+void SendNatDnsResponse(VH *v, NAT_ENTRY *n);
+void BuildDnsQueryPacket(BUF *b, char *hostname, bool ptr);
+void BuildDnsResponsePacketA(BUF *b, IP *ip);
+void BuildDnsResponsePacketPtr(BUF *b, char *hostname);
+bool ArpaToIP(IP *ip, char *str);
+BUF *BuildDnsHostName(char *hostname);
+bool CanCreateNewNatEntry(VH *v);
+void VirtualDhcpServer(VH *v, PKT *p);
+void InitDhcpServer(VH *v);
+void FreeDhcpServer(VH *v);
+void PollingDhcpServer(VH *v);
+int CompareDhcpLeaseList(void *p1, void *p2);
+DHCP_LEASE *NewDhcpLease(UINT expire, UCHAR *mac_address, UINT ip, UINT mask, char *hostname);
+void FreeDhcpLease(DHCP_LEASE *d);
+DHCP_LEASE *SearchDhcpLeaseByMac(VH *v, UCHAR *mac);
+DHCP_LEASE *SearchDhcpLeaseByIp(VH *v, UINT ip);
+UINT ServeDhcpDiscover(VH *v, UCHAR *mac, UINT request_ip);
+UINT GetFreeDhcpIpAddress(VH *v);
+UINT ServeDhcpRequest(VH *v, UCHAR *mac, UINT request_ip);
+void VirtualDhcpSend(VH *v, UINT tran_id, UINT dest_ip, UINT dest_port,
+ UINT new_ip, UCHAR *client_mac, BUF *b, UINT hw_type, UINT hw_addr_size);
+void VLog(VH *v, char *str);
+void SendBeacon(VH *v);
+void PollingBeacon(VH *v);
+HUB_OPTION *NatGetHubOption(VH *v);
+UINT GetNumNatEntriesPerIp(VH *v, UINT ip, UINT protocol, bool tcp_syn_sent);
+void NatSetHubOption(VH *v, HUB_OPTION *o);
+NAT_ENTRY *GetOldestNatEntryOfIp(VH *v, UINT ip, UINT protocol);
+void DisconnectNatEntryNow(VH *v, NAT_ENTRY *e);
+
+NATIVE_NAT *NewNativeNat(VH *v);
+void FreeNativeNat(NATIVE_NAT *t);
+void NativeNatThread(THREAD *thread, void *param);
+NATIVE_STACK *NnGetNextInterface(NATIVE_NAT *t);
+
+bool NnTestConnectivity(NATIVE_STACK *a, TUBE *halt_tube);
+void NnMainLoop(NATIVE_NAT *t, NATIVE_STACK *a);
+
+BUF *NnBuildDnsQueryPacket(char *hostname, USHORT tran_id);
+BUF *NnBuildUdpPacket(BUF *payload, UINT src_ip, USHORT src_port, UINT dst_ip, USHORT dst_port);
+BUF *NnBuildTcpPacket(BUF *payload, UINT src_ip, USHORT src_port, UINT dst_ip, USHORT dst_port, UINT seq, UINT ack, UINT flag, UINT window_size, UINT mss);
+BUF *NnBuildIpPacket(BUF *payload, UINT src_ip, UINT dst_ip, UCHAR protocol, UCHAR ttl);
+UINT NnGenSrcPort();
+bool NnParseDnsResponsePacket(UCHAR *data, UINT size, IP *ret_ip);
+BUF *NnReadDnsRecord(BUF *buf, bool answer, USHORT *ret_type, USHORT *ret_class);
+bool NnReadDnsLabel(BUF *buf);
+void NnClearQueue(NATIVE_NAT *t);
+
+int CmpNativeNatTableForSend(void *p1, void *p2);
+int CmpNativeNatTableForRecv(void *p1, void *p2);
+UINT GetHashNativeNatTableForSend(void *p);
+UINT GetHashNativeNatTableForRecv(void *p);
+void NnSetNat(NATIVE_NAT_ENTRY *e, UINT protocol, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, UINT pub_ip, UINT pub_port);
+
+bool NnIsActive(VH *v);
+void NnUdpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, void *data, UINT size, UINT max_l3_size);
+void NnTcpRecvForInternet(VH *v, UINT src_ip, UINT src_port, UINT dest_ip, UINT dest_port, TCP_HEADER *old_tcp, void *data, UINT size, UINT max_l3_size);
+void NnIcmpEchoRecvForInternet(VH *v, UINT src_ip, UINT dest_ip, void *data, UINT size, UCHAR ttl, void *icmp_data, UINT icmp_size, UCHAR *ip_header, UINT ip_header_size, UINT max_l3_size);
+UINT NnMapNewPublicPort(NATIVE_NAT *t, UINT protocol, UINT dest_ip, UINT dest_port, UINT public_ip);
+void NnIpSendForInternet(NATIVE_NAT *t, UCHAR ip_protocol, UCHAR ttl, UINT src_ip, UINT dest_ip, void *data, UINT size, UINT max_l3_size);
+void NnIpSendFragmentedForInternet(NATIVE_NAT *t, UCHAR ip_protocol, UINT src_ip, UINT dest_ip, USHORT id, USHORT total_size,
+ USHORT offset, void *data, UINT size, UCHAR ttl);
+void NnPoll(NATIVE_NAT *t);
+void NnLayer2(NATIVE_NAT *t, PKT *packet);
+void NnFragmentedIpReceived(NATIVE_NAT *t, PKT *packet);
+void NnIpReceived(NATIVE_NAT *t, UINT src_ip, UINT dest_ip, UINT protocol, void *data, UINT size,
+ UCHAR ttl, UCHAR *ip_header, UINT ip_header_size, UINT max_l3_size);
+void NnUdpReceived(NATIVE_NAT *t, UINT src_ip, UINT dest_ip, void *data, UINT size, UCHAR ttl, UINT max_l3_size);
+void NnTcpReceived(NATIVE_NAT *t, UINT src_ip, UINT dest_ip, void *data, UINT size, UCHAR ttl, UINT max_l3_size);
+void NnIcmpReceived(NATIVE_NAT *t, UINT src_ip, UINT dest_ip, void *data, UINT size, UCHAR ttl, UINT max_l3_size);
+
+void NnCombineIp(NATIVE_NAT *t, IP_COMBINE *c, UINT offset, void *data, UINT size, bool last_packet, UCHAR *head_ip_header_data, UINT head_ip_header_size);
+void NnFreeIpCombine(NATIVE_NAT *t, IP_COMBINE *c);
+IP_COMBINE *NnSearchIpCombine(NATIVE_NAT *t, UINT src_ip, UINT dest_ip, USHORT id, UCHAR protocol);
+IP_COMBINE *NnInsertIpCombine(NATIVE_NAT *t, UINT src_ip, UINT dest_ip, USHORT id, UCHAR protocol, bool mac_broadcast, UCHAR ttl, bool src_is_localmac);
+void NnInitIpCombineList(NATIVE_NAT *t);
+void NnFreeIpCombineList(NATIVE_NAT *t);
+void NnPollingIpCombine(NATIVE_NAT *t);
+void NnDeleteOldSessions(NATIVE_NAT *t);
+void NnDeleteSession(NATIVE_NAT *t, NATIVE_NAT_ENTRY *e);
+
+NATIVE_NAT_ENTRY *NnGetOldestNatEntryOfIp(NATIVE_NAT *t, UINT ip, UINT protocol);
+void NnDeleteOldestNatSession(NATIVE_NAT *t, UINT ip, UINT protocol);
+UINT NnGetNumNatEntriesPerIp(NATIVE_NAT *t, UINT src_ip, UINT protocol);
+void NnDeleteOldestNatSessionIfNecessary(NATIVE_NAT *t, UINT ip, UINT protocol);
+
+void NnSetSecureNatTargetHostname(char *name);
+
+
+#endif // VIRTUAL_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/WaterMark.c b/src/Cedar/WaterMark.c
new file mode 100644
index 00000000..f7a9a967
--- /dev/null
+++ b/src/Cedar/WaterMark.c
@@ -0,0 +1,4386 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// WaterMark.c
+// SoftEther protocol digital watermark data
+
+#include "CedarPch.h"
+
+// Digital watermark image data (JPEG)
+BYTE WaterMark[] =
+{
+ 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0xC8, 0x00, 0x33, 0x00, 0xF2, 0x00, 0x00, 0x36, 0x37, 0x34,
+ 0x79, 0x68, 0x54, 0x80, 0x80, 0x80, 0xAF, 0x7F, 0x5B, 0xB3, 0xA8, 0x9D, 0xD5, 0xD5, 0xD4, 0xFF,
+ 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x33, 0x00, 0x00, 0x03,
+ 0xFE, 0x08, 0x1A, 0xDC, 0x34, 0x0A, 0x04, 0x41, 0x6B, 0x65, 0x31, 0x4F, 0x11, 0x80, 0xF9, 0x60,
+ 0x28, 0x8E, 0x64, 0x69, 0x9E, 0x68, 0xAA, 0xAE, 0x6C, 0xEB, 0x9A, 0x4B, 0xE3, 0x0C, 0x0C, 0x25,
+ 0x6F, 0x56, 0xA7, 0xE9, 0xD2, 0xEB, 0xFF, 0xC0, 0xA0, 0x70, 0xC8, 0x8A, 0xDC, 0x2C, 0x9C, 0xC6,
+ 0x05, 0xC7, 0x31, 0x66, 0x24, 0x04, 0xA2, 0x74, 0x4A, 0xAD, 0x4E, 0x05, 0xB1, 0x0D, 0x61, 0xCB,
+ 0x25, 0xD4, 0xB8, 0x49, 0x1B, 0xE6, 0x19, 0xB1, 0x9A, 0xCF, 0xE8, 0xF4, 0x07, 0x2B, 0x11, 0x74,
+ 0x09, 0x85, 0x78, 0xFC, 0x0D, 0x6E, 0x90, 0x9F, 0xEA, 0x02, 0x81, 0x12, 0x35, 0xEF, 0x29, 0x6A,
+ 0x81, 0x2C, 0x04, 0x0A, 0x6E, 0x5C, 0x72, 0x88, 0x7A, 0x7A, 0x6F, 0x4D, 0x77, 0x19, 0x25, 0x71,
+ 0x16, 0x71, 0x2F, 0x05, 0x92, 0x06, 0x95, 0x80, 0x22, 0x48, 0x16, 0x7D, 0x98, 0x02, 0x9A, 0x7C,
+ 0x82, 0x06, 0x16, 0x23, 0x7F, 0x02, 0x05, 0x6B, 0x48, 0x70, 0x23, 0x15, 0x7D, 0x1F, 0x98, 0xA8,
+ 0x21, 0x7F, 0x87, 0x89, 0xB5, 0x8B, 0x7C, 0x7B, 0x3C, 0x8E, 0x23, 0x9E, 0x9B, 0xAE, 0x2B, 0xAD,
+ 0x20, 0xA6, 0xAC, 0x9B, 0x14, 0xB1, 0xC3, 0x21, 0x15, 0xB1, 0x81, 0x9E, 0x22, 0x9E, 0xAE, 0xC5,
+ 0x99, 0x20, 0x96, 0xAF, 0xC6, 0xA0, 0x70, 0xB6, 0xB6, 0x5B, 0x03, 0x1C, 0x16, 0x8E, 0x65, 0x21,
+ 0xBD, 0x9B, 0xCB, 0x2A, 0x9E, 0xCB, 0xC1, 0xE1, 0xD1, 0xA7, 0xA9, 0x6E, 0xE9, 0xD6, 0x82, 0xCD,
+ 0xC9, 0xCA, 0xD5, 0xD1, 0xAE, 0xBD, 0xCB, 0x7F, 0xAC, 0xB4, 0xD9, 0x73, 0x34, 0x37, 0x76, 0xDF,
+ 0x3C, 0xC8, 0x9A, 0x07, 0x42, 0x4E, 0x38, 0x4C, 0xAB, 0x0A, 0xFA, 0x12, 0x17, 0xEA, 0x52, 0x05,
+ 0x12, 0x0C, 0xDB, 0x35, 0xD3, 0xF3, 0xCE, 0xD9, 0x2C, 0x72, 0x13, 0xB7, 0x40, 0x22, 0xE8, 0xFE,
+ 0xB0, 0x61, 0xC7, 0x4F, 0xEC, 0x40, 0x7E, 0x94, 0xF6, 0x50, 0x13, 0x36, 0x83, 0xA8, 0x6A, 0x79,
+ 0xF9, 0x77, 0xE3, 0x1B, 0x28, 0x69, 0x1B, 0x55, 0x09, 0x1B, 0x67, 0x8A, 0x1A, 0xA9, 0x52, 0xC5,
+ 0x50, 0x71, 0x42, 0x82, 0x31, 0xDA, 0xB4, 0x56, 0x15, 0x9D, 0x71, 0xBC, 0x19, 0xF2, 0x27, 0x49,
+ 0x3E, 0xEF, 0x3C, 0x4E, 0xDB, 0x92, 0xED, 0x52, 0xBF, 0x01, 0xFE, 0x02, 0x44, 0x95, 0xB1, 0x6B,
+ 0xA0, 0x32, 0x72, 0x0A, 0x25, 0x72, 0x1C, 0xE5, 0x11, 0x99, 0x3C, 0x5F, 0x33, 0x61, 0x72, 0x75,
+ 0x93, 0x92, 0x28, 0x42, 0xA3, 0x7D, 0x72, 0x9A, 0x20, 0x68, 0x8A, 0x1C, 0x3A, 0x73, 0x3F, 0xE1,
+ 0x84, 0x82, 0x55, 0xEA, 0xE4, 0xA5, 0xBB, 0x89, 0xDE, 0x4C, 0x60, 0x30, 0x75, 0x0C, 0x9E, 0x97,
+ 0xD4, 0x8C, 0xC6, 0x32, 0x3B, 0xB4, 0x64, 0xD6, 0x71, 0x46, 0x45, 0x7E, 0x3C, 0x67, 0xB8, 0x30,
+ 0x20, 0xB8, 0x29, 0x82, 0x3D, 0x73, 0xE7, 0x93, 0x1E, 0xAA, 0x3F, 0x91, 0xD6, 0x89, 0x60, 0x9A,
+ 0xC8, 0x69, 0x36, 0xA8, 0x1B, 0xA4, 0xFE, 0x23, 0x03, 0x51, 0xED, 0xC7, 0xC4, 0x87, 0x19, 0xB7,
+ 0xA3, 0xCC, 0x13, 0x2D, 0x65, 0xD5, 0xB1, 0x22, 0x4A, 0xDE, 0xBA, 0xF6, 0xA1, 0x57, 0x7A, 0x0B,
+ 0xB3, 0x96, 0x3D, 0x95, 0xAF, 0x2E, 0x4A, 0xBC, 0x2A, 0xB9, 0x25, 0x61, 0x09, 0x10, 0x1C, 0x24,
+ 0x53, 0x7D, 0xBC, 0xA2, 0x33, 0xE0, 0x15, 0x72, 0x58, 0xC5, 0xAF, 0xAD, 0x8A, 0x84, 0x5C, 0x13,
+ 0xF1, 0xED, 0x13, 0xE6, 0x68, 0x57, 0x3F, 0x85, 0xB5, 0xF7, 0x58, 0xC3, 0xB2, 0x3A, 0xA7, 0x54,
+ 0xB9, 0x87, 0x86, 0x98, 0xBD, 0xA3, 0x8D, 0xD7, 0xCE, 0x44, 0xD4, 0xF1, 0x74, 0xDA, 0x44, 0x85,
+ 0x06, 0x25, 0x7C, 0x54, 0xEC, 0x57, 0xE8, 0x26, 0x18, 0xFE, 0x2A, 0xBA, 0xFE, 0xB9, 0xFE, 0xE6,
+ 0xCD, 0x88, 0x00, 0x57, 0x0B, 0x54, 0xFE, 0x20, 0x31, 0x1A, 0x0F, 0x01, 0x14, 0x94, 0xD0, 0x61,
+ 0x69, 0x95, 0x14, 0x0F, 0x3B, 0xAE, 0x5C, 0x37, 0x16, 0x56, 0xCF, 0xBD, 0x14, 0xA1, 0x61, 0x12,
+ 0x0E, 0xA6, 0x14, 0x76, 0x88, 0xBD, 0x44, 0xA1, 0x3C, 0xF6, 0x04, 0x76, 0x90, 0x78, 0xE4, 0x81,
+ 0x26, 0x80, 0x70, 0x0F, 0x10, 0xA7, 0xC4, 0x61, 0x95, 0x2D, 0xC6, 0x5C, 0x45, 0xCE, 0x89, 0x28,
+ 0x1B, 0x34, 0x1C, 0xC5, 0xE8, 0xD1, 0x64, 0xAF, 0xAC, 0xE2, 0x1C, 0x0A, 0xE2, 0xEC, 0xE7, 0x62,
+ 0x4C, 0xE4, 0xB4, 0x05, 0x51, 0x80, 0x93, 0x04, 0xE7, 0x8F, 0x70, 0x01, 0x6C, 0xA1, 0x62, 0x0D,
+ 0xFE, 0x75, 0xF8, 0xC1, 0x76, 0x3D, 0x55, 0x54, 0x5D, 0x27, 0xD1, 0xE0, 0x23, 0x13, 0x64, 0x3B,
+ 0x6E, 0x67, 0xCD, 0x8E, 0x28, 0x20, 0x51, 0x5A, 0x50, 0xF2, 0x45, 0x89, 0xDF, 0x2B, 0xB5, 0x78,
+ 0x26, 0x07, 0x17, 0x04, 0x8A, 0xE6, 0x46, 0x5F, 0x2C, 0x1D, 0x84, 0xDC, 0x24, 0xBC, 0x60, 0xD6,
+ 0x1D, 0x78, 0x1F, 0x25, 0xA4, 0xE5, 0x7F, 0x75, 0x5E, 0x66, 0x18, 0x97, 0x73, 0xF0, 0x01, 0xA7,
+ 0x84, 0x27, 0x88, 0x58, 0xA1, 0x09, 0xDE, 0xC5, 0x05, 0x09, 0x3F, 0x88, 0xA0, 0x79, 0x24, 0x54,
+ 0x0F, 0x80, 0xC6, 0x66, 0x07, 0xA2, 0x44, 0x2A, 0xE9, 0xA4, 0x23, 0x22, 0x3A, 0xC7, 0x36, 0x0D,
+ 0x0C, 0xD0, 0x28, 0x81, 0xA0, 0xB5, 0x44, 0xE9, 0xA7, 0xA0, 0xA2, 0x71, 0x52, 0x36, 0x70, 0xE8,
+ 0x25, 0x55, 0x9A, 0x9C, 0x46, 0xE5, 0x8F, 0x40, 0xA1, 0xB6, 0xEA, 0x6A, 0x10, 0xA3, 0x9E, 0x49,
+ 0x9E, 0x92, 0xA7, 0xA6, 0xCA, 0xA9, 0xA7, 0xAF, 0xE6, 0xAA, 0xEB, 0x0A, 0xA5, 0x4E, 0x99, 0x57,
+ 0x1D, 0xB5, 0x6E, 0x8A, 0xEA, 0x18, 0xBB, 0x16, 0x6B, 0xAC, 0x3E, 0x71, 0x20, 0xFE, 0x48, 0x16,
+ 0x36, 0x5D, 0x24, 0xC1, 0xA9, 0xB0, 0x69, 0xEA, 0x70, 0xEC, 0xB4, 0xC6, 0x26, 0xD9, 0x45, 0x0D,
+ 0x1C, 0x8C, 0x0A, 0x2C, 0x81, 0xD0, 0x76, 0x2A, 0x2D, 0xB5, 0xE0, 0xBE, 0x9A, 0xA4, 0x21, 0xB9,
+ 0x0C, 0x47, 0x6E, 0x9F, 0xB5, 0xDA, 0xEA, 0x28, 0xB1, 0x25, 0x88, 0x54, 0xD2, 0x98, 0x8D, 0xD5,
+ 0xA7, 0x09, 0x31, 0xF6, 0x25, 0x33, 0x4A, 0x48, 0x9F, 0x80, 0x34, 0xA6, 0x0A, 0x74, 0x56, 0xA1,
+ 0xAF, 0x0F, 0x6D, 0x10, 0x27, 0x41, 0x1B, 0x4C, 0x79, 0xA1, 0x2E, 0x5F, 0x9D, 0xAA, 0x67, 0xEF,
+ 0x1A, 0xD3, 0x30, 0xBC, 0xF0, 0xBD, 0xEE, 0xDE, 0xEB, 0x30, 0x57, 0xF3, 0x36, 0x4C, 0xC2, 0xBF,
+ 0x12, 0x5B, 0xBC, 0x6F, 0x97, 0x16, 0x9B, 0xB1, 0xB1, 0x0A, 0x59, 0xC8, 0x30, 0x9C, 0xC8, 0xDB,
+ 0x68, 0x9A, 0xEA, 0x02, 0x09, 0x2B, 0x70, 0x71, 0xC7, 0x15, 0xB3, 0x92, 0x71, 0xBE, 0x1A, 0x67,
+ 0x3C, 0xF1, 0x57, 0xF8, 0xC2, 0x6C, 0x14, 0xC4, 0xEE, 0xB2, 0x27, 0x33, 0xBC, 0x3A, 0xC3, 0x2C,
+ 0x2F, 0xC4, 0xEC, 0x8C, 0x25, 0xF1, 0xBB, 0xFD, 0x7E, 0x10, 0xB2, 0x12, 0xC4, 0x91, 0x5B, 0x32,
+ 0x54, 0x46, 0x14, 0xB7, 0xF2, 0xCC, 0x0F, 0xCF, 0x1B, 0x71, 0xC4, 0x40, 0x83, 0xF2, 0x30, 0xC6,
+ 0xFA, 0x92, 0x92, 0x35, 0xC3, 0x53, 0x43, 0x87, 0x5F, 0xD7, 0xA9, 0x70, 0xDD, 0xB0, 0xCE, 0x62,
+ 0x57, 0x6D, 0xF6, 0x98, 0x4D, 0x8B, 0x3C, 0x32, 0xD2, 0xE4, 0xA6, 0x8A, 0xB0, 0x5F, 0x4F, 0xCB,
+ 0x1C, 0x75, 0xCC, 0x65, 0x57, 0xBD, 0x2F, 0xD9, 0x43, 0x3B, 0xEC, 0xF5, 0xC4, 0xF9, 0x6A, 0xED,
+ 0x72, 0xCB, 0x36, 0xBF, 0x2C, 0xB8, 0x62, 0x7E, 0x9F, 0x2D, 0xF8, 0x08, 0x69, 0x87, 0xB1, 0xF6,
+ 0x3F, 0x6B, 0xAA, 0x0B, 0x9A, 0xC2, 0x7C, 0xB7, 0xFB, 0xF7, 0xE0, 0x63, 0xFE, 0xC7, 0x27, 0x35,
+ 0xDD, 0x18, 0xD3, 0x6D, 0x36, 0xD4, 0x72, 0x53, 0x1E, 0xF9, 0xD4, 0x1D, 0xDB, 0x1C, 0xF8, 0xE8,
+ 0x24, 0x2C, 0xB0, 0x44, 0x0E, 0x2C, 0x99, 0xDE, 0x6D, 0x9A, 0x90, 0xEF, 0x1C, 0x7A, 0xCB, 0x9E,
+ 0xBB, 0x1E, 0x35, 0xE9, 0x79, 0xCB, 0x9D, 0x39, 0xE9, 0xF0, 0x8E, 0xAD, 0x7B, 0xD8, 0x86, 0x53,
+ 0x0D, 0xC8, 0xBF, 0xA0, 0x73, 0x6E, 0x80, 0x12, 0x39, 0x9C, 0x27, 0x72, 0x07, 0x3A, 0xB4, 0xED,
+ 0x76, 0xEB, 0x5E, 0xC3, 0x44, 0xF8, 0x4D, 0xF1, 0xEE, 0x0D, 0xD8, 0xCD, 0x7A, 0xF7, 0xFD, 0xD0,
+ 0xEF, 0x1A, 0xE3, 0xFD, 0x12, 0xF5, 0x60, 0x07, 0xBD, 0xB3, 0xCF, 0xA2, 0xE3, 0x9D, 0xB9, 0x01,
+ 0xA6, 0x9F, 0x6E, 0x7C, 0x0D, 0x18, 0xE8, 0x60, 0x2D, 0xB4, 0xEC, 0x4E, 0x1E, 0x77, 0xB8, 0x81,
+ 0x7C, 0x9C, 0x06, 0xF1, 0x17, 0xD8, 0x60, 0x6E, 0x68, 0x03, 0x2F, 0xA0, 0x68, 0x54, 0x2A, 0x4B,
+ 0xFE, 0x3E, 0xFC, 0x6A, 0x90, 0x1F, 0x1A, 0xCA, 0x57, 0xBF, 0xD0, 0x98, 0x2B, 0x09, 0xF9, 0x03,
+ 0x80, 0x21, 0x6E, 0xD5, 0x3A, 0x00, 0x3A, 0x30, 0x0D, 0x04, 0xB4, 0x1F, 0x0E, 0x8E, 0xE0, 0x17,
+ 0x23, 0x48, 0xF0, 0x11, 0x67, 0x20, 0xDC, 0xF7, 0xDE, 0xF5, 0x3F, 0xF9, 0x79, 0x29, 0x52, 0x02,
+ 0x7C, 0x60, 0x1A, 0x70, 0x37, 0xBB, 0xB5, 0xC0, 0xEE, 0x7D, 0x21, 0x94, 0x42, 0x0A, 0x45, 0xE8,
+ 0xB1, 0xD8, 0xB9, 0x6E, 0x6B, 0xE0, 0x13, 0x9A, 0x0C, 0x59, 0x96, 0xB5, 0x9C, 0xD9, 0x50, 0x6C,
+ 0xBE, 0x3B, 0x4A, 0xE7, 0x58, 0x28, 0x0A, 0x12, 0x26, 0x06, 0x78, 0x61, 0xEB, 0x59, 0xE4, 0x7E,
+ 0xF8, 0xB9, 0xDD, 0xE1, 0xAC, 0x88, 0x65, 0xAB, 0x17, 0x0F, 0x03, 0x18, 0x33, 0x0D, 0xC6, 0xCE,
+ 0x87, 0x14, 0xAB, 0x98, 0x0D, 0xD9, 0x33, 0xC5, 0xC0, 0xD9, 0xAD, 0x55, 0x70, 0x3B, 0x5C, 0xE2,
+ 0x08, 0xA1, 0x27, 0xBB, 0xBC, 0x05, 0x6F, 0x73, 0xB6, 0xD3, 0x9C, 0x14, 0x61, 0x27, 0x3A, 0xC0,
+ 0x69, 0x11, 0x84, 0x97, 0x73, 0xA2, 0x17, 0x83, 0xB8, 0x3B, 0xAA, 0x0D, 0xF1, 0x8B, 0x50, 0x1C,
+ 0xE2, 0x15, 0xCF, 0xD8, 0xC3, 0x34, 0x96, 0x10, 0x86, 0x83, 0xAB, 0x21, 0x19, 0xBD, 0x37, 0x43,
+ 0x0E, 0xCE, 0x4E, 0x87, 0xE3, 0xA3, 0x63, 0xB8, 0x56, 0x28, 0xC8, 0x42, 0x82, 0xB0, 0x68, 0x86,
+ 0x4C, 0xA4, 0x22, 0x17, 0xC9, 0xC8, 0x46, 0x3A, 0xF2, 0x91, 0x90, 0x8C, 0xA4, 0x24, 0x75, 0x95,
+ 0x00, 0x00, 0x3B,
+};
+
+// Bonus data
+BYTE Saitama[] =
+{
+ 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x01, 0x00, 0x00, 0xFF, 0xDB, 0x00, 0x84, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01,
+ 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x04, 0x03, 0x03,
+ 0x03, 0x04, 0x03, 0x02, 0x02, 0x04, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x03, 0x03,
+ 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x01, 0x01, 0x02, 0x04, 0x03, 0x02, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0xFF, 0xC4, 0x01, 0xA2, 0x00, 0x00,
+ 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x01, 0x00, 0x03, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04,
+ 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05,
+ 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1,
+ 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A,
+ 0x16, 0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5,
+ 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3,
+ 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9,
+ 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0x11, 0x00, 0x02, 0x01, 0x02,
+ 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03,
+ 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81,
+ 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1,
+ 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A,
+ 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54,
+ 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74,
+ 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92,
+ 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9,
+ 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5,
+ 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0xC0,
+ 0x00, 0x11, 0x08, 0x01, 0x9B, 0x02, 0x1C, 0x03, 0x01, 0x11, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11,
+ 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3F, 0x00, 0xFA,
+ 0xFE, 0xBF, 0x5F, 0x3E, 0x18, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02,
+ 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A,
+ 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28,
+ 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0,
+ 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80,
+ 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00,
+ 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00,
+ 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x03, 0xF3, 0xB3,
+ 0xF6, 0x8A, 0xFF, 0x00, 0x82, 0xA1, 0xFE, 0xCA, 0xFF, 0x00, 0xB2, 0xE7, 0xC5, 0x3D, 0x5F, 0xE0,
+ 0xEF, 0xC5, 0x3B, 0xCF, 0x1F, 0x41, 0xE3, 0x2D, 0x0F, 0x4E, 0xB0, 0xD4, 0xEF, 0xA3, 0xF0, 0xFF,
+ 0x00, 0x83, 0x4E, 0xB1, 0xA6, 0x2C, 0x5A, 0x85, 0xA2, 0x5C, 0x5B, 0x6C, 0x9F, 0xCE, 0x4C, 0x9F,
+ 0x2E, 0x64, 0xC8, 0xDA, 0x30, 0x72, 0x3B, 0x57, 0x93, 0x8A, 0xCE, 0xB0, 0x38, 0x2A, 0xCF, 0x0F,
+ 0x5A, 0xFC, 0xC9, 0x2D, 0x96, 0x9A, 0xAD, 0x3F, 0x03, 0xB6, 0x86, 0x5F, 0x5E, 0xBD, 0x35, 0x52,
+ 0x9A, 0x5C, 0xBE, 0xB6, 0xD8, 0xF1, 0xD5, 0xFF, 0x00, 0x82, 0xD9, 0xFE, 0xC4, 0xCD, 0x67, 0x0D,
+ 0xFA, 0xFF, 0x00, 0xC2, 0xE6, 0x36, 0x33, 0xCA, 0x6D, 0xED, 0xEE, 0xD7, 0xE1, 0x74, 0x9F, 0x66,
+ 0x99, 0xD4, 0x7C, 0xC9, 0x1B, 0xFD, 0xA3, 0x6B, 0x11, 0xC6, 0x40, 0xE9, 0x59, 0x47, 0x3F, 0xC0,
+ 0x38, 0xA9, 0x46, 0x32, 0xB3, 0xD1, 0x5A, 0x3D, 0x7B, 0x2F, 0xF2, 0x3A, 0x61, 0x92, 0xE3, 0xE7,
+ 0x75, 0x4E, 0x17, 0xB2, 0x4F, 0x4E, 0x89, 0xE8, 0xB6, 0x5B, 0x74, 0x42, 0x43, 0xFF, 0x00, 0x05,
+ 0xB6, 0xFD, 0x88, 0x67, 0x1F, 0xB9, 0xB9, 0xF8, 0xB4, 0xFB, 0x47, 0x2A, 0x3E, 0x1E, 0xA2, 0x32,
+ 0xE3, 0xB1, 0x53, 0x74, 0x08, 0xE9, 0xD3, 0x15, 0xF7, 0x3C, 0x39, 0xC2, 0x7C, 0x53, 0xC5, 0xD8,
+ 0x7F, 0xAC, 0xF0, 0xCE, 0x01, 0xE2, 0x29, 0xA4, 0xDF, 0xB9, 0x57, 0x0C, 0x9A, 0x4B, 0x47, 0x78,
+ 0x4A, 0xB4, 0x66, 0x9F, 0x93, 0x8A, 0x7D, 0x91, 0xC5, 0x5F, 0x0B, 0x2C, 0x24, 0x9D, 0x3C, 0x43,
+ 0x51, 0x6B, 0x4B, 0x35, 0x25, 0xFF, 0x00, 0xB6, 0x93, 0x47, 0xFF, 0x00, 0x05, 0xAF, 0xFD, 0x89,
+ 0xA4, 0x46, 0x68, 0xE7, 0xF8, 0xB2, 0xCA, 0x98, 0xDD, 0x8F, 0x00, 0x44, 0x36, 0x8C, 0x71, 0xC7,
+ 0xDA, 0xC7, 0xA7, 0xA5, 0x7D, 0x16, 0x5B, 0xE1, 0x3F, 0x89, 0x79, 0xB6, 0x16, 0xAE, 0x2F, 0x2D,
+ 0xC9, 0xA5, 0x3A, 0x74, 0xB4, 0x9B, 0x58, 0x8C, 0x1A, 0x71, 0xF5, 0x8C, 0xB1, 0x2A, 0x5F, 0x72,
+ 0xB7, 0x4E, 0x86, 0x12, 0xF6, 0x34, 0xDA, 0x8C, 0xAA, 0x24, 0xDE, 0xDA, 0x4B, 0xF4, 0x8D, 0x8F,
+ 0x54, 0xF8, 0x65, 0xFF, 0x00, 0x05, 0x40, 0xFD, 0x9E, 0x7E, 0x32, 0x4B, 0xAA, 0x5B, 0xFC, 0x32,
+ 0xF0, 0xDF, 0xC5, 0x8F, 0x14, 0x4F, 0xA2, 0x47, 0x0C, 0xBA, 0xA4, 0x0B, 0xA1, 0x68, 0x9A, 0x14,
+ 0x96, 0x51, 0xCE, 0xC5, 0x62, 0x90, 0xAD, 0xEE, 0xAD, 0x06, 0xE4, 0xCA, 0x36, 0x59, 0x72, 0xAB,
+ 0x8C, 0xB1, 0x51, 0x5E, 0x7E, 0x71, 0xE1, 0xDF, 0x1E, 0xF0, 0xF5, 0x18, 0x56, 0xCE, 0x72, 0x99,
+ 0xD2, 0x84, 0xAF, 0xCB, 0xFB, 0xDC, 0x2C, 0xAF, 0x64, 0x9B, 0xB2, 0x85, 0x79, 0x37, 0x64, 0xD6,
+ 0x89, 0x79, 0x2D, 0x9A, 0x5C, 0x58, 0xAC, 0xC3, 0x2D, 0xC0, 0xA4, 0xF1, 0x55, 0xD4, 0x63, 0xDF,
+ 0x92, 0xA3, 0x5D, 0xB7, 0x50, 0x69, 0x7A, 0x36, 0xAD, 0xA7, 0x4B, 0x09, 0x27, 0xFC, 0x15, 0x07,
+ 0xF6, 0x7A, 0xB6, 0xF8, 0x85, 0x0F, 0xC2, 0x8B, 0xCF, 0x0B, 0xFC, 0x5F, 0xD3, 0x7E, 0x20, 0xCF,
+ 0x78, 0x9A, 0x7C, 0x1E, 0x1D, 0xD5, 0xFC, 0x33, 0xA4, 0x68, 0xAB, 0x2C, 0xB2, 0x21, 0x68, 0x95,
+ 0x2F, 0xA7, 0xD5, 0x23, 0xB2, 0x2A, 0xCA, 0x8C, 0x55, 0xC4, 0xDB, 0x1B, 0x18, 0x56, 0x27, 0x8A,
+ 0xD7, 0x0B, 0xE1, 0xB7, 0x88, 0x18, 0xCC, 0xAA, 0x59, 0xD6, 0x0F, 0x29, 0x94, 0xF0, 0xB1, 0xD1,
+ 0xCA, 0x35, 0xB0, 0x8E, 0x4B, 0x6F, 0xF9, 0x76, 0xB1, 0x1E, 0xD3, 0x4B, 0xA5, 0xF0, 0x69, 0xB7,
+ 0x4D, 0x1C, 0x71, 0xF9, 0x6C, 0xA9, 0x2A, 0xB4, 0xEB, 0xA7, 0x06, 0x9B, 0x56, 0x8C, 0xDE, 0x8A,
+ 0xD7, 0xD1, 0x42, 0xEA, 0xD7, 0x5A, 0x5B, 0xAA, 0xD3, 0x54, 0x69, 0x7C, 0x46, 0xFF, 0x00, 0x82,
+ 0x94, 0xFC, 0x0F, 0xF8, 0x47, 0x67, 0xA6, 0xDF, 0xFC, 0x46, 0xF0, 0x37, 0xC6, 0xCF, 0x0B, 0xD8,
+ 0x6A, 0xD7, 0x52, 0x58, 0x69, 0xD7, 0x72, 0xF8, 0x4B, 0x4A, 0xD5, 0x2D, 0xAE, 0x27, 0x84, 0x02,
+ 0xF0, 0x96, 0xB5, 0xD4, 0xE5, 0x08, 0xE0, 0x11, 0x85, 0x7D, 0xA4, 0xFF, 0x00, 0x08, 0x38, 0xE2,
+ 0x32, 0x8F, 0x0E, 0xB8, 0xFB, 0x3D, 0x9B, 0xA3, 0x94, 0x65, 0x33, 0x9C, 0x97, 0x4F, 0x6D, 0x85,
+ 0x83, 0x56, 0xF2, 0x9E, 0x22, 0x3D, 0xB4, 0x5D, 0x74, 0xB5, 0xF4, 0x0C, 0x1E, 0x3F, 0x2D, 0xC7,
+ 0xCE, 0x54, 0xF0, 0x58, 0x88, 0xC9, 0xC5, 0x2B, 0xA4, 0xA6, 0xB7, 0xDA, 0xD7, 0x82, 0xBD, 0xFA,
+ 0x25, 0xBD, 0xAC, 0x95, 0xD5, 0x88, 0x63, 0xFF, 0x00, 0x82, 0x99, 0x7C, 0x06, 0x97, 0xC1, 0x96,
+ 0x7F, 0x10, 0x6D, 0xFC, 0x1F, 0xF1, 0x8A, 0xEB, 0xC1, 0x77, 0xF6, 0xF3, 0x5C, 0x58, 0xEB, 0xD6,
+ 0x5E, 0x1A, 0xD1, 0xEF, 0x60, 0xBA, 0x4B, 0x76, 0x2B, 0x38, 0x8E, 0x08, 0xF5, 0x56, 0x98, 0xB2,
+ 0x15, 0x60, 0x53, 0xCB, 0xDC, 0x30, 0x78, 0xC0, 0xE2, 0x9F, 0x86, 0xDE, 0x20, 0xC7, 0x18, 0xF2,
+ 0xE7, 0x94, 0x4D, 0x57, 0x5B, 0xC3, 0xDB, 0x61, 0x6E, 0xB6, 0xDF, 0xFD, 0xA2, 0xC9, 0x6D, 0xAE,
+ 0xCB, 0x4B, 0xB4, 0x72, 0xBC, 0xF7, 0x23, 0x85, 0x7F, 0xAA, 0xD4, 0xC5, 0x46, 0x33, 0xDA, 0xD2,
+ 0x8D, 0x48, 0x76, 0x5B, 0xCA, 0x09, 0x7A, 0x2B, 0xEB, 0xD3, 0x44, 0xED, 0x83, 0xE0, 0x7F, 0xF8,
+ 0x2A, 0xC7, 0xEC, 0xD5, 0xF1, 0x22, 0xE6, 0xF2, 0xC7, 0xC0, 0xBE, 0x1E, 0xF8, 0xC7, 0xE2, 0x3B,
+ 0xDD, 0x3E, 0xD1, 0x6F, 0x6E, 0xAC, 0xAD, 0x3C, 0x1B, 0xA7, 0xDA, 0xDE, 0x24, 0x24, 0x90, 0x24,
+ 0x48, 0x66, 0xD4, 0x63, 0x69, 0x14, 0x15, 0x20, 0xEC, 0x0D, 0x8C, 0x73, 0x8C, 0x8A, 0xD7, 0x13,
+ 0xE1, 0x87, 0x88, 0x98, 0x2A, 0xB1, 0xA1, 0x8A, 0xCA, 0x25, 0x19, 0x35, 0x75, 0x7A, 0xF8, 0x3B,
+ 0x34, 0xAC, 0xB4, 0x92, 0xC4, 0xF2, 0xE9, 0x75, 0xA5, 0xEE, 0xBB, 0x59, 0x1D, 0xD8, 0xAC, 0x4E,
+ 0x0F, 0x03, 0x4E, 0x15, 0x31, 0x35, 0x79, 0x63, 0x2B, 0x28, 0xBE, 0x4A, 0x8D, 0x3B, 0xE8, 0xAD,
+ 0xCB, 0x07, 0xDB, 0xD2, 0xC9, 0xBD, 0x93, 0xB6, 0x27, 0x8A, 0xBF, 0xE0, 0xAF, 0x7F, 0xB2, 0x87,
+ 0x81, 0xB5, 0xDB, 0xCF, 0x0B, 0xF8, 0xBB, 0x49, 0xF8, 0xCD, 0xA0, 0x6B, 0xFA, 0x7A, 0xA1, 0xBC,
+ 0xD2, 0xAF, 0x7E, 0x1F, 0xC1, 0xF6, 0x8B, 0x71, 0x22, 0x06, 0x42, 0x4A, 0x5E, 0xB2, 0x90, 0x54,
+ 0xA9, 0xE0, 0x9F, 0xD3, 0x8E, 0xAC, 0xBB, 0xC2, 0x3F, 0x13, 0xF3, 0x58, 0xCA, 0x59, 0x66, 0x49,
+ 0x3A, 0x89, 0x68, 0xF9, 0x6B, 0xE0, 0xDD, 0xAC, 0xED, 0xFF, 0x00, 0x41, 0x3D, 0x1A, 0xB6, 0x9E,
+ 0x5D, 0x1A, 0x2E, 0x9D, 0x6C, 0x25, 0x4A, 0x6A, 0x70, 0xAA, 0xB9, 0x76, 0xDA, 0x6B, 0xF0, 0x71,
+ 0x4D, 0x7D, 0xC8, 0xE6, 0xFF, 0x00, 0xE1, 0xF5, 0x7F, 0xB1, 0x48, 0x1F, 0xEB, 0x7E, 0x2C, 0x80,
+ 0x00, 0xFF, 0x00, 0x99, 0x02, 0x2F, 0xC0, 0x01, 0xF6, 0xBF, 0xA5, 0x74, 0x4B, 0xC1, 0x8F, 0x16,
+ 0x20, 0xBD, 0xEC, 0x8A, 0x76, 0xFF, 0x00, 0xAF, 0xF8, 0x2F, 0xCB, 0xEB, 0x26, 0x89, 0xD0, 0xB2,
+ 0xB5, 0x48, 0xDB, 0xD2, 0x5F, 0xFC, 0x88, 0x9F, 0xF0, 0xFA, 0xCF, 0xD8, 0xA0, 0x0F, 0xF5, 0xBF,
+ 0x16, 0x80, 0x18, 0xFF, 0x00, 0x9A, 0x7F, 0x18, 0x03, 0xD3, 0xFE, 0x5E, 0xFE, 0x95, 0x9F, 0xFC,
+ 0x41, 0xDF, 0x15, 0x22, 0xB5, 0xC8, 0xAA, 0x5B, 0xFE, 0xBF, 0xE0, 0xFF, 0x00, 0xF9, 0xA4, 0x2F,
+ 0x43, 0xFE, 0x7E, 0x2F, 0xBA, 0x5F, 0xFC, 0x88, 0x9F, 0xF0, 0xFA, 0xFF, 0x00, 0xD8, 0x98, 0x0F,
+ 0xF5, 0xFF, 0x00, 0x16, 0x40, 0x18, 0x18, 0xFF, 0x00, 0x84, 0x02, 0x21, 0x8E, 0x38, 0x18, 0xFB,
+ 0x5D, 0x63, 0x3F, 0x09, 0x7C, 0x4D, 0xA5, 0x16, 0xE7, 0x92, 0xC9, 0x25, 0xFF, 0x00, 0x51, 0x18,
+ 0x2F, 0x96, 0x9F, 0x59, 0xFB, 0x92, 0xDF, 0xA2, 0x1A, 0x54, 0x74, 0x4A, 0xA2, 0xFB, 0xA5, 0xFF,
+ 0x00, 0xC8, 0x91, 0x2F, 0xFC, 0x16, 0xD3, 0xF6, 0x22, 0x27, 0x60, 0xB8, 0xF8, 0xB6, 0x08, 0xC0,
+ 0xF9, 0xBE, 0x1E, 0x2C, 0x6A, 0x3D, 0x30, 0x4D, 0xD0, 0x1D, 0xAB, 0xCA, 0xA3, 0xC0, 0x3C, 0x77,
+ 0x5B, 0x12, 0xF0, 0x70, 0xC9, 0xEA, 0xA9, 0xAF, 0xE7, 0x95, 0x0A, 0x71, 0xFF, 0x00, 0xC0, 0xE7,
+ 0x56, 0x34, 0xED, 0xA7, 0x49, 0x59, 0x2B, 0x74, 0xB1, 0x7E, 0xCA, 0x0A, 0x29, 0xF3, 0xC6, 0xDE,
+ 0x57, 0x7F, 0x82, 0x57, 0xFC, 0x07, 0xBF, 0xFC, 0x16, 0xC7, 0xF6, 0x23, 0x8D, 0xB6, 0x1B, 0xAF,
+ 0x8A, 0xC4, 0x80, 0x3F, 0xD5, 0xF8, 0x0A, 0x29, 0x13, 0x18, 0xEC, 0xCB, 0x78, 0x47, 0x61, 0xDE,
+ 0xB4, 0x9F, 0x87, 0x9C, 0x77, 0x4E, 0xA3, 0xA2, 0xF2, 0xB9, 0x73, 0x2E, 0xD5, 0xB0, 0x92, 0x5A,
+ 0x79, 0xC7, 0x10, 0xE3, 0xF7, 0x3F, 0x24, 0x53, 0xA3, 0x18, 0x59, 0x39, 0xC7, 0xE5, 0x76, 0xBF,
+ 0x05, 0x6F, 0xF2, 0x23, 0x4F, 0xF8, 0x2D, 0xB7, 0xEC, 0x40, 0xCD, 0xE5, 0xAD, 0xD7, 0xC5, 0x90,
+ 0x46, 0x07, 0xCF, 0xF0, 0xF5, 0x62, 0x8C, 0x71, 0xC7, 0xCC, 0x6E, 0x82, 0xFA, 0x77, 0xAF, 0x3A,
+ 0x9F, 0x09, 0x71, 0x75, 0x4A, 0xB3, 0xA1, 0x1C, 0xAE, 0xAA, 0x71, 0xDD, 0xC9, 0xD2, 0x84, 0x57,
+ 0xFD, 0xBF, 0x3A, 0x91, 0x83, 0xF9, 0x4B, 0x6F, 0x22, 0xA3, 0x86, 0xBD, 0x94, 0x67, 0x1D, 0x76,
+ 0xD6, 0xDF, 0xA6, 0x9F, 0xD2, 0x10, 0xFF, 0x00, 0xC1, 0x6E, 0x3F, 0x61, 0xF4, 0xE0, 0xDE, 0x7C,
+ 0x57, 0x00, 0x71, 0xC7, 0xC3, 0xF4, 0x65, 0xC0, 0x1D, 0x01, 0x17, 0x78, 0xED, 0x4B, 0x11, 0xC2,
+ 0x7C, 0x53, 0x84, 0x6A, 0x35, 0xB0, 0x0D, 0x2E, 0xEA, 0xAE, 0x1A, 0x51, 0xF2, 0xF7, 0xA3, 0x5D,
+ 0xC7, 0xD1, 0x5F, 0xC9, 0x2D, 0x89, 0x8E, 0x1E, 0xFA, 0x46, 0x4B, 0xEE, 0x6B, 0xF0, 0xB2, 0x18,
+ 0xBF, 0xF0, 0x5B, 0xCF, 0xD8, 0x70, 0xE0, 0x0B, 0xCF, 0x8B, 0x2A, 0x31, 0xC1, 0x6F, 0x87, 0x62,
+ 0x34, 0xC0, 0x1D, 0x98, 0xDD, 0x01, 0xDA, 0xB8, 0xA8, 0xE4, 0x99, 0xFD, 0x59, 0xAA, 0x71, 0xC0,
+ 0xCE, 0x2B, 0xF9, 0xA7, 0x2A, 0x54, 0xE1, 0xFF, 0x00, 0x83, 0x2A, 0x54, 0x8D, 0x3B, 0x2F, 0xF1,
+ 0x59, 0x22, 0xFE, 0xAB, 0x24, 0x97, 0xBC, 0xBE, 0x57, 0x7F, 0x82, 0x57, 0xFC, 0x06, 0x7F, 0xC3,
+ 0xF0, 0x3F, 0x61, 0x90, 0x76, 0x0B, 0xEF, 0x8B, 0x04, 0x80, 0x38, 0x5F, 0x87, 0x81, 0x97, 0x18,
+ 0xE3, 0x04, 0x5D, 0x63, 0xF2, 0xAE, 0x39, 0x61, 0x73, 0x08, 0x57, 0x78, 0x55, 0x86, 0x6E, 0x6B,
+ 0xA4, 0x67, 0x4A, 0x6B, 0x6E, 0x92, 0x85, 0x49, 0x41, 0xAE, 0xD6, 0x93, 0x5D, 0x8A, 0x58, 0x2A,
+ 0x9C, 0xA9, 0xA6, 0xAD, 0xF3, 0x5F, 0x85, 0x90, 0xDF, 0xF8, 0x7E, 0x0F, 0xEC, 0x30, 0x38, 0xFB,
+ 0x77, 0xC5, 0x91, 0x81, 0xD3, 0xFE, 0x15, 0xD0, 0x18, 0xC7, 0x6F, 0xF8, 0xF9, 0xAC, 0x5C, 0x31,
+ 0x70, 0xBC, 0x65, 0x86, 0x92, 0x6B, 0x4B, 0x37, 0x4D, 0x5B, 0xC9, 0xFB, 0xEA, 0xDE, 0x80, 0xB0,
+ 0x35, 0x6C, 0xAC, 0xD5, 0xBE, 0x7F, 0xE4, 0x1F, 0xF0, 0xFC, 0x2F, 0xD8, 0x5C, 0x01, 0xFE, 0x9F,
+ 0xF1, 0x60, 0x0E, 0xDF, 0xF1, 0x6E, 0xC0, 0x1C, 0x74, 0xC7, 0xFA, 0x4D, 0x66, 0xE5, 0x5E, 0x29,
+ 0x5E, 0x84, 0x92, 0xE9, 0xAD, 0x35, 0xFF, 0x00, 0xB7, 0xFD, 0xDF, 0x80, 0xD6, 0x06, 0xAE, 0xC9,
+ 0xAF, 0xC7, 0xFC, 0x80, 0x7F, 0xC1, 0x70, 0xBF, 0x61, 0x7C, 0x71, 0x7F, 0xF1, 0x63, 0x03, 0x1C,
+ 0x0F, 0x87, 0x63, 0x8F, 0x4E, 0x3E, 0xD3, 0xED, 0x49, 0x4E, 0xB5, 0x9B, 0x8D, 0x09, 0x59, 0x6F,
+ 0x67, 0x4D, 0xDB, 0xE4, 0xA7, 0xFA, 0x7E, 0x40, 0xB0, 0x15, 0x74, 0x57, 0x56, 0xF9, 0xFF, 0x00,
+ 0x90, 0x9F, 0xF0, 0xFC, 0x3F, 0xD8, 0x5F, 0xA7, 0xDB, 0xFE, 0x2C, 0xFA, 0x63, 0xFE, 0x15, 0xCF,
+ 0xB7, 0x4C, 0x7D, 0xA6, 0x92, 0xA9, 0x5B, 0x65, 0x42, 0x7F, 0xF9, 0x2F, 0xFF, 0x00, 0x24, 0x1F,
+ 0x50, 0xAB, 0xDD, 0x7D, 0xFF, 0x00, 0xF0, 0x03, 0xFE, 0x1F, 0x87, 0xFB, 0x0B, 0x0E, 0x3E, 0xDF,
+ 0xF1, 0x64, 0x76, 0xC7, 0xFC, 0x2B, 0xAC, 0x74, 0x1D, 0x31, 0xF6, 0x9F, 0xA5, 0x27, 0x5A, 0xA4,
+ 0x2C, 0xA5, 0x46, 0x4B, 0xFF, 0x00, 0x00, 0x5F, 0xFB, 0x70, 0xD6, 0x5F, 0x5B, 0xA3, 0x5F, 0x7F,
+ 0xFC, 0x01, 0x3F, 0xE1, 0xF8, 0x9F, 0xB0, 0xB7, 0xFC, 0xFF, 0x00, 0xFC, 0x58, 0xFF, 0x00, 0xC3,
+ 0x75, 0xFF, 0x00, 0xDD, 0x35, 0x1F, 0x5A, 0x69, 0x7F, 0x0A, 0x56, 0xF5, 0x87, 0xFF, 0x00, 0x24,
+ 0x1F, 0xD9, 0xF5, 0xFB, 0xAF, 0xEB, 0xE4, 0x1F, 0xF0, 0xFC, 0x4F, 0xD8, 0x5B, 0xFE, 0x7F, 0xFE,
+ 0x2C, 0x7F, 0xE1, 0xBA, 0xFF, 0x00, 0xEE, 0x9A, 0x7F, 0x59, 0x6A, 0xCB, 0xD9, 0x4B, 0xEF, 0x87,
+ 0xFF, 0x00, 0x24, 0x1F, 0xD9, 0xF5, 0xFB, 0xAF, 0xEB, 0xE4, 0x1F, 0xF0, 0xFC, 0x4F, 0xD8, 0x58,
+ 0x0F, 0xF8, 0xFF, 0x00, 0xF8, 0xB3, 0x80, 0x3A, 0x0F, 0x87, 0x5D, 0x80, 0xE8, 0x07, 0xDA, 0x7D,
+ 0xA9, 0x3C, 0x57, 0x2C, 0x5B, 0x74, 0xA5, 0x64, 0xBA, 0x72, 0xF4, 0xF2, 0x52, 0xBF, 0xC9, 0x2F,
+ 0x24, 0x0B, 0x2E, 0xAF, 0xA2, 0x4D, 0x7D, 0xFF, 0x00, 0xF0, 0x06, 0x8F, 0xF8, 0x2E, 0x3F, 0xEC,
+ 0x27, 0xD0, 0x6A, 0x1F, 0x16, 0x78, 0xC0, 0xC0, 0xF8, 0x70, 0x70, 0x38, 0xE0, 0x0F, 0xF4, 0x9F,
+ 0xA5, 0x71, 0xAC, 0xEB, 0x0A, 0xDB, 0x84, 0x69, 0xCD, 0xB4, 0xED, 0x65, 0x1B, 0xEA, 0xAD, 0xA6,
+ 0x97, 0x57, 0x5A, 0x69, 0xD0, 0xB5, 0x96, 0x62, 0x2C, 0xBE, 0x1B, 0x7A, 0x89, 0xFF, 0x00, 0x0F,
+ 0xC9, 0xFD, 0x84, 0xBF, 0xE8, 0x23, 0xF1, 0x63, 0xFF, 0x00, 0x0D, 0xC9, 0xFF, 0x00, 0xE4, 0x9A,
+ 0xC3, 0xFD, 0x63, 0xCB, 0x56, 0x9E, 0xF7, 0xFE, 0x02, 0x35, 0x95, 0x62, 0xAC, 0xAC, 0x95, 0xBD,
+ 0x7F, 0xE0, 0x07, 0xFC, 0x3F, 0x27, 0xF6, 0x12, 0xFF, 0x00, 0xA0, 0x8F, 0xC5, 0x8F, 0xFC, 0x37,
+ 0x27, 0xFF, 0x00, 0x92, 0x69, 0x7F, 0xAC, 0x99, 0x67, 0x79, 0x7F, 0xE0, 0x3F, 0xF0, 0x43, 0xFB,
+ 0x27, 0x15, 0xD9, 0x7D, 0xFF, 0x00, 0xF0, 0x07, 0x37, 0xFC, 0x17, 0x17, 0xF6, 0x15, 0x40, 0xBB,
+ 0xAF, 0xFE, 0x2D, 0x28, 0x65, 0x05, 0x7F, 0xE2, 0xDC, 0x10, 0x08, 0x23, 0x8C, 0x7F, 0xA4, 0xFD,
+ 0x2B, 0x79, 0x67, 0x78, 0x3A, 0x74, 0x63, 0x88, 0x94, 0x65, 0xEC, 0xDE, 0x8A, 0x5C, 0xBE, 0xEB,
+ 0x6B, 0xA2, 0x69, 0xDA, 0xEB, 0xAA, 0xDD, 0x6C, 0xD2, 0xB5, 0x87, 0x2C, 0xA3, 0x17, 0x09, 0x2A,
+ 0x72, 0x49, 0x3B, 0x27, 0x6B, 0xDB, 0x46, 0xB4, 0x76, 0xB6, 0xD6, 0xB5, 0x84, 0x5F, 0xF8, 0x2E,
+ 0x37, 0xEC, 0x28, 0x47, 0xCB, 0x7F, 0xF1, 0x68, 0x85, 0xC0, 0x3B, 0x7E, 0x1C, 0x1C, 0x2E, 0x7A,
+ 0x0F, 0xF8, 0xF9, 0xAE, 0x7F, 0xF5, 0x97, 0x2B, 0x8D, 0x93, 0x6D, 0x7C, 0xBB, 0x7C, 0xCA, 0x86,
+ 0x4D, 0x8E, 0x92, 0x6E, 0x11, 0x4D, 0x2B, 0x6D, 0xD2, 0xFA, 0x2D, 0x96, 0x97, 0xD9, 0x7E, 0x01,
+ 0xFF, 0x00, 0x0F, 0xC7, 0xFD, 0x85, 0x02, 0x86, 0xFE, 0xD0, 0xF8, 0xB4, 0x10, 0xFC, 0xAA, 0x7F,
+ 0xE1, 0x5C, 0x10, 0xB9, 0x03, 0x90, 0x0F, 0xDA, 0x7E, 0x95, 0xA2, 0xE2, 0x1C, 0xBB, 0x91, 0xCE,
+ 0x2A, 0x5C, 0xAA, 0xDB, 0x47, 0x45, 0x7B, 0xDB, 0xAE, 0x97, 0xB3, 0xB7, 0xA1, 0x9A, 0xCB, 0x31,
+ 0x17, 0xE4, 0x56, 0xBF, 0x6B, 0xFF, 0x00, 0xC0, 0x24, 0x87, 0xFE, 0x0B, 0x85, 0xFB, 0x0C, 0x4D,
+ 0xB8, 0x45, 0x7D, 0xF1, 0x65, 0x84, 0x69, 0xBD, 0xFF, 0x00, 0xE2, 0xDD, 0x05, 0x08, 0xA3, 0xB9,
+ 0xCD, 0xC8, 0xF6, 0xAF, 0x63, 0x25, 0xFA, 0xCF, 0x10, 0xFB, 0x75, 0x92, 0xE1, 0xE5, 0x55, 0x51,
+ 0x83, 0xA9, 0x52, 0xCE, 0x11, 0x50, 0x82, 0x69, 0x39, 0x37, 0x39, 0xC5, 0x59, 0x36, 0x96, 0x8D,
+ 0xBF, 0x2B, 0x19, 0xD4, 0xC0, 0x55, 0xA0, 0xA3, 0xED, 0x1A, 0x57, 0xD1, 0x7F, 0x49, 0x11, 0x7F,
+ 0xC3, 0xF2, 0x3F, 0x61, 0x30, 0x07, 0xFC, 0x4C, 0x7E, 0x2C, 0x0E, 0x38, 0x1F, 0xF0, 0xAE, 0x4F,
+ 0x00, 0x74, 0x18, 0xFB, 0x4F, 0xD2, 0xBC, 0x89, 0xE7, 0xF8, 0x0A, 0x36, 0x53, 0x52, 0x4F, 0xB5,
+ 0x95, 0xFE, 0x69, 0x3B, 0xAF, 0x2B, 0xA5, 0x75, 0x66, 0xB4, 0xB1, 0xA4, 0x72, 0xBC, 0x4B, 0x5E,
+ 0xEA, 0x56, 0xF5, 0xFF, 0x00, 0x80, 0x1F, 0xF0, 0xFC, 0x9F, 0xD8, 0x4B, 0xFE, 0x82, 0x3F, 0x16,
+ 0x3F, 0xF0, 0xDC, 0x9F, 0xFE, 0x49, 0xAC, 0xFF, 0x00, 0xD6, 0x4C, 0xB3, 0xBC, 0xBF, 0xF0, 0x1F,
+ 0xF8, 0x23, 0xFE, 0xC9, 0xC5, 0x76, 0x5F, 0x7F, 0xFC, 0x00, 0xFF, 0x00, 0x87, 0xE4, 0xFE, 0xC2,
+ 0x5F, 0xF4, 0x11, 0xF8, 0xB1, 0xFF, 0x00, 0x86, 0xE4, 0xFF, 0x00, 0xF2, 0x4D, 0x1F, 0xEB, 0x26,
+ 0x59, 0xDE, 0x5F, 0xF8, 0x0F, 0xFC, 0x10, 0xFE, 0xC9, 0xC5, 0x76, 0x5F, 0x7F, 0xFC, 0x03, 0x67,
+ 0x44, 0xFF, 0x00, 0x82, 0xD2, 0xFE, 0xC6, 0x5E, 0x24, 0xD5, 0x2C, 0xB4, 0x3F, 0x0F, 0x5B, 0x7C,
+ 0x6C, 0xD6, 0xF5, 0x8D, 0x44, 0x1F, 0xEC, 0xFD, 0x2F, 0x4A, 0xF8, 0x59, 0x25, 0xED, 0xF5, 0xD8,
+ 0x54, 0x2C, 0xDE, 0x5C, 0x49, 0x70, 0x58, 0xE1, 0x51, 0xCF, 0x03, 0x80, 0xA4, 0xF6, 0xAD, 0xE9,
+ 0xE7, 0x78, 0x3A, 0xA9, 0x3A, 0x71, 0x95, 0xB6, 0xBD, 0x92, 0x5B, 0x5E, 0xD7, 0x6D, 0x24, 0xEC,
+ 0xB4, 0x57, 0x57, 0xB6, 0x86, 0x53, 0xC0, 0xD5, 0xA5, 0x07, 0x39, 0xB4, 0x92, 0xDF, 0x5E, 0xDD,
+ 0x92, 0x57, 0x7F, 0x24, 0x5F, 0xF1, 0x1F, 0xFC, 0x16, 0x4B, 0xF6, 0x40, 0xF0, 0x79, 0xB0, 0x5F,
+ 0x13, 0xD8, 0x7C, 0x6A, 0xD1, 0x06, 0xA5, 0xA6, 0x5B, 0xEA, 0xF6, 0x06, 0xEF, 0xE1, 0xA0, 0xF2,
+ 0xEE, 0x2D, 0x6E, 0xD0, 0xB5, 0xB4, 0xAA, 0xEB, 0x74, 0x54, 0x6F, 0x55, 0x62, 0x14, 0x90, 0xC3,
+ 0x1C, 0x81, 0x5B, 0x62, 0x33, 0x3A, 0x78, 0x48, 0x46, 0xA5, 0x7A, 0x53, 0x8C, 0x1A, 0x4D, 0x3E,
+ 0x5B, 0xC6, 0xCF, 0x44, 0xEE, 0x9B, 0x5A, 0xDB, 0x4D, 0x76, 0xB5, 0xB4, 0xB1, 0x34, 0xF0, 0x73,
+ 0xA9, 0x2F, 0x65, 0x09, 0x47, 0x9B, 0xB5, 0xEC, 0xEC, 0xAD, 0xB2, 0x69, 0x3B, 0x2D, 0x35, 0x4A,
+ 0xDD, 0x0E, 0x6F, 0xFE, 0x1F, 0x87, 0xFB, 0x0C, 0x02, 0x89, 0xF6, 0xCF, 0x8B, 0xA1, 0x9F, 0x02,
+ 0x34, 0xFF, 0x00, 0x85, 0x6C, 0xC0, 0xBF, 0xA0, 0x51, 0xF6, 0x9E, 0x7B, 0x74, 0xAC, 0x5E, 0x77,
+ 0x85, 0x83, 0x8C, 0x25, 0x4E, 0x69, 0xB5, 0x74, 0xB9, 0x1A, 0xBA, 0xB6, 0xE9, 0x76, 0xB7, 0x6D,
+ 0x2C, 0x68, 0xB2, 0xEA, 0xDC, 0xAE, 0x4A, 0x51, 0xE5, 0x5B, 0xBB, 0xAB, 0x2F, 0xF2, 0x23, 0xFF,
+ 0x00, 0x87, 0xE3, 0xFE, 0xC2, 0x80, 0xED, 0xFE, 0xD0, 0xF8, 0xB2, 0x08, 0xF9, 0x76, 0xFF, 0x00,
+ 0xC2, 0xB8, 0x20, 0x82, 0x3B, 0x63, 0xED, 0x3E, 0xD5, 0x9A, 0xE2, 0x0C, 0x03, 0x9A, 0xA5, 0x18,
+ 0xCB, 0x9B, 0x6B, 0x72, 0xEB, 0x7D, 0xAD, 0x6F, 0xD0, 0xA5, 0x95, 0xE2, 0x79, 0x53, 0x5C, 0xB6,
+ 0xF5, 0xD0, 0x07, 0xFC, 0x17, 0x23, 0xF6, 0x13, 0xC7, 0x1A, 0x8F, 0xC5, 0x9C, 0x0C, 0x0E, 0x3E,
+ 0x1C, 0x1C, 0x0F, 0x41, 0xFF, 0x00, 0x1F, 0x3E, 0xD4, 0x97, 0x10, 0xE5, 0xFC, 0xAE, 0x49, 0x4B,
+ 0x95, 0x5A, 0xFE, 0xEE, 0x8B, 0xB7, 0xA6, 0xDA, 0x0D, 0x65, 0x58, 0x9D, 0x12, 0xB7, 0xDE, 0x03,
+ 0xFE, 0x0B, 0x91, 0xFB, 0x09, 0xF0, 0x06, 0xA3, 0xF1, 0x67, 0xD8, 0x0F, 0x87, 0x27, 0xB0, 0xEC,
+ 0x3E, 0xD3, 0xED, 0x44, 0x38, 0x87, 0x2E, 0x93, 0x51, 0x82, 0x93, 0x7D, 0x94, 0x7B, 0x79, 0x2E,
+ 0xC8, 0x3F, 0xB2, 0xB1, 0x49, 0x6C, 0xAD, 0xEB, 0xFF, 0x00, 0x00, 0x3F, 0xE1, 0xF9, 0x3F, 0xB0,
+ 0x97, 0xFD, 0x04, 0x7E, 0x2C, 0x7F, 0xE1, 0xB9, 0x3F, 0xFC, 0x93, 0x53, 0xFE, 0xB2, 0x65, 0x9D,
+ 0xE5, 0xFF, 0x00, 0x80, 0xFF, 0x00, 0xC1, 0x0F, 0xEC, 0x9C, 0x57, 0x65, 0xF7, 0xFF, 0x00, 0xC0,
+ 0x0F, 0xF8, 0x7E, 0x4F, 0xEC, 0x25, 0xFF, 0x00, 0x41, 0x1F, 0x8B, 0x1F, 0xF8, 0x6E, 0x4F, 0xFF,
+ 0x00, 0x24, 0xD1, 0xFE, 0xB2, 0x65, 0x89, 0x2D, 0x65, 0x6F, 0xF0, 0xFF, 0x00, 0xC1, 0x0F, 0xEC,
+ 0x9C, 0x57, 0x65, 0xF7, 0xFF, 0x00, 0xC0, 0x0F, 0xF8, 0x7E, 0x4F, 0xEC, 0x25, 0xFF, 0x00, 0x41,
+ 0x1F, 0x8B, 0x1F, 0xF8, 0x6E, 0x4F, 0xFF, 0x00, 0x24, 0xD1, 0xFE, 0xB2, 0x65, 0x9D, 0xE5, 0xFF,
+ 0x00, 0x80, 0xFF, 0x00, 0xC1, 0x0F, 0xEC, 0x9C, 0x57, 0x65, 0xF7, 0xFF, 0x00, 0xC0, 0x03, 0xFF,
+ 0x00, 0x05, 0xC7, 0xFD, 0x85, 0x17, 0x00, 0xEA, 0x1F, 0x16, 0x57, 0xE5, 0x04, 0x03, 0xF0, 0xE0,
+ 0x8E, 0x08, 0xE0, 0x81, 0xF6, 0x9E, 0x9D, 0x29, 0x2E, 0x25, 0xCA, 0xDA, 0xF7, 0x5C, 0xAD, 0xE9,
+ 0xFF, 0x00, 0x04, 0xA9, 0x64, 0xF8, 0xD8, 0x59, 0x4A, 0x29, 0x68, 0x9A, 0xBE, 0x9A, 0x3D, 0xBA,
+ 0x6D, 0x6D, 0x83, 0xFE, 0x1F, 0x93, 0xFB, 0x09, 0x7F, 0xD0, 0x47, 0xE2, 0xC7, 0xFE, 0x1B, 0x93,
+ 0xFF, 0x00, 0xC9, 0x34, 0xFF, 0x00, 0xD6, 0x4C, 0xB3, 0xBC, 0xBF, 0xF0, 0x1F, 0xF8, 0x24, 0xFF,
+ 0x00, 0x64, 0xE2, 0xBB, 0x2F, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0xF2, 0x7F, 0x61, 0x2F, 0xFA, 0x08,
+ 0xFC, 0x58, 0xFF, 0x00, 0xC3, 0x72, 0x7F, 0xF9, 0x26, 0x8F, 0xF5, 0x93, 0x2C, 0xEF, 0x2F, 0xFC,
+ 0x07, 0xFE, 0x08, 0x7F, 0x64, 0xE2, 0xBB, 0x2F, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0xF2, 0x7F, 0x61,
+ 0x2F, 0xFA, 0x08, 0xFC, 0x58, 0xFF, 0x00, 0xC3, 0x72, 0x7F, 0xF9, 0x26, 0x8F, 0xF5, 0x93, 0x2C,
+ 0xEF, 0x2F, 0xFC, 0x07, 0xFE, 0x08, 0x7F, 0x64, 0xE2, 0xBB, 0x2F, 0xBF, 0xFE, 0x00, 0xE4, 0xFF,
+ 0x00, 0x82, 0xE2, 0xFE, 0xC2, 0xAE, 0x42, 0xA5, 0xFF, 0x00, 0xC5, 0xA3, 0xD8, 0x01, 0xF0, 0xE0,
+ 0x81, 0xC0, 0xE9, 0xFF, 0x00, 0x1F, 0x3F, 0x4A, 0xED, 0xC1, 0x66, 0x54, 0xF3, 0x09, 0xC6, 0x8E,
+ 0x06, 0x94, 0xE7, 0x27, 0xB5, 0xA3, 0x65, 0xA2, 0xEE, 0xDA, 0x4A, 0xDE, 0xAB, 0xA2, 0xEC, 0x89,
+ 0x96, 0x5B, 0x5E, 0x9A, 0xF7, 0x9C, 0x52, 0xF5, 0xFF, 0x00, 0x80, 0x5C, 0x4F, 0xF8, 0x2D, 0xB7,
+ 0xEC, 0x40, 0xEA, 0x0A, 0x5D, 0x7C, 0x59, 0x23, 0xA0, 0xC7, 0xC3, 0xD5, 0x5E, 0x83, 0xD3, 0xED,
+ 0x43, 0xDA, 0xBE, 0xDB, 0x07, 0xC1, 0x7C, 0x63, 0x8E, 0xA7, 0x1A, 0x98, 0x4C, 0xB2, 0x6E, 0x2F,
+ 0x6F, 0x7F, 0x0F, 0x1F, 0xC2, 0x55, 0x93, 0xFC, 0x0E, 0x57, 0x45, 0x43, 0x47, 0x25, 0xF8, 0xFE,
+ 0x88, 0x5F, 0xF8, 0x7D, 0xA7, 0xEC, 0x44, 0x38, 0xFB, 0x4F, 0xC5, 0x91, 0x81, 0xFF, 0x00, 0x44,
+ 0xF9, 0x30, 0x30, 0x3A, 0x7F, 0xC7, 0xDF, 0xD2, 0xBA, 0xDF, 0x87, 0xDC, 0x77, 0x15, 0xAE, 0x55,
+ 0x3B, 0x79, 0x55, 0xC3, 0x3F, 0xCA, 0xBB, 0xFC, 0x04, 0xA9, 0xC3, 0x44, 0xA6, 0xBF, 0x1F, 0xF2,
+ 0x01, 0xFF, 0x00, 0x05, 0xB4, 0xFD, 0x88, 0x71, 0xFF, 0x00, 0x1F, 0x5F, 0x16, 0x46, 0x38, 0xC7,
+ 0xFC, 0x2B, 0xD4, 0x1D, 0x07, 0x18, 0xFF, 0x00, 0x4A, 0xFA, 0x56, 0x1F, 0xEA, 0x37, 0x1A, 0x47,
+ 0x4F, 0xEC, 0xB9, 0xFF, 0x00, 0xE0, 0xCC, 0x37, 0xFF, 0x00, 0x2E, 0x1A, 0xA2, 0xAC, 0xAD, 0x25,
+ 0x6F, 0x9F, 0xF9, 0x07, 0xFC, 0x3E, 0xD7, 0xF6, 0x20, 0x18, 0x1F, 0x6A, 0xF8, 0xB3, 0xD0, 0x70,
+ 0x3E, 0x1E, 0xA6, 0x00, 0xED, 0xFF, 0x00, 0x2F, 0x55, 0x3F, 0xEA, 0x4F, 0x19, 0xAD, 0x3F, 0xB3,
+ 0x27, 0xD3, 0xFE, 0x5E, 0x61, 0xFF, 0x00, 0xF9, 0x77, 0xFC, 0x37, 0x5B, 0x68, 0x1E, 0xC5, 0x59,
+ 0x7B, 0xCA, 0xDF, 0x3F, 0xF2, 0x2A, 0xCB, 0xFF, 0x00, 0x05, 0xC1, 0xFD, 0x86, 0x2D, 0xC8, 0x49,
+ 0x6F, 0xBE, 0x2D, 0x46, 0x71, 0xC0, 0xFF, 0x00, 0x85, 0x75, 0x91, 0x80, 0x3B, 0x11, 0x73, 0x8F,
+ 0x4A, 0xF9, 0x6C, 0xEF, 0xEB, 0x5C, 0x35, 0x5E, 0x38, 0x5C, 0xF3, 0x0D, 0x3A, 0x33, 0x7B, 0x26,
+ 0xA3, 0x24, 0xEC, 0x96, 0xCE, 0x12, 0x94, 0x5A, 0x57, 0x5B, 0x3F, 0x2E, 0x86, 0xF4, 0xB0, 0x15,
+ 0x6B, 0x46, 0xF4, 0x9A, 0x6B, 0xD6, 0xDF, 0xA2, 0x22, 0xFF, 0x00, 0x87, 0xE4, 0xFE, 0xC2, 0x5F,
+ 0xF4, 0x11, 0xF8, 0xB1, 0xFF, 0x00, 0x86, 0xE4, 0xFF, 0x00, 0xF2, 0x4D, 0x78, 0x7F, 0xEB, 0x26,
+ 0x59, 0xDE, 0x5F, 0xF8, 0x0F, 0xFC, 0x13, 0x5F, 0xEC, 0x9C, 0x57, 0x65, 0xF7, 0xFF, 0x00, 0xC0,
+ 0x0F, 0xF8, 0x7E, 0x4F, 0xEC, 0x25, 0xFF, 0x00, 0x41, 0x1F, 0x8B, 0x1F, 0xF8, 0x6E, 0x4F, 0xFF,
+ 0x00, 0x24, 0xD1, 0xFE, 0xB2, 0x65, 0x9D, 0xE5, 0xFF, 0x00, 0x80, 0xFF, 0x00, 0xC1, 0x0F, 0xEC,
+ 0x9C, 0x57, 0x65, 0xF7, 0xFF, 0x00, 0xC0, 0x0F, 0xF8, 0x7E, 0x4F, 0xEC, 0x25, 0xFF, 0x00, 0x41,
+ 0x1F, 0x8B, 0x1F, 0xF8, 0x6E, 0x4F, 0xFF, 0x00, 0x24, 0xD1, 0xFE, 0xB2, 0x65, 0x9D, 0xE5, 0xFF,
+ 0x00, 0x80, 0xFF, 0x00, 0xC1, 0x0F, 0xEC, 0x9C, 0x57, 0x65, 0xF7, 0xFF, 0x00, 0xC0, 0x3B, 0xAF,
+ 0x08, 0xFF, 0x00, 0xC1, 0x5E, 0xBF, 0x65, 0x5F, 0x1D, 0xB8, 0x8F, 0xC1, 0xDE, 0x1F, 0xF8, 0xED,
+ 0xAF, 0x0E, 0x07, 0x9D, 0x65, 0xF0, 0xB4, 0xC7, 0x66, 0x3D, 0x01, 0xB8, 0x7B, 0xA5, 0x88, 0x74,
+ 0xE8, 0x58, 0x57, 0x44, 0x33, 0x9C, 0x2C, 0xE2, 0xA5, 0x08, 0x4E, 0xCF, 0x6F, 0x75, 0x2B, 0xFA,
+ 0x5D, 0xAB, 0xFC, 0x8C, 0x67, 0x82, 0x9D, 0x2D, 0x27, 0x28, 0xAF, 0x2B, 0xFE, 0x89, 0x1E, 0xA6,
+ 0x3F, 0xE0, 0xA1, 0xDF, 0x09, 0x76, 0x07, 0xFF, 0x00, 0x85, 0x71, 0xF1, 0xC4, 0x26, 0x38, 0xFF,
+ 0x00, 0x8A, 0x53, 0x47, 0x04, 0x01, 0xEA, 0xBF, 0xDA, 0xB9, 0x1D, 0x07, 0x6F, 0x4A, 0xDD, 0x66,
+ 0x11, 0xB5, 0xD5, 0x19, 0xDB, 0xBF, 0x2A, 0xB7, 0xE7, 0x63, 0x0F, 0x65, 0x04, 0xBE, 0x38, 0xFE,
+ 0x3F, 0xE4, 0x79, 0xA7, 0x8B, 0x3F, 0xE0, 0xAE, 0x1F, 0xB2, 0xEF, 0x80, 0xD7, 0x77, 0x8B, 0xBC,
+ 0x35, 0xF1, 0xDF, 0x42, 0x88, 0x0E, 0x6E, 0x2E, 0x3E, 0x17, 0x79, 0xF6, 0x49, 0x83, 0x8C, 0x19,
+ 0xE2, 0xBA, 0x78, 0x87, 0x4E, 0x85, 0x85, 0x63, 0x3C, 0xE3, 0x0B, 0x4A, 0x37, 0x9C, 0x24, 0x97,
+ 0xF8, 0x56, 0x96, 0xB7, 0x44, 0xF4, 0xDD, 0x76, 0xED, 0xD1, 0xA5, 0xB5, 0x3C, 0x1C, 0xEA, 0x59,
+ 0x53, 0x94, 0x7E, 0xFB, 0x7E, 0x87, 0x9E, 0xFF, 0x00, 0xC3, 0xF2, 0x7F, 0x61, 0x2F, 0xFA, 0x08,
+ 0xFC, 0x58, 0xFF, 0x00, 0xC3, 0x72, 0x7F, 0xF9, 0x26, 0xB9, 0xBF, 0xD6, 0x4C, 0xB3, 0xBC, 0xBF,
+ 0xF0, 0x1F, 0xF8, 0x26, 0xFF, 0x00, 0xD9, 0x38, 0xAE, 0xCB, 0xEF, 0xFF, 0x00, 0x80, 0x7D, 0x93,
+ 0xFB, 0x25, 0x7E, 0xDB, 0x5F, 0x04, 0x7F, 0x6D, 0x48, 0x3E, 0x22, 0xDC, 0x7C, 0x0F, 0x3E, 0x31,
+ 0xBB, 0xB7, 0xF8, 0x58, 0x74, 0x75, 0xF1, 0x64, 0xBE, 0x25, 0xF0, 0xC9, 0xD0, 0x52, 0x03, 0xAE,
+ 0x2D, 0xF9, 0xB1, 0xF2, 0x71, 0x23, 0xEF, 0x18, 0xD1, 0x6F, 0x4B, 0x13, 0xB4, 0x2E, 0x13, 0xAE,
+ 0x7E, 0x5F, 0x43, 0x01, 0x99, 0x61, 0xB3, 0x05, 0x3F, 0xAB, 0x5E, 0xD1, 0xB5, 0xEE, 0xAD, 0xBD,
+ 0xED, 0x6F, 0xB8, 0xE6, 0xC4, 0x61, 0x2A, 0xE1, 0x79, 0x55, 0x44, 0xB5, 0xDA, 0xDE, 0x56, 0xFF,
+ 0x00, 0x34, 0x7D, 0x77, 0x5D, 0xE7, 0x30, 0x50, 0x01, 0x40, 0x05, 0x00, 0x7F, 0x14, 0x5F, 0xF0,
+ 0x5A, 0xFF, 0x00, 0xF9, 0x48, 0x1F, 0xC4, 0x8F, 0xFB, 0x12, 0xFC, 0x27, 0xFF, 0x00, 0xA8, 0xF5,
+ 0xAD, 0x7E, 0x75, 0xC4, 0x1F, 0xF2, 0x34, 0x9F, 0xA4, 0x7F, 0xF4, 0x94, 0x7D, 0x46, 0x57, 0xFE,
+ 0xE5, 0x1F, 0x9F, 0xE6, 0x7E, 0x58, 0xE9, 0x5A, 0xBD, 0xEE, 0x91, 0x75, 0x6F, 0x75, 0x69, 0x3C,
+ 0x91, 0xBD, 0xB1, 0x2D, 0x00, 0x59, 0x64, 0x8D, 0x22, 0x2C, 0x30, 0xC5, 0x42, 0x32, 0x91, 0x91,
+ 0x91, 0xC1, 0x15, 0xE6, 0xE1, 0x2A, 0xD3, 0xC3, 0xD4, 0x75, 0x25, 0x14, 0xDD, 0xAC, 0xB4, 0x5D,
+ 0xD7, 0x5D, 0xD6, 0x97, 0xD6, 0x2D, 0x3E, 0x89, 0xA4, 0x7A, 0x4A, 0xA5, 0x78, 0x45, 0x42, 0x95,
+ 0x47, 0x18, 0xDE, 0xED, 0x68, 0xD3, 0xF5, 0x8B, 0x4E, 0x2F, 0xA6, 0x8D, 0x74, 0x47, 0xAB, 0x9F,
+ 0xEC, 0xFF, 0x00, 0x16, 0xAE, 0x90, 0x9E, 0x18, 0xB2, 0x98, 0xF8, 0x86, 0x35, 0xB8, 0x6D, 0x40,
+ 0xD9, 0xE9, 0xB7, 0xD3, 0xFF, 0x00, 0x68, 0x00, 0x01, 0x86, 0x12, 0x86, 0x69, 0xD8, 0x15, 0x55,
+ 0x6C, 0x6D, 0x00, 0x63, 0x76, 0x49, 0xE2, 0xBF, 0x6D, 0xF0, 0xBF, 0x31, 0xE3, 0xDC, 0xAF, 0x19,
+ 0x2E, 0x2A, 0xE1, 0x0C, 0x15, 0x49, 0xE0, 0x30, 0xCD, 0x46, 0xBC, 0xA1, 0x07, 0xC8, 0xAF, 0x1D,
+ 0x14, 0xB5, 0xBC, 0xA4, 0x93, 0xBD, 0xB5, 0xBE, 0x9A, 0xEC, 0x8E, 0x2C, 0xD3, 0xFB, 0x32, 0x58,
+ 0x7F, 0x69, 0x9A, 0x62, 0x52, 0xAD, 0x34, 0xB9, 0x57, 0xBA, 0x92, 0x6B, 0x74, 0xE2, 0xA3, 0x15,
+ 0x15, 0xA2, 0xB5, 0x9B, 0x5B, 0xBB, 0x6B, 0x65, 0x07, 0x87, 0x35, 0x26, 0xD0, 0xF5, 0xFB, 0x1B,
+ 0xDB, 0x9B, 0x37, 0x8E, 0x5D, 0x36, 0xF5, 0x4D, 0xEE, 0x9F, 0x73, 0x6A, 0x48, 0x2D, 0x1B, 0x7C,
+ 0xD1, 0xCB, 0x0B, 0x15, 0x0C, 0x38, 0xC1, 0x42, 0x57, 0x23, 0x23, 0x23, 0x39, 0x1F, 0xDC, 0xDC,
+ 0x07, 0xC5, 0xF4, 0x73, 0x59, 0x43, 0x36, 0xC9, 0xE8, 0xBB, 0xD4, 0x8B, 0x8D, 0x7A, 0x5C, 0xAE,
+ 0x0A, 0x57, 0x8D, 0x9B, 0xBB, 0x56, 0x52, 0x57, 0xE6, 0x8F, 0x33, 0xDD, 0x25, 0x6E, 0x87, 0xC2,
+ 0xE6, 0x18, 0x5F, 0xAC, 0x60, 0xA5, 0x46, 0x13, 0x5C, 0xB2, 0x5E, 0xEC, 0xB4, 0x69, 0x2F, 0x2D,
+ 0xD2, 0x7D, 0x9D, 0x9D, 0x9D, 0x9D, 0xB4, 0xB1, 0xF6, 0xA6, 0xA1, 0xE3, 0x3F, 0x03, 0xFC, 0x1C,
+ 0xF1, 0x17, 0x80, 0xFE, 0x3C, 0x7E, 0xCE, 0xFF, 0x00, 0x10, 0xB4, 0xA8, 0x7C, 0x4E, 0x97, 0x82,
+ 0xCF, 0xC5, 0x7F, 0x0C, 0xE4, 0x17, 0x29, 0x1C, 0x64, 0xC4, 0x3E, 0xD0, 0xA2, 0x31, 0x1C, 0x49,
+ 0x26, 0x9D, 0x32, 0x86, 0x47, 0x89, 0x98, 0x61, 0x89, 0xC0, 0x23, 0x04, 0xFA, 0x54, 0x70, 0x78,
+ 0xDE, 0x2E, 0xFA, 0xC7, 0x0E, 0x66, 0x94, 0x13, 0xC2, 0x35, 0x29, 0x50, 0x9D, 0x49, 0x41, 0xD4,
+ 0xA3, 0x27, 0x7D, 0x23, 0xCC, 0xEC, 0xAD, 0x7B, 0x59, 0x7C, 0x2A, 0xFC, 0xAE, 0xFB, 0x7C, 0x7E,
+ 0x45, 0x4B, 0x34, 0x96, 0x0E, 0x59, 0x6E, 0x79, 0x41, 0xB8, 0x5B, 0x49, 0x4A, 0xD2, 0xBA, 0x56,
+ 0xB2, 0x7B, 0xB6, 0xD3, 0xD5, 0x3D, 0x1D, 0x92, 0x4F, 0x4B, 0x1F, 0x62, 0xFE, 0xD0, 0x7E, 0x36,
+ 0xFD, 0x97, 0xFF, 0x00, 0x6A, 0x8F, 0x84, 0x3E, 0x1C, 0xF1, 0x86, 0x8F, 0xF1, 0x13, 0xC3, 0x3F,
+ 0x0C, 0x3E, 0x2F, 0x78, 0x6C, 0x47, 0x3E, 0x87, 0xA7, 0x78, 0x8E, 0xF1, 0xED, 0x75, 0x6D, 0x3D,
+ 0x95, 0x43, 0x4B, 0xA2, 0xDC, 0x4D, 0xE4, 0xB4, 0x92, 0x5B, 0x2B, 0xB1, 0x78, 0x66, 0x46, 0x18,
+ 0x63, 0x82, 0xA0, 0x27, 0x3F, 0x15, 0xC2, 0xB9, 0x67, 0x1C, 0x70, 0x67, 0x11, 0x3C, 0x16, 0x37,
+ 0x05, 0x3A, 0x94, 0x2A, 0x73, 0x42, 0xD0, 0xB5, 0x9B, 0xBA, 0x49, 0xBB, 0x5A, 0x31, 0x4D, 0x45,
+ 0x2F, 0x7B, 0x9A, 0x56, 0xBD, 0xA5, 0x75, 0x61, 0x42, 0x55, 0x72, 0x89, 0xFD, 0x4E, 0x8D, 0x19,
+ 0x55, 0xC3, 0xA8, 0xBD, 0x14, 0x64, 0xDA, 0x57, 0x6E, 0xC9, 0xB5, 0x18, 0xC9, 0x7E, 0x37, 0x6F,
+ 0xA6, 0x8A, 0x5F, 0x84, 0xBF, 0xB4, 0x6F, 0xC1, 0xFF, 0x00, 0x8E, 0x1F, 0x05, 0xEF, 0x3E, 0x0F,
+ 0xFE, 0xD2, 0x3E, 0x24, 0xD0, 0xF4, 0x8D, 0x6A, 0xC5, 0x63, 0xD1, 0xA4, 0xD5, 0x6E, 0xB4, 0x89,
+ 0x9D, 0x3C, 0x56, 0x40, 0x64, 0xD3, 0xB5, 0x1B, 0x29, 0x21, 0x8C, 0x95, 0xBC, 0x85, 0x4E, 0x0B,
+ 0xB2, 0x86, 0x94, 0x9C, 0x82, 0x30, 0x05, 0x7A, 0xFC, 0x61, 0xC1, 0x5C, 0x55, 0xC3, 0xD9, 0xAD,
+ 0x3C, 0xF7, 0x22, 0xC3, 0x54, 0xF6, 0x36, 0x53, 0x71, 0x72, 0xF7, 0xA3, 0x17, 0x6E, 0x66, 0xDD,
+ 0xDC, 0x5B, 0x6D, 0x26, 0xE2, 0xA7, 0xCA, 0xA2, 0x92, 0x7A, 0x5E, 0xD9, 0xD7, 0xCB, 0x6B, 0x65,
+ 0xD5, 0xDE, 0x3B, 0x06, 0xD2, 0xA5, 0xA4, 0x9A, 0xD5, 0x72, 0xAB, 0x5D, 0xA7, 0xEE, 0xA8, 0x27,
+ 0x14, 0xAD, 0x1B, 0xFB, 0xB6, 0x52, 0xD5, 0xA7, 0xAF, 0x83, 0xFC, 0x35, 0xF1, 0x31, 0xFD, 0x99,
+ 0xBC, 0x73, 0xE2, 0x4F, 0x00, 0xF8, 0x9B, 0x53, 0x6F, 0x15, 0xFC, 0x08, 0xF1, 0x05, 0xD4, 0xDF,
+ 0x63, 0xF1, 0x8D, 0xB5, 0x9D, 0xCA, 0xDB, 0x69, 0xC0, 0xA4, 0x82, 0xDE, 0xE6, 0x2B, 0x77, 0x83,
+ 0xCE, 0xCB, 0xAA, 0xC7, 0x1C, 0x88, 0xAA, 0x07, 0xCE, 0x59, 0x72, 0x47, 0x1F, 0x79, 0x8D, 0xC1,
+ 0x62, 0xB8, 0xC7, 0x25, 0xA7, 0x99, 0x50, 0xA0, 0xE9, 0xE6, 0x09, 0x46, 0x33, 0x4D, 0x2E, 0x69,
+ 0xBB, 0x45, 0xDE, 0xC9, 0xB4, 0xA3, 0x7F, 0x89, 0x35, 0xAB, 0xEB, 0x6D, 0x1F, 0x97, 0x98, 0x3C,
+ 0xAF, 0x3C, 0xC2, 0xA8, 0x61, 0xE4, 0xBE, 0xB4, 0xD4, 0x5D, 0x92, 0xB3, 0x92, 0xB5, 0xAF, 0xB2,
+ 0xD1, 0x2B, 0xBE, 0xAD, 0x46, 0x36, 0xB6, 0xC8, 0xF1, 0xDF, 0x89, 0xBE, 0x1C, 0x9F, 0xE1, 0x67,
+ 0xC4, 0x3D, 0x1F, 0xE2, 0x67, 0xC1, 0x6D, 0x42, 0xF7, 0x53, 0xD0, 0x24, 0x95, 0xB5, 0x78, 0xDF,
+ 0x4F, 0xD2, 0x6E, 0xAC, 0xAC, 0xF4, 0x6F, 0x9F, 0x33, 0x5A, 0x32, 0x4B, 0x04, 0x43, 0xEC, 0xF2,
+ 0x2B, 0x36, 0x13, 0x61, 0x18, 0xC8, 0x20, 0x64, 0x2D, 0x74, 0x64, 0xD2, 0xA5, 0x9B, 0xE5, 0x2F,
+ 0x87, 0xF1, 0x54, 0x17, 0xB4, 0x8D, 0x9B, 0x6D, 0xAD, 0xFE, 0x1B, 0x36, 0x9B, 0x76, 0xF7, 0x53,
+ 0xBA, 0x6D, 0xAB, 0xA7, 0x16, 0xD9, 0xE8, 0xE5, 0x59, 0x8D, 0x0C, 0x7E, 0x5F, 0x1C, 0xA7, 0x38,
+ 0xAF, 0x1A, 0x92, 0x4F, 0x92, 0x3A, 0x3B, 0x49, 0x73, 0x7B, 0xAA, 0x37, 0xD2, 0x4D, 0x3D, 0x2E,
+ 0xAD, 0x7D, 0xAD, 0xA5, 0xCF, 0x56, 0xFD, 0xA4, 0xFC, 0x71, 0xFB, 0x3F, 0x7C, 0x6E, 0xF8, 0x63,
+ 0xE1, 0x9F, 0x1A, 0xE9, 0xBE, 0x3A, 0xB1, 0xD1, 0x3E, 0x2F, 0xE9, 0x5A, 0x54, 0x24, 0xF8, 0x4A,
+ 0x4D, 0x1F, 0x52, 0x92, 0x79, 0xE1, 0x77, 0x02, 0xE3, 0x4D, 0xBA, 0xBB, 0x4B, 0x51, 0x6C, 0x65,
+ 0x8C, 0x96, 0x91, 0x66, 0xDC, 0x03, 0x0D, 0xA8, 0x00, 0x0B, 0x5F, 0x31, 0xC2, 0xD9, 0x77, 0x15,
+ 0xF0, 0xC7, 0x12, 0x4E, 0x8E, 0x17, 0x0B, 0x27, 0x97, 0xCD, 0xA8, 0xC9, 0xA7, 0x15, 0x17, 0x07,
+ 0x74, 0xE6, 0x9D, 0xF9, 0x96, 0xDE, 0xEC, 0x53, 0x6D, 0x6E, 0xD6, 0xA9, 0x1E, 0xB6, 0x1E, 0x96,
+ 0x23, 0x2F, 0xB5, 0x1F, 0x67, 0xCD, 0x1B, 0xEC, 0xAE, 0xDA, 0xEC, 0x93, 0x71, 0x8C, 0x7D, 0xDD,
+ 0x6F, 0x7B, 0x69, 0x64, 0xBA, 0x5B, 0xF3, 0xD6, 0xCB, 0x47, 0xBF, 0xD5, 0x27, 0x10, 0x69, 0x76,
+ 0x37, 0x57, 0x65, 0xD8, 0x08, 0xD2, 0x18, 0x8B, 0xF5, 0x20, 0x01, 0x91, 0xC7, 0x52, 0x05, 0x7E,
+ 0xB7, 0x8B, 0xAB, 0x80, 0xCB, 0xE0, 0xE7, 0x8A, 0xAD, 0x18, 0xC5, 0x79, 0xC5, 0xEC, 0xAE, 0xD2,
+ 0xB5, 0xAF, 0xB3, 0xB5, 0x92, 0x5A, 0x6B, 0x67, 0xA2, 0xFA, 0xDC, 0x16, 0x59, 0x98, 0xE6, 0x75,
+ 0x1C, 0x32, 0xDC, 0x3C, 0xA6, 0xBC, 0x96, 0x89, 0x79, 0xBD, 0x22, 0x92, 0x5B, 0xB6, 0xD2, 0x4B,
+ 0x5D, 0x11, 0xE9, 0x7A, 0x5F, 0xC1, 0x1F, 0x1A, 0x5F, 0xC6, 0xB3, 0xDD, 0xDB, 0x5B, 0x69, 0x56,
+ 0xBB, 0x41, 0x69, 0x6F, 0x65, 0x55, 0xD8, 0xB9, 0x00, 0x9C, 0x74, 0xEE, 0x31, 0xC8, 0xCF, 0x6A,
+ 0xF8, 0x5C, 0xD3, 0x8F, 0x78, 0x6B, 0x0E, 0xD5, 0x1C, 0x3C, 0x9D, 0x59, 0x5B, 0x45, 0x18, 0xBB,
+ 0x7C, 0xB7, 0x76, 0xB2, 0xBB, 0xD1, 0x59, 0x6B, 0xD2, 0xC7, 0xD6, 0xE0, 0x7C, 0x3F, 0xCC, 0xEA,
+ 0xA4, 0xF1, 0xB5, 0x61, 0x49, 0x76, 0x57, 0x9C, 0xAD, 0xE4, 0xA2, 0xB9, 0x76, 0x4E, 0xD7, 0x92,
+ 0xDA, 0xCE, 0xC7, 0x62, 0xFF, 0x00, 0xB3, 0xF4, 0x1A, 0x75, 0x8C, 0xD7, 0xBA, 0xCE, 0xBC, 0x7C,
+ 0xAB, 0x68, 0x44, 0x93, 0x47, 0xA7, 0x46, 0x19, 0x94, 0x8C, 0x64, 0x29, 0x23, 0x07, 0x86, 0x5E,
+ 0x33, 0xEB, 0xE9, 0x8A, 0xF8, 0x2C, 0x67, 0x88, 0x2B, 0x12, 0xFD, 0x86, 0x1F, 0x0B, 0xC9, 0x16,
+ 0xD6, 0xB3, 0x7A, 0x47, 0x5B, 0x6B, 0xCA, 0xEE, 0xBE, 0xEB, 0x77, 0xB5, 0xB4, 0xFA, 0xAC, 0xB3,
+ 0xC3, 0x7C, 0xB2, 0xB5, 0x58, 0x61, 0xEA, 0x57, 0xA9, 0x3A, 0x8E, 0xC9, 0x28, 0xA8, 0x41, 0x5F,
+ 0x6D, 0xDF, 0x3E, 0x9A, 0x5A, 0xD6, 0x4E, 0xF6, 0x39, 0x96, 0xF0, 0x07, 0x84, 0xE2, 0x26, 0x37,
+ 0x9B, 0x50, 0x65, 0x00, 0xAC, 0x2E, 0xD8, 0x51, 0x23, 0x63, 0xE5, 0x0C, 0xA1, 0x88, 0xEA, 0x07,
+ 0x39, 0x1F, 0x4E, 0x80, 0xFE, 0x7F, 0xC7, 0x9C, 0x6B, 0xE2, 0x1E, 0x59, 0x81, 0x82, 0xC9, 0x68,
+ 0x53, 0xAB, 0x18, 0xBD, 0x6D, 0x09, 0x49, 0xD9, 0x5A, 0xDE, 0xEF, 0x34, 0x5D, 0xAF, 0x78, 0xCA,
+ 0xD7, 0x71, 0x7C, 0xAD, 0x2B, 0x58, 0xFB, 0x9A, 0x5E, 0x14, 0xF0, 0xCD, 0x2A, 0x14, 0xEB, 0x38,
+ 0x4A, 0x52, 0x6D, 0x47, 0x95, 0xD4, 0x7B, 0xB5, 0xA6, 0xD0, 0x8E, 0xFD, 0x12, 0xD1, 0xE8, 0xB4,
+ 0x7A, 0xA8, 0xFC, 0x4B, 0xF0, 0xC7, 0x44, 0xD1, 0x26, 0x8A, 0xDC, 0x59, 0xDE, 0x79, 0x8D, 0x1C,
+ 0x44, 0x5B, 0xC9, 0x70, 0x62, 0x9B, 0xE7, 0x23, 0x2A, 0xA3, 0x90, 0x48, 0xC8, 0xC0, 0x03, 0xF9,
+ 0x54, 0xE1, 0x73, 0xBC, 0x6C, 0xF0, 0x71, 0xAB, 0x9D, 0x42, 0x38, 0x69, 0x49, 0x2D, 0x2A, 0xA8,
+ 0xD3, 0x4B, 0x44, 0xFD, 0xDE, 0x66, 0xD6, 0xFA, 0x25, 0x77, 0x6B, 0x6A, 0x93, 0x22, 0xB7, 0x00,
+ 0xF0, 0x83, 0xCA, 0x9E, 0x63, 0x4A, 0x8C, 0xAF, 0x19, 0xA8, 0xB8, 0xC2, 0xA3, 0x4B, 0x95, 0xB4,
+ 0xB9, 0xB5, 0xBE, 0xCB, 0xA6, 0xD6, 0x5B, 0xA3, 0xE8, 0x7F, 0x09, 0xFF, 0x00, 0xC1, 0x31, 0x7F,
+ 0x6C, 0x0F, 0x8A, 0xFA, 0x4D, 0xB6, 0xB5, 0xF0, 0xD7, 0xF6, 0x7E, 0xF8, 0xA6, 0xBA, 0x24, 0xAA,
+ 0xB7, 0x2F, 0xAF, 0xF8, 0xC3, 0x41, 0x1E, 0x02, 0xF0, 0x74, 0x36, 0xCC, 0xA0, 0x9B, 0x87, 0xD5,
+ 0xF5, 0x36, 0xB5, 0xB5, 0x48, 0x40, 0x39, 0x32, 0x34, 0x9B, 0x31, 0x9F, 0x9B, 0x8E, 0x7F, 0x26,
+ 0xE3, 0x3F, 0x12, 0xB3, 0x2C, 0x1D, 0x6C, 0x3E, 0x0F, 0x26, 0x54, 0xAA, 0x61, 0x9C, 0xAD, 0x28,
+ 0xC2, 0x57, 0x94, 0x9A, 0x7F, 0x0D, 0xE3, 0x78, 0x7B, 0xC9, 0x5E, 0x2A, 0x32, 0x96, 0x9A, 0x4D,
+ 0x45, 0xD9, 0x1F, 0x2F, 0x9D, 0xF0, 0xA7, 0x01, 0x60, 0x69, 0xCA, 0xB6, 0x13, 0x34, 0xE5, 0x97,
+ 0x2D, 0xF9, 0x5B, 0x55, 0x39, 0x6C, 0x96, 0x8D, 0x41, 0x5E, 0xFA, 0x5A, 0xCA, 0x4E, 0xDB, 0xBB,
+ 0x23, 0xA3, 0x9F, 0xFE, 0x09, 0xA3, 0x17, 0x82, 0xE0, 0x5B, 0xBF, 0x8F, 0xDF, 0xB6, 0xA7, 0xEC,
+ 0x51, 0xF0, 0x3E, 0xDA, 0x38, 0xE4, 0x37, 0x7A, 0x4C, 0x7F, 0x14, 0xEF, 0xBE, 0x34, 0xF8, 0xBE,
+ 0xD1, 0xE3, 0x6C, 0x79, 0x42, 0xC7, 0xC2, 0xDA, 0x7E, 0xA5, 0x03, 0xB1, 0x0A, 0xC4, 0x2A, 0x5C,
+ 0xB1, 0x38, 0xE0, 0x1E, 0x71, 0xEE, 0x57, 0xE2, 0xCF, 0xED, 0x38, 0xD1, 0xA1, 0x97, 0x64, 0xF5,
+ 0xAF, 0xCA, 0x9C, 0xA3, 0xEE, 0x53, 0x69, 0xD9, 0x36, 0xBD, 0xED, 0x54, 0x75, 0x5D, 0x12, 0x7B,
+ 0xDE, 0xCA, 0xE7, 0xE7, 0x78, 0xAC, 0xA3, 0x1D, 0x81, 0x8B, 0xAD, 0x52, 0x9C, 0xFD, 0x8D, 0xED,
+ 0x19, 0xB8, 0x4A, 0x31, 0x7A, 0x5D, 0x2F, 0x79, 0x2B, 0x36, 0x96, 0xDF, 0x75, 0xF4, 0x31, 0xA1,
+ 0xF8, 0x09, 0xFF, 0x00, 0x04, 0xD7, 0xF0, 0xF5, 0xC5, 0xB5, 0x97, 0x89, 0xBF, 0x6E, 0x6F, 0x8D,
+ 0xBF, 0x16, 0x64, 0x54, 0x6B, 0xDB, 0xD5, 0xFD, 0x9D, 0xFF, 0x00, 0x63, 0xDB, 0xA1, 0xA4, 0x25,
+ 0xBC, 0x4B, 0xBA, 0x65, 0x17, 0x7E, 0x29, 0xD6, 0x34, 0x7B, 0x84, 0x60, 0xAA, 0xFF, 0x00, 0x38,
+ 0xB3, 0x91, 0x47, 0x07, 0x04, 0x0C, 0x57, 0xC5, 0x66, 0xB9, 0xC7, 0x88, 0x78, 0xAB, 0x61, 0x28,
+ 0xE5, 0xA9, 0x61, 0x5A, 0x7C, 0xB4, 0xE5, 0x4D, 0x27, 0x1E, 0x89, 0xCA, 0x53, 0x9C, 0x62, 0xFA,
+ 0x6C, 0xDA, 0x6A, 0xDA, 0xAD, 0x97, 0x0C, 0x5D, 0x28, 0x2E, 0x79, 0x24, 0xAD, 0x65, 0x76, 0xFA,
+ 0x69, 0xAA, 0xE5, 0x4E, 0xC9, 0x75, 0xBD, 0xAD, 0x6E, 0xCA, 0xE4, 0x0D, 0x65, 0xFF, 0x00, 0x04,
+ 0xA4, 0x82, 0xE2, 0x2B, 0x6F, 0x0F, 0x78, 0x2F, 0xFE, 0x0A, 0x3D, 0xF1, 0x24, 0xC2, 0x49, 0xFB,
+ 0x4A, 0x78, 0xB3, 0xE1, 0xDF, 0x80, 0xED, 0x6E, 0xF0, 0xC3, 0xCB, 0x51, 0x69, 0x1E, 0x8F, 0xA8,
+ 0x4A, 0x8A, 0x40, 0x39, 0xC4, 0xD9, 0x1C, 0x00, 0x7B, 0xD7, 0x93, 0x5F, 0x0B, 0xC5, 0xB1, 0xA5,
+ 0x0E, 0x77, 0x4A, 0x11, 0xFE, 0x5E, 0x78, 0xC2, 0xCA, 0xDD, 0x25, 0x04, 0xD5, 0xD3, 0xEC, 0x9A,
+ 0x4A, 0xDB, 0xB7, 0x60, 0xFA, 0xC5, 0x3A, 0x56, 0xF6, 0xD5, 0x20, 0xB6, 0x4F, 0xA7, 0xA2, 0x57,
+ 0x7D, 0xB4, 0xD5, 0x7A, 0x2E, 0x87, 0x71, 0x61, 0x65, 0xFB, 0x05, 0x4D, 0x23, 0x7F, 0x60, 0x7F,
+ 0xC1, 0x3E, 0x3F, 0x6B, 0xDF, 0x15, 0x5B, 0x04, 0x1F, 0x67, 0x3E, 0x26, 0xFD, 0xAF, 0x74, 0xBF,
+ 0x0A, 0x49, 0x28, 0x55, 0xF9, 0x77, 0xBC, 0x5E, 0x14, 0x65, 0x05, 0x88, 0x39, 0x0A, 0x0E, 0x06,
+ 0x30, 0x0D, 0x7C, 0xED, 0x6C, 0x17, 0x10, 0x41, 0x45, 0x3C, 0x5C, 0x54, 0x76, 0x76, 0xAA, 0xA6,
+ 0xED, 0x7D, 0xB4, 0xA5, 0xA5, 0x92, 0xF3, 0xBD, 0x92, 0x4B, 0x42, 0x23, 0x99, 0xE0, 0x21, 0x27,
+ 0xFB, 0xE4, 0xEF, 0xA4, 0x52, 0x83, 0xD3, 0xD6, 0xCF, 0x5E, 0xCB, 0x64, 0xFA, 0x6E, 0x91, 0xD9,
+ 0xE9, 0xBE, 0x04, 0xFD, 0x91, 0xB5, 0x34, 0x1B, 0xBF, 0xE0, 0x9A, 0xBF, 0x15, 0x74, 0xC0, 0xF1,
+ 0x92, 0x8D, 0x7F, 0xFF, 0x00, 0x05, 0x12, 0x01, 0x93, 0x8C, 0x0F, 0x91, 0x3C, 0x14, 0xD9, 0x23,
+ 0x23, 0x80, 0x3B, 0x11, 0x5E, 0x6C, 0xA7, 0x9A, 0xC6, 0xA7, 0x2E, 0x33, 0x1B, 0xA2, 0xD3, 0x47,
+ 0xCC, 0xFA, 0x69, 0x67, 0x08, 0xDB, 0x45, 0xDF, 0x7B, 0x2D, 0xAE, 0x44, 0xB3, 0x7C, 0x3C, 0x12,
+ 0xE5, 0x5D, 0x6D, 0x65, 0x0B, 0x5B, 0xB3, 0xD6, 0x69, 0x5B, 0xF1, 0xE9, 0x6E, 0x87, 0xAA, 0xE8,
+ 0xBF, 0xB2, 0x2F, 0xEC, 0x51, 0xE2, 0xB8, 0xD6, 0x5D, 0x47, 0xF6, 0x52, 0xFD, 0xAB, 0xBC, 0x23,
+ 0x0D, 0xE2, 0xC6, 0xA0, 0x78, 0x17, 0xF6, 0x9B, 0xD2, 0x3C, 0x5F, 0xF6, 0x14, 0x50, 0x37, 0xC9,
+ 0x04, 0xD7, 0x7E, 0x10, 0x55, 0x91, 0x8E, 0x3A, 0x3A, 0x00, 0x39, 0xEA, 0x06, 0x46, 0x2A, 0xAE,
+ 0x61, 0xCA, 0xF9, 0x6B, 0xCA, 0x53, 0xE9, 0x65, 0x14, 0x9A, 0x5F, 0xCD, 0x68, 0xF3, 0x6D, 0x65,
+ 0x78, 0xDD, 0x25, 0x7D, 0x51, 0x2B, 0x36, 0x93, 0xAA, 0xBD, 0x8D, 0x2B, 0xD3, 0x49, 0x5E, 0xE9,
+ 0xDE, 0xF6, 0xD1, 0x24, 0x9D, 0x92, 0xED, 0x76, 0x9D, 0xBA, 0x2B, 0x23, 0x76, 0x1F, 0xF8, 0x26,
+ 0xAF, 0xEC, 0x3B, 0xAE, 0x59, 0xC9, 0x1D, 0xB0, 0xFF, 0x00, 0x82, 0x80, 0x78, 0x26, 0xFC, 0xC1,
+ 0x21, 0x82, 0xEA, 0xE3, 0x4E, 0xF0, 0x3F, 0xC4, 0xAB, 0x31, 0x27, 0x22, 0x15, 0x6B, 0x61, 0x69,
+ 0xA5, 0x39, 0x00, 0x85, 0x0C, 0x3C, 0xC1, 0xD0, 0xE3, 0xDB, 0x69, 0x4F, 0x39, 0x95, 0x59, 0x4A,
+ 0xA5, 0x59, 0xA5, 0xA3, 0x49, 0x28, 0x49, 0x25, 0xDA, 0xEE, 0x2D, 0xB5, 0x65, 0x64, 0xF4, 0x6B,
+ 0xB3, 0x4B, 0x5D, 0x23, 0x9A, 0x41, 0x28, 0xC5, 0xD3, 0x49, 0xA7, 0x66, 0xAC, 0xD7, 0x45, 0xA2,
+ 0xD6, 0xD7, 0xBB, 0x5A, 0x68, 0xAD, 0xDB, 0xA7, 0x9E, 0xCD, 0xFF, 0x00, 0x04, 0x9B, 0xFD, 0x9F,
+ 0x35, 0x6B, 0xC4, 0xB5, 0xD0, 0x7F, 0x6B, 0xAF, 0x89, 0x7E, 0x10, 0x6F, 0x31, 0x61, 0x16, 0xDF,
+ 0x19, 0x3F, 0x64, 0x5F, 0x13, 0xE8, 0x82, 0x46, 0x72, 0x42, 0x91, 0x79, 0xA1, 0x49, 0xAC, 0xDA,
+ 0x45, 0x18, 0x0B, 0xF7, 0xE6, 0x92, 0x30, 0x72, 0x08, 0x1C, 0x10, 0x3D, 0x0F, 0x63, 0x99, 0x4E,
+ 0x92, 0x9E, 0x25, 0xA9, 0xC7, 0x5B, 0x28, 0xA5, 0x15, 0x1B, 0x5A, 0xFC, 0xD7, 0x92, 0x7B, 0x74,
+ 0x49, 0xB5, 0xDB, 0x54, 0x63, 0x0C, 0xDA, 0xBD, 0x56, 0xA3, 0x87, 0xA3, 0xCA, 0xD7, 0xC4, 0xA4,
+ 0x9A, 0x6D, 0x2D, 0xF9, 0x34, 0xB3, 0xB6, 0x97, 0xE9, 0xAA, 0xD7, 0x43, 0xB1, 0xD3, 0xFF, 0x00,
+ 0xE0, 0x84, 0xDE, 0x30, 0xD6, 0xAD, 0xF4, 0xF9, 0x3C, 0x15, 0xF1, 0x53, 0xE1, 0xFF, 0x00, 0xC5,
+ 0x26, 0xBF, 0x8B, 0x30, 0x5A, 0xF8, 0x17, 0xE2, 0x96, 0x87, 0xA2, 0xEB, 0x0C, 0x09, 0xFD, 0xD6,
+ 0x74, 0xDD, 0x69, 0x2C, 0x6E, 0x4B, 0x38, 0x20, 0xAA, 0x45, 0x1C, 0x87, 0x04, 0x0C, 0x7A, 0xF9,
+ 0xF5, 0x27, 0x8B, 0x8C, 0x9D, 0x1A, 0x54, 0xEC, 0x9D, 0x95, 0xAD, 0xAE, 0x8A, 0xFA, 0x2D, 0xAC,
+ 0xB6, 0x6E, 0xEB, 0x6D, 0x2C, 0x82, 0x96, 0x65, 0x8A, 0x74, 0xDD, 0x69, 0x72, 0xB8, 0xA7, 0x6B,
+ 0xD9, 0xA4, 0x96, 0x89, 0x76, 0xD3, 0xF0, 0xED, 0xD0, 0xF3, 0x5F, 0x1E, 0x7F, 0xC1, 0x22, 0xBC,
+ 0x51, 0xF0, 0x87, 0xCC, 0x6F, 0x8A, 0x1F, 0x0E, 0xFF, 0x00, 0x68, 0x3F, 0x08, 0xDB, 0xC7, 0x0A,
+ 0x5C, 0x3D, 0xEF, 0x88, 0x3C, 0x25, 0x26, 0x9B, 0xA5, 0xC5, 0x1B, 0x01, 0xB5, 0xBE, 0xD6, 0x2C,
+ 0xFC, 0x9C, 0x10, 0xCA, 0x73, 0xBF, 0xB8, 0xF5, 0x15, 0xC6, 0xAA, 0xD5, 0x51, 0x57, 0x94, 0x53,
+ 0x57, 0xD2, 0xCF, 0xA6, 0x9D, 0x1F, 0x7D, 0x17, 0xF9, 0x6D, 0x53, 0xCC, 0x31, 0x52, 0xA6, 0x9D,
+ 0x35, 0x6D, 0x2F, 0xA2, 0x4F, 0x45, 0x6E, 0xF7, 0x5F, 0xD7, 0xA2, 0x3E, 0x55, 0xD4, 0x7E, 0x04,
+ 0x7E, 0xCC, 0x9A, 0x27, 0x88, 0xED, 0xBC, 0x2B, 0xA9, 0xEB, 0x9E, 0x31, 0x4D, 0x52, 0xED, 0xDA,
+ 0x38, 0x21, 0x17, 0x29, 0xF3, 0xB2, 0x1C, 0x32, 0x03, 0xE5, 0x81, 0xC6, 0x06, 0x4E, 0x3F, 0xFA,
+ 0xDE, 0xA5, 0x2C, 0x9F, 0x34, 0xAD, 0x43, 0xDA, 0x42, 0x70, 0xB5, 0xBE, 0x1E, 0xB6, 0xF4, 0xBE,
+ 0x8B, 0xA5, 0xB4, 0xBE, 0xC9, 0x6C, 0x78, 0x32, 0xE2, 0xFF, 0x00, 0x63, 0xED, 0x5B, 0xA7, 0x37,
+ 0x4E, 0x9B, 0x51, 0x9C, 0xD4, 0x3D, 0xC8, 0xB7, 0x6B, 0x5D, 0xE9, 0xE5, 0x6B, 0x45, 0xDA, 0xFA,
+ 0xF9, 0x7A, 0xEC, 0x1F, 0xB1, 0x2F, 0xC1, 0x2B, 0x88, 0x62, 0x9A, 0x19, 0x7C, 0x52, 0x63, 0x74,
+ 0x0C, 0x9B, 0x75, 0xA1, 0xB4, 0x02, 0xA3, 0x1F, 0xC1, 0xF4, 0xE3, 0xA5, 0x7C, 0xEB, 0xA1, 0xCB,
+ 0x65, 0x39, 0x6A, 0x9E, 0x8B, 0xB5, 0xB4, 0xB2, 0xB3, 0xF8, 0x55, 0xB4, 0x5B, 0x2E, 0x8A, 0xFA,
+ 0x9E, 0xF5, 0x3C, 0xD3, 0x13, 0x3A, 0x71, 0x9A, 0xB5, 0x9F, 0x97, 0xF9, 0x3B, 0x2E, 0xC3, 0xFF,
+ 0x00, 0xE1, 0x87, 0x7E, 0x0A, 0x74, 0x1F, 0xF0, 0x94, 0x93, 0x8E, 0xDA, 0xC8, 0x23, 0x8F, 0x70,
+ 0x9E, 0xC6, 0xB8, 0xDE, 0x53, 0x85, 0xAA, 0xDD, 0x4B, 0xEE, 0xF5, 0xDF, 0x7E, 0xBD, 0x7B, 0x9B,
+ 0x2C, 0xD3, 0x19, 0x18, 0xE8, 0xD5, 0x97, 0x95, 0xBB, 0x7E, 0x9F, 0xD6, 0xC3, 0x7F, 0xE1, 0x87,
+ 0xFE, 0x0A, 0x0F, 0x97, 0x3E, 0x28, 0x04, 0x10, 0x98, 0x1A, 0xDA, 0x83, 0xDB, 0xA1, 0x29, 0x8E,
+ 0xE3, 0xF2, 0xA7, 0x4F, 0x2B, 0xC1, 0xD3, 0xBA, 0x49, 0x59, 0xAB, 0x6A, 0xAF, 0x6B, 0xA5, 0xB6,
+ 0xBA, 0x35, 0xD2, 0xC2, 0xFE, 0xD5, 0xC5, 0xAB, 0x5D, 0xAB, 0x7A, 0x5B, 0xF2, 0x7D, 0xBA, 0x75,
+ 0x35, 0x2F, 0x7F, 0x63, 0x9F, 0x84, 0x5A, 0x86, 0x95, 0xA6, 0xE9, 0x21, 0xBC, 0x41, 0x69, 0x6D,
+ 0xA4, 0xA3, 0xA2, 0xB5, 0xBD, 0xE4, 0x30, 0xCB, 0x71, 0xB9, 0xCB, 0x16, 0x9A, 0x41, 0x10, 0x32,
+ 0x63, 0xA7, 0xCC, 0x4E, 0x00, 0x18, 0xC6, 0x0E, 0x3D, 0x4C, 0x64, 0xFE, 0xB9, 0x95, 0xE1, 0xF2,
+ 0x8A, 0xB6, 0xF6, 0x34, 0x6F, 0xCB, 0x6B, 0xDF, 0x5B, 0xDA, 0xFA, 0xA5, 0xA5, 0xED, 0xB6, 0xDA,
+ 0x2B, 0x58, 0xE7, 0x58, 0xFC, 0x4D, 0x3A, 0xBE, 0xD1, 0x34, 0xDB, 0xDA, 0xEA, 0xF6, 0xD9, 0x3B,
+ 0x75, 0x4B, 0xCA, 0x36, 0x5A, 0xBB, 0xA6, 0xD9, 0xE9, 0x7A, 0x97, 0xEC, 0xF9, 0xF0, 0x3B, 0xFE,
+ 0x11, 0x1F, 0x04, 0xF8, 0x6F, 0x42, 0xF0, 0x35, 0x86, 0x91, 0x37, 0x87, 0x3C, 0x29, 0x77, 0xA1,
+ 0xF8, 0x8F, 0x55, 0xBA, 0xD3, 0xF4, 0xFD, 0x5E, 0xEF, 0xC6, 0x17, 0x77, 0x25, 0x80, 0xD4, 0xE5,
+ 0x77, 0x80, 0x48, 0x93, 0xC7, 0x1B, 0xA2, 0xA1, 0x0C, 0x76, 0x95, 0xC8, 0xE7, 0x18, 0xFB, 0x5E,
+ 0x16, 0xE2, 0xEC, 0x93, 0x86, 0xF2, 0x89, 0xE5, 0x78, 0xAC, 0x9E, 0x86, 0x26, 0x6D, 0x59, 0x4A,
+ 0xA4, 0x13, 0xD1, 0xA5, 0xA3, 0x6D, 0xDD, 0x27, 0xD5, 0x47, 0x46, 0xAD, 0x64, 0x9D, 0xDC, 0xBC,
+ 0x2C, 0x5C, 0x71, 0x58, 0xBC, 0xC2, 0x18, 0xF8, 0xE2, 0x67, 0x4E, 0x49, 0x25, 0x68, 0xCA, 0xD1,
+ 0x69, 0x3B, 0xD9, 0xC6, 0xDC, 0xAF, 0xAD, 0xB4, 0xBA, 0xD3, 0x6B, 0x59, 0xF8, 0xEF, 0x8D, 0xFF,
+ 0x00, 0x62, 0xEF, 0x85, 0x9A, 0xF4, 0xFA, 0x4C, 0x3A, 0x2E, 0xAD, 0xA9, 0xE9, 0x16, 0x7A, 0x1E,
+ 0x8B, 0x0E, 0x93, 0x0C, 0xDA, 0x46, 0x9F, 0x6B, 0x65, 0x26, 0xAC, 0x50, 0xE5, 0xAE, 0x6F, 0x81,
+ 0x8B, 0x2F, 0x39, 0x2C, 0xC0, 0xB7, 0x19, 0xC2, 0x81, 0xC0, 0x00, 0x7C, 0x87, 0x14, 0x4B, 0x25,
+ 0xCD, 0xF3, 0x57, 0x8B, 0xCB, 0x70, 0xB1, 0xA3, 0x49, 0x24, 0x94, 0x63, 0xCC, 0x94, 0xB4, 0x4D,
+ 0xDD, 0x39, 0x49, 0xC5, 0x27, 0xEE, 0xA5, 0x16, 0x92, 0x4A, 0xF6, 0xBB, 0x6C, 0xF5, 0x30, 0xB9,
+ 0xB6, 0x61, 0x86, 0xA4, 0xFD, 0xAB, 0x4E, 0x4F, 0xBA, 0xBD, 0xAD, 0xD1, 0x5B, 0x97, 0x4B, 0x79,
+ 0x3D, 0xB4, 0xF2, 0xF3, 0xD7, 0xFD, 0x84, 0x3C, 0x39, 0x05, 0xBC, 0xE9, 0x63, 0xE3, 0xCD, 0x62,
+ 0x33, 0x30, 0x58, 0x4F, 0xDA, 0xB4, 0xC8, 0x25, 0x2A, 0x33, 0xDB, 0x69, 0x5E, 0x31, 0x9E, 0xC7,
+ 0xA0, 0xFC, 0x7D, 0x6E, 0x19, 0xC5, 0xAC, 0x83, 0x87, 0x33, 0x3A, 0x58, 0x68, 0x3B, 0xE2, 0x62,
+ 0xA8, 0xB9, 0x3B, 0x5D, 0x42, 0x51, 0x77, 0x49, 0x24, 0x93, 0xD6, 0xDA, 0x37, 0x65, 0xDA, 0xF6,
+ 0x15, 0x5C, 0xF3, 0x11, 0x3A, 0xB4, 0xFD, 0xA4, 0x15, 0xE3, 0xAE, 0x8A, 0xCB, 0xCB, 0x4B, 0xF7,
+ 0xB5, 0x9A, 0x69, 0x79, 0x6D, 0x6E, 0x1E, 0xFB, 0xF6, 0x0F, 0xB9, 0x4F, 0xF8, 0xF0, 0xF8, 0x85,
+ 0x6C, 0x40, 0x07, 0x02, 0xEB, 0x45, 0x6C, 0x11, 0xC6, 0xD0, 0x19, 0x64, 0x03, 0xA0, 0x6E, 0xDC,
+ 0x6D, 0xAF, 0x8A, 0x96, 0x45, 0x46, 0xA4, 0x12, 0xA5, 0x51, 0xF3, 0x2B, 0x2B, 0xBB, 0x35, 0xD9,
+ 0x5A, 0xC9, 0x59, 0x5A, 0xC9, 0x2B, 0xF4, 0x7D, 0x12, 0x3B, 0x69, 0x71, 0x2D, 0x48, 0xE9, 0x52,
+ 0x94, 0x6D, 0xD2, 0xCD, 0xAB, 0x74, 0xF3, 0xEB, 0xB6, 0xD7, 0xEC, 0xBA, 0x70, 0xFA, 0x9F, 0xEC,
+ 0x57, 0xE2, 0xEB, 0x16, 0x55, 0x87, 0xC6, 0x7E, 0x13, 0x62, 0xF8, 0x58, 0xE3, 0xBC, 0x79, 0x2C,
+ 0x64, 0x93, 0xFD, 0xD5, 0xF9, 0xB3, 0xD3, 0xB5, 0x25, 0xC3, 0x15, 0xE5, 0x04, 0xE8, 0x4F, 0x9B,
+ 0xD2, 0x3A, 0x25, 0xA7, 0x5B, 0xAB, 0x7E, 0x16, 0xB0, 0x2E, 0x2D, 0xC3, 0xD3, 0x51, 0x8D, 0x7A,
+ 0x6A, 0x32, 0x7B, 0x2E, 0x64, 0x97, 0x45, 0xD5, 0x27, 0xE5, 0xA2, 0x7D, 0x3E, 0x5C, 0x7E, 0xA1,
+ 0xFB, 0x21, 0xFC, 0x5D, 0xB0, 0x0C, 0x62, 0x8B, 0xC3, 0x97, 0xEA, 0x00, 0x31, 0x8B, 0x5D, 0x64,
+ 0x23, 0x38, 0x39, 0xC0, 0x01, 0xD1, 0x54, 0x7D, 0xD3, 0xD4, 0x8E, 0x9E, 0xDC, 0x62, 0xF8, 0x6B,
+ 0x1A, 0x9D, 0xA1, 0x28, 0xDB, 0xE6, 0xBA, 0x76, 0xB7, 0xDD, 0x6D, 0x7C, 0x96, 0x88, 0xE8, 0x8F,
+ 0x15, 0xE5, 0xE9, 0xA8, 0xCE, 0x12, 0x4A, 0xDB, 0xD9, 0x5B, 0xE5, 0xAD, 0xFF, 0x00, 0x0F, 0x43,
+ 0xB9, 0xF8, 0x73, 0xF0, 0x8B, 0xE2, 0xEC, 0x7E, 0x36, 0xD0, 0x2E, 0x7C, 0x6B, 0xA1, 0x6A, 0x13,
+ 0x5A, 0xE8, 0x3A, 0x4C, 0x3A, 0x26, 0x8D, 0x31, 0xD3, 0xAD, 0x7C, 0x53, 0x67, 0x6B, 0x02, 0x9C,
+ 0x0B, 0x76, 0xB2, 0x84, 0x3D, 0xC4, 0x91, 0x08, 0x4D, 0xC2, 0x9F, 0x25, 0x1A, 0x45, 0x2C, 0xA7,
+ 0xA6, 0x6B, 0xDF, 0xC9, 0xB2, 0x0A, 0xEA, 0x51, 0xAF, 0x39, 0x72, 0xCA, 0x36, 0x56, 0xF7, 0x67,
+ 0x77, 0xD6, 0xD1, 0xE5, 0x49, 0x45, 0xA4, 0xD3, 0x77, 0x93, 0x8A, 0xB3, 0x4A, 0x4B, 0x6E, 0x1C,
+ 0x5E, 0x7B, 0x93, 0xCB, 0x08, 0xE1, 0x4E, 0x56, 0x52, 0x7B, 0x59, 0xA7, 0x7E, 0xF7, 0xD9, 0x3B,
+ 0xA5, 0xAB, 0xFD, 0x34, 0xD5, 0xFD, 0xA2, 0x3C, 0x03, 0x79, 0xAF, 0xF8, 0xBF, 0x40, 0xD0, 0xFC,
+ 0x2F, 0x67, 0x6F, 0x3F, 0xF6, 0x9D, 0xDF, 0xF6, 0x57, 0x86, 0xED, 0xF4, 0xED, 0x2A, 0xF2, 0x18,
+ 0xB4, 0x8D, 0x16, 0xD4, 0xAC, 0x7A, 0x54, 0x72, 0x08, 0xA2, 0x10, 0x80, 0x11, 0xE7, 0x62, 0xAC,
+ 0xA6, 0x54, 0x08, 0x77, 0x00, 0x4E, 0x0F, 0xD0, 0x67, 0xB9, 0x6D, 0x7A, 0xB4, 0x70, 0x99, 0x56,
+ 0x0A, 0x2E, 0x31, 0xA8, 0xD4, 0x9F, 0x95, 0x38, 0x35, 0xCA, 0xDC, 0xAC, 0xF5, 0x69, 0xA6, 0x9C,
+ 0x74, 0x6A, 0x2D, 0x35, 0x74, 0x91, 0x39, 0x56, 0x65, 0x96, 0x51, 0xF6, 0xB8, 0xBC, 0x46, 0x22,
+ 0x2B, 0x95, 0x45, 0x25, 0xCB, 0x67, 0x26, 0xEC, 0xA5, 0xC8, 0xAC, 0x9B, 0x69, 0xA4, 0xA5, 0xCC,
+ 0xD3, 0x77, 0x49, 0xAB, 0xD8, 0xF2, 0x5B, 0x9F, 0x07, 0xEB, 0x7A, 0x8F, 0x8F, 0x3C, 0x4F, 0x73,
+ 0xF6, 0x18, 0x12, 0xC7, 0xE1, 0x46, 0x93, 0x1F, 0xFC, 0x24, 0xD3, 0x49, 0x25, 0xC6, 0xAB, 0xA2,
+ 0xDA, 0x3D, 0x90, 0x16, 0xF1, 0x4B, 0x24, 0x8E, 0x89, 0xB2, 0x39, 0xA6, 0x44, 0xC6, 0xE2, 0xBD,
+ 0x70, 0x0E, 0x70, 0x07, 0x9B, 0x4E, 0xA6, 0x1E, 0xB7, 0x11, 0xD4, 0xFA, 0xD5, 0x48, 0xBC, 0x35,
+ 0x38, 0x38, 0xB9, 0x25, 0x28, 0xA4, 0xD4, 0x1F, 0x2B, 0x4A, 0xCE, 0x57, 0xDE, 0x29, 0xD9, 0x5D,
+ 0xDD, 0x34, 0x95, 0xCE, 0xDC, 0x35, 0x3C, 0x1D, 0x1C, 0xB5, 0xAA, 0x11, 0x76, 0xA9, 0x2E, 0x64,
+ 0xED, 0xAC, 0x94, 0x9A, 0xD2, 0xC9, 0x6C, 0xAE, 0x97, 0x2C, 0xB4, 0xB7, 0xBB, 0x67, 0x14, 0x79,
+ 0xA0, 0xD2, 0xF5, 0xA8, 0x7C, 0x27, 0xAD, 0x78, 0xDA, 0x7D, 0x1F, 0x45, 0x1A, 0x4E, 0xBD, 0xAE,
+ 0x3E, 0x91, 0x65, 0x75, 0x2A, 0x45, 0x2D, 0xC5, 0xA5, 0xDA, 0x91, 0x24, 0xB1, 0xDA, 0x43, 0xB8,
+ 0x94, 0x01, 0x25, 0xC6, 0x4A, 0x91, 0x85, 0x00, 0x1C, 0x8E, 0x7E, 0x69, 0x50, 0xC1, 0xC3, 0x01,
+ 0x8D, 0x9D, 0x79, 0x4B, 0xDA, 0xD4, 0x95, 0xA1, 0x16, 0xD2, 0x6A, 0xCD, 0xB6, 0xE4, 0xF4, 0xD6,
+ 0xD6, 0x6A, 0xD6, 0xD6, 0x3A, 0x5F, 0x67, 0xEA, 0xC6, 0xAA, 0xA7, 0x8C, 0xC3, 0xA8, 0x5E, 0xF1,
+ 0x57, 0xD9, 0x72, 0xD9, 0x6D, 0xCD, 0x1D, 0x17, 0x4D, 0x17, 0x2B, 0x5D, 0x2C, 0x93, 0x4D, 0x69,
+ 0x45, 0xE0, 0x5F, 0x16, 0x6A, 0x97, 0x5E, 0x1A, 0xF8, 0x77, 0x61, 0xE1, 0x5B, 0x73, 0xE2, 0x4B,
+ 0xDB, 0xF2, 0xF6, 0xE2, 0x2F, 0x21, 0x75, 0x1D, 0x45, 0xA7, 0x8C, 0xB2, 0x42, 0xD3, 0x6E, 0xDB,
+ 0x85, 0x58, 0x5C, 0x85, 0x27, 0x8E, 0x78, 0x1D, 0xFE, 0x93, 0x37, 0xCA, 0x70, 0x78, 0x58, 0xE0,
+ 0x72, 0x2C, 0x1D, 0x39, 0x3A, 0xEB, 0x92, 0x55, 0x92, 0x70, 0x51, 0xB2, 0x4A, 0xE9, 0xDD, 0xE8,
+ 0xDB, 0x7E, 0xEF, 0x3A, 0x49, 0xB5, 0xB5, 0xAC, 0xDC, 0xE1, 0xB1, 0x54, 0xB1, 0x14, 0x2B, 0x63,
+ 0x61, 0x27, 0x68, 0x35, 0x1B, 0x3D, 0x1D, 0xE5, 0x7B, 0x5A, 0x2D, 0x45, 0xE8, 0x93, 0xBB, 0xBF,
+ 0x2A, 0xB6, 0x96, 0xD4, 0xA0, 0xBE, 0x10, 0xBE, 0xFE, 0xD0, 0xD7, 0x6F, 0xEE, 0x34, 0x6B, 0xD3,
+ 0xA3, 0x78, 0x7A, 0x46, 0xB3, 0xD4, 0x1E, 0xDE, 0xD4, 0xC0, 0xB0, 0x4A, 0x43, 0xAC, 0x68, 0xC5,
+ 0x54, 0x46, 0x1C, 0x98, 0xDB, 0x0A, 0xA4, 0x67, 0x1C, 0x71, 0x92, 0x3C, 0x5C, 0x77, 0xF6, 0x2E,
+ 0x2F, 0x34, 0xC4, 0xB7, 0x85, 0xA9, 0x4F, 0x0B, 0x08, 0xF2, 0xC1, 0x28, 0xDD, 0xF3, 0x27, 0x16,
+ 0x93, 0xE5, 0x93, 0x51, 0xBA, 0x76, 0x5A, 0xB5, 0x6F, 0xC1, 0xCB, 0xDB, 0x60, 0xB0, 0xD4, 0x3D,
+ 0x9C, 0xEC, 0xE6, 0x94, 0xEE, 0xE4, 0x9B, 0x51, 0xBB, 0x56, 0x6D, 0xCA, 0x2F, 0x75, 0x67, 0x67,
+ 0xA2, 0xBA, 0xDE, 0xC8, 0xC0, 0xFF, 0x00, 0x84, 0x57, 0x54, 0x4D, 0x16, 0xCB, 0x51, 0x97, 0x4E,
+ 0xD4, 0x52, 0xE3, 0x57, 0xBF, 0x16, 0x7A, 0x1D, 0xB4, 0x9A, 0x65, 0xC0, 0xFE, 0xD6, 0x89, 0x4F,
+ 0x97, 0x23, 0xDA, 0xC8, 0x17, 0x63, 0xED, 0x94, 0x47, 0x1E, 0xD0, 0x49, 0xCB, 0x01, 0x8E, 0xC5,
+ 0x50, 0xC2, 0xE0, 0x70, 0x39, 0x1C, 0xAA, 0x54, 0xA2, 0xBE, 0xB3, 0x56, 0xAF, 0x22, 0xD6, 0x4B,
+ 0x96, 0x9D, 0x93, 0x6D, 0x59, 0xFB, 0xAF, 0x99, 0x72, 0xDD, 0xB7, 0x75, 0x74, 0xD3, 0x5B, 0xF5,
+ 0x53, 0x94, 0x2A, 0xCB, 0x96, 0x93, 0xD5, 0x24, 0xF4, 0xE5, 0xB3, 0xBA, 0x6F, 0x6B, 0xA6, 0xDB,
+ 0x5A, 0xE8, 0xAD, 0x6F, 0x3D, 0xBA, 0x79, 0xBC, 0x09, 0xA9, 0xDC, 0x6B, 0x7A, 0x3F, 0x84, 0x74,
+ 0xEF, 0x0F, 0xEB, 0x6D, 0xA9, 0xDA, 0x59, 0xAC, 0xDE, 0x20, 0x9A, 0x0D, 0x13, 0x55, 0x7B, 0xEB,
+ 0x28, 0x09, 0xDF, 0x71, 0x3C, 0xF6, 0x4D, 0x08, 0x78, 0xE2, 0x8A, 0x27, 0x04, 0xB2, 0xC7, 0x8D,
+ 0xAB, 0xBB, 0x3C, 0xF1, 0xCB, 0x8A, 0xCB, 0x30, 0x78, 0x7C, 0x45, 0x1C, 0x0E, 0x1A, 0x9F, 0xBF,
+ 0x3B, 0x73, 0x4A, 0x51, 0x8B, 0xE5, 0x4D, 0x2B, 0x34, 0xE3, 0x29, 0x27, 0x65, 0x77, 0x29, 0x35,
+ 0x1E, 0x5B, 0x5D, 0x24, 0x91, 0x9D, 0x2A, 0xB2, 0xA4, 0xAA, 0xD4, 0x8D, 0x45, 0xCC, 0xD3, 0x76,
+ 0x57, 0xD2, 0xCA, 0xD6, 0xD1, 0x26, 0xD3, 0xB2, 0xBA, 0xF7, 0x9B, 0xD9, 0x59, 0x68, 0x5A, 0xD5,
+ 0x34, 0xAF, 0x05, 0x69, 0x36, 0x96, 0xF2, 0x5D, 0xD9, 0xEA, 0x1A, 0x77, 0xF6, 0xFE, 0xA2, 0xAF,
+ 0xA6, 0xDD, 0x5B, 0xC7, 0x35, 0xD4, 0xBA, 0x6E, 0x9B, 0x01, 0x0A, 0x2F, 0xAD, 0x11, 0xCC, 0x69,
+ 0x3F, 0x9E, 0xC9, 0x26, 0x15, 0x9C, 0x6D, 0x1B, 0x48, 0xC7, 0x7D, 0x33, 0x3C, 0xAF, 0x2F, 0xC1,
+ 0xE0, 0x28, 0xCE, 0x69, 0x35, 0x51, 0xAB, 0x28, 0xB8, 0xEC, 0x92, 0xBE, 0xAD, 0xB6, 0x95, 0xAD,
+ 0x67, 0x67, 0x1D, 0x5B, 0x4E, 0xEA, 0xC1, 0x85, 0xA9, 0x8B, 0xA5, 0x17, 0x3A, 0x32, 0x6E, 0x71,
+ 0xB7, 0x2B, 0x97, 0xBA, 0xEF, 0xA3, 0x57, 0x4A, 0x29, 0x2B, 0x5F, 0xA2, 0x5D, 0x13, 0x57, 0xDB,
+ 0xC9, 0xEE, 0x64, 0x12, 0x4F, 0x23, 0x2C, 0x92, 0x4B, 0x18, 0x62, 0xB0, 0xBC, 0xB1, 0xAC, 0x52,
+ 0x32, 0x29, 0xC2, 0x16, 0x40, 0x48, 0x53, 0x80, 0x38, 0x04, 0x81, 0xEB, 0x5F, 0x23, 0x1A, 0x74,
+ 0xE9, 0x27, 0x0A, 0x4A, 0xD1, 0xE8, 0x7A, 0x3C, 0xF5, 0x6A, 0x46, 0x2E, 0xB4, 0x9B, 0x92, 0x49,
+ 0x6A, 0xDB, 0xD9, 0x6D, 0x77, 0xAD, 0x97, 0x4F, 0x22, 0x0A, 0xA0, 0x0A, 0x00, 0x55, 0x52, 0x70,
+ 0x14, 0x7D, 0x00, 0x1D, 0x38, 0xE3, 0xF9, 0x56, 0xD8, 0x7C, 0x35, 0x6C, 0x4C, 0xD5, 0x2C, 0x3C,
+ 0x2E, 0xFC, 0xBA, 0x7F, 0x91, 0x2E, 0x51, 0x82, 0x57, 0xD8, 0xE8, 0x2D, 0x2C, 0xC4, 0x11, 0xA4,
+ 0xCF, 0x1E, 0x41, 0x03, 0x74, 0x68, 0x01, 0x74, 0x5C, 0x75, 0x3D, 0x38, 0x15, 0xFD, 0x3D, 0xC1,
+ 0xFC, 0x1B, 0x1C, 0x83, 0x2E, 0xA3, 0x9F, 0x62, 0x70, 0xD2, 0x94, 0x5A, 0x4A, 0x74, 0xE9, 0xC5,
+ 0x3A, 0x94, 0xE2, 0xD2, 0xBC, 0xE6, 0xDD, 0x97, 0x2A, 0xFB, 0x4E, 0x32, 0x7A, 0x2D, 0x22, 0xF4,
+ 0x3C, 0x3A, 0xF8, 0x8F, 0x69, 0x27, 0x4A, 0x2D, 0x2E, 0xCF, 0xA7, 0xA2, 0xFD, 0x34, 0x47, 0x49,
+ 0x1C, 0x49, 0xE5, 0xAB, 0x26, 0x19, 0x0A, 0x82, 0xA5, 0x7A, 0x11, 0x8E, 0x30, 0x3F, 0x0A, 0xFE,
+ 0xAB, 0xCB, 0xB2, 0xDC, 0x33, 0xCB, 0xE8, 0xE2, 0x30, 0x32, 0x52, 0xA3, 0x38, 0xA9, 0x46, 0x49,
+ 0xBB, 0x34, 0xD6, 0x8F, 0x64, 0xD7, 0xCD, 0x2D, 0x0F, 0x0E, 0x53, 0xB3, 0x71, 0x92, 0xB3, 0x5A,
+ 0x58, 0x0A, 0x00, 0x06, 0xD0, 0x06, 0x31, 0x8E, 0xC3, 0x18, 0xE3, 0x1F, 0xA5, 0x5C, 0xF0, 0xAE,
+ 0x2B, 0xDD, 0x56, 0xB7, 0xDC, 0xD6, 0x9B, 0x74, 0xFC, 0x81, 0x35, 0x65, 0x62, 0x2C, 0x63, 0x8E,
+ 0x06, 0x38, 0xC0, 0x1D, 0x87, 0x61, 0x5E, 0x25, 0x4C, 0x2C, 0xEF, 0x75, 0x6E, 0x55, 0xD3, 0xCB,
+ 0xB2, 0xE8, 0xBB, 0x2F, 0x97, 0xA1, 0xAC, 0x5C, 0x62, 0x92, 0x48, 0x00, 0x1C, 0x71, 0x8C, 0x0C,
+ 0x01, 0xC0, 0xC7, 0x1D, 0x3F, 0x41, 0x51, 0xF5, 0x78, 0x69, 0xEE, 0xB5, 0x6F, 0x2F, 0xEA, 0xDF,
+ 0x2F, 0x45, 0x60, 0xE6, 0x69, 0x69, 0x62, 0x8D, 0xFD, 0x92, 0x5C, 0x42, 0xA3, 0x18, 0x91, 0x40,
+ 0xD8, 0x7B, 0x28, 0xC7, 0x03, 0xF4, 0xAF, 0x82, 0xF1, 0x27, 0x81, 0xB0, 0x7C, 0x57, 0x93, 0xD3,
+ 0xA2, 0xD5, 0xB1, 0x31, 0x8D, 0xE1, 0x27, 0xB4, 0x52, 0x5D, 0x5A, 0x5F, 0x7A, 0xB6, 0xDA, 0x69,
+ 0xA1, 0xD5, 0x82, 0xC4, 0x4A, 0x84, 0xEE, 0xBE, 0x1E, 0xA7, 0x20, 0xF1, 0x98, 0x9C, 0xC6, 0xC0,
+ 0x02, 0x87, 0x1C, 0x0C, 0x0C, 0x0E, 0x98, 0x1F, 0x95, 0x7F, 0x0C, 0x66, 0xB9, 0x66, 0x23, 0x27,
+ 0xC7, 0xD5, 0xCB, 0xB1, 0x4B, 0xDF, 0x83, 0xB6, 0xCD, 0x27, 0x6D, 0x9A, 0xBA, 0x5A, 0x5B, 0xC8,
+ 0xFA, 0x7A, 0x53, 0x8D, 0x48, 0x29, 0x47, 0x61, 0x95, 0xE7, 0x9A, 0x1F, 0xA3, 0x5F, 0xB1, 0xDF,
+ 0xEC, 0x78, 0x7E, 0x28, 0x1B, 0x3F, 0x1C, 0xF8, 0xE6, 0xCE, 0x46, 0xF0, 0xDF, 0x9A, 0xAF, 0xA4,
+ 0x68, 0xE4, 0x05, 0x5D, 0x49, 0x54, 0x9F, 0xDE, 0x4C, 0xB8, 0xE5, 0x4E, 0xD1, 0xB5, 0x7A, 0x10,
+ 0x09, 0x39, 0x1C, 0x0F, 0xAD, 0xE1, 0xEE, 0x1D, 0xAB, 0x99, 0x54, 0x8E, 0x9A, 0x68, 0xDB, 0xE9,
+ 0x15, 0xBA, 0xB7, 0x46, 0xDA, 0x5B, 0x74, 0xEA, 0xBB, 0x7C, 0xDE, 0x73, 0x9B, 0xC7, 0x05, 0x0E,
+ 0x48, 0xBD, 0x36, 0xEC, 0xDB, 0x76, 0x56, 0x4F, 0xA2, 0x5E, 0x49, 0xDF, 0x44, 0x95, 0xF4, 0x7F,
+ 0xD0, 0xFF, 0x00, 0xC2, 0xFF, 0x00, 0xD9, 0xAB, 0xC3, 0xBA, 0x26, 0x8F, 0x69, 0x01, 0xD3, 0x6D,
+ 0xB4, 0xAB, 0x48, 0xA0, 0x45, 0x86, 0xC6, 0xC6, 0x04, 0x80, 0xA0, 0x0B, 0xB5, 0x54, 0xED, 0x5E,
+ 0x3B, 0x0C, 0x73, 0xD4, 0xF4, 0xC0, 0xCF, 0xE8, 0x70, 0xA5, 0x95, 0xE5, 0x91, 0x54, 0xF0, 0xB4,
+ 0x94, 0xA7, 0xB3, 0x94, 0xB5, 0x6E, 0xD6, 0xDB, 0x6F, 0xF2, 0x56, 0xD1, 0x58, 0xF9, 0x35, 0xF5,
+ 0xFC, 0xC2, 0xD2, 0x9C, 0xF9, 0x29, 0xE9, 0x64, 0xBB, 0x6B, 0x65, 0xA5, 0xBD, 0x35, 0xBD, 0xED,
+ 0xBD, 0x99, 0xED, 0x9F, 0xF0, 0xA9, 0xBC, 0x0C, 0x22, 0xF2, 0x1B, 0x4E, 0x80, 0xE5, 0x40, 0x04,
+ 0xBA, 0x86, 0x50, 0x00, 0x03, 0x00, 0x77, 0x19, 0x1C, 0x77, 0xE0, 0x77, 0xAA, 0x8E, 0x3A, 0xBA,
+ 0xB7, 0x2C, 0x55, 0xBD, 0x17, 0xF9, 0x6D, 0xA7, 0xF5, 0x65, 0x66, 0xB2, 0xDC, 0x3A, 0x87, 0x2B,
+ 0x9C, 0xAF, 0xEA, 0xBB, 0x5B, 0x55, 0xB6, 0xD6, 0xDD, 0x75, 0x5D, 0x16, 0x9E, 0x3B, 0xF1, 0x13,
+ 0xF6, 0x6C, 0xF0, 0xC6, 0xBF, 0xA6, 0xDD, 0x47, 0xA7, 0xDB, 0xDB, 0x4E, 0xCD, 0x13, 0x2B, 0xD8,
+ 0xDD, 0x46, 0x93, 0x43, 0x2A, 0x95, 0x19, 0x50, 0x08, 0x38, 0xE3, 0x23, 0x27, 0x8F, 0x63, 0x9C,
+ 0x07, 0x2F, 0xA8, 0x63, 0xA2, 0xA9, 0xE3, 0xA9, 0x2B, 0x59, 0x2B, 0xA5, 0xAA, 0xF9, 0xAD, 0x56,
+ 0xDA, 0x25, 0xE6, 0xAF, 0xA6, 0xB0, 0xE8, 0xE2, 0xF0, 0x51, 0xBE, 0x12, 0xAB, 0x71, 0x49, 0x5E,
+ 0x32, 0xBB, 0x56, 0xB7, 0x4D, 0xDE, 0x9D, 0x34, 0xED, 0xBA, 0x3F, 0x9F, 0xDF, 0xDB, 0x0B, 0xF6,
+ 0x2C, 0x6F, 0x01, 0xC1, 0xA8, 0x78, 0xEF, 0xC0, 0x7A, 0x64, 0x96, 0x96, 0x96, 0x8C, 0xD2, 0xEB,
+ 0xBE, 0x1E, 0x85, 0x14, 0x45, 0x02, 0x80, 0x4B, 0xCB, 0x02, 0x0C, 0x6D, 0xC0, 0x00, 0xED, 0x03,
+ 0x91, 0xD0, 0x0C, 0x73, 0xF0, 0x1C, 0x43, 0xC3, 0x8F, 0x01, 0x35, 0x3A, 0x29, 0x72, 0x35, 0xEE,
+ 0xB5, 0x6B, 0x4B, 0xAD, 0x9D, 0xB4, 0xE6, 0xED, 0x6D, 0x1E, 0xDB, 0xED, 0xF5, 0x39, 0x1E, 0x73,
+ 0xF5, 0xBA, 0x71, 0x85, 0x4E, 0x9A, 0x5B, 0xAA, 0x7D, 0x2D, 0x65, 0xAA, 0x7B, 0x74, 0xB5, 0xAD,
+ 0xA5, 0xB5, 0xF9, 0xC3, 0xF6, 0x0D, 0xBB, 0xBA, 0xB6, 0xFD, 0xB5, 0xFF, 0x00, 0x64, 0x18, 0x6D,
+ 0xEE, 0x6E, 0x20, 0x86, 0xE7, 0xF6, 0xA3, 0xF8, 0x7D, 0x1D, 0xCC, 0x50, 0xCC, 0xD1, 0x45, 0x70,
+ 0xA3, 0xC5, 0x76, 0x20, 0x2C, 0x8A, 0x08, 0x0C, 0x30, 0xCC, 0x30, 0x47, 0x73, 0xEB, 0x5F, 0x2F,
+ 0x96, 0x69, 0x98, 0x61, 0xD2, 0xDB, 0x9E, 0x1F, 0xFA, 0x52, 0x3E, 0x87, 0x12, 0x97, 0xD5, 0xAA,
+ 0x69, 0xF6, 0x5F, 0xE4, 0x7F, 0xA0, 0x6D, 0x7E, 0xA6, 0x7C, 0x70, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x7F, 0x14, 0x5F, 0xF0, 0x5A, 0xFF, 0x00, 0xF9, 0x48, 0x1F, 0xC4, 0x8F, 0xFB, 0x12, 0xFC, 0x27,
+ 0xFF, 0x00, 0xA8, 0xF5, 0xAD, 0x7E, 0x75, 0xC4, 0x1F, 0xF2, 0x34, 0x9F, 0xA4, 0x7F, 0xF4, 0x94,
+ 0x7D, 0x46, 0x57, 0xFE, 0xE5, 0x1F, 0x9F, 0xE6, 0x7E, 0x78, 0x7C, 0x31, 0xF8, 0x37, 0xE3, 0x9F,
+ 0x8B, 0x1A, 0x9C, 0x1A, 0x7F, 0x85, 0xB4, 0xC5, 0x5B, 0x47, 0xB8, 0x5B, 0x5B, 0x8D, 0x73, 0x52,
+ 0x63, 0x65, 0xA2, 0x59, 0x31, 0xC6, 0x55, 0xA6, 0xC1, 0xDC, 0xC0, 0x10, 0x76, 0x46, 0xAE, 0xD8,
+ 0xFE, 0x1C, 0x57, 0x1E, 0x0B, 0x2E, 0xC4, 0xE3, 0x54, 0xA5, 0x46, 0x3E, 0xE4, 0x56, 0xAF, 0xA2,
+ 0xF2, 0xFE, 0xB4, 0xEF, 0x61, 0xE3, 0x73, 0x2C, 0x26, 0x03, 0x96, 0x15, 0xA5, 0xEF, 0xCB, 0x48,
+ 0xC5, 0x6E, 0xFF, 0x00, 0x44, 0x97, 0x9F, 0xCB, 0xB1, 0xF7, 0xB7, 0x89, 0xFF, 0x00, 0xE0, 0x9E,
+ 0xED, 0xE0, 0x2F, 0x06, 0x47, 0xAC, 0x2F, 0xC4, 0x9B, 0x8B, 0x8F, 0x13, 0xB1, 0x8F, 0x2D, 0x6B,
+ 0x60, 0xDA, 0x7E, 0x8D, 0x01, 0xE3, 0x7A, 0x05, 0x0D, 0xE6, 0x9F, 0xBC, 0xA0, 0x31, 0x61, 0xD3,
+ 0xEE, 0xF6, 0xAF, 0xAF, 0xE1, 0x7F, 0xAB, 0xD1, 0xAB, 0x2C, 0x1C, 0xE5, 0x51, 0xC1, 0xB4, 0xDA,
+ 0x53, 0x94, 0x22, 0xDA, 0xEF, 0x18, 0xC9, 0x27, 0xDB, 0x57, 0xB6, 0x9A, 0x2B, 0x9F, 0x3D, 0x9B,
+ 0xE6, 0x98, 0xCC, 0x35, 0x38, 0xE2, 0xA9, 0x53, 0x83, 0x84, 0x77, 0x4F, 0x77, 0x75, 0x64, 0x94,
+ 0xAC, 0xD4, 0x6D, 0xBD, 0xF9, 0x5A, 0x69, 0x5B, 0x4B, 0xDD, 0x67, 0x78, 0x53, 0xF6, 0x06, 0xF1,
+ 0xE6, 0xAD, 0xA4, 0x5B, 0xEB, 0x17, 0x5E, 0x26, 0xD0, 0x61, 0x96, 0xE7, 0x32, 0x1D, 0xB6, 0x93,
+ 0x5C, 0x45, 0x1C, 0x78, 0xE1, 0xDA, 0x52, 0xC0, 0x93, 0x81, 0xD0, 0x29, 0xEA, 0x39, 0xAF, 0xDE,
+ 0x78, 0x3F, 0xC5, 0xDE, 0x1C, 0xE0, 0xEC, 0x54, 0x70, 0xB4, 0xF2, 0x7A, 0x36, 0x57, 0xBB, 0x8C,
+ 0x64, 0x9D, 0xEC, 0xD5, 0xD2, 0x72, 0xB5, 0xDB, 0xEA, 0xF5, 0x7D, 0xAF, 0x63, 0xC8, 0x95, 0x5C,
+ 0xE3, 0x19, 0x42, 0x35, 0x70, 0x94, 0x23, 0x18, 0x36, 0xAD, 0x19, 0x54, 0xB3, 0xB7, 0x57, 0xEE,
+ 0xD3, 0x69, 0x7A, 0x5E, 0xDA, 0x59, 0xB5, 0xD3, 0xD5, 0x35, 0x3F, 0xF8, 0x27, 0xFF, 0x00, 0xC4,
+ 0x3D, 0x17, 0xC3, 0xB7, 0xDA, 0xDF, 0x84, 0x6D, 0xB4, 0x2F, 0x1E, 0xCB, 0xA6, 0x58, 0x1B, 0xFB,
+ 0xED, 0x2D, 0x74, 0x2B, 0x99, 0x2E, 0xAD, 0xE2, 0x8D, 0x5C, 0xC8, 0xC8, 0xC9, 0x2F, 0x4C, 0x02,
+ 0x30, 0x41, 0xF6, 0x2A, 0x42, 0xE7, 0xFA, 0x27, 0x85, 0xFC, 0x68, 0xE1, 0xFC, 0xE2, 0x93, 0xFA,
+ 0xEE, 0x5D, 0xEC, 0xA0, 0x9C, 0x5F, 0x3C, 0x6D, 0x64, 0xB4, 0xD1, 0xBB, 0xA7, 0x64, 0xD6, 0xC9,
+ 0x29, 0x37, 0x7B, 0xA6, 0xAE, 0x7C, 0xFE, 0x39, 0x66, 0x98, 0x38, 0xC2, 0x78, 0xC9, 0xBF, 0x67,
+ 0x75, 0x77, 0x4E, 0x49, 0x34, 0x9A, 0xD5, 0x72, 0xB8, 0xA5, 0x2B, 0x5B, 0x45, 0x78, 0xEB, 0xB5,
+ 0xAE, 0xD1, 0x43, 0xE0, 0xD7, 0xEC, 0xF5, 0xA8, 0xF8, 0xFF, 0x00, 0xC3, 0xB7, 0x5E, 0x21, 0xD4,
+ 0x74, 0x0F, 0x87, 0x3A, 0x4A, 0xDB, 0xCB, 0x25, 0xA5, 0xBD, 0x95, 0xEE, 0x87, 0x73, 0x7B, 0x34,
+ 0x4F, 0x0E, 0xE1, 0x22, 0xC8, 0x9F, 0x6B, 0x55, 0x5C, 0xB0, 0x38, 0x03, 0x00, 0x11, 0x81, 0xD7,
+ 0x8F, 0xB6, 0xCD, 0x78, 0xD3, 0x07, 0x93, 0x62, 0x21, 0x83, 0xC3, 0xD4, 0x9D, 0x45, 0x34, 0xA5,
+ 0xCC, 0xA4, 0xD2, 0x4A, 0x49, 0x4A, 0x29, 0x3B, 0x5D, 0xC5, 0x2B, 0x24, 0x92, 0xDA, 0xEE, 0xDA,
+ 0x2B, 0xFC, 0xFD, 0x3A, 0x19, 0x9E, 0x69, 0xCD, 0xFD, 0x99, 0x8E, 0xAA, 0xE8, 0x41, 0x38, 0xA9,
+ 0x4E, 0x69, 0x4A, 0x5B, 0x69, 0x18, 0xA8, 0x5A, 0x0A, 0x37, 0x6F, 0x99, 0xBB, 0xF5, 0x6A, 0xDA,
+ 0x8E, 0xF8, 0x4D, 0xE0, 0xF9, 0xE1, 0xF8, 0xD1, 0x7D, 0xE1, 0xBD, 0x57, 0xC0, 0xBF, 0x0E, 0x1A,
+ 0xCB, 0xC1, 0x64, 0x6A, 0x72, 0xEA, 0x3A, 0x46, 0x93, 0x75, 0x1A, 0xCE, 0x48, 0xC5, 0xB2, 0xAB,
+ 0x3D, 0xC3, 0x60, 0x70, 0x40, 0x53, 0x9E, 0xA0, 0x74, 0xE2, 0xBD, 0x7C, 0xEF, 0x15, 0x7E, 0x1E,
+ 0x86, 0x6B, 0x84, 0xC5, 0xD6, 0x75, 0x2B, 0x7B, 0xAA, 0x37, 0x94, 0xA2, 0x96, 0x8A, 0x4D, 0xA5,
+ 0x24, 0xBC, 0xD5, 0xBC, 0xED, 0xAA, 0x8A, 0x5C, 0x75, 0x2A, 0x62, 0x73, 0x0A, 0x14, 0xB0, 0x33,
+ 0xC5, 0x56, 0x72, 0x94, 0x9A, 0x9C, 0x65, 0x28, 0xDA, 0xD4, 0xD2, 0xB2, 0xF7, 0x63, 0x1B, 0xAB,
+ 0xB8, 0xDB, 0x45, 0xCA, 0x93, 0x49, 0x2D, 0x4F, 0x6F, 0xF8, 0xC5, 0xE2, 0x1B, 0x6F, 0x13, 0x78,
+ 0xCF, 0xC0, 0xBF, 0x0B, 0x6C, 0x7C, 0x27, 0xE1, 0x3B, 0xCF, 0xED, 0x82, 0xDA, 0xA6, 0xBC, 0xD7,
+ 0x3A, 0x5C, 0xF3, 0x25, 0x9C, 0x10, 0x38, 0x65, 0x2A, 0x04, 0xBB, 0x55, 0xF3, 0x1A, 0xE0, 0x63,
+ 0x83, 0x8C, 0xE4, 0x6D, 0xDB, 0xF3, 0xFC, 0x31, 0x95, 0xCB, 0x05, 0x96, 0x62, 0x78, 0x83, 0x17,
+ 0x5A, 0xA4, 0x63, 0x04, 0xA3, 0x0B, 0xB9, 0xC5, 0x36, 0xD3, 0x4D, 0x7C, 0x5A, 0xB7, 0x17, 0x6D,
+ 0x6F, 0xA6, 0xA9, 0xAB, 0xD9, 0xF2, 0xE6, 0x14, 0xAA, 0xBA, 0xAA, 0x9D, 0x1A, 0xD3, 0xE6, 0x8D,
+ 0xA3, 0x16, 0xB9, 0x64, 0xEF, 0x3B, 0xA7, 0x6F, 0x76, 0xF6, 0x50, 0x53, 0x72, 0x5D, 0x9C, 0x5A,
+ 0xB3, 0xBB, 0x3D, 0x2B, 0xC7, 0x3A, 0x74, 0x3A, 0xEE, 0x87, 0x63, 0xE0, 0x6D, 0x1E, 0xC3, 0xC3,
+ 0x96, 0x17, 0x1A, 0xFE, 0x34, 0xAB, 0x76, 0xB8, 0xD3, 0x9A, 0x45, 0x82, 0x05, 0x5F, 0xDE, 0x10,
+ 0x9E, 0x71, 0xCF, 0xC8, 0x63, 0x50, 0x32, 0x33, 0xBB, 0xD1, 0x4E, 0x3E, 0x7F, 0x2F, 0x9D, 0x3C,
+ 0x25, 0x6A, 0x99, 0xC6, 0x3F, 0x95, 0xC6, 0x9A, 0x6D, 0xA4, 0xE6, 0x9B, 0x7B, 0x24, 0x9F, 0x32,
+ 0xB2, 0x76, 0x49, 0xDD, 0x34, 0xB4, 0x5B, 0xB4, 0x8F, 0x52, 0x39, 0x2E, 0x3F, 0x16, 0xA8, 0xE0,
+ 0x32, 0xD7, 0x37, 0x28, 0xB8, 0xBB, 0xA7, 0xEE, 0xC1, 0x45, 0xA7, 0x77, 0x34, 0xBD, 0xDB, 0x59,
+ 0x38, 0xB5, 0xCA, 0xFA, 0xA7, 0x6B, 0x33, 0xCF, 0xAE, 0xFF, 0x00, 0x62, 0xBD, 0x27, 0xC3, 0x11,
+ 0xDB, 0x6A, 0x9A, 0x9C, 0x3E, 0x12, 0xD6, 0x6D, 0xE5, 0x22, 0x39, 0x22, 0x8F, 0xC3, 0x23, 0x4F,
+ 0xB7, 0x80, 0xB2, 0x80, 0xAA, 0x54, 0x48, 0xD8, 0xCE, 0x18, 0xE7, 0x9C, 0x1F, 0x4E, 0x05, 0x72,
+ 0xD6, 0xF1, 0x72, 0xB6, 0x61, 0x09, 0x60, 0x72, 0xEA, 0x72, 0xA5, 0x18, 0xDB, 0x4E, 0x69, 0x3D,
+ 0x13, 0xFB, 0x29, 0xCA, 0x2A, 0xCA, 0xC9, 0x26, 0x9A, 0xEA, 0xDE, 0x89, 0x5F, 0xF5, 0x6C, 0x83,
+ 0x84, 0xB0, 0x78, 0x75, 0x1A, 0xB9, 0xAD, 0x6A, 0xB5, 0x6B, 0x5D, 0x35, 0xFB, 0xD9, 0x28, 0x2B,
+ 0x6A, 0xEF, 0x1D, 0x5C, 0xEC, 0xF4, 0x6A, 0x4E, 0xCD, 0x36, 0xF9, 0x53, 0x49, 0x1D, 0x3E, 0xBF,
+ 0xF0, 0x12, 0xFB, 0xC1, 0xFE, 0x1A, 0x8B, 0x5B, 0xF0, 0xAE, 0x9D, 0xA0, 0x45, 0x6B, 0x0C, 0xAA,
+ 0x2F, 0x6D, 0x13, 0x41, 0x53, 0x24, 0x50, 0x1C, 0x6E, 0x11, 0x80, 0xC0, 0xE0, 0x02, 0x4F, 0xDE,
+ 0xFE, 0x11, 0x9E, 0xA3, 0x1F, 0x1D, 0x4B, 0x88, 0xF0, 0xB9, 0x86, 0x61, 0x2C, 0xB7, 0x18, 0xAF,
+ 0x56, 0xDE, 0xEB, 0x77, 0x6B, 0x4B, 0xDA, 0xEB, 0x5B, 0xC9, 0xE9, 0xE6, 0xAF, 0x64, 0xEC, 0x9D,
+ 0xBF, 0x47, 0x87, 0x12, 0x46, 0x86, 0x0B, 0x5A, 0x55, 0x27, 0x4E, 0x0A, 0xCA, 0x31, 0x92, 0x4D,
+ 0x28, 0xE8, 0xE5, 0x18, 0xF2, 0xF2, 0xB6, 0x92, 0x72, 0x51, 0x4A, 0x2A, 0x5B, 0x26, 0xB4, 0x46,
+ 0x7E, 0xB5, 0xF0, 0x7E, 0xD3, 0x53, 0xD1, 0xED, 0xA7, 0x17, 0x76, 0x89, 0x6F, 0x3C, 0xB1, 0x2B,
+ 0x34, 0xB6, 0x70, 0x3F, 0x94, 0xCC, 0x32, 0xAB, 0x08, 0x6C, 0x64, 0x70, 0x79, 0xE3, 0x95, 0x5E,
+ 0xFC, 0x57, 0x2E, 0x5F, 0x9E, 0x62, 0x30, 0x38, 0x99, 0xDE, 0x84, 0x65, 0x08, 0xFC, 0x56, 0x8B,
+ 0x4E, 0x29, 0x74, 0x6A, 0xFA, 0x59, 0xA4, 0xAE, 0xF4, 0x49, 0x3B, 0x36, 0xB5, 0x5D, 0x0B, 0x89,
+ 0xF1, 0x4A, 0x84, 0xE5, 0x80, 0x93, 0x55, 0x25, 0x06, 0xE1, 0x24, 0xF5, 0x57, 0x8B, 0x4A, 0x4B,
+ 0x44, 0x9D, 0xB4, 0x7C, 0xB6, 0x7A, 0x36, 0xB9, 0x76, 0x89, 0xED, 0xBA, 0x67, 0xFC, 0x13, 0xCF,
+ 0xE3, 0x2E, 0xA5, 0xE0, 0x75, 0xD7, 0xEF, 0x6E, 0x3C, 0x1F, 0xF0, 0xD7, 0xE1, 0x84, 0xD6, 0xCB,
+ 0x04, 0x1F, 0x13, 0xBE, 0x34, 0xDD, 0x41, 0xF0, 0xDB, 0xC0, 0x31, 0x89, 0xC6, 0xC8, 0x52, 0xCE,
+ 0x69, 0x10, 0xDC, 0xDF, 0x93, 0xE6, 0x9F, 0xDD, 0xD8, 0xDB, 0x5C, 0xC8, 0x48, 0xC2, 0x8E, 0x48,
+ 0x5F, 0x9F, 0xC4, 0xF8, 0x85, 0x80, 0xA9, 0x8A, 0xE5, 0xC2, 0xE1, 0x9D, 0x4C, 0x4A, 0x92, 0x6E,
+ 0x9C, 0x21, 0xCD, 0x29, 0x28, 0xDB, 0x99, 0xA4, 0xDA, 0xB2, 0x8A, 0x8D, 0xF9, 0x9F, 0x2C, 0x14,
+ 0x52, 0x77, 0xEF, 0xAE, 0x53, 0xC5, 0xD5, 0x28, 0x54, 0xA3, 0xFD, 0xAE, 0xA5, 0x3C, 0x44, 0x6D,
+ 0xCD, 0x2A, 0x4A, 0xFC, 0xF6, 0xB3, 0x72, 0xB6, 0x8A, 0x32, 0xB2, 0x6A, 0x4A, 0xE9, 0x5F, 0x5B,
+ 0x24, 0xD5, 0xB9, 0x8D, 0x6F, 0xE1, 0x3F, 0xEC, 0x3D, 0xFB, 0x36, 0x84, 0xD0, 0xBE, 0x21, 0xD9,
+ 0x7C, 0x62, 0xFD, 0xB0, 0xBC, 0x77, 0x04, 0x31, 0x6B, 0x0B, 0x07, 0x87, 0x2D, 0xCF, 0xEC, 0xD7,
+ 0xFB, 0x3B, 0xDC, 0x92, 0xA3, 0x36, 0xE3, 0x54, 0xB8, 0x49, 0xBC, 0x47, 0xA8, 0xDB, 0xE1, 0xD7,
+ 0x7B, 0xC3, 0x06, 0x9E, 0xDF, 0x22, 0xA8, 0x68, 0xB2, 0x0B, 0xED, 0xFE, 0xB8, 0x71, 0x8E, 0x6F,
+ 0x88, 0x8D, 0x6C, 0xBA, 0x9D, 0x0C, 0x2D, 0x1D, 0x55, 0xED, 0x1A, 0xD5, 0x15, 0xF4, 0xE6, 0x7A,
+ 0xBA, 0x30, 0x5A, 0x24, 0x9B, 0x8C, 0xA3, 0x6B, 0xC9, 0xF3, 0xDB, 0x91, 0x7D, 0x3E, 0x1F, 0x38,
+ 0xCE, 0x73, 0xFA, 0x1E, 0xD7, 0x07, 0x3A, 0x78, 0x6A, 0x32, 0x6E, 0x0E, 0xED, 0xD6, 0xA8, 0x92,
+ 0x69, 0xAF, 0x75, 0x38, 0xC2, 0x32, 0x4F, 0x58, 0xA6, 0xF7, 0xBB, 0x57, 0xB5, 0xD7, 0x9B, 0x4D,
+ 0xFF, 0x00, 0x05, 0x09, 0xF8, 0xDB, 0xE0, 0xD9, 0xE7, 0xD0, 0x7F, 0x66, 0xBF, 0x85, 0xFF, 0x00,
+ 0x02, 0xBF, 0x64, 0x5D, 0x33, 0xE7, 0x4D, 0x30, 0x7C, 0x28, 0xF8, 0x63, 0xA7, 0x5F, 0x7C, 0x40,
+ 0x8A, 0xDE, 0x58, 0xC2, 0x98, 0xBF, 0xE1, 0x34, 0xD6, 0x96, 0xFB, 0x59, 0xDC, 0x7C, 0xA6, 0x26,
+ 0x48, 0xAE, 0x61, 0x24, 0x92, 0x4D, 0x79, 0x3F, 0xEA, 0xAE, 0x57, 0x83, 0xA9, 0x46, 0x39, 0xFD,
+ 0x79, 0xE3, 0x6A, 0xD4, 0xB3, 0xB4, 0xAA, 0x4A, 0x51, 0x6F, 0x74, 0x9C, 0x14, 0x94, 0x39, 0x52,
+ 0x71, 0x4E, 0x3F, 0x0B, 0x8A, 0x4A, 0x31, 0x8D, 0xDA, 0x5F, 0x4B, 0x4F, 0x85, 0xB8, 0x7B, 0x13,
+ 0x86, 0x9D, 0x6C, 0xF7, 0x15, 0x57, 0x17, 0x38, 0xB4, 0xDD, 0xE7, 0x35, 0x06, 0x93, 0x49, 0x4F,
+ 0xD9, 0xC1, 0xA4, 0x9A, 0x8D, 0xD3, 0x4F, 0x99, 0xAB, 0xBB, 0x26, 0x9A, 0x3C, 0x03, 0xC4, 0xF0,
+ 0xFE, 0xD0, 0x9F, 0xB4, 0x2D, 0xFB, 0x78, 0xAB, 0xE2, 0xDF, 0x8D, 0x3C, 0x63, 0xE3, 0x51, 0x34,
+ 0xCD, 0x72, 0xDA, 0xA7, 0xC4, 0xAD, 0x7E, 0xF7, 0xC4, 0x5E, 0x4B, 0xB8, 0x0B, 0x24, 0xB6, 0xD1,
+ 0x5C, 0x4A, 0xE5, 0x32, 0xB1, 0xA8, 0x3B, 0x51, 0x06, 0x00, 0xC7, 0x18, 0xCE, 0xD8, 0xAC, 0xD3,
+ 0x2E, 0xCB, 0xE8, 0x3C, 0x16, 0x0B, 0x28, 0xC3, 0xFB, 0x34, 0xEC, 0xA3, 0xEC, 0xE0, 0xE3, 0xEE,
+ 0xEB, 0x76, 0x9A, 0xDD, 0x5D, 0xF5, 0x6E, 0x2E, 0xE9, 0x69, 0xAB, 0xCF, 0x35, 0xE2, 0x1E, 0x0F,
+ 0xE1, 0x1A, 0x12, 0x8E, 0x02, 0x09, 0xC5, 0x2B, 0x35, 0x4D, 0xA4, 0xD7, 0x44, 0xDB, 0x49, 0x26,
+ 0xAF, 0x65, 0x67, 0x75, 0x75, 0xAF, 0x53, 0x9B, 0xF1, 0xCF, 0xEC, 0xF9, 0xAF, 0xD9, 0x78, 0x3E,
+ 0xF7, 0xFB, 0x0F, 0x46, 0xD5, 0xBC, 0x67, 0xA9, 0xDC, 0xDA, 0x0B, 0x5B, 0x4D, 0x33, 0xC3, 0x7A,
+ 0x11, 0xD6, 0xE5, 0x9A, 0x46, 0x4C, 0xAA, 0xAD, 0x94, 0x0A, 0xF3, 0x67, 0xE5, 0x66, 0x07, 0x03,
+ 0x01, 0x7F, 0x0A, 0xE7, 0xC1, 0x71, 0x26, 0x6B, 0x4B, 0x13, 0x87, 0xC4, 0x56, 0xC1, 0x50, 0xA7,
+ 0x05, 0x35, 0x18, 0xB9, 0x42, 0x2E, 0x2B, 0x7B, 0x2B, 0x5D, 0xA4, 0xAC, 0xAD, 0xF0, 0xC6, 0x2D,
+ 0x3B, 0x7B, 0xAA, 0xD6, 0xF0, 0xB1, 0x1C, 0x77, 0x84, 0xE2, 0x2C, 0xA3, 0x11, 0x81, 0xC5, 0xC6,
+ 0x2A, 0x83, 0xA4, 0xDA, 0xE6, 0x94, 0xAE, 0xDB, 0x8D, 0xE0, 0xE2, 0xF6, 0x6D, 0x36, 0xBD, 0xD8,
+ 0xA6, 0xEF, 0xE6, 0x8E, 0x57, 0xE1, 0x77, 0xEC, 0xE1, 0xAE, 0xF8, 0x46, 0xE2, 0xD8, 0xFC, 0x52,
+ 0x97, 0xE1, 0x47, 0xC3, 0xFB, 0xF9, 0x49, 0x91, 0x6D, 0xBC, 0x4D, 0xAC, 0xC7, 0xE2, 0x8F, 0x17,
+ 0x40, 0xA3, 0x69, 0x08, 0x74, 0x3B, 0x05, 0xB8, 0x96, 0x39, 0x00, 0x03, 0xE4, 0x94, 0xC5, 0xD5,
+ 0x73, 0xB4, 0x8C, 0xD7, 0xD3, 0x66, 0xBC, 0x4B, 0x86, 0xC7, 0xE1, 0xF9, 0x30, 0xF8, 0x0A, 0x0E,
+ 0xCB, 0x45, 0xEC, 0xA3, 0x16, 0xE5, 0x66, 0xA2, 0xED, 0x1E, 0x69, 0x24, 0xDD, 0xB5, 0x4D, 0x34,
+ 0x93, 0xB2, 0x7A, 0x23, 0xF9, 0x1F, 0x8A, 0xE8, 0x56, 0xE7, 0x84, 0xE5, 0x98, 0xBA, 0x14, 0x76,
+ 0xE5, 0xDE, 0xF6, 0xFE, 0x54, 0xAE, 0xE7, 0x76, 0xD4, 0x52, 0xB6, 0xFA, 0x5E, 0xDB, 0x7D, 0x5F,
+ 0xA7, 0x78, 0x1B, 0xC2, 0x96, 0xF0, 0xA8, 0xFB, 0x7F, 0x8C, 0xFC, 0x4E, 0xF1, 0x94, 0x91, 0x7E,
+ 0xC7, 0x63, 0x61, 0xF0, 0xD7, 0x42, 0x65, 0xC1, 0xC4, 0x7B, 0x31, 0x73, 0x73, 0x82, 0xA4, 0x64,
+ 0xFC, 0x87, 0x04, 0x63, 0x19, 0xC0, 0xF8, 0xEC, 0x5F, 0x10, 0x60, 0xF2, 0xFB, 0xA7, 0x81, 0xA3,
+ 0x29, 0xDA, 0xD7, 0x54, 0x20, 0xA3, 0x7D, 0x2E, 0xD3, 0x7C, 0xCE, 0x51, 0xD2, 0xC9, 0xB8, 0xC5,
+ 0xAE, 0xAA, 0xE9, 0x27, 0xF3, 0xB4, 0xB2, 0x7A, 0x35, 0x94, 0x64, 0xA7, 0x5E, 0xAB, 0xB5, 0x94,
+ 0xA5, 0x25, 0x4A, 0x32, 0x4F, 0x5F, 0x86, 0x37, 0x6B, 0x4B, 0x2D, 0x6F, 0xB5, 0xB4, 0x7B, 0x69,
+ 0xDC, 0x41, 0xAE, 0x69, 0x2A, 0xCD, 0xE0, 0x7F, 0x06, 0x7C, 0x3C, 0xD2, 0x65, 0xE1, 0x56, 0x6F,
+ 0x11, 0xC1, 0xA8, 0xF8, 0xDA, 0xEF, 0x80, 0x30, 0xE1, 0xAF, 0x2E, 0x1A, 0x25, 0x62, 0x15, 0x49,
+ 0xDB, 0x18, 0x19, 0xCE, 0x14, 0x64, 0xD7, 0xCC, 0x57, 0xE2, 0x7A, 0x13, 0xAA, 0x9D, 0x6A, 0x54,
+ 0x6D, 0xCC, 0x9D, 0xA3, 0x46, 0x0F, 0x4D, 0x6E, 0xB4, 0xB5, 0xD7, 0x55, 0xB2, 0xD1, 0x34, 0xD6,
+ 0x89, 0x7A, 0x3F, 0xD9, 0x75, 0xB0, 0xF1, 0x7F, 0x51, 0xC1, 0xD2, 0xE5, 0xB6, 0x8A, 0x55, 0x2A,
+ 0x49, 0xDB, 0x4D, 0x79, 0x9D, 0xEC, 0xEC, 0x93, 0x56, 0x49, 0x2D, 0x94, 0x56, 0x87, 0x23, 0xF1,
+ 0x47, 0xE3, 0x2F, 0xC7, 0xDF, 0x84, 0x36, 0x7F, 0x0F, 0x75, 0xAB, 0x3F, 0x17, 0x59, 0xDC, 0xE8,
+ 0xFE, 0x2C, 0xB8, 0x7B, 0x7D, 0x46, 0xD7, 0x40, 0xF0, 0x76, 0x89, 0xE1, 0xBB, 0xFD, 0x05, 0xE3,
+ 0x74, 0x44, 0x58, 0xD2, 0xC1, 0x4D, 0xC3, 0xC5, 0xBE, 0x53, 0x8F, 0x33, 0x6B, 0xE0, 0x29, 0x00,
+ 0x92, 0x71, 0xF6, 0x38, 0x5C, 0x26, 0x16, 0x4F, 0x0D, 0x4E, 0xAA, 0xA5, 0xEC, 0xB1, 0x0F, 0x97,
+ 0x9A, 0x38, 0x78, 0x5A, 0x37, 0x77, 0x4A, 0x30, 0x94, 0xD3, 0x8D, 0xF9, 0x5E, 0xAA, 0x5C, 0x8D,
+ 0xC7, 0x46, 0xBA, 0x67, 0x43, 0xDB, 0x66, 0x15, 0xE1, 0x97, 0xD3, 0xC4, 0xCA, 0x86, 0x22, 0xD7,
+ 0x84, 0x25, 0x18, 0xB8, 0x4A, 0x51, 0xB7, 0x32, 0xE6, 0x49, 0x69, 0xAA, 0xE5, 0xB3, 0xD6, 0xCD,
+ 0x3B, 0x6C, 0x7A, 0x5F, 0x80, 0x7E, 0x3A, 0x78, 0xB3, 0xE2, 0x05, 0xAD, 0xDC, 0xFA, 0x9F, 0x8A,
+ 0x7C, 0x48, 0xD7, 0xF6, 0x37, 0x4D, 0x67, 0x72, 0x92, 0x6A, 0x17, 0x96, 0xAE, 0x4A, 0x80, 0x18,
+ 0x98, 0xCB, 0x02, 0x9D, 0x40, 0x2A, 0xC1, 0x4F, 0xB7, 0x35, 0xF2, 0x1C, 0x47, 0x96, 0x4B, 0x2D,
+ 0xC0, 0x62, 0xF3, 0x8C, 0x2E, 0x22, 0x33, 0x85, 0x3A, 0xDE, 0xCD, 0x46, 0x58, 0x78, 0x6A, 0x93,
+ 0x69, 0x4A, 0x52, 0xF6, 0x92, 0xE5, 0x6B, 0x64, 0xA2, 0x9C, 0x6F, 0x65, 0x7B, 0x24, 0x7A, 0x19,
+ 0x5E, 0x65, 0x88, 0xA9, 0x8A, 0x9E, 0x59, 0x8D, 0x49, 0x55, 0x86, 0xEE, 0x2D, 0xF2, 0xC9, 0x74,
+ 0x94, 0x5B, 0x4B, 0x47, 0xD2, 0xDA, 0xAD, 0x3B, 0x26, 0x65, 0xFC, 0x40, 0x93, 0xE2, 0x8E, 0xAB,
+ 0x11, 0x6F, 0x0F, 0x6B, 0x89, 0x80, 0x98, 0x91, 0x75, 0x29, 0x65, 0xBA, 0x32, 0xA0, 0x4E, 0x10,
+ 0x96, 0x63, 0xE9, 0x80, 0x71, 0x8E, 0x78, 0xC6, 0x39, 0xF8, 0xFC, 0xA3, 0x3F, 0xC0, 0x53, 0x4A,
+ 0x35, 0xF0, 0xD4, 0x9B, 0x4B, 0x4B, 0x52, 0x8A, 0x49, 0xF7, 0x56, 0xB6, 0xDA, 0x5A, 0xF7, 0xB7,
+ 0x66, 0xB6, 0xD7, 0x39, 0xC3, 0x67, 0x75, 0xA2, 0x9E, 0x5F, 0x59, 0xA8, 0xF5, 0x57, 0x49, 0xB5,
+ 0xD2, 0xCD, 0xA6, 0xBC, 0xAC, 0xD6, 0xDA, 0x26, 0xAC, 0xEF, 0xF9, 0x61, 0xF1, 0x71, 0x3C, 0x79,
+ 0x6D, 0xF1, 0x27, 0x43, 0x5D, 0x52, 0xE7, 0x4B, 0xB9, 0xD5, 0x65, 0xBC, 0xFF, 0x00, 0x40, 0x75,
+ 0xB3, 0xDB, 0x14, 0x52, 0x02, 0x9B, 0xD9, 0xCE, 0xE2, 0x4F, 0x51, 0xD3, 0x1C, 0x00, 0x38, 0xC5,
+ 0x7E, 0x89, 0x4F, 0x8A, 0x31, 0x7E, 0xC9, 0x2C, 0x36, 0x13, 0x0A, 0xE0, 0xD7, 0x5C, 0x3C, 0x1B,
+ 0xB2, 0xE8, 0x9F, 0x4B, 0x5A, 0xDB, 0x36, 0xDB, 0xBB, 0x67, 0x3F, 0x0D, 0x53, 0xC9, 0xD6, 0x45,
+ 0x98, 0xD2, 0xC5, 0x42, 0xA2, 0x94, 0x6F, 0xED, 0xAF, 0x34, 0xDC, 0xAE, 0x9D, 0xAC, 0xD2, 0x4B,
+ 0x6F, 0x96, 0xBB, 0x5B, 0x45, 0xFA, 0x0B, 0xF0, 0xE5, 0xBE, 0x36, 0x7D, 0x83, 0x4A, 0x6B, 0xC9,
+ 0x7C, 0x3E, 0x9A, 0x47, 0xD9, 0xD5, 0x0A, 0x15, 0x71, 0x72, 0x91, 0x95, 0x00, 0x2A, 0x1F, 0xBC,
+ 0x07, 0x04, 0xF5, 0xE9, 0xEB, 0xC5, 0x7C, 0x76, 0x67, 0xC4, 0x39, 0x6A, 0x94, 0xE9, 0xCA, 0x85,
+ 0x2F, 0x68, 0xF7, 0xE5, 0xA5, 0x1B, 0x37, 0xAF, 0x4D, 0xBC, 0xB4, 0x4B, 0x64, 0xD2, 0x48, 0xF3,
+ 0xF2, 0x6C, 0x3E, 0x7A, 0xA9, 0xD1, 0x96, 0x06, 0x52, 0x58, 0x7B, 0xAE, 0x5E, 0x77, 0x1E, 0x65,
+ 0x0B, 0x69, 0x65, 0x15, 0x75, 0xA5, 0x92, 0xBE, 0xAB, 0xAD, 0xAD, 0xA7, 0xD8, 0x3A, 0x17, 0xED,
+ 0x2B, 0xFB, 0x5D, 0x7C, 0x18, 0xB4, 0x69, 0x3E, 0x01, 0x7C, 0x5C, 0xF1, 0xA7, 0x84, 0x27, 0x96,
+ 0xDD, 0x2D, 0xAE, 0x74, 0xEB, 0x4F, 0x17, 0x5E, 0xC3, 0xA3, 0x5C, 0x44, 0x8F, 0xB9, 0x21, 0x96,
+ 0xC1, 0x9D, 0xAD, 0x64, 0x8C, 0x30, 0x07, 0xCB, 0x78, 0xD9, 0x4F, 0x39, 0x1E, 0xBF, 0x39, 0x83,
+ 0xCD, 0x70, 0xD5, 0xD3, 0xA3, 0x98, 0x46, 0x2A, 0x29, 0xDE, 0x36, 0xA7, 0x15, 0x67, 0x6B, 0x5F,
+ 0x4D, 0x16, 0x9A, 0x2D, 0xD2, 0xD2, 0xC9, 0x23, 0xE8, 0xF3, 0x05, 0x9C, 0xD2, 0xA5, 0x0F, 0xEC,
+ 0xD8, 0xC6, 0xFF, 0x00, 0x6B, 0x6B, 0xDB, 0x7D, 0x16, 0x8B, 0xE4, 0xDA, 0x56, 0x56, 0xF4, 0xF1,
+ 0xCD, 0x6F, 0xFE, 0x0A, 0xA5, 0xF1, 0xA7, 0x57, 0xF1, 0xD5, 0x8F, 0x84, 0x3F, 0x6A, 0x9F, 0xD9,
+ 0xB7, 0xE0, 0x07, 0xC7, 0xE9, 0xF5, 0x19, 0xCC, 0x96, 0xDE, 0x28, 0xD0, 0x74, 0x88, 0xFE, 0x0A,
+ 0xFC, 0x50, 0x56, 0x00, 0xF9, 0xF2, 0xC9, 0xAA, 0x69, 0x50, 0x0D, 0x3E, 0x79, 0x40, 0x65, 0x20,
+ 0x5D, 0x69, 0xB7, 0x28, 0x71, 0xF3, 0xAC, 0x9B, 0x88, 0xAF, 0x66, 0x86, 0x16, 0xBE, 0x1F, 0x11,
+ 0x4F, 0x17, 0x94, 0x4A, 0x9C, 0x57, 0x2D, 0x92, 0x94, 0x23, 0x38, 0xA5, 0xA2, 0xD3, 0x9B, 0x5E,
+ 0x9A, 0xEB, 0xE9, 0x64, 0x74, 0x60, 0x33, 0x8C, 0x0D, 0x4C, 0x87, 0x13, 0x3C, 0xCE, 0x73, 0xE6,
+ 0xA4, 0xD2, 0xAA, 0xB9, 0x62, 0xB5, 0x7F, 0x0F, 0x2C, 0x63, 0x78, 0xBD, 0xD5, 0xAD, 0xEA, 0xD6,
+ 0x89, 0x9F, 0x7E, 0xF8, 0x56, 0xDF, 0xF6, 0x7C, 0xF8, 0xBF, 0xA6, 0x2C, 0xDE, 0x15, 0xF1, 0x9E,
+ 0x85, 0xF0, 0x8B, 0xC4, 0x66, 0xD9, 0x4C, 0x5E, 0x00, 0xFD, 0xA9, 0xBC, 0x1B, 0x6F, 0xA0, 0xDB,
+ 0x6A, 0xD2, 0xB1, 0x3B, 0x57, 0x4F, 0xF8, 0x81, 0xE1, 0x59, 0x06, 0x9F, 0x18, 0x20, 0xC6, 0x14,
+ 0x5E, 0xE9, 0xF6, 0x89, 0x90, 0x0B, 0x48, 0xA3, 0x81, 0xE3, 0x63, 0x33, 0x7A, 0xB7, 0x54, 0xEA,
+ 0x53, 0xA0, 0xE7, 0x1D, 0x9C, 0x69, 0x41, 0x2E, 0xF6, 0x97, 0xB9, 0x1B, 0xEA, 0xB5, 0xEE, 0x9D,
+ 0x92, 0xB2, 0x3A, 0x30, 0x56, 0x9C, 0x17, 0xB3, 0x53, 0x54, 0xD7, 0x49, 0xAE, 0x56, 0xF6, 0x57,
+ 0xBC, 0x25, 0xAE, 0xDA, 0xAB, 0x2D, 0x5B, 0x69, 0x59, 0xD9, 0x7C, 0xFB, 0xFB, 0x4E, 0x68, 0x7A,
+ 0xA7, 0xEC, 0xBF, 0x63, 0x6D, 0xAC, 0x7C, 0x5D, 0xF8, 0x41, 0xF1, 0x37, 0xC2, 0x1E, 0x1C, 0xD4,
+ 0x64, 0x58, 0x74, 0xAF, 0x89, 0xBE, 0x0B, 0x9A, 0xCB, 0xE2, 0x37, 0xC1, 0xDD, 0x71, 0x5C, 0xAE,
+ 0xC9, 0xB4, 0xED, 0x69, 0x59, 0x2D, 0x2E, 0x21, 0x6F, 0x31, 0x36, 0x18, 0xAF, 0xA4, 0x63, 0x90,
+ 0x0E, 0x0F, 0x03, 0x2C, 0x16, 0x22, 0xBD, 0x7A, 0x73, 0xAB, 0xEE, 0x28, 0xA7, 0x1B, 0x25, 0x4E,
+ 0x9E, 0xAB, 0xFB, 0xA9, 0xC1, 0xAD, 0x3A, 0xED, 0x6D, 0xD2, 0x77, 0x3A, 0xA5, 0x26, 0xF1, 0xB4,
+ 0x72, 0xDA, 0x74, 0xE5, 0x17, 0x3B, 0xDA, 0x4E, 0xDC, 0x89, 0xA4, 0x9D, 0x9B, 0x7C, 0xB6, 0xD2,
+ 0xFA, 0x2B, 0xFE, 0x16, 0x7E, 0x11, 0xE0, 0xEF, 0x15, 0x69, 0xFF, 0x00, 0x16, 0x74, 0xC1, 0x71,
+ 0xF0, 0x67, 0xC5, 0x3E, 0x08, 0xF1, 0xEE, 0xA9, 0x24, 0x24, 0xC7, 0xA0, 0xEA, 0xFA, 0xC1, 0xF8,
+ 0x6B, 0xAC, 0xE1, 0x63, 0x2C, 0x55, 0xA2, 0xD4, 0x15, 0x2D, 0xCB, 0x02, 0xAA, 0x30, 0x97, 0x2F,
+ 0x93, 0xC0, 0x39, 0x27, 0x1E, 0xBD, 0x3C, 0x16, 0x63, 0x3A, 0x53, 0xC4, 0x4E, 0xAC, 0x23, 0x46,
+ 0x9D, 0xB5, 0xF6, 0x54, 0x93, 0xBC, 0xBA, 0x2D, 0x35, 0xDF, 0x65, 0xB2, 0xE9, 0xA1, 0xE7, 0x63,
+ 0x2B, 0x57, 0xC3, 0xD7, 0x78, 0x0A, 0x12, 0x84, 0xAB, 0xDD, 0x5A, 0x2E, 0x4E, 0x1A, 0x59, 0x7B,
+ 0xD6, 0xB4, 0xB4, 0xD5, 0x25, 0xAD, 0xAF, 0xA3, 0x6B, 0x46, 0xFC, 0xD7, 0xC5, 0x7E, 0x28, 0xFD,
+ 0xA0, 0xBC, 0x11, 0x24, 0x8D, 0xE2, 0x4F, 0x81, 0x1A, 0x9D, 0xA4, 0x11, 0x6E, 0x22, 0x2F, 0xB5,
+ 0x29, 0x79, 0x95, 0x0E, 0x09, 0x89, 0xC8, 0xF2, 0xA4, 0xED, 0x82, 0x8C, 0x41, 0x03, 0x8E, 0xBC,
+ 0xC5, 0x0A, 0xB8, 0x7E, 0x65, 0x4E, 0x96, 0x2D, 0x45, 0xE9, 0x6F, 0x72, 0x92, 0xFB, 0x97, 0x22,
+ 0x49, 0x2F, 0x5D, 0x2D, 0xDD, 0x58, 0xF2, 0xEA, 0xE3, 0x33, 0x7A, 0x3E, 0xEE, 0x2A, 0x8F, 0x2C,
+ 0x56, 0xEF, 0x96, 0x72, 0x8E, 0x9D, 0x9C, 0x39, 0x9D, 0xB4, 0xD1, 0xF2, 0xDB, 0xAA, 0xD0, 0xA5,
+ 0xE0, 0x6F, 0xDA, 0x0B, 0xC3, 0x1E, 0x31, 0xD5, 0x5B, 0xC3, 0xB7, 0x56, 0xB7, 0xDE, 0x16, 0xF1,
+ 0x2C, 0x20, 0xA4, 0x9A, 0x26, 0xB5, 0x0A, 0xC1, 0x37, 0xA6, 0x63, 0x70, 0x30, 0xC0, 0x90, 0x00,
+ 0x20, 0x9F, 0xC3, 0xB7, 0x26, 0x32, 0x96, 0x6F, 0x4E, 0x9B, 0xAB, 0x4A, 0xA4, 0x67, 0x04, 0xB6,
+ 0xF6, 0x74, 0xE3, 0x24, 0xAD, 0xBF, 0x2F, 0x2E, 0xD6, 0xDD, 0xAF, 0x91, 0xD5, 0x87, 0xCC, 0xE8,
+ 0xF2, 0x42, 0x58, 0x88, 0xA5, 0x4E, 0x4E, 0xD1, 0x9C, 0x65, 0xCD, 0x4D, 0xCB, 0xF9, 0x79, 0xAD,
+ 0x17, 0x19, 0x59, 0x7C, 0x32, 0x8C, 0x5F, 0x44, 0x99, 0xED, 0x57, 0xF7, 0xEF, 0x63, 0x63, 0x71,
+ 0x78, 0xCA, 0x64, 0x5B, 0x68, 0x5A, 0x57, 0x8E, 0x14, 0x0C, 0x5C, 0x2A, 0xE4, 0x2A, 0x8C, 0x63,
+ 0x3D, 0x3F, 0xFD, 0x5C, 0x1F, 0x0B, 0x0B, 0x8E, 0xCC, 0x1D, 0x48, 0xE1, 0xE1, 0x51, 0x2B, 0xE9,
+ 0x7E, 0x48, 0x7A, 0x6F, 0xCB, 0x7F, 0xEA, 0xFB, 0x9D, 0xD8, 0x8A, 0xB0, 0xA3, 0x46, 0x55, 0x79,
+ 0x6F, 0x18, 0xAB, 0xE9, 0xE5, 0xFF, 0x00, 0x0D, 0xB6, 0xDE, 0x5D, 0x0F, 0x28, 0xF0, 0x77, 0xC6,
+ 0x4D, 0x07, 0xC6, 0xDA, 0xA5, 0xCF, 0x87, 0x74, 0xFD, 0x33, 0x5C, 0xB2, 0xBE, 0xB1, 0x2F, 0x2D,
+ 0xC3, 0xEA, 0x36, 0x8B, 0x05, 0xBB, 0x81, 0xC2, 0x18, 0xDB, 0xA9, 0xC8, 0x52, 0x70, 0x3D, 0xBD,
+ 0x6B, 0xEC, 0xB3, 0xCC, 0xA7, 0x13, 0x82, 0xE1, 0x6C, 0x2F, 0xB4, 0xAB, 0x16, 0xE7, 0x39, 0x4A,
+ 0x49, 0x45, 0xAD, 0xAC, 0xA2, 0xF6, 0x49, 0x2B, 0x5E, 0xD6, 0xD1, 0xF4, 0xDB, 0x5F, 0x13, 0x0B,
+ 0x98, 0x2C, 0x46, 0x26, 0x8C, 0x65, 0x49, 0xC7, 0xDA, 0x43, 0x9E, 0x0E, 0xF1, 0x77, 0x8A, 0x4B,
+ 0xA2, 0x77, 0x5B, 0xE9, 0x75, 0x6D, 0x1A, 0x57, 0x4A, 0xC7, 0xA0, 0xDD, 0xC8, 0xAA, 0x9B, 0xCB,
+ 0x60, 0x2A, 0x07, 0x24, 0x01, 0xB5, 0x54, 0x73, 0xEC, 0x0A, 0x80, 0xAB, 0xEA, 0x0E, 0x3A, 0xF1,
+ 0x5F, 0x0F, 0x42, 0x17, 0xB2, 0xB7, 0x92, 0x4B, 0xEE, 0xFE, 0xAD, 0xB3, 0xED, 0x63, 0xD7, 0xA9,
+ 0xCA, 0xA2, 0x97, 0x4F, 0x2F, 0x2D, 0xFF, 0x00, 0xE0, 0x79, 0x76, 0x3E, 0x3C, 0x13, 0x49, 0xF1,
+ 0x4B, 0xE3, 0x54, 0x8D, 0x1B, 0x93, 0xE1, 0xBF, 0x00, 0xAB, 0x44, 0x76, 0x30, 0x68, 0x6E, 0x2E,
+ 0xCA, 0x8D, 0xA0, 0x91, 0xC7, 0xCA, 0x88, 0x09, 0xE7, 0xF8, 0x87, 0xA5, 0x7D, 0x8A, 0x8C, 0x72,
+ 0xFC, 0xBA, 0x11, 0x4B, 0xDF, 0x6B, 0xB7, 0x59, 0x7D, 0xDB, 0x45, 0xDB, 0x6D, 0x1B, 0xE9, 0xA5,
+ 0xFE, 0x46, 0x71, 0x78, 0xFA, 0xB1, 0x8C, 0x96, 0xB5, 0xA5, 0xA7, 0xF7, 0x68, 0x52, 0x6F, 0x55,
+ 0xFF, 0x00, 0x5F, 0x67, 0xA2, 0x6B, 0xEC, 0xAD, 0x36, 0x47, 0xAA, 0xFC, 0x52, 0xF1, 0x34, 0xBE,
+ 0x17, 0xF0, 0x7E, 0xA3, 0x7B, 0x65, 0x1B, 0x1B, 0xB9, 0xD6, 0x3D, 0x2F, 0x4D, 0x48, 0xF6, 0xA6,
+ 0x6E, 0x2E, 0x58, 0x45, 0x6C, 0x85, 0xF8, 0x58, 0xF2, 0x4A, 0x60, 0xB6, 0xD1, 0xCA, 0xE4, 0x90,
+ 0x33, 0x5E, 0x7E, 0x02, 0x8C, 0x25, 0x55, 0xD4, 0xAA, 0xBD, 0xC8, 0x6A, 0xF4, 0x6D, 0x68, 0xB4,
+ 0x56, 0x5B, 0xEA, 0xD2, 0xB7, 0xDC, 0xBA, 0x1E, 0xAE, 0x22, 0x9D, 0x4C, 0x44, 0xA1, 0x81, 0xC2,
+ 0xE9, 0x2A, 0x8D, 0x46, 0xFA, 0x7B, 0xB1, 0x4A, 0xF3, 0x97, 0x64, 0xA3, 0x04, 0xDA, 0x7A, 0x6B,
+ 0x6B, 0x3D, 0x8F, 0x42, 0xF8, 0x7D, 0xA7, 0xDC, 0xFC, 0x3C, 0xB6, 0xF0, 0xC6, 0x8B, 0xE2, 0x1D,
+ 0x63, 0xC2, 0xFF, 0x00, 0x0D, 0xFC, 0x73, 0xE1, 0xAB, 0x0B, 0x2B, 0x5B, 0xB5, 0x93, 0x5B, 0x3A,
+ 0x66, 0xAF, 0xE2, 0x5B, 0xCB, 0x95, 0x70, 0xB7, 0xB6, 0xEB, 0xF6, 0x97, 0x32, 0x12, 0xA6, 0x5F,
+ 0x32, 0x58, 0x18, 0xC4, 0xA4, 0xAA, 0x9C, 0x16, 0xAF, 0xA7, 0x84, 0xA1, 0x84, 0xA1, 0x41, 0xCE,
+ 0x0D, 0xB9, 0x47, 0x9E, 0x52, 0xBC, 0x9B, 0x92, 0x95, 0xD4, 0x53, 0xD5, 0x72, 0x38, 0x2B, 0xF2,
+ 0xE9, 0x1B, 0xAD, 0x1D, 0xD7, 0x29, 0xCE, 0xA8, 0x29, 0xD6, 0xAB, 0x52, 0x34, 0x63, 0x42, 0x95,
+ 0x39, 0x46, 0x2E, 0xD6, 0xE5, 0x82, 0xBD, 0xA0, 0xDC, 0x95, 0xD3, 0x73, 0x56, 0xBD, 0x9D, 0x9C,
+ 0x95, 0xB4, 0x6A, 0xEA, 0x9E, 0xAB, 0x7B, 0xA4, 0xE8, 0xCD, 0xE2, 0x7F, 0x11, 0xB7, 0x8E, 0xF4,
+ 0x7D, 0x27, 0x4A, 0xF0, 0xA5, 0xAB, 0x9B, 0x2D, 0x7B, 0xC4, 0x26, 0x3D, 0x37, 0xFB, 0x69, 0x59,
+ 0xC4, 0x69, 0x04, 0x11, 0x48, 0x5C, 0x09, 0x1D, 0x1D, 0x98, 0x29, 0xCE, 0x02, 0xF5, 0xCE, 0x2B,
+ 0xC4, 0x84, 0x63, 0x4A, 0x33, 0x9C, 0xA7, 0x15, 0x18, 0xAB, 0xAB, 0xD9, 0x2E, 0x8B, 0x77, 0x64,
+ 0x97, 0xE2, 0xB7, 0xB7, 0x6B, 0x85, 0x1F, 0x69, 0x7A, 0x74, 0x97, 0x32, 0xD6, 0xD1, 0x49, 0xBE,
+ 0x66, 0x95, 0xED, 0x14, 0xAE, 0xDB, 0x56, 0x69, 0x24, 0xAE, 0xD6, 0xB6, 0xB2, 0x39, 0x3B, 0x8F,
+ 0x08, 0xCB, 0x27, 0x85, 0x6D, 0x2D, 0x6C, 0xF4, 0xBD, 0x3A, 0x7D, 0x27, 0xE2, 0xF4, 0x09, 0x63,
+ 0x6F, 0x69, 0x67, 0x0A, 0x2B, 0xF8, 0xC2, 0xDE, 0x1B, 0xB5, 0xF2, 0xE1, 0x66, 0x42, 0x37, 0xA0,
+ 0xB8, 0x50, 0x54, 0x1C, 0x7C, 0xE1, 0x4F, 0xB8, 0x5F, 0x56, 0xA7, 0x37, 0x15, 0x51, 0x46, 0x49,
+ 0xAD, 0x53, 0x49, 0xDB, 0xA2, 0x5A, 0xA7, 0x6E, 0x96, 0x4B, 0x4B, 0x6C, 0xAC, 0xAC, 0x79, 0xB4,
+ 0xEB, 0x63, 0x30, 0x54, 0x14, 0x30, 0x32, 0x74, 0xE3, 0x59, 0xA5, 0x05, 0x1B, 0xC5, 0xC9, 0xA7,
+ 0xA5, 0xB6, 0xB5, 0x9D, 0x93, 0xBD, 0x9A, 0xD9, 0x5B, 0x44, 0x79, 0xC6, 0xBB, 0xF0, 0x8B, 0xFE,
+ 0x13, 0xAD, 0x63, 0x41, 0xF8, 0x74, 0xDA, 0x25, 0x96, 0xA1, 0x6F, 0xF0, 0x7B, 0x46, 0x9E, 0xEB,
+ 0xFE, 0x11, 0xCD, 0x2F, 0x5A, 0xB8, 0xB4, 0xD3, 0x56, 0xDA, 0xD0, 0x99, 0x6E, 0x96, 0xF4, 0xC7,
+ 0x28, 0xDD, 0x22, 0x15, 0x74, 0xCA, 0xEC, 0x6C, 0x29, 0x50, 0x78, 0x38, 0x2A, 0xE4, 0x39, 0x3D,
+ 0x7E, 0x4C, 0x4D, 0x45, 0xFB, 0xCD, 0x1C, 0x5A, 0x69, 0x5A, 0xDD, 0x95, 0xEC, 0xE3, 0x7D, 0x1D,
+ 0xD5, 0x9F, 0x55, 0xB1, 0x74, 0x38, 0xAB, 0x8C, 0x30, 0xD9, 0x85, 0x4C, 0x24, 0x54, 0x27, 0x4E,
+ 0x8C, 0x5F, 0x3B, 0x9A, 0xB5, 0xD2, 0x49, 0xD9, 0xCE, 0xCA, 0xD2, 0xB3, 0x49, 0x25, 0x6B, 0xEF,
+ 0xAE, 0xEF, 0xC9, 0xB5, 0x9F, 0x0A, 0xFC, 0x42, 0xB0, 0xD5, 0x7C, 0x6F, 0xF1, 0x99, 0xE0, 0xD3,
+ 0x3C, 0x5D, 0x75, 0xF1, 0x1F, 0x4A, 0xBD, 0xF0, 0x6E, 0x9B, 0x73, 0xAB, 0xAC, 0x76, 0x33, 0x69,
+ 0xB3, 0xB5, 0xBC, 0x69, 0x1B, 0xDA, 0x28, 0x8D, 0xD2, 0x57, 0x82, 0x28, 0x21, 0x50, 0x0A, 0xAE,
+ 0x40, 0x19, 0x6C, 0x9E, 0x79, 0x6A, 0x70, 0xF6, 0x33, 0x0B, 0x5A, 0xA6, 0x23, 0x2A, 0xAF, 0xFE,
+ 0xD0, 0xEE, 0xDD, 0xFD, 0xD5, 0xCA, 0x92, 0xD1, 0xA8, 0xD9, 0x28, 0xAD, 0x2F, 0xEE, 0x5D, 0xB4,
+ 0x93, 0x7D, 0xBD, 0xEC, 0xAB, 0x8D, 0xF0, 0x38, 0xAC, 0xA2, 0x11, 0xCD, 0xB0, 0x93, 0xA5, 0x85,
+ 0x94, 0x9C, 0x53, 0x8C, 0xE5, 0x3B, 0xBD, 0x53, 0x8B, 0x72, 0xF7, 0xF5, 0xBE, 0x8D, 0x4B, 0x44,
+ 0x9A, 0x8A, 0x4A, 0xC9, 0x78, 0x5C, 0xFE, 0x19, 0xF8, 0xA3, 0x69, 0xA7, 0x78, 0x67, 0xE0, 0x35,
+ 0xBF, 0x81, 0xB5, 0x81, 0xE2, 0x5F, 0x17, 0x5C, 0x2F, 0x8D, 0x35, 0x4D, 0x36, 0xC8, 0x5B, 0xBE,
+ 0xAB, 0xE2, 0x58, 0x62, 0x59, 0x25, 0xB6, 0x10, 0x6F, 0xB7, 0x57, 0xB6, 0x68, 0xA1, 0x8A, 0x71,
+ 0xF2, 0x4A, 0xCA, 0x40, 0x19, 0x5E, 0x30, 0x3F, 0x3F, 0xC5, 0x61, 0xF3, 0x08, 0xD1, 0x8E, 0x4B,
+ 0x2C, 0x3F, 0xBC, 0xE4, 0xE5, 0x29, 0xE9, 0x15, 0x2D, 0x79, 0x9A, 0x5A, 0x28, 0xB6, 0xB4, 0xF8,
+ 0xAF, 0xA5, 0x92, 0xE5, 0x56, 0x47, 0xEA, 0x58, 0x79, 0x65, 0xF5, 0xA9, 0xFD, 0x6D, 0x4E, 0xF0,
+ 0xE5, 0x8C, 0x63, 0x75, 0x29, 0x38, 0xA8, 0xAB, 0x45, 0x72, 0xB6, 0xAD, 0x16, 0x9E, 0xAA, 0xD7,
+ 0xBA, 0xBB, 0xEE, 0x5B, 0xBD, 0xF8, 0x8D, 0x1F, 0x88, 0x7C, 0x65, 0xA6, 0x78, 0xF2, 0xDB, 0xE1,
+ 0xE5, 0xFD, 0xAF, 0x81, 0x3E, 0x14, 0xE8, 0x16, 0xDA, 0x5D, 0x9F, 0x86, 0xEC, 0x6F, 0xE1, 0xB2,
+ 0xD3, 0x6C, 0x2F, 0xAD, 0xBF, 0xD4, 0xDE, 0x31, 0x8E, 0xDD, 0x60, 0x32, 0xB4, 0xCB, 0x0C, 0x92,
+ 0x20, 0x4C, 0xBF, 0x97, 0x96, 0x24, 0x70, 0x7A, 0x9E, 0x23, 0x1F, 0x8C, 0xAD, 0x0C, 0x74, 0x68,
+ 0xFE, 0xE6, 0x94, 0x22, 0xDA, 0x82, 0x49, 0x25, 0x1D, 0x39, 0xA4, 0xF5, 0x4A, 0x49, 0xD9, 0x35,
+ 0x25, 0xB5, 0xE2, 0x9D, 0x9A, 0x4F, 0x47, 0x46, 0x34, 0xA8, 0xAC, 0x35, 0x1A, 0xAE, 0x2A, 0x57,
+ 0x4D, 0xB4, 0xEE, 0xEF, 0xBA, 0x49, 0xBB, 0x2B, 0xDD, 0x59, 0x27, 0xA2, 0xB3, 0x49, 0x3B, 0x35,
+ 0x4B, 0xC2, 0x7E, 0x31, 0xD5, 0xE2, 0x9F, 0x5D, 0xD7, 0xBC, 0x4A, 0x35, 0x0D, 0x27, 0xC4, 0x1F,
+ 0x12, 0x84, 0xD7, 0xB3, 0xF8, 0xC9, 0x8C, 0x36, 0x4B, 0x63, 0xA2, 0xC7, 0x39, 0x3A, 0x9C, 0x5A,
+ 0x4B, 0xB3, 0xAB, 0xAC, 0x8E, 0x0C, 0xD1, 0x08, 0x49, 0xD8, 0xC3, 0xCB, 0x4C, 0x00, 0x2B, 0xD8,
+ 0xC9, 0xA7, 0x9D, 0x51, 0xC5, 0xBA, 0xD2, 0xC3, 0xB9, 0x2A, 0xB0, 0x9B, 0x73, 0x8C, 0x1B, 0x8A,
+ 0xA4, 0xE2, 0xF9, 0x9A, 0x49, 0x45, 0xF2, 0xD9, 0xE9, 0xAD, 0xDB, 0x5B, 0xE8, 0x8E, 0x2A, 0xD0,
+ 0xC3, 0xBA, 0x6E, 0x9D, 0x29, 0x24, 0xA3, 0x68, 0xA4, 0xEF, 0x6E, 0x77, 0xA2, 0xBB, 0xD6, 0xE9,
+ 0x75, 0xE5, 0x4D, 0xDD, 0x5B, 0xAB, 0x3C, 0x3F, 0xC7, 0xBE, 0x2F, 0xB8, 0xF1, 0x9F, 0x89, 0x6E,
+ 0xF5, 0x89, 0x12, 0xDA, 0x2B, 0x58, 0xD5, 0x2C, 0x34, 0xBB, 0x5B, 0x4B, 0x31, 0xA7, 0xD9, 0xC1,
+ 0x6B, 0x6E, 0xA1, 0x20, 0x09, 0x6C, 0x19, 0x92, 0x32, 0x51, 0x14, 0xB2, 0xA9, 0xC6, 0xE2, 0xD8,
+ 0xAF, 0x8B, 0xCE, 0xF3, 0x17, 0x99, 0xE2, 0xE5, 0x38, 0xCA, 0x5E, 0xCD, 0x7B, 0xB0, 0xBE, 0x96,
+ 0x8A, 0x56, 0x56, 0x4A, 0xCA, 0x37, 0x49, 0x68, 0x97, 0x45, 0x76, 0xDD, 0xDB, 0xF5, 0x70, 0xF8,
+ 0x68, 0x50, 0xA2, 0xA9, 0x45, 0x5B, 0xD3, 0x43, 0x8B, 0xFC, 0x00, 0xF6, 0x03, 0x00, 0x7B, 0x01,
+ 0x5E, 0x42, 0x56, 0x49, 0x1D, 0x29, 0x59, 0x24, 0x14, 0xC6, 0x00, 0x74, 0x00, 0x7D, 0x00, 0x1E,
+ 0x83, 0xB0, 0xFC, 0x29, 0xC2, 0x12, 0x93, 0x50, 0x82, 0xBB, 0xE8, 0x92, 0xFD, 0x10, 0xB4, 0x4B,
+ 0xC8, 0xDD, 0xD2, 0xEC, 0x0C, 0x87, 0x24, 0x7A, 0x0C, 0x0E, 0x14, 0x63, 0xA6, 0x2B, 0xFA, 0x4F,
+ 0xC1, 0xFF, 0x00, 0x0E, 0x6B, 0x66, 0xB5, 0xBD, 0xA5, 0x68, 0xB6, 0xDD, 0xAE, 0xAE, 0xD4, 0x55,
+ 0xAF, 0xA6, 0xC9, 0x6D, 0xA2, 0x6E, 0xF6, 0x77, 0xE5, 0xF2, 0xF1, 0x71, 0xF8, 0xB8, 0xC1, 0x24,
+ 0xAD, 0x6F, 0xF8, 0x63, 0xB0, 0x8E, 0x08, 0xD2, 0x2F, 0x2F, 0x23, 0x38, 0x00, 0x71, 0xC7, 0x03,
+ 0xA1, 0xF6, 0xE2, 0xBF, 0xB7, 0xF2, 0xFE, 0x1F, 0xCB, 0xB0, 0xD9, 0x5C, 0xB2, 0xF7, 0x35, 0xED,
+ 0x1A, 0xB2, 0x6D, 0x6F, 0x65, 0x6E, 0x56, 0xF4, 0xBC, 0x7C, 0xB5, 0x4B, 0x56, 0x7C, 0xE4, 0xAA,
+ 0xC9, 0xC9, 0x49, 0x2D, 0x08, 0x2C, 0xD3, 0xC9, 0x9D, 0xB4, 0xE6, 0x11, 0xA0, 0x94, 0x09, 0x6D,
+ 0xA7, 0x6C, 0x84, 0x8C, 0x00, 0x77, 0x20, 0x03, 0xB7, 0x03, 0x8C, 0x1E, 0xD5, 0xF1, 0xDC, 0x33,
+ 0x4E, 0xB7, 0x0E, 0x67, 0xF5, 0x78, 0x0B, 0x13, 0x0F, 0x72, 0xB2, 0xF6, 0xB8, 0x5A, 0x89, 0x2E,
+ 0x48, 0xB9, 0x5D, 0xD5, 0x82, 0x5D, 0x54, 0x2C, 0x9A, 0x8D, 0xED, 0x18, 0xB4, 0x96, 0xD6, 0x5D,
+ 0x52, 0x51, 0xAF, 0x49, 0x57, 0x8B, 0x49, 0xAD, 0x1D, 0xEF, 0xD1, 0x69, 0xB6, 0xD7, 0xDB, 0x6F,
+ 0xB8, 0x9C, 0xA0, 0x2B, 0xB9, 0x31, 0x8C, 0x80, 0x06, 0x31, 0xD0, 0x73, 0x8F, 0xCA, 0xBE, 0xD7,
+ 0x13, 0x83, 0xA3, 0x5A, 0x93, 0xC4, 0x61, 0xE4, 0x9D, 0x3E, 0x6E, 0x54, 0xAD, 0x6D, 0x63, 0xA3,
+ 0x6B, 0x6D, 0x1B, 0x5D, 0x34, 0xD3, 0xA6, 0xC7, 0x1C, 0x5F, 0x2D, 0x95, 0xB5, 0xFE, 0xBF, 0x22,
+ 0x3F, 0x24, 0x71, 0xC0, 0xF4, 0xF6, 0xE9, 0xC6, 0x05, 0x79, 0x7F, 0xD9, 0x70, 0xB2, 0xD3, 0xF1,
+ 0xFF, 0x00, 0x81, 0xF2, 0xF2, 0xB7, 0x62, 0xF9, 0xDA, 0xB2, 0x4B, 0x41, 0x86, 0x3C, 0x01, 0x80,
+ 0x06, 0x06, 0x00, 0xC0, 0x18, 0xC0, 0xE9, 0x8F, 0xCA, 0xB8, 0xEA, 0xE0, 0x65, 0x0B, 0x28, 0x2D,
+ 0x15, 0xF4, 0xF4, 0xB7, 0xA5, 0xFC, 0x8A, 0x52, 0x56, 0x5F, 0x22, 0x2C, 0x6D, 0x39, 0x18, 0xF9,
+ 0x70, 0x06, 0x06, 0x17, 0x18, 0xE0, 0x63, 0xF0, 0xAF, 0x3B, 0xD9, 0x2A, 0x75, 0xD5, 0x5B, 0x5A,
+ 0x6B, 0x4F, 0x2F, 0xBB, 0x6F, 0xC0, 0xB5, 0xF0, 0xD9, 0x6C, 0x61, 0xEA, 0xD6, 0x21, 0xE3, 0xFB,
+ 0x4C, 0x4A, 0x14, 0xA6, 0x44, 0x98, 0x1C, 0x1C, 0xFD, 0xD0, 0x07, 0xE0, 0x6B, 0xF9, 0xD7, 0xC6,
+ 0xBF, 0x0E, 0xA9, 0x63, 0x70, 0x0F, 0x8A, 0xF2, 0xC8, 0x28, 0xCE, 0x95, 0xFD, 0xAB, 0x57, 0x7C,
+ 0xD7, 0x4B, 0x95, 0x24, 0xB4, 0x56, 0xB3, 0xD9, 0x75, 0xDA, 0xD7, 0x67, 0xAD, 0x96, 0x62, 0xF9,
+ 0x24, 0xA8, 0x4D, 0xE8, 0xF6, 0x2E, 0xFC, 0x3B, 0xF0, 0xC1, 0xF1, 0x97, 0x8E, 0x7C, 0x29, 0xE1,
+ 0x50, 0x06, 0xDD, 0x6F, 0x5B, 0xB7, 0xB0, 0x94, 0x64, 0xA7, 0xEE, 0xD9, 0xC7, 0x98, 0x01, 0x03,
+ 0x23, 0xE4, 0x56, 0xE9, 0x5F, 0xC9, 0x78, 0x7A, 0x57, 0xC4, 0x42, 0x94, 0xD5, 0xAC, 0xF5, 0x56,
+ 0xED, 0xAD, 0xAC, 0xFD, 0x2D, 0xB7, 0xCB, 0xA1, 0xED, 0xD7, 0xA9, 0xEC, 0xE8, 0x4A, 0x71, 0xED,
+ 0xA7, 0xF5, 0xA7, 0xF5, 0xB7, 0x63, 0xFA, 0xEE, 0xFD, 0x99, 0x7E, 0x1E, 0x69, 0x9A, 0x4E, 0x97,
+ 0x60, 0xB0, 0x58, 0x43, 0x0D, 0x86, 0x89, 0x6D, 0x1D, 0xA5, 0x8C, 0x6B, 0x19, 0x48, 0xD4, 0xC6,
+ 0x00, 0xCA, 0x01, 0xC7, 0x00, 0x28, 0xED, 0x8E, 0x0F, 0xB8, 0xFD, 0xB3, 0x0F, 0x4E, 0x39, 0x6E,
+ 0x4F, 0x4E, 0x8C, 0x1D, 0xAA, 0x4D, 0x5E, 0x4D, 0x79, 0xEB, 0x67, 0xE4, 0x9D, 0xF6, 0x56, 0x76,
+ 0xB7, 0x4B, 0x3F, 0xCC, 0x1B, 0x58, 0xFC, 0xCE, 0x53, 0x97, 0xC3, 0x0D, 0x12, 0xFB, 0xBB, 0x3B,
+ 0x6B, 0x6D, 0xD2, 0x7E, 0xA9, 0x68, 0x7D, 0x11, 0xE3, 0xEF, 0x1E, 0xDB, 0xF8, 0x50, 0x58, 0x68,
+ 0xD6, 0x0A, 0xB7, 0x1A, 0xF6, 0xB1, 0x28, 0xB4, 0xD3, 0x6D, 0x23, 0x0A, 0xEC, 0xB9, 0x1C, 0xB1,
+ 0x40, 0x0F, 0xCA, 0x02, 0xFE, 0x87, 0xD3, 0x15, 0xBE, 0x55, 0x95, 0x3C, 0x72, 0x96, 0x26, 0xAB,
+ 0xE5, 0xA3, 0x0D, 0x64, 0xFE, 0x5B, 0x6E, 0xBF, 0x44, 0xB4, 0xEE, 0x83, 0x32, 0xCC, 0xE1, 0x81,
+ 0x8C, 0x68, 0x52, 0x57, 0xA8, 0xF4, 0x49, 0x5B, 0xA5, 0x93, 0xD3, 0xA2, 0xB5, 0x97, 0x96, 0xD6,
+ 0xD9, 0x2B, 0xD6, 0xFA, 0x04, 0xD6, 0xFA, 0x0C, 0xFA, 0x8E, 0xB1, 0x7B, 0x3C, 0xFA, 0x8F, 0xD9,
+ 0xCD, 0xD3, 0x48, 0x58, 0x46, 0xB0, 0xB1, 0x53, 0x80, 0x14, 0x11, 0xD3, 0x23, 0xE5, 0xCE, 0x38,
+ 0x1D, 0x33, 0xC6, 0x13, 0xC4, 0x53, 0x96, 0x21, 0x51, 0xC3, 0x41, 0x28, 0x6D, 0xD5, 0xE9, 0xA6,
+ 0x9F, 0xF0, 0x77, 0xE9, 0xB5, 0x91, 0x51, 0xC1, 0xCE, 0x9E, 0x0A, 0x55, 0xF1, 0x12, 0xF7, 0xD2,
+ 0xBE, 0xFB, 0x26, 0xBF, 0xE0, 0x5A, 0xEB, 0xB5, 0x9B, 0xB5, 0xAD, 0xE2, 0x1F, 0x00, 0x2E, 0xFC,
+ 0x47, 0xE2, 0x0D, 0x6F, 0xC6, 0x3A, 0xA6, 0xAF, 0xAA, 0xDD, 0xEA, 0x1A, 0x5D, 0xAE, 0xAC, 0xF6,
+ 0x1A, 0x5C, 0x52, 0xE0, 0x44, 0xB1, 0xC2, 0x4A, 0x83, 0xC0, 0xEF, 0x8C, 0x63, 0x07, 0x1C, 0x7D,
+ 0x0F, 0xD1, 0x71, 0x2C, 0x30, 0xB8, 0x5A, 0x34, 0x68, 0xD0, 0xA7, 0x18, 0xB6, 0xAF, 0x74, 0x92,
+ 0x7D, 0x34, 0x76, 0xE9, 0x7B, 0xDB, 0xD3, 0xA7, 0x4F, 0x1F, 0x20, 0xF6, 0xB5, 0xB1, 0x33, 0xAE,
+ 0xE5, 0x74, 0xAF, 0xA5, 0xD6, 0x8F, 0x75, 0x6D, 0x76, 0xE5, 0x76, 0xDA, 0xD7, 0xD3, 0x65, 0xA1,
+ 0xF1, 0x67, 0xC1, 0xBA, 0x6F, 0x89, 0xE4, 0xF1, 0x4E, 0x8F, 0x25, 0xAA, 0x4F, 0x1C, 0x9A, 0x2C,
+ 0x93, 0x4B, 0x16, 0xD0, 0x54, 0x1C, 0x6D, 0x6D, 0xC3, 0xD0, 0x80, 0x38, 0xE4, 0x64, 0x8C, 0x63,
+ 0x1C, 0xFC, 0xF6, 0x36, 0x9A, 0xC5, 0x64, 0x6A, 0x15, 0x52, 0xBA, 0x7E, 0xEF, 0x4D, 0x2C, 0x9E,
+ 0x9F, 0x7B, 0xE9, 0xD3, 0x67, 0xA5, 0xBD, 0x8C, 0x1C, 0xA5, 0x47, 0x36, 0x95, 0x28, 0x2D, 0x25,
+ 0xA3, 0xE9, 0xB2, 0x4D, 0x3B, 0x3D, 0x15, 0x9B, 0xDE, 0xCA, 0xC9, 0x5B, 0xD3, 0xF9, 0xB5, 0xF8,
+ 0x03, 0xE0, 0xB8, 0xFE, 0x1E, 0xFF, 0x00, 0xC1, 0x4C, 0xBF, 0x67, 0x0F, 0x08, 0xC0, 0x02, 0xDA,
+ 0xE9, 0x5F, 0xB5, 0xFF, 0x00, 0x80, 0x3E, 0xC6, 0xAB, 0xF7, 0x52, 0x19, 0xBC, 0x55, 0xA7, 0x4B,
+ 0x12, 0x8E, 0x07, 0x01, 0x65, 0x51, 0xF8, 0x57, 0xE4, 0x54, 0xE9, 0xFB, 0x3C, 0xEE, 0x92, 0xB7,
+ 0xFC, 0xBC, 0x83, 0xDA, 0xDB, 0xB4, 0xF6, 0xF5, 0x3F, 0x44, 0x8C, 0xDD, 0x4C, 0xB6, 0x52, 0x6B,
+ 0x5E, 0x59, 0x2F, 0xB9, 0x35, 0xFD, 0x6D, 0xE8, 0xB6, 0x3F, 0xBC, 0x2A, 0xFD, 0x1C, 0xF9, 0x60,
+ 0xA0, 0x02, 0x80, 0x0A, 0x00, 0xFE, 0x28, 0xFF, 0x00, 0xE0, 0xB5, 0xEB, 0x8F, 0xF8, 0x28, 0x17,
+ 0xC4, 0x83, 0x8F, 0x97, 0xFE, 0x10, 0xCF, 0x09, 0xA8, 0xC6, 0x38, 0xC7, 0x87, 0x6D, 0x78, 0xC7,
+ 0xE5, 0x5F, 0x03, 0xC4, 0x18, 0x6A, 0xBF, 0x5C, 0x9E, 0x29, 0x47, 0xF7, 0x77, 0x51, 0xBF, 0x9A,
+ 0x8C, 0x5D, 0xAD, 0xDA, 0xCD, 0x79, 0x1F, 0x4F, 0x95, 0xCA, 0x2B, 0x09, 0x18, 0x75, 0xD7, 0xF3,
+ 0xB1, 0x8F, 0xA5, 0x5A, 0x41, 0xAB, 0x78, 0x67, 0xF6, 0x69, 0xF1, 0x37, 0xC2, 0xF9, 0xD6, 0xD7,
+ 0xC1, 0xBE, 0x1B, 0x7B, 0x5D, 0x37, 0xC5, 0x96, 0xF6, 0x17, 0x82, 0xD9, 0xAD, 0x75, 0x23, 0x22,
+ 0x0B, 0xB8, 0xAE, 0xE0, 0x53, 0x9F, 0x31, 0xA4, 0x2C, 0xE5, 0x98, 0x7C, 0xCA, 0x54, 0x82, 0x41,
+ 0x15, 0xF5, 0xFC, 0x2B, 0x53, 0x0D, 0x3C, 0x9E, 0xB6, 0x1A, 0x9B, 0x4A, 0x76, 0x6E, 0xDD, 0xD2,
+ 0x8B, 0xBE, 0x9B, 0x3D, 0x57, 0x53, 0xF3, 0x9E, 0x2A, 0x6B, 0x0B, 0x99, 0xFB, 0x6C, 0x5D, 0x26,
+ 0xD4, 0x94, 0x14, 0x27, 0x6B, 0xA8, 0x49, 0x4E, 0x2D, 0xEB, 0xF6, 0x6F, 0x1D, 0x13, 0x4A, 0xCF,
+ 0x6E, 0x96, 0x3E, 0xE6, 0xFD, 0xAA, 0x7C, 0x33, 0xE2, 0x2F, 0x17, 0xFC, 0x1C, 0x16, 0xFE, 0x18,
+ 0x9E, 0xE2, 0x3B, 0x94, 0x10, 0x5C, 0xC8, 0xF6, 0x77, 0xBF, 0x63, 0x93, 0x62, 0x94, 0x2D, 0xB5,
+ 0xB3, 0x83, 0x80, 0xAC, 0x71, 0xFE, 0xCF, 0xD2, 0xBC, 0xFE, 0x19, 0xAD, 0x4F, 0x0D, 0x99, 0xCA,
+ 0x33, 0xB2, 0x93, 0x4D, 0x46, 0xEB, 0x44, 0xFE, 0x5A, 0xA5, 0x6D, 0x34, 0xB6, 0xFD, 0x11, 0xE8,
+ 0x71, 0x05, 0x39, 0xCF, 0x01, 0x4A, 0xA2, 0xA4, 0xAA, 0x42, 0x32, 0x8C, 0xA5, 0x16, 0x93, 0x52,
+ 0x8F, 0x2B, 0x56, 0xB6, 0x89, 0xEA, 0xD3, 0x4B, 0xCB, 0x45, 0x7B, 0x1E, 0x87, 0xE1, 0x25, 0xD5,
+ 0xEE, 0x7E, 0x07, 0x69, 0xC9, 0x6D, 0x24, 0xAB, 0xAC, 0x8F, 0x0B, 0x08, 0xF7, 0xC6, 0xE1, 0x66,
+ 0x49, 0x96, 0x1C, 0xE1, 0x58, 0x8C, 0x02, 0x08, 0x3F, 0x95, 0x72, 0xE3, 0x15, 0x1A, 0x79, 0xF4,
+ 0xB4, 0xF7, 0x14, 0xD7, 0xDD, 0x7F, 0xF2, 0xFF, 0x00, 0x80, 0x3C, 0xB9, 0x62, 0x67, 0xC3, 0x54,
+ 0xEC, 0xDF, 0xB4, 0xF6, 0x49, 0x2D, 0x93, 0x4F, 0x97, 0x6F, 0x5F, 0x5B, 0x6B, 0xBD, 0x8F, 0x42,
+ 0xFD, 0x8F, 0xBE, 0x26, 0xF8, 0xA7, 0xE1, 0xB7, 0x84, 0xEC, 0x75, 0x2F, 0x8B, 0xBF, 0xE9, 0x1F,
+ 0xBB, 0x9A, 0xD7, 0x5E, 0x8E, 0xF9, 0xD2, 0xF6, 0xE4, 0x5A, 0x86, 0x71, 0x15, 0xC1, 0x00, 0x95,
+ 0x32, 0x28, 0x00, 0x80, 0x08, 0x07, 0x00, 0x90, 0x70, 0x01, 0xFD, 0x17, 0x0B, 0x9A, 0xD2, 0x86,
+ 0x75, 0x4A, 0x96, 0x5D, 0x36, 0xA9, 0x54, 0x51, 0x53, 0x51, 0x8D, 0xA3, 0x7D, 0x2C, 0xF4, 0x5A,
+ 0x35, 0xD9, 0x25, 0x75, 0xB3, 0x4D, 0x9C, 0x38, 0x4C, 0x2D, 0x4A, 0xD9, 0x13, 0x79, 0xAC, 0x2F,
+ 0x28, 0x29, 0x38, 0xF3, 0xB4, 0xDD, 0xAE, 0xD2, 0xBB, 0xBB, 0x5A, 0x69, 0xAB, 0x77, 0xD3, 0x56,
+ 0x92, 0x3C, 0xAB, 0xE3, 0xDF, 0xEC, 0xD9, 0xF1, 0x2A, 0xF7, 0xC4, 0x9A, 0xA7, 0xC5, 0x7F, 0xD9,
+ 0xCF, 0xC7, 0x1A, 0x7F, 0x86, 0x3E, 0x15, 0xFC, 0x40, 0xBB, 0x6B, 0xFB, 0xFD, 0x1A, 0xD1, 0x7E,
+ 0xD1, 0xA5, 0xE9, 0x1A, 0x84, 0xC9, 0xF2, 0xC9, 0x65, 0x28, 0xC8, 0xF2, 0xA7, 0x0A, 0xAD, 0x90,
+ 0x51, 0xFC, 0xCD, 0xE3, 0x68, 0x00, 0x33, 0x7F, 0x50, 0xF0, 0x5F, 0x1D, 0x64, 0x59, 0x4D, 0x28,
+ 0x61, 0xF8, 0xA3, 0x07, 0xCC, 0xE3, 0x68, 0x45, 0xDA, 0x2F, 0x44, 0xD7, 0x2B, 0x69, 0x34, 0xF5,
+ 0x77, 0x4D, 0x5B, 0x91, 0x2D, 0x9B, 0xBB, 0x4F, 0xE3, 0xF0, 0xF8, 0x78, 0xE2, 0xE9, 0xCA, 0x78,
+ 0x1A, 0x4D, 0xC9, 0xAE, 0x67, 0xCB, 0x39, 0x53, 0x8E, 0xBB, 0x6B, 0x67, 0x79, 0x35, 0x66, 0xE7,
+ 0xA3, 0xBB, 0x77, 0xD1, 0x24, 0xBC, 0x8B, 0xE0, 0x8F, 0xC3, 0xAD, 0x4F, 0xE1, 0x9E, 0x83, 0xE2,
+ 0x1B, 0xCF, 0x18, 0xDE, 0xC7, 0xA8, 0x78, 0xA7, 0x52, 0xD4, 0x1F, 0x52, 0xD5, 0x75, 0x17, 0x76,
+ 0x91, 0x65, 0x48, 0x8B, 0x08, 0x83, 0x12, 0x07, 0xCA, 0xA3, 0x2D, 0x8E, 0xC4, 0x0C, 0x74, 0xAF,
+ 0xD3, 0xF8, 0x93, 0x33, 0xC3, 0x67, 0xD8, 0xDC, 0x3E, 0x13, 0x28, 0x87, 0x2E, 0x1E, 0x31, 0x5C,
+ 0xB1, 0x56, 0xB2, 0xE6, 0xE5, 0x76, 0x6A, 0xCA, 0xF7, 0x49, 0xEE, 0x9A, 0xD5, 0xAB, 0x3D, 0x9C,
+ 0xE1, 0x69, 0x2C, 0x2B, 0xAD, 0x88, 0x9D, 0x25, 0x49, 0x45, 0x28, 0x28, 0x5D, 0x3E, 0x54, 0x96,
+ 0xAF, 0x99, 0x5D, 0x36, 0xDB, 0x6D, 0xBE, 0xD6, 0x4D, 0xC6, 0xED, 0xAE, 0x4F, 0xE0, 0x55, 0x8C,
+ 0x9E, 0x3C, 0xF1, 0xA7, 0xC4, 0x2F, 0x8A, 0xF7, 0x7B, 0xA5, 0xB4, 0x97, 0x54, 0x3E, 0x18, 0xD0,
+ 0x24, 0x6F, 0x9B, 0xCB, 0xB3, 0xB4, 0x07, 0x70, 0x45, 0x39, 0xE4, 0x85, 0x04, 0xFD, 0x09, 0xC7,
+ 0x07, 0x1E, 0xCF, 0x16, 0x57, 0x86, 0x47, 0x95, 0x61, 0x32, 0x08, 0x46, 0xD6, 0xD6, 0x4D, 0x25,
+ 0x67, 0x51, 0xDE, 0x4A, 0x3A, 0x6B, 0x7B, 0x24, 0x93, 0x69, 0x27, 0xF0, 0xDE, 0xEE, 0xCF, 0x87,
+ 0x2F, 0xF6, 0x75, 0xB1, 0xAB, 0xDB, 0x24, 0xB9, 0x57, 0xB4, 0x92, 0x49, 0xB6, 0x9C, 0xED, 0xAE,
+ 0xDB, 0x42, 0x1C, 0xB1, 0xB3, 0x4D, 0xBB, 0xB5, 0xA6, 0xEB, 0x1F, 0xE3, 0xEF, 0x89, 0x6E, 0xA0,
+ 0xF1, 0x06, 0x8C, 0xDA, 0x13, 0x47, 0x15, 0xEE, 0x99, 0x71, 0x0A, 0x68, 0x46, 0x3B, 0x88, 0x82,
+ 0xDE, 0x48, 0x18, 0x19, 0x91, 0xD8, 0x31, 0xDA, 0x32, 0x02, 0x1F, 0x30, 0xA6, 0x03, 0x36, 0x41,
+ 0x07, 0x29, 0xF9, 0xC6, 0x0F, 0x8A, 0xB8, 0x67, 0x21, 0xC5, 0x51, 0xCA, 0xB8, 0xA7, 0x10, 0xA9,
+ 0x55, 0xC4, 0x35, 0x15, 0x07, 0x19, 0xBF, 0x7A, 0x4F, 0x96, 0x09, 0x72, 0xC5, 0xC6, 0x2E, 0x3E,
+ 0xEC, 0x96, 0x96, 0xD2, 0xD1, 0x49, 0xBD, 0x7F, 0xAB, 0x32, 0x1E, 0x1F, 0xCA, 0xEB, 0xF0, 0x6E,
+ 0x61, 0x0A, 0x1F, 0xC0, 0x95, 0x29, 0x4E, 0x53, 0x49, 0xF3, 0xA5, 0x05, 0xCC, 0xA5, 0x16, 0x95,
+ 0xDC, 0x95, 0xAF, 0x0E, 0x58, 0xB7, 0x74, 0x93, 0xD1, 0x28, 0x9F, 0xA1, 0xFF, 0x00, 0x0B, 0x7C,
+ 0x53, 0x63, 0xE3, 0x9F, 0x03, 0xDA, 0x5A, 0x6B, 0x32, 0x5B, 0x4F, 0x27, 0xD9, 0x7C, 0x99, 0x63,
+ 0x79, 0xE3, 0xB8, 0xF9, 0xED, 0xD5, 0x5A, 0x54, 0x0C, 0x09, 0x52, 0x63, 0xF9, 0x0E, 0x41, 0xE3,
+ 0x00, 0xF6, 0x15, 0xF9, 0x96, 0x7D, 0x96, 0x62, 0x32, 0xFC, 0xC2, 0x59, 0x8E, 0x59, 0x16, 0xE0,
+ 0xA5, 0x66, 0xE2, 0x9D, 0x97, 0x5B, 0x35, 0xBD, 0x9A, 0x6D, 0x3B, 0x2D, 0xEC, 0x9E, 0x8D, 0x23,
+ 0xE4, 0x63, 0x4D, 0xE5, 0xB8, 0x87, 0x96, 0x56, 0xA9, 0x79, 0x47, 0x58, 0x4A, 0xD6, 0x72, 0x8B,
+ 0xD2, 0x3A, 0x6E, 0x9A, 0x56, 0x4D, 0x4A, 0xCE, 0x4B, 0xDE, 0x4B, 0x57, 0x6F, 0xA4, 0xBE, 0x04,
+ 0xFC, 0x1C, 0xD7, 0xFE, 0x26, 0xF8, 0x7F, 0x5A, 0xD7, 0x35, 0xFB, 0x8D, 0x23, 0xC0, 0x1F, 0x07,
+ 0xBC, 0x31, 0xA8, 0x3E, 0x91, 0xAD, 0x7C, 0x60, 0xF1, 0xEC, 0xAD, 0xA6, 0x78, 0x3A, 0x70, 0x81,
+ 0x7F, 0x73, 0xA6, 0xC6, 0x37, 0x5C, 0x6A, 0x97, 0x78, 0x20, 0xFD, 0x96, 0xCA, 0x39, 0x9B, 0x81,
+ 0x9D, 0xBC, 0x91, 0xF2, 0xFC, 0x45, 0x5E, 0x8E, 0x07, 0x1F, 0x42, 0xB6, 0x19, 0x73, 0xE2, 0xE4,
+ 0x93, 0x54, 0xA1, 0x34, 0xA5, 0x19, 0x36, 0xD2, 0x52, 0x71, 0x56, 0x87, 0x92, 0x9B, 0x8B, 0xB2,
+ 0x5B, 0x26, 0xAF, 0x2B, 0x17, 0x46, 0x94, 0xEA, 0x52, 0xB3, 0x8C, 0xAE, 0x95, 0xAC, 0xF5, 0x72,
+ 0x4A, 0x5A, 0x69, 0x6B, 0x6B, 0x6B, 0xEC, 0x9A, 0x6B, 0xA5, 0x97, 0xCD, 0xBF, 0x1C, 0xFF, 0x00,
+ 0x69, 0xBF, 0x83, 0x3F, 0xB2, 0xD7, 0x88, 0xF4, 0xCF, 0x04, 0x7E, 0xCC, 0xFF, 0x00, 0x0D, 0xB4,
+ 0xEF, 0x1D, 0x78, 0x9A, 0xDE, 0x43, 0x75, 0x79, 0xFB, 0x47, 0xFC, 0x79, 0xD1, 0xF4, 0xFF, 0x00,
+ 0x10, 0x6A, 0x1A, 0x0C, 0xEE, 0x76, 0xDB, 0x37, 0x85, 0xBC, 0x17, 0x22, 0xC9, 0xA6, 0xE9, 0xE1,
+ 0x59, 0x8B, 0x2C, 0xD7, 0x6D, 0x7B, 0x71, 0x85, 0xCA, 0x98, 0x99, 0x85, 0x7D, 0x5F, 0x0D, 0x70,
+ 0x9E, 0x67, 0xC5, 0x14, 0xE7, 0x9A, 0xE7, 0xB8, 0x88, 0xC6, 0x94, 0x24, 0x93, 0xC3, 0x51, 0xAA,
+ 0xE1, 0xCD, 0x1B, 0x3B, 0xFB, 0x5A, 0xAA, 0xD2, 0x6D, 0x5D, 0x59, 0x46, 0xEB, 0x95, 0x3B, 0xE8,
+ 0xAE, 0x7D, 0x2F, 0x0C, 0xF0, 0xEC, 0x73, 0x15, 0x52, 0x58, 0xEA, 0xAE, 0x18, 0x77, 0xEE, 0xC2,
+ 0x9C, 0x13, 0x51, 0x72, 0x93, 0x52, 0x71, 0x6F, 0xA4, 0x64, 0x93, 0xE5, 0x4B, 0xDD, 0x52, 0x6A,
+ 0x3A, 0x2E, 0x54, 0x43, 0xA6, 0xFC, 0x65, 0xD5, 0xBF, 0x68, 0x1F, 0x09, 0xB6, 0xBF, 0xF1, 0x43,
+ 0xC6, 0x7A, 0xBF, 0x8C, 0x3C, 0x55, 0x10, 0x65, 0x7D, 0x5F, 0xC5, 0x37, 0xD3, 0x6A, 0x72, 0xCA,
+ 0x42, 0x96, 0x46, 0xB7, 0x12, 0x65, 0x52, 0x2D, 0xAC, 0xC5, 0x55, 0x42, 0x2A, 0x8D, 0xA4, 0x01,
+ 0x8E, 0x3E, 0x7B, 0x1F, 0x91, 0xAE, 0x16, 0xCF, 0xE5, 0x4F, 0x29, 0xA4, 0xA1, 0x4A, 0x49, 0x2B,
+ 0x38, 0x27, 0xEE, 0x3B, 0x59, 0x4B, 0x95, 0xA5, 0x34, 0xDA, 0x4E, 0xF7, 0xE5, 0x76, 0xBF, 0x2A,
+ 0xBD, 0xCE, 0x0A, 0xB8, 0x19, 0x61, 0xB9, 0x68, 0xB8, 0xD9, 0xAB, 0x3D, 0x1E, 0x89, 0xA4, 0x93,
+ 0x4D, 0xAD, 0x1F, 0x66, 0x92, 0xB3, 0x5A, 0x5B, 0x44, 0x8F, 0x99, 0x3E, 0x21, 0xFC, 0x41, 0xF0,
+ 0x56, 0xAF, 0xE1, 0x0D, 0x4B, 0xC2, 0x9A, 0x8C, 0x76, 0xBA, 0x96, 0xB3, 0xA0, 0x6B, 0xD1, 0x43,
+ 0xA7, 0xD8, 0x88, 0x08, 0xBC, 0x59, 0x55, 0x90, 0xCE, 0xEA, 0xDD, 0x55, 0x04, 0x4C, 0xFB, 0x9B,
+ 0x18, 0x39, 0x51, 0xC9, 0x38, 0x3D, 0x13, 0xE1, 0xBA, 0xF8, 0x4C, 0x7D, 0x3C, 0xCA, 0xF1, 0xF6,
+ 0x75, 0x62, 0xB9, 0xA2, 0xA9, 0x4B, 0x95, 0xC6, 0xCF, 0x95, 0x36, 0xBD, 0xDB, 0xDD, 0xA8, 0xC5,
+ 0x5D, 0x5B, 0x55, 0x64, 0x95, 0xCF, 0x6F, 0x85, 0xFE, 0xBD, 0x5F, 0x11, 0x52, 0xBD, 0x0A, 0x53,
+ 0xA7, 0x04, 0xE5, 0x17, 0x29, 0x68, 0x9D, 0x97, 0x4B, 0xA5, 0x75, 0xCC, 0xAC, 0xAC, 0xDA, 0xD1,
+ 0xB4, 0xEC, 0x7C, 0xF5, 0xE1, 0x3F, 0x82, 0x5E, 0x21, 0xF1, 0x67, 0x8A, 0x24, 0xF1, 0x0E, 0x97,
+ 0x61, 0x04, 0x7E, 0x1C, 0xF0, 0xDD, 0xC3, 0x4B, 0xAC, 0xF8, 0x8F, 0x5C, 0xBE, 0x83, 0x45, 0xF0,
+ 0x8E, 0x8D, 0x1C, 0x71, 0x16, 0x32, 0x3E, 0xA1, 0x23, 0xF9, 0x2E, 0xD1, 0x0D, 0xA1, 0xA2, 0x8D,
+ 0x9D, 0xDF, 0x2B, 0xB5, 0x4E, 0x78, 0xF5, 0xB0, 0xF8, 0xC9, 0x65, 0x78, 0x5A, 0xF9, 0x4D, 0x14,
+ 0xEB, 0xD4, 0xFB, 0x2D, 0x45, 0xA8, 0x72, 0xB6, 0xB7, 0x6A, 0x2D, 0x45, 0x59, 0xBB, 0x59, 0xDD,
+ 0x2B, 0x26, 0xB6, 0xBF, 0xDA, 0x67, 0x99, 0xB5, 0x3C, 0x47, 0x0F, 0xCB, 0x24, 0x75, 0x5D, 0x3A,
+ 0xF3, 0xB3, 0xA6, 0xE0, 0x9B, 0xAA, 0xDD, 0xD5, 0xE3, 0xCB, 0xFC, 0xB3, 0xD9, 0x39, 0x24, 0x92,
+ 0xBA, 0x4D, 0x3B, 0x5B, 0xED, 0xDB, 0x2B, 0xDF, 0x84, 0x5A, 0x36, 0x9D, 0x1D, 0xC5, 0x8E, 0xA9,
+ 0xFF, 0x00, 0x0B, 0x3A, 0x54, 0xB6, 0x74, 0x53, 0x62, 0x92, 0x68, 0x3E, 0x09, 0x8A, 0x40, 0x3E,
+ 0x42, 0x1C, 0xA8, 0xBC, 0xB9, 0x41, 0xB1, 0xB7, 0x02, 0xB6, 0xBD, 0x32, 0x09, 0x18, 0xAF, 0x85,
+ 0x95, 0x0A, 0x4E, 0x6E, 0x92, 0x4F, 0xDA, 0xD9, 0x5A, 0x2A, 0x2E, 0xC9, 0xDB, 0x58, 0xB9, 0x26,
+ 0x9A, 0xBA, 0x76, 0x4E, 0x2A, 0xCE, 0xD6, 0x49, 0xD9, 0x27, 0xF9, 0x7E, 0x3E, 0xAE, 0x2B, 0x0B,
+ 0x0A, 0x8F, 0x34, 0x4A, 0x8C, 0x23, 0xBA, 0x95, 0x9C, 0xAC, 0x96, 0xA9, 0xAB, 0x72, 0xEA, 0xAC,
+ 0xEC, 0xAE, 0xB6, 0x5A, 0x5B, 0x4F, 0x8D, 0xBF, 0x69, 0xAF, 0x8B, 0x9A, 0xCE, 0xAB, 0xE1, 0x6B,
+ 0xDF, 0x0F, 0x5A, 0x78, 0xB6, 0x5F, 0x86, 0x7A, 0x05, 0xAC, 0x9B, 0x53, 0x4B, 0xF0, 0x1F, 0x87,
+ 0xDF, 0x48, 0xB1, 0xBB, 0x42, 0x09, 0x41, 0x70, 0xF6, 0x8D, 0x1C, 0xD3, 0xFC, 0xFB, 0x50, 0x99,
+ 0xE4, 0x90, 0xFC, 0xCC, 0xC4, 0xE0, 0x36, 0xEF, 0xD2, 0x78, 0x3B, 0x87, 0xF0, 0xCE, 0x0F, 0x11,
+ 0x89, 0xA7, 0xED, 0x71, 0x0E, 0x36, 0xA7, 0x4E, 0x70, 0x4E, 0x94, 0x55, 0x95, 0xDA, 0xEA, 0x9B,
+ 0x4B, 0x4E, 0xA9, 0x2B, 0x37, 0xCD, 0xCA, 0x97, 0xE4, 0x58, 0x9E, 0x31, 0x78, 0xEE, 0x22, 0xA3,
+ 0x92, 0x65, 0xCB, 0x97, 0x0D, 0x1D, 0x5B, 0x76, 0xE6, 0x9F, 0xBB, 0xA6, 0x96, 0x51, 0x8C, 0x53,
+ 0x8F, 0xBB, 0x15, 0x67, 0xB6, 0x9A, 0x26, 0x79, 0x1F, 0xEC, 0x13, 0xA4, 0xF8, 0x27, 0x59, 0xF1,
+ 0xA6, 0x87, 0x07, 0xC4, 0xE8, 0xAF, 0xCF, 0x85, 0xEF, 0x6F, 0xE7, 0x8F, 0x58, 0xBE, 0xD3, 0x6F,
+ 0xA3, 0xD3, 0x2E, 0x61, 0x91, 0xCE, 0xDB, 0x69, 0xE4, 0xBA, 0x96, 0x29, 0x51, 0x15, 0x58, 0x29,
+ 0x25, 0x90, 0x8C, 0x01, 0x9C, 0x63, 0x23, 0xE7, 0x38, 0x83, 0x1F, 0x9F, 0x4E, 0xAD, 0x7C, 0xB7,
+ 0x30, 0x84, 0x69, 0xD3, 0xA5, 0x07, 0xA5, 0x35, 0x68, 0x25, 0xCA, 0x9C, 0x6D, 0x3D, 0x3A, 0xB5,
+ 0x65, 0x2B, 0x6A, 0xF5, 0x69, 0x5E, 0xFF, 0x00, 0x3B, 0x9D, 0x2A, 0x15, 0x78, 0xD2, 0x93, 0xC4,
+ 0x45, 0xCE, 0x94, 0x20, 0x9A, 0x5A, 0x68, 0xDA, 0x49, 0xDB, 0xB7, 0xC4, 0xED, 0xD5, 0x6E, 0xBA,
+ 0x23, 0xF4, 0x5B, 0xE2, 0xAF, 0x86, 0xFC, 0x1F, 0xE1, 0x8F, 0x1A, 0xEA, 0x3A, 0x6F, 0x80, 0x35,
+ 0xEB, 0x7F, 0x11, 0xF8, 0x40, 0x2C, 0x52, 0xE8, 0x9A, 0x94, 0x1A, 0x8C, 0x5A, 0x9C, 0xC6, 0x23,
+ 0x18, 0xDE, 0x93, 0x4B, 0x1A, 0xAA, 0x86, 0x0C, 0x1B, 0x80, 0x07, 0x18, 0xF5, 0xAF, 0xCF, 0xAA,
+ 0xD0, 0xC1, 0xD5, 0x8A, 0x9B, 0x9B, 0x6A, 0x50, 0x4D, 0x34, 0xD3, 0xE5, 0x76, 0xE5, 0x6B, 0xCA,
+ 0xF6, 0xD1, 0x6A, 0xAF, 0xB2, 0x49, 0x33, 0xE8, 0x29, 0xF2, 0xA7, 0x15, 0x49, 0x3E, 0x5B, 0xDB,
+ 0x5B, 0x74, 0xDB, 0x44, 0x96, 0x96, 0xB7, 0x45, 0xA5, 0xB4, 0x3C, 0xFC, 0x0C, 0x00, 0x30, 0x07,
+ 0x03, 0x80, 0x30, 0x3D, 0xB0, 0x3F, 0x2A, 0xF9, 0xEC, 0x4A, 0x8C, 0x6A, 0x4E, 0x34, 0xDF, 0xBA,
+ 0x9D, 0x97, 0xA2, 0xD1, 0x74, 0x5B, 0x69, 0xD1, 0x1D, 0x4A, 0xD6, 0x56, 0x5A, 0x1F, 0x26, 0xFE,
+ 0xD2, 0xF3, 0xCD, 0xA6, 0xE9, 0x29, 0xA9, 0xD9, 0xC9, 0xF6, 0x4B, 0xDD, 0x35, 0x5B, 0x52, 0xB3,
+ 0xBA, 0x50, 0x14, 0xDB, 0xCB, 0x02, 0xA3, 0xC7, 0x20, 0xFA, 0x34, 0x6A, 0x46, 0x01, 0xF4, 0xF5,
+ 0xC7, 0xBB, 0x90, 0x61, 0xA3, 0x57, 0x0F, 0x7A, 0xF1, 0x6E, 0x8A, 0x9C, 0x1C, 0x92, 0xB6, 0xCA,
+ 0x4B, 0xE1, 0xBB, 0x4A, 0xF6, 0xBA, 0x49, 0xE9, 0x6E, 0xA9, 0x1F, 0x25, 0x98, 0x5A, 0x3C, 0x53,
+ 0x97, 0x72, 0xAD, 0x5B, 0x6A, 0xD6, 0xDD, 0x37, 0x15, 0x67, 0xD3, 0xAA, 0xD1, 0xE9, 0x6B, 0x37,
+ 0xD1, 0x1B, 0x3F, 0xB3, 0xDB, 0xDB, 0xEA, 0xBA, 0x9E, 0xB9, 0x7D, 0x14, 0xBA, 0xD5, 0xCD, 0xD6,
+ 0xAF, 0xA6, 0x5B, 0x6A, 0x92, 0xBE, 0xA8, 0xD1, 0xB5, 0xE5, 0xC5, 0xE4, 0xAA, 0x92, 0x5D, 0xCD,
+ 0x28, 0x45, 0x00, 0xA9, 0xDC, 0xFB, 0x70, 0x09, 0xE8, 0x4F, 0x4E, 0x7F, 0x45, 0xE2, 0xDE, 0x19,
+ 0x79, 0x7E, 0x03, 0x31, 0xCA, 0x68, 0xE2, 0x29, 0x4B, 0xEB, 0x34, 0x69, 0xD4, 0xA6, 0xA9, 0xF3,
+ 0x3F, 0x75, 0x4E, 0x2E, 0xD3, 0x8C, 0x60, 0xDF, 0x34, 0x6C, 0xEF, 0x65, 0x24, 0x9A, 0x6F, 0x45,
+ 0x76, 0xB9, 0x68, 0xD6, 0xA8, 0xF8, 0xA5, 0x4D, 0xAB, 0x46, 0x11, 0xB4, 0xAF, 0xA2, 0xDD, 0xC5,
+ 0x72, 0x2E, 0xCD, 0xA5, 0x65, 0xA5, 0x96, 0x8B, 0xA2, 0x3E, 0xA7, 0x96, 0x33, 0x83, 0x0A, 0x14,
+ 0xF9, 0xD0, 0xE0, 0x07, 0xE1, 0x14, 0xFD, 0xD1, 0x9E, 0x3B, 0x1F, 0xE8, 0x3D, 0xFF, 0x00, 0x9E,
+ 0x6A, 0xE5, 0x35, 0xF0, 0x39, 0x8C, 0x32, 0xE9, 0x54, 0x8D, 0xDD, 0x9A, 0x69, 0x4F, 0x95, 0x5F,
+ 0xAB, 0xBC, 0x39, 0xAD, 0xA7, 0x48, 0xB4, 0xBD, 0x36, 0xFD, 0x0B, 0x9F, 0xF7, 0x4D, 0xF2, 0xF4,
+ 0xB7, 0x4E, 0x8A, 0xD6, 0xB2, 0xEB, 0xA7, 0xDD, 0xF8, 0x7E, 0x69, 0x7C, 0x67, 0xF0, 0xE5, 0xFD,
+ 0xFF, 0x00, 0xC5, 0x4F, 0x0F, 0x5E, 0x27, 0x93, 0x6F, 0x6F, 0x65, 0x77, 0x33, 0x99, 0x27, 0x8A,
+ 0x62, 0x92, 0x32, 0x22, 0x6E, 0x89, 0x1D, 0x62, 0x61, 0xBC, 0x6D, 0xC7, 0x25, 0x47, 0x23, 0xF1,
+ 0xFD, 0xD7, 0x26, 0xE0, 0xAC, 0xCF, 0x17, 0x80, 0x78, 0x8A, 0x1E, 0xCD, 0xD3, 0x8C, 0x5B, 0x6D,
+ 0xAA, 0xCB, 0x48, 0x59, 0xC9, 0xC5, 0x7B, 0x1D, 0x55, 0xA4, 0xBB, 0x68, 0xBA, 0xDF, 0x5F, 0xCF,
+ 0xF0, 0x58, 0xAA, 0x14, 0x30, 0x79, 0xE5, 0x3A, 0xBA, 0x39, 0xDA, 0xCB, 0xD2, 0x2B, 0x4B, 0x2E,
+ 0xD7, 0xE8, 0xAC, 0xAC, 0xF5, 0x4B, 0x6F, 0xD1, 0xEF, 0x01, 0x69, 0xB3, 0xDC, 0x68, 0x1A, 0x6C,
+ 0x31, 0xF9, 0x6B, 0x88, 0x10, 0x2E, 0xE5, 0x70, 0x84, 0x01, 0xD0, 0x00, 0xA4, 0xFA, 0x0E, 0x71,
+ 0xDB, 0xD2, 0xBF, 0x21, 0xC7, 0xF0, 0xF5, 0x59, 0x66, 0x95, 0x29, 0x7B, 0x68, 0x45, 0xDE, 0xD7,
+ 0xE5, 0xAD, 0x65, 0x64, 0xDE, 0xCA, 0x93, 0x7E, 0x9A, 0x7C, 0x92, 0x3E, 0xC7, 0x24, 0xAA, 0xA9,
+ 0xE5, 0x34, 0x13, 0x8E, 0xAA, 0x11, 0xBA, 0x56, 0xD2, 0xD1, 0x4A, 0xFA, 0xB4, 0x95, 0xAD, 0x7F,
+ 0x93, 0xD3, 0x4B, 0x1D, 0x65, 0xD5, 0xBF, 0xD9, 0xE2, 0x52, 0xF2, 0xC4, 0xFE, 0x64, 0x41, 0xC8,
+ 0x8D, 0x24, 0x40, 0x8B, 0x91, 0xC1, 0x0C, 0x8B, 0xD0, 0x0E, 0x80, 0x11, 0x5F, 0x2F, 0x57, 0x0F,
+ 0x1C, 0x2C, 0xE3, 0x1E, 0x74, 0xD5, 0xB7, 0x8A, 0x92, 0xB6, 0x96, 0xB5, 0xA5, 0x18, 0xBB, 0xDE,
+ 0xC9, 0xD9, 0x35, 0xD8, 0xF5, 0x22, 0xA2, 0xAF, 0x14, 0xAC, 0xD6, 0x89, 0x69, 0xDB, 0xCB, 0x4F,
+ 0xCA, 0xD7, 0xEF, 0xA1, 0xF9, 0x7F, 0xF1, 0x56, 0xD0, 0xC9, 0xFB, 0x41, 0xF8, 0x41, 0x51, 0xA0,
+ 0x0D, 0x2D, 0xF5, 0xC8, 0xDD, 0x2C, 0x82, 0xDE, 0x35, 0xDD, 0x1A, 0xE7, 0x73, 0x1C, 0x05, 0x00,
+ 0x9E, 0xA4, 0xF4, 0xC7, 0xA1, 0xC7, 0xEA, 0xB8, 0x2C, 0x1D, 0x2F, 0xEC, 0xAA, 0x75, 0xA8, 0x4E,
+ 0x2D, 0x28, 0x45, 0x59, 0xF3, 0x27, 0xBF, 0x4F, 0x75, 0x2B, 0x5F, 0x4B, 0xDD, 0x5E, 0xDA, 0x24,
+ 0x91, 0xF0, 0x3C, 0xEE, 0x58, 0x0C, 0xEA, 0x92, 0xDF, 0xDA, 0x51, 0x4A, 0xF6, 0x4B, 0x74, 0x96,
+ 0xFA, 0x25, 0x65, 0xF8, 0x75, 0xD0, 0xFD, 0x34, 0xD2, 0xAD, 0xB6, 0xE9, 0xB0, 0x85, 0x16, 0x8A,
+ 0x12, 0x24, 0x8C, 0x2C, 0x37, 0x02, 0x68, 0xC6, 0xD4, 0x00, 0x04, 0x7E, 0x77, 0x0F, 0xBD, 0x8F,
+ 0xA7, 0xD2, 0xBF, 0x32, 0xCC, 0x30, 0xB2, 0x85, 0x7A, 0x93, 0x4A, 0x11, 0x82, 0xB7, 0xBA, 0xA4,
+ 0x9D, 0xAF, 0xD1, 0x27, 0x66, 0xDA, 0xD2, 0xFA, 0x69, 0xF9, 0x7D, 0xEE, 0x0A, 0x50, 0x78, 0x78,
+ 0x4A, 0xCD, 0x2B, 0x2D, 0x2D, 0xB6, 0xD6, 0x5A, 0x68, 0xAD, 0xBF, 0x4F, 0x97, 0x4F, 0x39, 0xF8,
+ 0x81, 0xFB, 0x54, 0xFE, 0xD0, 0x1F, 0xB3, 0x0D, 0x97, 0xF6, 0xCF, 0xC1, 0xCF, 0x18, 0xC9, 0x69,
+ 0xA4, 0x5E, 0xAA, 0xDA, 0xF8, 0x9F, 0xE1, 0xEF, 0x89, 0x74, 0xDB, 0x7F, 0x1B, 0xFC, 0x27, 0xF1,
+ 0xA5, 0xB3, 0x4A, 0xAA, 0xF6, 0xDA, 0xDF, 0x86, 0x2F, 0x52, 0x5D, 0x3E, 0xF1, 0x30, 0xC4, 0x0D,
+ 0xF1, 0x6F, 0x5C, 0xE5, 0x59, 0x48, 0x06, 0xBE, 0xA3, 0x86, 0xB8, 0x5E, 0xBE, 0x7D, 0x97, 0x56,
+ 0xF6, 0x74, 0xD5, 0xA3, 0x67, 0xCD, 0xCC, 0xA3, 0x64, 0x93, 0xEF, 0xB2, 0x76, 0x49, 0xD9, 0x35,
+ 0x74, 0x95, 0xBB, 0x79, 0xD2, 0xC5, 0x62, 0x69, 0xF1, 0x36, 0x0B, 0x03, 0x46, 0xEE, 0x35, 0x54,
+ 0xE3, 0xC8, 0x95, 0xEE, 0xD4, 0x79, 0xA3, 0x6B, 0x2B, 0x26, 0xAC, 0xEC, 0xD6, 0xB6, 0xBE, 0x96,
+ 0x3E, 0xBA, 0xF8, 0x1B, 0x2F, 0xEC, 0x6F, 0xF1, 0xFB, 0xC2, 0x16, 0x17, 0xCD, 0xE0, 0xEF, 0x0B,
+ 0xFE, 0xC6, 0x3F, 0x17, 0xF5, 0xA5, 0x3B, 0xDB, 0xC3, 0x56, 0xB7, 0x7A, 0x9F, 0xEC, 0x97, 0xE2,
+ 0x3B, 0xA7, 0x1F, 0xBB, 0x56, 0xD3, 0xD1, 0x65, 0xD5, 0x3C, 0x36, 0xD2, 0x33, 0x03, 0xBD, 0x24,
+ 0xBC, 0xB3, 0x43, 0xD5, 0x61, 0x4E, 0x47, 0x9B, 0x98, 0xC9, 0x60, 0x25, 0x3C, 0xBB, 0x13, 0x49,
+ 0x54, 0x51, 0x49, 0xC1, 0xC9, 0xBB, 0xC3, 0x4D, 0x95, 0x9A, 0xBE, 0xF6, 0xD3, 0xC9, 0xD9, 0xEC,
+ 0x2C, 0x9A, 0xA5, 0x3C, 0xD6, 0x32, 0xCC, 0xA3, 0x1F, 0x67, 0x56, 0x4D, 0xF3, 0xB4, 0x93, 0xBB,
+ 0x8B, 0xE5, 0xDD, 0xAD, 0x15, 0xA2, 0x9F, 0x2E, 0x89, 0x6C, 0xB5, 0x37, 0x75, 0x6F, 0x83, 0x3F,
+ 0xB4, 0xBF, 0xC2, 0x6F, 0x17, 0x69, 0x7F, 0x0E, 0xEE, 0x3C, 0x35, 0xA8, 0xCD, 0x37, 0x89, 0xB4,
+ 0xFB, 0x8D, 0x67, 0xC2, 0xD1, 0x59, 0xDD, 0x59, 0x78, 0xBF, 0xE1, 0x9F, 0xC4, 0x3B, 0x0B, 0x68,
+ 0x4B, 0xCD, 0xA8, 0x68, 0xF7, 0xE5, 0x9F, 0x4D, 0xBE, 0xB5, 0x11, 0x6E, 0x62, 0xF1, 0xB9, 0x2A,
+ 0x32, 0x18, 0x29, 0xE0, 0x78, 0x0A, 0x55, 0x22, 0x92, 0xA2, 0xF4, 0xBE, 0x89, 0xE8, 0x96, 0x96,
+ 0xD1, 0x6C, 0xB4, 0xF2, 0x5D, 0x3A, 0xA5, 0x6F, 0xA2, 0x97, 0x32, 0x82, 0x8C, 0x2D, 0x6D, 0x1B,
+ 0x56, 0x49, 0x69, 0x6B, 0x69, 0xB6, 0x96, 0x5B, 0xAB, 0x25, 0x6B, 0xE8, 0x7E, 0x75, 0x7E, 0xD7,
+ 0x9E, 0x12, 0xF8, 0x5B, 0xE1, 0x4F, 0x1F, 0x68, 0x36, 0x3F, 0x15, 0x7C, 0x21, 0xE2, 0x0F, 0x82,
+ 0xDF, 0x13, 0xEC, 0x75, 0x0B, 0x59, 0x57, 0xC4, 0x9F, 0x0E, 0x22, 0xB7, 0xD5, 0x74, 0x88, 0xCD,
+ 0xDA, 0xAB, 0xC6, 0xBA, 0x86, 0x86, 0xCF, 0xB9, 0x91, 0xD5, 0xC1, 0xDD, 0x6B, 0x73, 0x1E, 0xD5,
+ 0x23, 0xF7, 0x67, 0x6E, 0xD3, 0xF5, 0x79, 0x44, 0xB3, 0x3F, 0xA9, 0xA7, 0x4E, 0x29, 0xC2, 0x12,
+ 0x49, 0xA6, 0x9B, 0xB4, 0x1E, 0x97, 0xDF, 0x64, 0xF6, 0xF4, 0xB5, 0x92, 0xBB, 0x5F, 0x37, 0x38,
+ 0x65, 0x72, 0xC5, 0x62, 0x72, 0xCA, 0xB4, 0xB9, 0x5D, 0x5A, 0x32, 0x9C, 0x9C, 0x5D, 0xA0, 0x9C,
+ 0x76, 0x9B, 0x8D, 0xB4, 0x92, 0xBA, 0xB4, 0x93, 0x4D, 0xD9, 0xAD, 0x5D, 0xAD, 0xF4, 0x1D, 0xB7,
+ 0x83, 0x35, 0x6B, 0x7F, 0x0A, 0xE9, 0xFA, 0xD5, 0x95, 0xD6, 0x9F, 0xE2, 0xDF, 0x0F, 0x1B, 0x58,
+ 0x99, 0xBC, 0x47, 0xE1, 0xB7, 0x6B, 0xAB, 0x14, 0x47, 0x5C, 0x23, 0x5D, 0xC0, 0xCA, 0x27, 0xB5,
+ 0x62, 0x03, 0x7C, 0x93, 0x22, 0x1E, 0xB8, 0x24, 0x00, 0x4F, 0xCC, 0xE3, 0x30, 0xED, 0x62, 0x27,
+ 0x0A, 0x11, 0xB2, 0x6D, 0x24, 0xBF, 0x95, 0xDE, 0xDA, 0xA5, 0x6B, 0x6E, 0xB5, 0xB5, 0xBB, 0x76,
+ 0x37, 0xC1, 0x42, 0x73, 0xC1, 0x53, 0x97, 0x32, 0x9C, 0x6C, 0xBD, 0xE8, 0xEA, 0x9A, 0xB6, 0x92,
+ 0xDB, 0x4B, 0xDA, 0xE9, 0x34, 0x9A, 0x5D, 0x17, 0x5E, 0x5E, 0x5B, 0x2B, 0x08, 0xA7, 0xDD, 0x6F,
+ 0x67, 0x67, 0x13, 0xA4, 0x62, 0x03, 0x24, 0x36, 0xE8, 0x0B, 0x60, 0x92, 0x72, 0xEA, 0x06, 0x7E,
+ 0xF0, 0x18, 0xE9, 0xD7, 0xAE, 0x33, 0x5E, 0xB7, 0x13, 0x62, 0xA5, 0x2C, 0x5D, 0x2C, 0x1A, 0x93,
+ 0xB5, 0x1A, 0x54, 0xE9, 0xCA, 0xCD, 0xB8, 0xB9, 0x41, 0x59, 0xB5, 0x7E, 0x8F, 0x65, 0x6B, 0x26,
+ 0x96, 0x89, 0x2B, 0x25, 0xCB, 0x47, 0x0D, 0x46, 0x84, 0xA4, 0xE9, 0xC2, 0x29, 0xB7, 0xD2, 0x29,
+ 0x3B, 0x6E, 0x96, 0x89, 0x68, 0xBB, 0x6B, 0xFE, 0x5E, 0x45, 0xF1, 0x93, 0xC6, 0x31, 0x78, 0x2F,
+ 0xC1, 0x5A, 0x9D, 0xFE, 0xFD, 0xD7, 0xD7, 0x10, 0xB5, 0x8D, 0x8C, 0x23, 0x22, 0x59, 0x65, 0x95,
+ 0x48, 0x45, 0x53, 0x8E, 0xA4, 0xB2, 0xA8, 0x00, 0xF5, 0xF4, 0xE9, 0x59, 0x64, 0xB8, 0x65, 0x5F,
+ 0x11, 0xCF, 0x28, 0xFB, 0x90, 0x57, 0xE8, 0x96, 0x9B, 0x2B, 0x74, 0x5B, 0x7C, 0xB5, 0xB5, 0x8E,
+ 0x7C, 0xDE, 0x72, 0xF6, 0x10, 0xC2, 0xD1, 0x76, 0x9D, 0x57, 0xCA, 0x9E, 0xDC, 0xB1, 0xB7, 0xBF,
+ 0x2D, 0xAD, 0x68, 0xC5, 0x37, 0xD2, 0xCD, 0x2E, 0x87, 0x21, 0xF0, 0x4F, 0xC1, 0xEF, 0xE1, 0x4F,
+ 0x05, 0xDA, 0xDD, 0x6A, 0x08, 0x3F, 0xB6, 0xB5, 0xEC, 0xEB, 0x3A, 0xA4, 0xAC, 0x06, 0x5A, 0x59,
+ 0x8E, 0xE6, 0x04, 0x1E, 0x70, 0x37, 0x00, 0x3B, 0xFC, 0xB8, 0xED, 0x5E, 0x86, 0x67, 0x5F, 0xDA,
+ 0xE2, 0x3D, 0x94, 0x7E, 0x15, 0xA7, 0x6D, 0x7A, 0xF9, 0x69, 0xA2, 0xD3, 0x4B, 0x5B, 0x43, 0x93,
+ 0x2B, 0xA5, 0x1A, 0x8A, 0x78, 0xE8, 0x2B, 0x53, 0x92, 0x51, 0xA6, 0xB4, 0xF7, 0x69, 0x41, 0x38,
+ 0xC1, 0x76, 0x57, 0x5E, 0xF3, 0xB5, 0xB5, 0x6C, 0xE6, 0xAF, 0x2E, 0x63, 0xF1, 0xE7, 0xC6, 0x9F,
+ 0x0D, 0x78, 0x2E, 0xEA, 0x6D, 0x56, 0x6F, 0x03, 0xF8, 0x66, 0x44, 0xD7, 0x3C, 0x6D, 0xA6, 0xE8,
+ 0x97, 0x2B, 0x6B, 0x36, 0xA4, 0xD1, 0x12, 0x6D, 0x61, 0x66, 0x78, 0xE4, 0x87, 0x86, 0x1B, 0x87,
+ 0x98, 0x8C, 0x32, 0x99, 0xC0, 0xAF, 0x4F, 0x2D, 0xC3, 0x53, 0x85, 0x3A, 0x5C, 0xE9, 0x5D, 0xB5,
+ 0x2D, 0x5B, 0x4B, 0xB2, 0x57, 0x49, 0xBD, 0x77, 0x56, 0x4D, 0xAD, 0xBC, 0x97, 0x32, 0xC7, 0xC2,
+ 0x12, 0xAD, 0xCE, 0xA5, 0xC9, 0x51, 0xFB, 0x15, 0x6B, 0x2B, 0xC5, 0x6B, 0x55, 0xEA, 0x9E, 0x8D,
+ 0x72, 0xD3, 0xD9, 0x5E, 0xEE, 0xDA, 0xBB, 0x2E, 0x83, 0xE3, 0xDD, 0xA7, 0x86, 0xF4, 0x7F, 0x06,
+ 0xBF, 0x8F, 0x34, 0xDF, 0x0D, 0x4D, 0xA9, 0x6A, 0x9E, 0x17, 0x79, 0xB6, 0x8D, 0x7A, 0x67, 0xFB,
+ 0x25, 0xAD, 0xB3, 0xCA, 0xBF, 0xD9, 0xD7, 0x36, 0x62, 0x01, 0x08, 0xF3, 0xA1, 0x09, 0x36, 0xE2,
+ 0xE4, 0xC6, 0xDC, 0x81, 0x19, 0xC8, 0x03, 0xAB, 0x1B, 0x5A, 0xAD, 0x0C, 0x33, 0xA3, 0x42, 0x0E,
+ 0x3A, 0xF3, 0x24, 0x95, 0xA1, 0x68, 0xE9, 0x2E, 0x56, 0xF7, 0x4D, 0x75, 0x51, 0x8B, 0x4F, 0x95,
+ 0xEB, 0xB1, 0xD1, 0x95, 0x51, 0xC2, 0x57, 0xC7, 0x4B, 0x0D, 0x59, 0x47, 0xD9, 0xD6, 0x84, 0xE9,
+ 0x6A, 0xED, 0x66, 0xD3, 0xF6, 0x7A, 0x27, 0x6B, 0xDF, 0xDD, 0x56, 0xBB, 0x4D, 0xA4, 0xAD, 0x64,
+ 0x9F, 0x8E, 0x7C, 0x56, 0x1E, 0x1F, 0xF8, 0x8D, 0x6F, 0xF0, 0xA7, 0xC0, 0x56, 0xA5, 0xA6, 0x7F,
+ 0x11, 0xC2, 0xDE, 0x32, 0xF1, 0x5D, 0xFC, 0x69, 0x24, 0x73, 0x69, 0x56, 0x91, 0xC0, 0x3E, 0xCD,
+ 0x0D, 0xB0, 0x2C, 0xB9, 0x0C, 0xF2, 0x80, 0xDB, 0x90, 0x8C, 0x85, 0x28, 0xF8, 0xC9, 0x1E, 0x76,
+ 0x33, 0x03, 0x84, 0xC4, 0x61, 0x29, 0xE1, 0xE5, 0x2E, 0x6A, 0x52, 0x7C, 0xD3, 0x4A, 0xE9, 0x38,
+ 0x24, 0xDC, 0x53, 0x69, 0x24, 0xB5, 0xE5, 0x6D, 0x2E, 0xCD, 0x76, 0x44, 0xE5, 0x99, 0x9B, 0xCA,
+ 0xB0, 0x55, 0x73, 0x47, 0x4A, 0xD8, 0x9A, 0x6A, 0x34, 0xA3, 0xCC, 0xB4, 0xF6, 0x92, 0x92, 0x73,
+ 0x51, 0x49, 0xA7, 0xA4, 0x21, 0x27, 0xCC, 0xD2, 0x4D, 0x34, 0x93, 0xB5, 0xAD, 0x52, 0xC3, 0x5D,
+ 0xD2, 0x35, 0x4F, 0x87, 0x5E, 0x38, 0x8B, 0x40, 0xB7, 0xD4, 0x74, 0x0D, 0x33, 0xE1, 0xC8, 0x5D,
+ 0x02, 0x2B, 0x08, 0x3C, 0x4A, 0x9A, 0x7F, 0x8A, 0x4B, 0xB4, 0x89, 0x0D, 0xA5, 0xC5, 0x94, 0x92,
+ 0xF9, 0x87, 0xCD, 0x69, 0x64, 0x47, 0xD8, 0x9B, 0x88, 0x03, 0x82, 0x02, 0x8A, 0xEC, 0x82, 0xCB,
+ 0xB0, 0x70, 0x9D, 0x1A, 0xCA, 0x72, 0x8C, 0x53, 0xA4, 0x92, 0xB5, 0xF9, 0x9A, 0x51, 0x85, 0xEF,
+ 0x14, 0x9C, 0x75, 0x4F, 0x58, 0xAF, 0x73, 0x56, 0xF6, 0x14, 0xB2, 0xEF, 0xAF, 0x71, 0x4D, 0x2C,
+ 0xC3, 0x0A, 0xA3, 0x0C, 0x2B, 0x8C, 0x31, 0x57, 0x5A, 0x2B, 0x28, 0xB9, 0x4E, 0xD1, 0x6F, 0xAC,
+ 0xA2, 0xDC, 0xA3, 0xCC, 0x92, 0xBE, 0x8A, 0xEE, 0xC7, 0x45, 0xE3, 0x7F, 0x03, 0xEB, 0xBF, 0x0A,
+ 0xFC, 0x03, 0xF0, 0x7B, 0xC6, 0x50, 0x78, 0x87, 0xC4, 0xD6, 0x7E, 0x20, 0xF1, 0xBE, 0xB1, 0x6D,
+ 0xA2, 0xDF, 0x68, 0xF6, 0xFA, 0x8A, 0xFD, 0x83, 0xC5, 0x5A, 0x2C, 0xA4, 0xC6, 0x6F, 0x2F, 0x4A,
+ 0xB8, 0x9E, 0x59, 0x0D, 0xD3, 0x4A, 0x3E, 0x7C, 0x80, 0x49, 0x39, 0x3B, 0xB8, 0xE2, 0xAD, 0x08,
+ 0xD1, 0x9E, 0x17, 0xD8, 0x53, 0x4E, 0x34, 0x5C, 0x60, 0xDD, 0xF6, 0x83, 0x8F, 0x2F, 0x9D, 0xDA,
+ 0x92, 0x4F, 0xDE, 0x4F, 0x6B, 0xAE, 0x57, 0xAA, 0xC7, 0x2D, 0xA5, 0x5B, 0x1D, 0x95, 0x66, 0x52,
+ 0xC4, 0xD5, 0x71, 0xAD, 0x8E, 0x84, 0xEB, 0x53, 0x57, 0xB3, 0xF7, 0x7D, 0xE5, 0xCB, 0xAD, 0xEC,
+ 0xE3, 0x64, 0xD2, 0x56, 0xB6, 0x97, 0xE8, 0x72, 0x97, 0xBA, 0x67, 0x89, 0x75, 0x0F, 0x1D, 0xCF,
+ 0xA7, 0x69, 0x1F, 0x10, 0xA7, 0xD4, 0x7C, 0x0B, 0xF0, 0xC7, 0x52, 0x97, 0x51, 0xD4, 0xEC, 0x9E,
+ 0x45, 0xB7, 0xD0, 0xB4, 0xE9, 0xDB, 0x4F, 0x8D, 0xAF, 0x65, 0xD2, 0xC1, 0x20, 0xCD, 0x3E, 0x64,
+ 0x85, 0x70, 0xEA, 0x99, 0x65, 0x70, 0x31, 0xB2, 0xB6, 0xA9, 0x4B, 0x0E, 0xF8, 0x8D, 0xE3, 0xA5,
+ 0x89, 0xB6, 0x1A, 0x12, 0x54, 0x5B, 0x4B, 0xDD, 0x92, 0x94, 0x3D, 0xEB, 0x45, 0xA4, 0xF9, 0x93,
+ 0x71, 0x5A, 0x49, 0x2B, 0x26, 0xBD, 0x7A, 0x28, 0x61, 0xAA, 0x61, 0xF8, 0x62, 0x3C, 0x2D, 0xEC,
+ 0x5F, 0xD6, 0x55, 0x27, 0x89, 0x4D, 0x5A, 0xF1, 0xB4, 0xD7, 0x2E, 0x8D, 0x26, 0xA3, 0x64, 0xEC,
+ 0x97, 0x4B, 0x3B, 0x7B, 0xC7, 0x90, 0x6B, 0xDF, 0x12, 0x7C, 0x65, 0x67, 0x2F, 0x8D, 0x3E, 0x25,
+ 0xE9, 0xDE, 0x29, 0xF1, 0x44, 0x1E, 0x3B, 0xF1, 0xF7, 0x8A, 0xDF, 0xC3, 0x9E, 0x1F, 0xD5, 0x46,
+ 0x82, 0xD7, 0xF1, 0x78, 0x8B, 0x4D, 0xB5, 0x1E, 0x4D, 0xC2, 0xDB, 0xEA, 0x12, 0x02, 0xB1, 0xB8,
+ 0x72, 0xB9, 0x58, 0x81, 0x24, 0x90, 0x32, 0x31, 0x5F, 0x35, 0x9D, 0x4D, 0x61, 0xE8, 0xCF, 0x19,
+ 0x42, 0xBD, 0xA5, 0x56, 0xB7, 0xB3, 0xA7, 0x69, 0xDA, 0x51, 0x8D, 0x3B, 0x41, 0xB7, 0x1D, 0x13,
+ 0x4D, 0xA6, 0xEE, 0xF6, 0xBA, 0xD8, 0xFB, 0xFC, 0x8E, 0x86, 0x61, 0x18, 0x61, 0xDE, 0x2E, 0x3F,
+ 0xB9, 0xF6, 0x4A, 0x53, 0x52, 0x8A, 0x8A, 0x95, 0x49, 0xFB, 0xD7, 0x69, 0x6F, 0xCA, 0xB9, 0x52,
+ 0x8B, 0xD1, 0x2D, 0xDB, 0xD8, 0xF3, 0xCF, 0x0C, 0x4D, 0xE3, 0xEF, 0x10, 0x69, 0xAD, 0xFB, 0x3F,
+ 0xFF, 0x00, 0xC2, 0x47, 0xA3, 0x68, 0x9E, 0x0E, 0xB8, 0xF1, 0x18, 0xF8, 0x85, 0xE2, 0x1B, 0x7D,
+ 0x4A, 0xCA, 0x3D, 0x3C, 0x58, 0xEA, 0x16, 0xD6, 0x8D, 0x1C, 0x93, 0x5C, 0xCD, 0x2C, 0x71, 0xDC,
+ 0x34, 0xD1, 0xC0, 0xCE, 0x8B, 0x0E, 0xF0, 0xAC, 0xC1, 0x07, 0x7D, 0xC3, 0xE6, 0x2B, 0xE5, 0xD8,
+ 0x88, 0x4D, 0x65, 0x14, 0xF1, 0x2A, 0x74, 0x6D, 0x19, 0xBE, 0x5E, 0x55, 0x14, 0xDF, 0xBA, 0xDC,
+ 0x92, 0x92, 0x5C, 0xD1, 0x82, 0x6E, 0xF6, 0xBB, 0xD3, 0x99, 0x2E, 0x9E, 0xE3, 0xC5, 0x61, 0x1C,
+ 0x63, 0x98, 0x4E, 0x16, 0x9F, 0xC2, 0xA5, 0x65, 0x77, 0x1D, 0x25, 0xA5, 0xAE, 0xB9, 0x7A, 0xDB,
+ 0xA2, 0x4E, 0xCB, 0x44, 0x64, 0x7C, 0x51, 0xF8, 0xA1, 0xE2, 0xFF, 0x00, 0x18, 0x6A, 0x57, 0xB3,
+ 0xEB, 0xDE, 0x2C, 0x3E, 0x26, 0x9A, 0xF3, 0x4E, 0xB5, 0xD0, 0x56, 0xFA, 0x3D, 0x1A, 0xDB, 0x45,
+ 0x82, 0x7D, 0x33, 0x4F, 0x8C, 0x47, 0xA7, 0xA9, 0xB5, 0x8D, 0x17, 0xC9, 0x72, 0x88, 0x8E, 0x40,
+ 0xE4, 0xE7, 0xE6, 0x27, 0x15, 0xEC, 0x67, 0x38, 0x99, 0x64, 0xDC, 0x3F, 0x2C, 0xB3, 0x0D, 0x56,
+ 0xA2, 0xAD, 0x5A, 0x56, 0xA8, 0xAC, 0xD5, 0x35, 0x4D, 0x26, 0xE3, 0x14, 0xAE, 0xA2, 0xD4, 0x9A,
+ 0x53, 0x8B, 0xE5, 0xBD, 0x9B, 0xBD, 0xB4, 0x3B, 0x70, 0xB3, 0xC2, 0xD7, 0x85, 0xA3, 0x09, 0x5E,
+ 0x32, 0x96, 0xFA, 0x45, 0xED, 0xAA, 0xB5, 0xA4, 0xEC, 0xD7, 0x5F, 0x77, 0x4D, 0xAF, 0x73, 0xC4,
+ 0xEB, 0xF3, 0x83, 0xB8, 0x28, 0x00, 0xA0, 0x0D, 0x2D, 0x3E, 0xCC, 0xCC, 0xEA, 0xC4, 0x61, 0x06,
+ 0x30, 0x00, 0xED, 0x8E, 0x98, 0xFC, 0xAB, 0xF5, 0xFF, 0x00, 0x0C, 0x38, 0x22, 0xB6, 0x77, 0x8D,
+ 0x86, 0x3E, 0xBC, 0x3F, 0x74, 0x9E, 0x9B, 0xDE, 0xD6, 0x69, 0xDD, 0x5A, 0xD6, 0x7A, 0x59, 0xEA,
+ 0x9F, 0x63, 0xCD, 0xC6, 0xE2, 0x55, 0x38, 0xF2, 0x44, 0xEF, 0x2D, 0x2D, 0x44, 0x30, 0xAF, 0x0A,
+ 0x00, 0x51, 0x81, 0xD3, 0x00, 0x0E, 0x9D, 0x3D, 0x85, 0x7F, 0xA3, 0x3C, 0x19, 0xC2, 0x94, 0xB2,
+ 0x4C, 0x96, 0x9C, 0xDA, 0x49, 0x72, 0xAD, 0x2F, 0x6D, 0x3B, 0x3D, 0x17, 0xF9, 0x5F, 0x6D, 0x34,
+ 0x3E, 0x4A, 0xBD, 0x67, 0x52, 0x6E, 0xDB, 0x7F, 0x5B, 0x0D, 0x5B, 0xB8, 0x1E, 0xE3, 0xEC, 0x8A,
+ 0x58, 0xCD, 0x8C, 0x85, 0x08, 0x42, 0xED, 0x1D, 0xC1, 0xF4, 0x18, 0x15, 0xE7, 0x61, 0x78, 0xD3,
+ 0x20, 0xC6, 0x71, 0x43, 0xE0, 0xEC, 0x2D, 0x49, 0xCB, 0x1E, 0x95, 0xD4, 0x55, 0x39, 0xF2, 0xB8,
+ 0x68, 0xB9, 0xD4, 0xAD, 0x6E, 0x58, 0xBD, 0x1B, 0x76, 0x69, 0xD9, 0x5B, 0x44, 0x5B, 0xC3, 0xD5,
+ 0x8D, 0x05, 0x5D, 0xC5, 0x72, 0x7A, 0xAF, 0xBA, 0xC2, 0xDD, 0x5B, 0x19, 0x51, 0x36, 0x90, 0x92,
+ 0xC0, 0xDB, 0xAD, 0x88, 0x05, 0x7E, 0x60, 0x39, 0x03, 0x8E, 0x84, 0x0C, 0x1A, 0xDB, 0x8C, 0xB8,
+ 0x67, 0x11, 0x9D, 0x60, 0x29, 0xCF, 0x05, 0x35, 0x1C, 0x7E, 0x12, 0x4E, 0x78, 0x49, 0x3B, 0xC5,
+ 0x7B, 0x5B, 0x5D, 0xA4, 0xF9, 0x79, 0x9C, 0x26, 0x93, 0x84, 0xDA, 0x4B, 0xDD, 0x6D, 0x59, 0xDD,
+ 0x35, 0x38, 0x7A, 0xCA, 0x93, 0x69, 0xAF, 0x71, 0xA4, 0xA4, 0xBC, 0xBF, 0x2D, 0x37, 0x5F, 0xF0,
+ 0x09, 0xED, 0xC2, 0xDC, 0x5B, 0x3D, 0xCC, 0x40, 0xF9, 0x51, 0x5C, 0x7D, 0x9D, 0xD2, 0x45, 0x54,
+ 0x96, 0x16, 0x2A, 0x70, 0x85, 0x41, 0x38, 0xE1, 0x73, 0xC6, 0x6B, 0x5E, 0x0C, 0xCD, 0xE8, 0xF1,
+ 0x4E, 0x4B, 0xF5, 0xCA, 0xA9, 0x47, 0x13, 0x4E, 0x6E, 0x15, 0xE9, 0x34, 0x93, 0xA1, 0x56, 0x3A,
+ 0x4E, 0x92, 0x4D, 0xBF, 0x72, 0xEF, 0x9A, 0x0D, 0xFC, 0x51, 0xE5, 0x6D, 0x2D, 0x82, 0xA6, 0x1E,
+ 0xB5, 0x18, 0x2A, 0x92, 0x4B, 0x97, 0x44, 0x9A, 0xD9, 0xDD, 0x5D, 0x5B, 0x44, 0xF6, 0x5D, 0x95,
+ 0x85, 0xDA, 0x00, 0xC7, 0x1C, 0x0E, 0x30, 0xA0, 0x0E, 0x07, 0x61, 0xF9, 0x57, 0xD2, 0x4B, 0x09,
+ 0x04, 0x9C, 0x16, 0xF6, 0xD3, 0xDD, 0x56, 0xEC, 0xAF, 0x65, 0x75, 0xD2, 0xDF, 0x86, 0x9A, 0x18,
+ 0x29, 0x2D, 0x34, 0xD0, 0x85, 0x94, 0xE0, 0x01, 0x80, 0x31, 0xC7, 0x18, 0xE9, 0xED, 0x5E, 0x16,
+ 0x27, 0x0D, 0x38, 0xB5, 0x1D, 0x2D, 0x6F, 0xCB, 0xCA, 0xC9, 0xA5, 0xD1, 0x5D, 0x2D, 0x8D, 0x15,
+ 0xAC, 0xAC, 0x57, 0x65, 0xE3, 0x6F, 0x03, 0x18, 0x03, 0x18, 0xC7, 0x03, 0x80, 0x05, 0x78, 0x38,
+ 0xAC, 0x3C, 0xE4, 0xDD, 0x9A, 0xD2, 0xDF, 0x87, 0xF5, 0xFE, 0x66, 0xB0, 0x69, 0x25, 0x1B, 0x11,
+ 0xAA, 0x80, 0x55, 0x5F, 0x21, 0x08, 0xC1, 0xDA, 0x07, 0x1C, 0x71, 0x81, 0x5E, 0x5C, 0x28, 0x51,
+ 0xA9, 0x5E, 0x34, 0xF1, 0xB7, 0xFA, 0xBB, 0x8B, 0x52, 0xE5, 0xB3, 0x69, 0xE9, 0x6D, 0x2E, 0xBF,
+ 0x35, 0xE5, 0xD8, 0xBD, 0x54, 0x7D, 0xD5, 0xAE, 0x96, 0x3B, 0x1F, 0x82, 0xB2, 0xDB, 0x78, 0x77,
+ 0xE3, 0x67, 0xC3, 0xAD, 0x4A, 0xE8, 0xC6, 0xB6, 0x2B, 0xE2, 0x58, 0x11, 0xDD, 0xC1, 0x2B, 0x1F,
+ 0x9A, 0x0C, 0x6A, 0x48, 0xED, 0xCB, 0xAE, 0x2B, 0xF8, 0xB3, 0xC5, 0x4E, 0x00, 0xAD, 0xC2, 0x3C,
+ 0x4F, 0x2C, 0xC3, 0x0B, 0x14, 0xF0, 0x75, 0x6E, 0xD3, 0xBB, 0xBA, 0x6E, 0xEB, 0x54, 0xD2, 0x4A,
+ 0xF7, 0x56, 0x49, 0xBB, 0xED, 0xA5, 0xCF, 0x6E, 0x96, 0x25, 0x62, 0x70, 0x2E, 0x9B, 0xF8, 0x95,
+ 0xB6, 0xF2, 0xB7, 0xF9, 0x7D, 0xC7, 0xF5, 0xEF, 0xFB, 0x3B, 0x5E, 0xDB, 0xDC, 0x78, 0x5A, 0xE1,
+ 0x22, 0xC1, 0x92, 0x29, 0x99, 0x99, 0x55, 0x81, 0x21, 0x5D, 0x03, 0x29, 0x1F, 0x86, 0xEF, 0xCA,
+ 0xAB, 0x1A, 0xD5, 0x4A, 0x14, 0x2A, 0x53, 0xB7, 0x27, 0x2C, 0x52, 0xB7, 0x6D, 0x7F, 0xCF, 0xA2,
+ 0xED, 0xB1, 0xF1, 0x39, 0x74, 0x3D, 0x9E, 0x26, 0xB5, 0x1B, 0x6A, 0x9E, 0xD6, 0xE9, 0xAB, 0xD5,
+ 0x2B, 0x77, 0xD3, 0xAF, 0x4B, 0x1C, 0x05, 0x8E, 0xA9, 0x6D, 0xAB, 0xFE, 0xD1, 0xB7, 0xF6, 0xDA,
+ 0xEC, 0xAB, 0x6E, 0xBA, 0x26, 0x99, 0xFF, 0x00, 0x12, 0x98, 0x6E, 0x58, 0x2C, 0x79, 0x60, 0x7C,
+ 0xD7, 0x4C, 0xF1, 0xC6, 0x3A, 0x8C, 0x71, 0xF8, 0xE3, 0xE9, 0xEA, 0x52, 0x95, 0x0E, 0x18, 0x82,
+ 0xC3, 0xC5, 0x5E, 0x56, 0x6E, 0xC9, 0x3D, 0xDB, 0x4B, 0x6D, 0x74, 0xB2, 0x5D, 0x12, 0xD2, 0xD6,
+ 0xE6, 0x57, 0xF0, 0x29, 0xA5, 0x57, 0x3B, 0x75, 0x6B, 0xA4, 0xA2, 0x9D, 0x97, 0x6D, 0x6D, 0x65,
+ 0xAE, 0x8A, 0xED, 0xDB, 0x6D, 0xD2, 0xE8, 0x8F, 0x55, 0xF8, 0xED, 0xE3, 0x99, 0xF4, 0x5F, 0x01,
+ 0xEB, 0x3F, 0xF0, 0x8E, 0xA7, 0xDA, 0x6E, 0xBE, 0xCA, 0xF0, 0x97, 0x83, 0x2B, 0x14, 0x4B, 0xE5,
+ 0x9D, 0xCF, 0xB8, 0x60, 0x00, 0x14, 0x37, 0x42, 0x0E, 0x07, 0xD3, 0x3E, 0x37, 0x0D, 0xE5, 0xF1,
+ 0xAB, 0x8F, 0x8C, 0xB1, 0x09, 0x5A, 0x29, 0xB4, 0x9D, 0xB5, 0x6A, 0xD6, 0x8B, 0xD1, 0xEE, 0xED,
+ 0x75, 0x67, 0xA2, 0x6A, 0xD6, 0xBD, 0xBD, 0x6C, 0xF7, 0x1F, 0x1F, 0xAA, 0x2A, 0x34, 0x5F, 0xBA,
+ 0xDA, 0x4D, 0xAD, 0x92, 0xBA, 0x4E, 0xDE, 0x89, 0xBB, 0x5F, 0x7B, 0x58, 0xCF, 0xF8, 0x09, 0x06,
+ 0x9F, 0xE1, 0xCF, 0x85, 0xDA, 0x4D, 0xDC, 0xD7, 0x11, 0xBC, 0xF7, 0x96, 0xBF, 0x6D, 0xB8, 0x55,
+ 0x3F, 0xBC, 0x92, 0x59, 0x57, 0x73, 0x80, 0x3A, 0x82, 0x49, 0x1F, 0x87, 0xD2, 0xAB, 0x88, 0x1D,
+ 0x7C, 0x4E, 0x69, 0x2A, 0x7C, 0xBB, 0x5A, 0x2A, 0xC9, 0x6D, 0x1B, 0x25, 0xA2, 0xD3, 0x4F, 0xF2,
+ 0x23, 0x24, 0x74, 0x70, 0xB8, 0x09, 0x55, 0x6D, 0x5D, 0xBB, 0x25, 0xBB, 0x69, 0x6C, 0xB4, 0xF2,
+ 0xB6, 0xB6, 0x49, 0x2D, 0x16, 0x8B, 0x5D, 0x0D, 0x4E, 0x64, 0xB0, 0xD0, 0x7C, 0x4F, 0xE2, 0x6D,
+ 0x61, 0xD2, 0xC9, 0xB5, 0x0B, 0x49, 0x2D, 0xED, 0x55, 0xBE, 0x51, 0xE5, 0x91, 0x84, 0x61, 0x81,
+ 0xC8, 0xEA, 0x40, 0xF4, 0x1D, 0x38, 0xC9, 0xF3, 0xF1, 0xD2, 0xA7, 0x0C, 0x2C, 0x70, 0xB4, 0xBE,
+ 0x18, 0xA6, 0xDB, 0x5A, 0xDB, 0x7B, 0xA5, 0xB6, 0x89, 0x25, 0xB5, 0x93, 0xB2, 0xB3, 0x6D, 0xA4,
+ 0xBB, 0x32, 0xE8, 0xC7, 0xEB, 0x2F, 0x17, 0x57, 0xAB, 0xD1, 0x77, 0x49, 0xDD, 0xEB, 0x64, 0xAD,
+ 0x7D, 0x2F, 0x6B, 0x7A, 0xD9, 0x5B, 0xF9, 0xB6, 0xF0, 0x4E, 0xB1, 0x69, 0xAE, 0x7F, 0xC1, 0x57,
+ 0xFF, 0x00, 0x67, 0xEB, 0xDB, 0x22, 0x8D, 0x6E, 0x9F, 0xB5, 0xAF, 0xC3, 0x6B, 0x30, 0xD1, 0x8C,
+ 0x29, 0x68, 0x3C, 0x41, 0xA5, 0xA4, 0x98, 0xFA, 0x32, 0xB0, 0xFA, 0x01, 0x5F, 0x93, 0xCE, 0x7C,
+ 0xD9, 0xDD, 0x08, 0xD9, 0x69, 0x38, 0x6C, 0xD3, 0xDE, 0x5C, 0xDD, 0x3B, 0x5E, 0xD6, 0xF2, 0x3F,
+ 0x40, 0xA3, 0x15, 0x1C, 0xB2, 0x7F, 0xE1, 0x97, 0x4B, 0x2D, 0xAC, 0xAD, 0xE5, 0x64, 0xAC, 0x7F,
+ 0x70, 0xF5, 0xFA, 0x09, 0xF3, 0x41, 0x40, 0x05, 0x00, 0x14, 0x01, 0xFC, 0x57, 0xFF, 0x00, 0xC1,
+ 0x6A, 0x13, 0x3F, 0xB7, 0xF7, 0xC4, 0xA3, 0x81, 0x81, 0xE0, 0xEF, 0x0A, 0x0C, 0x60, 0x60, 0x81,
+ 0xE1, 0xDB, 0x4E, 0x31, 0x51, 0x43, 0x06, 0xAB, 0xE1, 0xF1, 0x13, 0x49, 0x59, 0x4E, 0xD6, 0x7B,
+ 0x35, 0xEC, 0xE9, 0x3B, 0x5B, 0xFE, 0x07, 0x6D, 0xB4, 0x3D, 0xBC, 0x13, 0x51, 0xA1, 0x05, 0xD2,
+ 0xCF, 0xF3, 0x67, 0xE5, 0xA6, 0x8F, 0xE2, 0x3F, 0x11, 0xF8, 0x5C, 0xDC, 0xB6, 0x81, 0xAC, 0x5F,
+ 0xE9, 0x49, 0x78, 0xAA, 0xB7, 0x71, 0x59, 0xCE, 0xD1, 0x41, 0x72, 0x10, 0xE5, 0x04, 0x91, 0x7D,
+ 0xC6, 0xDA, 0x49, 0xC1, 0x20, 0xE3, 0x9C, 0x63, 0x35, 0xF2, 0x35, 0xF0, 0x99, 0xAE, 0x49, 0x5E,
+ 0x59, 0x8E, 0x5F, 0x2E, 0x58, 0x6A, 0xEC, 0x92, 0x56, 0x4F, 0xA7, 0x2B, 0x5C, 0xAD, 0x74, 0xD3,
+ 0xA7, 0x44, 0x8D, 0xF1, 0x78, 0x0C, 0xBB, 0x36, 0xC3, 0xAC, 0x26, 0x61, 0x49, 0x4E, 0x1A, 0x68,
+ 0xFC, 0xB6, 0xD5, 0x59, 0xAF, 0xC8, 0xFA, 0x7E, 0x1F, 0xDB, 0x7B, 0xE3, 0x47, 0xFC, 0x22, 0x71,
+ 0x78, 0x4A, 0xEE, 0xEB, 0x47, 0xB9, 0x86, 0x2B, 0x61, 0x68, 0x35, 0x56, 0xB0, 0x23, 0x50, 0xD8,
+ 0x17, 0x01, 0x8A, 0x86, 0x11, 0x96, 0xC7, 0x70, 0xA3, 0xA0, 0xE9, 0x8A, 0x30, 0x3C, 0x45, 0x81,
+ 0x85, 0x78, 0xD6, 0xC6, 0xE1, 0x17, 0x36, 0x97, 0x70, 0x6D, 0x2F, 0x5E, 0x47, 0x75, 0xF2, 0xBA,
+ 0x8F, 0x68, 0xA5, 0x64, 0x79, 0x15, 0xB8, 0x5A, 0x53, 0xA4, 0xF0, 0xD4, 0xB1, 0x73, 0x54, 0x76,
+ 0x51, 0x7C, 0xAD, 0xA5, 0xFC, 0xAA, 0x5C, 0xB7, 0x49, 0x6C, 0x9D, 0x9C, 0x92, 0xFB, 0x4C, 0xFD,
+ 0x1C, 0xF8, 0x45, 0xFB, 0x5E, 0x7C, 0x0F, 0x4F, 0x84, 0xFA, 0x76, 0x8B, 0x7B, 0xF1, 0x0E, 0xD7,
+ 0x4A, 0xF1, 0x3D, 0x9E, 0x8C, 0x2D, 0xEE, 0x6D, 0x75, 0xFB, 0x19, 0x74, 0xD7, 0x69, 0xF6, 0x00,
+ 0xD8, 0x91, 0x97, 0xCB, 0x60, 0x4A, 0xB1, 0xC8, 0x73, 0xD4, 0x7B, 0x01, 0x38, 0xAC, 0x5E, 0x0F,
+ 0x1D, 0x9A, 0xBA, 0xB4, 0x26, 0x95, 0x39, 0x49, 0x5A, 0xEF, 0x95, 0x25, 0xBF, 0x5D, 0x15, 0xBE,
+ 0xE5, 0xB2, 0xD8, 0xE6, 0xC1, 0x60, 0x31, 0xF9, 0x5E, 0x49, 0x1A, 0x15, 0x20, 0xDD, 0x48, 0x45,
+ 0xAD, 0x13, 0x9D, 0xDF, 0xD9, 0xB2, 0x5A, 0xBE, 0x9D, 0x13, 0xB2, 0xBB, 0x3F, 0x3B, 0xFE, 0x26,
+ 0xFE, 0xD6, 0x3F, 0x12, 0xBC, 0x44, 0xFA, 0xA7, 0x85, 0xE1, 0xD7, 0x34, 0x75, 0xD0, 0x04, 0x86,
+ 0xDC, 0x5C, 0x68, 0x31, 0x18, 0x86, 0xA1, 0x0F, 0x50, 0x4C, 0x9B, 0xDB, 0x83, 0x91, 0x90, 0x0E,
+ 0x32, 0x3D, 0x00, 0xAF, 0xD4, 0xB8, 0x7F, 0x31, 0xE1, 0xBC, 0x9F, 0x1A, 0xAA, 0x42, 0x74, 0xEA,
+ 0x46, 0xCF, 0x69, 0xC5, 0xC9, 0x74, 0xD1, 0xA9, 0x2B, 0x5B, 0xD3, 0xB7, 0x91, 0xE6, 0xE0, 0xF2,
+ 0x1A, 0xB9, 0xA6, 0x06, 0x8D, 0x6C, 0xD2, 0x55, 0x15, 0xD5, 0xDD, 0x27, 0x15, 0x08, 0xDF, 0xFB,
+ 0xC9, 0x25, 0x26, 0xBA, 0xA8, 0xB7, 0x6B, 0x5A, 0xEA, 0xE8, 0xFB, 0x6F, 0xFE, 0x09, 0xE5, 0xFB,
+ 0x71, 0x5C, 0x78, 0x1E, 0x3B, 0x9F, 0xD9, 0xF3, 0xE2, 0x96, 0xAE, 0x8F, 0xF0, 0xE7, 0xC6, 0x5B,
+ 0xEC, 0xFC, 0x37, 0xAC, 0x6A, 0x72, 0x41, 0x1E, 0x9F, 0xE1, 0x6B, 0xAB, 0x95, 0x0B, 0x25, 0xBD,
+ 0xD4, 0xAE, 0x54, 0xA5, 0xAC, 0xA1, 0x54, 0x6E, 0x42, 0x5D, 0x19, 0x50, 0x26, 0x37, 0x57, 0xEB,
+ 0xD9, 0xAD, 0x0A, 0x59, 0x9E, 0x1A, 0x86, 0x69, 0x93, 0x61, 0xD5, 0x47, 0xA2, 0x94, 0x14, 0xAF,
+ 0x4E, 0x31, 0x76, 0x76, 0x94, 0x55, 0xD4, 0x93, 0x69, 0x6A, 0xEE, 0xA3, 0x76, 0xEC, 0xEE, 0x63,
+ 0x98, 0x64, 0xB5, 0xE9, 0xFE, 0xF3, 0x2F, 0xAA, 0xE9, 0xB5, 0x6B, 0xA4, 0xF5, 0xD3, 0x4F, 0x71,
+ 0xB4, 0xF9, 0x5D, 0xB7, 0xB5, 0xAE, 0x95, 0xAF, 0xA2, 0x47, 0x29, 0xFB, 0x5C, 0x58, 0xFC, 0x70,
+ 0xF8, 0x2B, 0xE3, 0x2D, 0x53, 0xC3, 0x17, 0xBA, 0xC9, 0xBD, 0xF0, 0x0F, 0x8E, 0x21, 0x96, 0xF3,
+ 0xC1, 0xFE, 0x2B, 0x48, 0x5A, 0x18, 0x35, 0x0B, 0x47, 0x53, 0xE6, 0x59, 0xCB, 0x70, 0x42, 0xC4,
+ 0x97, 0x11, 0x82, 0x55, 0xA3, 0x19, 0x60, 0x3C, 0xB2, 0x79, 0x3C, 0x7F, 0x56, 0xF8, 0x39, 0x9B,
+ 0x70, 0x7F, 0x11, 0xE0, 0x29, 0xE1, 0xEB, 0xD0, 0x70, 0xC7, 0xD0, 0x8A, 0x4A, 0x2D, 0xA4, 0xAF,
+ 0x0E, 0x55, 0x75, 0x14, 0xDC, 0x9A, 0x49, 0xDA, 0xEA, 0xE9, 0x3B, 0xC6, 0xD6, 0x52, 0x3E, 0x46,
+ 0x9E, 0x4F, 0x85, 0xAD, 0x07, 0x5E, 0xBC, 0xEA, 0x49, 0x42, 0x49, 0x4A, 0x37, 0xBC, 0x5B, 0x4D,
+ 0x35, 0x65, 0x14, 0xEE, 0x96, 0x97, 0x49, 0xD9, 0xA5, 0xAA, 0x4A, 0xE9, 0x78, 0x0F, 0xC0, 0x9F,
+ 0x8D, 0xDA, 0x9F, 0xC3, 0x9D, 0x4A, 0x1D, 0x27, 0x54, 0x9A, 0x75, 0xF0, 0x3E, 0xAC, 0x1B, 0x4D,
+ 0xD6, 0x11, 0x11, 0xA4, 0xFB, 0x11, 0x96, 0x3F, 0xDD, 0x5C, 0x42, 0x72, 0x0A, 0x6C, 0x71, 0x1B,
+ 0xB0, 0x5C, 0x92, 0x37, 0xED, 0xC6, 0x40, 0x1F, 0xA2, 0xF1, 0xA7, 0x07, 0xAC, 0xFB, 0x29, 0xAB,
+ 0x89, 0xC3, 0x5D, 0x62, 0xD4, 0x95, 0xB9, 0x6D, 0x05, 0x28, 0xAB, 0x3F, 0x3B, 0x38, 0xE9, 0xEF,
+ 0x24, 0xBA, 0x5D, 0xDD, 0x24, 0xFE, 0x8B, 0x27, 0xCB, 0xB2, 0xAA, 0x1C, 0x43, 0x4F, 0x34, 0xC4,
+ 0x49, 0xA9, 0x24, 0xD5, 0x93, 0x4A, 0x2D, 0x35, 0xCA, 0xD4, 0xD2, 0xB2, 0x69, 0xC5, 0xCA, 0x0B,
+ 0x58, 0xA4, 0x9A, 0xE6, 0xBA, 0x4E, 0xFF, 0x00, 0x44, 0xEA, 0xFE, 0x1F, 0xD6, 0xB5, 0xAB, 0x39,
+ 0x3C, 0x15, 0x03, 0xCB, 0xE2, 0x45, 0xBB, 0xBD, 0x86, 0xDB, 0x48, 0x83, 0x46, 0xD3, 0xA1, 0xBA,
+ 0x9B, 0xC4, 0x91, 0xDE, 0xB1, 0x16, 0x33, 0xD9, 0xDB, 0xA4, 0x66, 0x49, 0xAE, 0xD8, 0x90, 0xA6,
+ 0x14, 0x04, 0xE3, 0x7F, 0x3C, 0x82, 0xBF, 0x81, 0x67, 0xB9, 0x27, 0x0F, 0xF1, 0x64, 0x23, 0x53,
+ 0x88, 0xE8, 0x5A, 0xBE, 0x19, 0x27, 0x26, 0xE5, 0x38, 0xB8, 0xC5, 0x5A, 0xD5, 0x3D, 0xD9, 0x59,
+ 0x28, 0x36, 0xB9, 0xE4, 0xD2, 0xE9, 0xCB, 0xA6, 0x8F, 0xF5, 0xEE, 0x17, 0xC5, 0x65, 0xDC, 0x25,
+ 0x98, 0xC7, 0x01, 0x86, 0x9C, 0x5E, 0x51, 0x8D, 0x8C, 0xD6, 0x12, 0x52, 0x9C, 0xA7, 0x1A, 0x35,
+ 0x54, 0x3F, 0x7D, 0x86, 0xAB, 0x27, 0x2B, 0x46, 0x9C, 0x93, 0xE7, 0xA0, 0xDB, 0xD5, 0xFB, 0xBB,
+ 0xE8, 0xBF, 0x4D, 0xF4, 0xEF, 0x02, 0x78, 0x33, 0xF6, 0x33, 0xF0, 0x96, 0x9F, 0xAD, 0xFE, 0xD2,
+ 0xB6, 0xB3, 0xFC, 0x41, 0xF8, 0xFD, 0xA9, 0x68, 0x16, 0x5A, 0xFF, 0x00, 0x81, 0xBF, 0x64, 0x9F,
+ 0x0F, 0xEB, 0xE2, 0x6F, 0x0E, 0xF8, 0x11, 0x9A, 0xD5, 0x4D, 0xBD, 0xEF, 0xC5, 0x3B, 0xFB, 0x73,
+ 0x14, 0xD6, 0xEC, 0x42, 0x89, 0x17, 0x4B, 0xB2, 0x91, 0xA4, 0x7C, 0x91, 0x2C, 0x91, 0xA3, 0x97,
+ 0x5F, 0xCE, 0xA8, 0xE3, 0x31, 0xDC, 0x53, 0x8C, 0x79, 0x3F, 0x08, 0x46, 0x54, 0xB2, 0x8E, 0x69,
+ 0x52, 0xA9, 0x8A, 0x9C, 0x64, 0xE5, 0x56, 0x2D, 0xD9, 0xFD, 0x56, 0x13, 0x72, 0x5C, 0x89, 0x2B,
+ 0x73, 0x4D, 0x5A, 0x2E, 0xDC, 0xA9, 0xC9, 0x28, 0x2D, 0x23, 0x95, 0x53, 0xE2, 0xDC, 0x16, 0x19,
+ 0xC2, 0x11, 0x84, 0xA1, 0x18, 0x37, 0x5D, 0xC6, 0x50, 0x92, 0x9C, 0x56, 0xAA, 0x92, 0x52, 0xBD,
+ 0x93, 0x76, 0x69, 0xB5, 0x78, 0x37, 0x16, 0x95, 0xD2, 0x7F, 0x0A, 0x78, 0xA7, 0xF6, 0xC4, 0xFD,
+ 0xA3, 0x3E, 0x3E, 0xFC, 0x4A, 0xB9, 0xF1, 0x6F, 0xC5, 0x8F, 0x15, 0x4F, 0x34, 0xBA, 0x7E, 0x94,
+ 0x74, 0x6D, 0x03, 0xC2, 0xF6, 0x1A, 0x6C, 0x5A, 0x17, 0xC3, 0x5F, 0x07, 0x5B, 0x43, 0x13, 0x95,
+ 0xB7, 0xF0, 0xF6, 0x8F, 0x1A, 0xA5, 0xB5, 0x8D, 0xB0, 0x58, 0xA3, 0x5D, 0xB1, 0x2F, 0x23, 0x2C,
+ 0xE5, 0xD8, 0x92, 0x7F, 0x48, 0xAB, 0xC0, 0x1C, 0x39, 0xC3, 0x39, 0x05, 0x0C, 0x26, 0x43, 0x49,
+ 0x4E, 0xD2, 0xE6, 0x72, 0x76, 0x9D, 0x4A, 0x8E, 0x52, 0x49, 0x3A, 0xB3, 0x51, 0x52, 0x72, 0xD7,
+ 0x45, 0x15, 0x14, 0x94, 0x7D, 0xD4, 0x91, 0xF5, 0xB8, 0x3E, 0x1B, 0xCA, 0xE9, 0xE1, 0xEA, 0xC2,
+ 0x58, 0x5F, 0x67, 0x51, 0x72, 0x27, 0x24, 0xE5, 0x79, 0x3B, 0xEA, 0xD4, 0xBA, 0xC5, 0xBB, 0x3B,
+ 0x74, 0xD1, 0x5D, 0x6A, 0x72, 0xFE, 0x2D, 0x5B, 0xAF, 0x18, 0xDB, 0x5C, 0x26, 0xB7, 0x70, 0x2E,
+ 0x65, 0x11, 0x18, 0xE2, 0x9E, 0x48, 0x55, 0x7C, 0xA2, 0xC3, 0x00, 0xAC, 0x6B, 0xD4, 0x1E, 0x0B,
+ 0x0C, 0xF2, 0x14, 0x7C, 0xC7, 0x68, 0x0D, 0xE6, 0xE0, 0xA1, 0x98, 0x60, 0x67, 0x2A, 0xF8, 0x48,
+ 0xA8, 0x41, 0x24, 0x9A, 0x4A, 0x31, 0x56, 0x4B, 0xAB, 0x49, 0xB5, 0xDD, 0x5F, 0x4B, 0x3D, 0xA2,
+ 0xDE, 0x9E, 0xA6, 0x03, 0x0F, 0x85, 0xC0, 0x53, 0x78, 0x6A, 0x10, 0x5E, 0xCE, 0x57, 0xE6, 0x8D,
+ 0xDD, 0x9D, 0xF7, 0x57, 0xD1, 0xAF, 0x2E, 0xCD, 0xDD, 0x59, 0xBD, 0x35, 0x7E, 0x1D, 0x58, 0xF8,
+ 0xC5, 0x2C, 0x2C, 0xB4, 0x2F, 0x0F, 0xDD, 0xDC, 0x6A, 0x9A, 0xF4, 0xF7, 0x51, 0xE9, 0x3F, 0x65,
+ 0xD1, 0xA3, 0x92, 0xE7, 0x53, 0xBA, 0x62, 0x42, 0xDB, 0xC8, 0xA0, 0x80, 0x3E, 0x52, 0xB1, 0xC4,
+ 0x4E, 0x31, 0x80, 0xBC, 0x0C, 0x1D, 0xDE, 0x4E, 0x77, 0x8A, 0xA3, 0x8D, 0x6F, 0x13, 0x8D, 0xA6,
+ 0x92, 0x8F, 0xBB, 0x35, 0x6B, 0x4F, 0x91, 0xB4, 0xD3, 0x5E, 0xF5, 0x92, 0xE6, 0xD1, 0x7B, 0xAE,
+ 0xCD, 0xBB, 0xBB, 0x34, 0x71, 0xE3, 0x30, 0x79, 0x3E, 0x0F, 0x91, 0x72, 0xB8, 0xE1, 0xE0, 0xAF,
+ 0x1E, 0x76, 0xAC, 0x92, 0x4D, 0xB8, 0xBB, 0x6D, 0x7D, 0x64, 0xFA, 0xDF, 0x4D, 0x9D, 0x97, 0x55,
+ 0xE2, 0x26, 0xF8, 0x31, 0xF0, 0x36, 0x69, 0x65, 0xF8, 0xAA, 0xFA, 0x0F, 0xC4, 0x0F, 0x8A, 0x56,
+ 0x11, 0x08, 0x93, 0xC0, 0x3A, 0x4E, 0xBC, 0x66, 0xF0, 0x7F, 0x86, 0x67, 0x2A, 0x59, 0x9F, 0xC4,
+ 0x1A, 0x84, 0x33, 0xB3, 0x5D, 0x4C, 0x0E, 0xDC, 0xDA, 0xDA, 0xB4, 0x67, 0x3B, 0x43, 0xCC, 0xA4,
+ 0x61, 0x70, 0xC2, 0x70, 0xFF, 0x00, 0x1A, 0x71, 0x64, 0xA9, 0x43, 0x09, 0x87, 0x73, 0xA3, 0xAF,
+ 0x23, 0xB3, 0x8C, 0x54, 0x5D, 0x92, 0x72, 0xE6, 0x56, 0x8C, 0x6C, 0xEF, 0xAA, 0x9A, 0x6F, 0xDE,
+ 0x8C, 0x1A, 0x69, 0xBE, 0x4F, 0xED, 0x3A, 0xB5, 0xB0, 0xDC, 0xF4, 0x71, 0x0B, 0x0B, 0x81, 0x6F,
+ 0xF8, 0x93, 0xE5, 0x8C, 0xA6, 0x96, 0x96, 0xA5, 0x16, 0x97, 0x2A, 0xDD, 0x29, 0x34, 0xF4, 0xBF,
+ 0x2A, 0x6F, 0x43, 0xE5, 0xFF, 0x00, 0x88, 0x7F, 0xB5, 0x27, 0x89, 0xBC, 0x7D, 0x77, 0x65, 0x34,
+ 0xE9, 0xA3, 0x6A, 0x5A, 0x26, 0x9D, 0x1C, 0x92, 0xE9, 0x3E, 0x15, 0x69, 0xAC, 0xFC, 0x33, 0xE0,
+ 0x9D, 0x0D, 0x11, 0x76, 0x91, 0xA6, 0xE9, 0x7B, 0xC4, 0x36, 0xEE, 0x16, 0x38, 0xD5, 0x58, 0x46,
+ 0x5D, 0xC2, 0xFC, 0xC5, 0x8B, 0x02, 0x7E, 0xBF, 0x28, 0xF0, 0xBF, 0x13, 0x87, 0xA9, 0x4F, 0x11,
+ 0x98, 0x42, 0x1E, 0xC6, 0x17, 0x5C, 0xAA, 0x2D, 0xB5, 0xA6, 0xB2, 0xE6, 0x4F, 0x9A, 0xFE, 0xF2,
+ 0xB7, 0x3B, 0x94, 0x79, 0xAE, 0xD2, 0x5B, 0x2F, 0x9A, 0xC6, 0x71, 0xBF, 0x0D, 0x64, 0xB8, 0x79,
+ 0xE1, 0xB2, 0x58, 0x54, 0xAB, 0x89, 0x96, 0xF5, 0x2C, 0xFC, 0x9B, 0xE6, 0x95, 0x9C, 0xE4, 0x9F,
+ 0x44, 0x94, 0x15, 0xEC, 0xA2, 0xED, 0x1D, 0x3E, 0x6D, 0x4F, 0x1D, 0xF8, 0xF7, 0x46, 0xDF, 0x7F,
+ 0xA6, 0xF9, 0xBE, 0x75, 0xF2, 0x43, 0xA9, 0xC5, 0x79, 0x65, 0x2B, 0x4C, 0x96, 0xB6, 0xC0, 0x32,
+ 0xAC, 0x73, 0x24, 0x0D, 0xB7, 0x71, 0xE3, 0x21, 0xC9, 0x6E, 0x14, 0x10, 0x2B, 0xDF, 0x7C, 0x17,
+ 0x95, 0x52, 0xCB, 0x55, 0x18, 0xE1, 0xD4, 0xF9, 0x64, 0x9B, 0xE7, 0xB4, 0xA4, 0xA3, 0xBA, 0x57,
+ 0x85, 0x9B, 0x4B, 0x65, 0x18, 0xEF, 0xB7, 0x45, 0x6F, 0xCC, 0xF8, 0x8F, 0x3F, 0xC7, 0xF1, 0x6D,
+ 0x7A, 0x5F, 0xDB, 0xB8, 0xA4, 0xA3, 0x0B, 0xA8, 0xC2, 0x16, 0x84, 0x13, 0x49, 0x5F, 0x92, 0x2D,
+ 0xDA, 0xCA, 0xEE, 0xF7, 0x4E, 0x49, 0xBD, 0xED, 0xA3, 0xD3, 0xB8, 0xF8, 0x9B, 0xE3, 0xAD, 0x7A,
+ 0x0F, 0xB4, 0x78, 0x9B, 0xC3, 0x3E, 0x18, 0xD7, 0xB4, 0xF9, 0x40, 0xBB, 0x4B, 0x7F, 0x13, 0xC1,
+ 0x71, 0xA6, 0x69, 0xB7, 0xB1, 0x44, 0xE0, 0x14, 0x46, 0x5B, 0x98, 0x1E, 0x40, 0x19, 0x63, 0x18,
+ 0x49, 0x32, 0x30, 0x07, 0x7C, 0x57, 0x87, 0x5F, 0x87, 0x30, 0x38, 0x0C, 0x3C, 0x71, 0x34, 0x63,
+ 0x28, 0x7B, 0xCE, 0xEA, 0x29, 0xD9, 0x37, 0x6B, 0xF3, 0x26, 0x9C, 0xA2, 0x96, 0xBB, 0xC9, 0x2E,
+ 0x8D, 0x59, 0x34, 0x7C, 0x55, 0x3E, 0x1E, 0xC9, 0xBF, 0xB5, 0xFE, 0xB9, 0x84, 0xC5, 0x4E, 0x35,
+ 0xE3, 0x74, 0xF9, 0x25, 0x07, 0xCB, 0x75, 0x64, 0x9A, 0xE4, 0x6A, 0x29, 0x26, 0xEC, 0x9A, 0x49,
+ 0xEE, 0xEF, 0x66, 0x7A, 0x17, 0xC1, 0xAF, 0x89, 0x76, 0xDE, 0x0E, 0xBD, 0x9D, 0xF5, 0x3F, 0x0B,
+ 0xEA, 0x36, 0x76, 0x77, 0x17, 0x73, 0x4E, 0x90, 0xF8, 0x4A, 0x16, 0xD5, 0xB4, 0xDB, 0x48, 0xCB,
+ 0x99, 0x4A, 0x45, 0x08, 0x91, 0xE5, 0xF2, 0x91, 0x49, 0xC3, 0x16, 0x7C, 0x2A, 0x8F, 0x9F, 0x38,
+ 0xAF, 0x92, 0xE2, 0x0C, 0xA2, 0xA6, 0x3B, 0x08, 0xA5, 0x46, 0x50, 0x4E, 0xDC, 0xBE, 0xF3, 0x51,
+ 0x6E, 0xE9, 0x24, 0xAE, 0xD2, 0x4D, 0x5B, 0x5B, 0x5B, 0x7D, 0x34, 0x57, 0xB7, 0x3E, 0x2F, 0x27,
+ 0x9C, 0xF3, 0xB8, 0xE6, 0x18, 0x4C, 0x44, 0x65, 0x15, 0x1E, 0x49, 0x46, 0x52, 0x51, 0x9F, 0x32,
+ 0x4A, 0xD2, 0x7B, 0x29, 0x2B, 0xC7, 0x56, 0xAD, 0x66, 0xF4, 0x5D, 0x0F, 0xAD, 0xB4, 0x6F, 0xDA,
+ 0x1F, 0xE0, 0xE6, 0xA6, 0xA8, 0x57, 0xC6, 0x76, 0x16, 0x24, 0xC6, 0x18, 0x47, 0xAB, 0x23, 0xE9,
+ 0xC5, 0x01, 0xE8, 0x18, 0xB8, 0x03, 0x23, 0x03, 0x80, 0x4F, 0x6E, 0xD5, 0xF9, 0x1E, 0x6F, 0xC3,
+ 0x39, 0xD6, 0x1A, 0x8C, 0xB0, 0xEB, 0x0B, 0x68, 0xED, 0xEE, 0x24, 0xDE, 0xCB, 0x66, 0xB5, 0xB6,
+ 0x8A, 0xCF, 0xA3, 0xED, 0x64, 0x7B, 0xD0, 0xC3, 0xE2, 0x69, 0xB5, 0x1F, 0x66, 0xFB, 0x6C, 0xDE,
+ 0xB6, 0xD3, 0x6E, 0x8B, 0xBE, 0x8B, 0xA7, 0x4B, 0x1E, 0x9B, 0xA6, 0x78, 0xD3, 0xC1, 0x9A, 0xB2,
+ 0x07, 0xD3, 0x7C, 0x55, 0xE1, 0xEB, 0xD4, 0x61, 0x94, 0xFB, 0x36, 0xB1, 0x6E, 0xFC, 0x63, 0x8E,
+ 0x37, 0x7A, 0x02, 0x78, 0xF4, 0x3E, 0x95, 0xF9, 0xEE, 0x27, 0x2F, 0xC4, 0x61, 0xDA, 0x85, 0x4A,
+ 0x32, 0x8B, 0xBB, 0x5A, 0xC5, 0xAD, 0xBA, 0x3B, 0xA5, 0x6B, 0x5E, 0xDB, 0x5B, 0xA5, 0xDB, 0x45,
+ 0x29, 0x34, 0xD5, 0xB6, 0xDB, 0xCA, 0xFA, 0x5D, 0x2E, 0x9A, 0x5D, 0x2B, 0x74, 0x3E, 0x74, 0xFD,
+ 0xA6, 0x2C, 0xA6, 0xD5, 0xFC, 0x35, 0x77, 0x0E, 0x95, 0x17, 0xDB, 0x9E, 0x4D, 0x3E, 0x6B, 0x7C,
+ 0x59, 0xED, 0x98, 0xEE, 0x64, 0x01, 0x50, 0x10, 0x71, 0x92, 0x09, 0xFC, 0x05, 0x7B, 0x5C, 0x39,
+ 0x4E, 0x95, 0x4A, 0x55, 0x28, 0x4E, 0x56, 0x8E, 0x8D, 0xDB, 0x47, 0x65, 0x34, 0xAF, 0xDB, 0x45,
+ 0xE4, 0xF5, 0x69, 0x5B, 0xBF, 0xC8, 0xE6, 0xB5, 0x69, 0xE1, 0x78, 0x87, 0x2E, 0xC6, 0x57, 0x6A,
+ 0x34, 0xA1, 0x3F, 0x7A, 0x4F, 0xE1, 0x5F, 0x0D, 0xAF, 0xFF, 0x00, 0x80, 0xB4, 0xB6, 0xD5, 0x59,
+ 0x1A, 0x3F, 0xB2, 0xAD, 0xAE, 0xA6, 0x90, 0x68, 0x57, 0x1A, 0x9A, 0xEA, 0x3A, 0x66, 0xA1, 0x26,
+ 0x8B, 0x3D, 0xB6, 0xA5, 0xF6, 0xC8, 0xD8, 0xC5, 0x10, 0x89, 0x59, 0x60, 0x48, 0x94, 0xE7, 0x1B,
+ 0x80, 0x07, 0x04, 0x91, 0xF3, 0x37, 0xDD, 0x00, 0x01, 0xF6, 0xBC, 0x47, 0x1A, 0x78, 0xE7, 0x96,
+ 0xD6, 0xAD, 0x35, 0xCD, 0x52, 0x85, 0x5A, 0x72, 0x6A, 0x2D, 0x5B, 0xD9, 0xC7, 0x96, 0x0A, 0xCA,
+ 0xDA, 0xDA, 0x36, 0xE6, 0x5A, 0x3B, 0x27, 0x6D, 0x8C, 0xE9, 0xD6, 0xA1, 0x89, 0xE2, 0x4C, 0x5D,
+ 0x7C, 0x03, 0xF6, 0x94, 0x57, 0x24, 0x53, 0x4D, 0x38, 0xB5, 0x78, 0xD9, 0x26, 0xF5, 0xF7, 0x52,
+ 0x69, 0xDB, 0x45, 0x65, 0x6B, 0xDF, 0x5F, 0xAB, 0xC8, 0x02, 0x37, 0xDB, 0x1A, 0xAF, 0xEE, 0xFE,
+ 0xE9, 0x1B, 0x70, 0xA4, 0x02, 0x54, 0xFA, 0x77, 0xFE, 0x7C, 0xF4, 0xAF, 0xE6, 0xDF, 0x66, 0xF0,
+ 0xEA, 0x71, 0xE5, 0x4D, 0xA4, 0xE2, 0xD3, 0x57, 0xB6, 0xEA, 0xE9, 0x74, 0x6A, 0xD6, 0x4E, 0xEB,
+ 0xB2, 0x56, 0x3F, 0x43, 0x71, 0xBC, 0x54, 0x62, 0xAD, 0xA6, 0xDA, 0x2B, 0xDB, 0xA7, 0xA5, 0xBB,
+ 0x5A, 0xD6, 0x3E, 0x48, 0xF8, 0x83, 0xE1, 0xFD, 0x66, 0xC3, 0xC4, 0x77, 0x5A, 0xE5, 0xD7, 0x86,
+ 0x2F, 0x35, 0x8F, 0x0F, 0xE9, 0xF6, 0xD7, 0x71, 0xDB, 0x8D, 0x32, 0x13, 0x34, 0xD6, 0xD7, 0x17,
+ 0xAB, 0x12, 0xC2, 0xEC, 0x41, 0x19, 0x00, 0xC0, 0xC3, 0x68, 0xC7, 0xDE, 0x18, 0xCE, 0x7E, 0x5F,
+ 0xE8, 0x9E, 0x1E, 0x58, 0x6C, 0x45, 0x2C, 0x3E, 0x4B, 0x83, 0xA9, 0x19, 0x37, 0x39, 0x53, 0x9F,
+ 0x25, 0xEC, 0x94, 0xA9, 0xAB, 0x5B, 0x54, 0x95, 0xD2, 0xB2, 0x6F, 0x9A, 0xF2, 0xBA, 0x71, 0xB6,
+ 0xDF, 0x9D, 0x73, 0xBC, 0xBB, 0x15, 0x8D, 0xA5, 0x98, 0x47, 0x96, 0x95, 0x5B, 0x38, 0xC9, 0xC5,
+ 0x38, 0xC9, 0x34, 0xA3, 0x28, 0xC9, 0x36, 0x92, 0x4E, 0xC9, 0x5E, 0x36, 0x69, 0x75, 0x5A, 0xA3,
+ 0xB3, 0xF8, 0x73, 0xF1, 0x76, 0xDE, 0x6B, 0x2D, 0x3B, 0x47, 0xBD, 0xF0, 0xEE, 0xB9, 0x6B, 0x7D,
+ 0x0C, 0x7E, 0x40, 0x7F, 0xEC, 0xD7, 0x8E, 0x30, 0x14, 0x63, 0x24, 0x63, 0x8C, 0x60, 0xF0, 0x38,
+ 0x03, 0x1C, 0xE0, 0xE4, 0xFE, 0x4B, 0x99, 0x70, 0xF3, 0xF6, 0xB5, 0x31, 0x74, 0x6A, 0x2B, 0x36,
+ 0xDB, 0x4F, 0x46, 0xAC, 0xDE, 0x8A, 0xD6, 0xD3, 0x45, 0x7B, 0x2E, 0xB6, 0xB6, 0x8A, 0xDE, 0x96,
+ 0x47, 0xC4, 0x94, 0xF0, 0xF4, 0xA8, 0xE5, 0x53, 0xA5, 0x76, 0x94, 0x62, 0xA5, 0x06, 0xA5, 0x16,
+ 0x92, 0x49, 0x3B, 0x2F, 0x79, 0x69, 0xBD, 0xD5, 0x96, 0xB7, 0x7A, 0x59, 0x7D, 0x27, 0x04, 0xBF,
+ 0x69, 0x84, 0xB0, 0x05, 0x15, 0xE1, 0x66, 0x11, 0x72, 0xAC, 0x00, 0x4E, 0x14, 0xE7, 0xF9, 0x74,
+ 0xFC, 0x2B, 0xE4, 0x28, 0x50, 0xF6, 0x78, 0xB8, 0x53, 0x8B, 0x69, 0xF4, 0x6A, 0xCB, 0x64, 0xEC,
+ 0xD5, 0x9E, 0x8A, 0xEB, 0x74, 0xD3, 0xB6, 0xCA, 0xFA, 0x1F, 0x6F, 0x15, 0x17, 0x18, 0xCA, 0x31,
+ 0xB7, 0x4F, 0xBB, 0xF2, 0xB7, 0x97, 0x96, 0x87, 0xC0, 0xBF, 0x17, 0xFC, 0x0B, 0xF1, 0x0A, 0xD3,
+ 0xE2, 0x9F, 0x85, 0x7C, 0x67, 0xE1, 0xAF, 0x0F, 0x6A, 0xDA, 0xE4, 0x7A, 0x6E, 0xA6, 0x5A, 0x38,
+ 0xF4, 0x39, 0x36, 0x6A, 0xA7, 0x78, 0x0A, 0x86, 0x06, 0xC8, 0x01, 0xF8, 0x18, 0x24, 0x8E, 0x71,
+ 0xD3, 0x3C, 0x7E, 0x99, 0x91, 0xE7, 0x15, 0x31, 0x58, 0x0A, 0x58, 0x5F, 0x6F, 0x2B, 0xAE, 0x58,
+ 0xF2, 0xA9, 0xB5, 0xAA, 0x92, 0xE5, 0x51, 0x57, 0xB5, 0xD6, 0xF1, 0xB2, 0xD3, 0x74, 0xB6, 0xBF,
+ 0xC4, 0xBC, 0x1C, 0xF0, 0xB5, 0xF1, 0xF8, 0x4C, 0x42, 0x95, 0x35, 0x5D, 0xC2, 0x54, 0xE7, 0x18,
+ 0xB7, 0x14, 0xE2, 0xD6, 0x92, 0xE5, 0x8C, 0x9C, 0x5E, 0x8B, 0x5E, 0x56, 0xAD, 0x6D, 0xED, 0x63,
+ 0xEA, 0x0F, 0x04, 0xFC, 0x4F, 0xD5, 0xF5, 0x99, 0x46, 0x91, 0xA9, 0x78, 0x4F, 0xC5, 0xDA, 0x45,
+ 0xEC, 0x44, 0x25, 0xD4, 0xBA, 0xBD, 0xBB, 0xA2, 0x17, 0x18, 0x0D, 0xE6, 0xC9, 0x9E, 0x4F, 0x4C,
+ 0x91, 0x9E, 0xE6, 0xBE, 0x5F, 0x3B, 0xC2, 0xE2, 0xE9, 0x7B, 0x5C, 0x55, 0x3C, 0x54, 0xB9, 0x2E,
+ 0xEF, 0x19, 0x4D, 0xDF, 0x4E, 0x8F, 0x65, 0xA7, 0x45, 0xDE, 0xD6, 0x47, 0xA5, 0x94, 0xE7, 0x2E,
+ 0x73, 0x86, 0x06, 0xA6, 0x19, 0xDD, 0x2B, 0x29, 0x47, 0xE0, 0xB2, 0xD1, 0x5A, 0xE9, 0x35, 0xB5,
+ 0x92, 0xB3, 0x56, 0x56, 0x5D, 0x2D, 0xF3, 0xE7, 0xED, 0x98, 0x65, 0x9B, 0xC2, 0x03, 0x60, 0x95,
+ 0x9C, 0xC4, 0x80, 0x2C, 0x4C, 0x01, 0x04, 0x4C, 0x80, 0x31, 0xF6, 0xE0, 0x75, 0xE9, 0x81, 0xE9,
+ 0xC7, 0xA5, 0xC2, 0x50, 0xC6, 0xCA, 0x85, 0x68, 0x52, 0xE7, 0x6E, 0xC9, 0xA4, 0xA6, 0xA3, 0xB2,
+ 0x76, 0x7D, 0x92, 0x4A, 0xFA, 0x6E, 0xD5, 0xEC, 0xD1, 0xB6, 0x2D, 0xC2, 0x97, 0x15, 0xE5, 0xB2,
+ 0x6D, 0x24, 0x9D, 0x4D, 0x5A, 0xD7, 0xE0, 0xBF, 0x4B, 0x59, 0xF4, 0xB7, 0xC8, 0x8B, 0xE0, 0x84,
+ 0xBF, 0x15, 0x3C, 0x09, 0xF0, 0xF2, 0xDA, 0xE1, 0x3C, 0x2B, 0x7D, 0xE3, 0x5D, 0x16, 0x38, 0x92,
+ 0x38, 0xA6, 0xD3, 0xAF, 0x62, 0x1F, 0x64, 0xC8, 0xF9, 0x36, 0xC5, 0xB7, 0x2C, 0xA0, 0x29, 0x5F,
+ 0xBC, 0x39, 0x15, 0xE9, 0x66, 0xB9, 0x76, 0x57, 0x8B, 0xCA, 0x69, 0xD6, 0xC7, 0x42, 0x71, 0xC6,
+ 0x59, 0xFE, 0xF1, 0x4E, 0x3C, 0x96, 0x56, 0xDE, 0x0E, 0x2B, 0x65, 0xE7, 0xAD, 0xD7, 0x44, 0x93,
+ 0xF1, 0xB0, 0xB9, 0xA4, 0xFE, 0xB9, 0x88, 0xC6, 0xE5, 0x18, 0x79, 0xAA, 0x33, 0x93, 0x76, 0x6B,
+ 0xDD, 0xE6, 0x4E, 0xD2, 0x6B, 0x95, 0x39, 0x45, 0x3B, 0x6A, 0xB9, 0x5A, 0xD3, 0x4B, 0x58, 0xFB,
+ 0xF7, 0xF6, 0x7B, 0xFF, 0x00, 0x82, 0x99, 0x7C, 0x68, 0xFD, 0x9D, 0xD0, 0xF8, 0x5B, 0x4A, 0xF8,
+ 0x29, 0xE2, 0x0F, 0x89, 0xDF, 0x0B, 0xB5, 0x9B, 0x81, 0x27, 0x89, 0x7E, 0x0E, 0xFC, 0x44, 0xD3,
+ 0x23, 0xD5, 0xFC, 0x19, 0x20, 0x72, 0x56, 0x5B, 0xCD, 0x1E, 0x47, 0x24, 0xE9, 0x1A, 0x88, 0x49,
+ 0x1C, 0x2D, 0xDD, 0xB0, 0x07, 0x3C, 0x48, 0xB2, 0xA1, 0x68, 0xCF, 0xCB, 0xAC, 0x8F, 0x04, 0xA8,
+ 0xC6, 0x70, 0xC5, 0x24, 0xD6, 0xFA, 0xAD, 0x5E, 0xEA, 0xCA, 0xFA, 0x6F, 0x67, 0x6F, 0x55, 0xAA,
+ 0x4C, 0xF5, 0x28, 0xF1, 0x26, 0x26, 0xA3, 0x8A, 0x8D, 0x15, 0x1D, 0x52, 0x77, 0x75, 0x1B, 0xB7,
+ 0x5B, 0x25, 0x4A, 0xFA, 0x2B, 0xD9, 0x3B, 0x2D, 0x76, 0xE8, 0x59, 0xFD, 0xA4, 0x7F, 0x63, 0x2B,
+ 0xBF, 0xDA, 0x67, 0x5C, 0x5F, 0xDB, 0x27, 0xE0, 0x97, 0x8E, 0xBC, 0x4F, 0xF1, 0x1B, 0xE0, 0x8D,
+ 0x94, 0x56, 0xDA, 0xA7, 0x8F, 0xFE, 0x13, 0x78, 0xCF, 0x4B, 0xB5, 0xB1, 0xF8, 0xFF, 0x00, 0xF0,
+ 0x02, 0xFD, 0x90, 0x2A, 0xDB, 0x78, 0x8B, 0x4C, 0xB4, 0x2F, 0x0D, 0xCE, 0x97, 0x1E, 0x76, 0x41,
+ 0xA8, 0xDB, 0x13, 0x09, 0x1C, 0x39, 0x56, 0x47, 0xDB, 0x78, 0x6C, 0xF6, 0x78, 0x3C, 0x35, 0x4C,
+ 0x3C, 0xDA, 0x73, 0xDA, 0xF1, 0x77, 0x4E, 0xC9, 0x6A, 0xF7, 0xEC, 0xAC, 0x95, 0x92, 0x4B, 0x54,
+ 0x74, 0x63, 0x72, 0xB7, 0x8C, 0x55, 0x6B, 0x60, 0xE4, 0xEF, 0x5F, 0xDC, 0x9C, 0xE5, 0xA4, 0xA3,
+ 0x49, 0x6B, 0xEC, 0xE9, 0xC1, 0x45, 0x38, 0xA7, 0xD5, 0xCD, 0x26, 0xF5, 0x5A, 0xB5, 0xAF, 0x1F,
+ 0xA2, 0x6A, 0xFA, 0xCF, 0x84, 0x96, 0xD6, 0xE3, 0xC2, 0x57, 0xF3, 0x69, 0xD7, 0xD6, 0xD6, 0xBE,
+ 0x55, 0xAB, 0xD9, 0xCF, 0xE4, 0xC7, 0x32, 0xAA, 0xFC, 0xB0, 0xC8, 0xA3, 0xE5, 0x92, 0x36, 0xF9,
+ 0x41, 0x56, 0x52, 0xA4, 0x71, 0x8E, 0x95, 0xE7, 0x70, 0xD5, 0x0C, 0x3E, 0x65, 0xC4, 0x38, 0x4C,
+ 0x36, 0x3E, 0x6D, 0x52, 0xA9, 0x34, 0xA6, 0xE2, 0xD2, 0x92, 0x56, 0x6D, 0x34, 0xDA, 0x69, 0x6A,
+ 0x96, 0x8D, 0x35, 0xE4, 0xFA, 0x76, 0xD7, 0xE7, 0xC2, 0x60, 0x65, 0x0C, 0x22, 0x57, 0x51, 0x69,
+ 0x2D, 0x52, 0xD1, 0x59, 0x27, 0x6E, 0x9D, 0xF7, 0xD3, 0x4D, 0x3A, 0xE2, 0xF8, 0x47, 0xC6, 0x1A,
+ 0xCF, 0xC5, 0x2D, 0x7B, 0x58, 0x8B, 0xE2, 0x6F, 0x86, 0x74, 0xBF, 0x85, 0x9E, 0x23, 0x9A, 0xE9,
+ 0xCE, 0x9F, 0xE2, 0xAD, 0x0E, 0x08, 0xA1, 0xF8, 0x7B, 0xE2, 0x1C, 0x63, 0x0D, 0xA8, 0xD8, 0xAB,
+ 0x19, 0x74, 0xF9, 0x49, 0x0A, 0x77, 0xC0, 0xAF, 0x11, 0x38, 0x26, 0x35, 0xC9, 0xC6, 0xF9, 0xDB,
+ 0xC1, 0x62, 0x71, 0xF8, 0x8C, 0x5A, 0xA9, 0x16, 0xE5, 0x26, 0xD5, 0xB9, 0xAF, 0xDB, 0x64, 0xAD,
+ 0x6B, 0x59, 0x2D, 0x13, 0xB6, 0xBA, 0xEE, 0x73, 0x65, 0xD3, 0xF6, 0x98, 0x3A, 0x14, 0xF1, 0x34,
+ 0xE5, 0x0A, 0xEA, 0x36, 0x9B, 0x71, 0x8A, 0xA7, 0x74, 0x92, 0x4A, 0x2D, 0xC9, 0xEE, 0xF6, 0x7A,
+ 0x2D, 0x36, 0x49, 0x24, 0x78, 0x47, 0xC6, 0x1F, 0x84, 0xBE, 0x3F, 0xD4, 0x3E, 0x26, 0x78, 0x6E,
+ 0xC3, 0xC4, 0xBA, 0x23, 0xD8, 0x78, 0x4F, 0x41, 0x74, 0xD4, 0xA2, 0xBB, 0x92, 0xE2, 0x39, 0xF4,
+ 0xFD, 0x68, 0xA8, 0x06, 0x19, 0x6D, 0x1D, 0x09, 0x49, 0x62, 0x3B, 0xB7, 0x6E, 0x53, 0x83, 0xC7,
+ 0x4E, 0x95, 0xB6, 0x0A, 0xBE, 0x1F, 0x03, 0x81, 0xF6, 0x71, 0x92, 0xE7, 0x7A, 0xF6, 0x77, 0x5A,
+ 0x47, 0xB2, 0xB2, 0xD5, 0xDD, 0x3B, 0x69, 0x66, 0xBB, 0x78, 0xD9, 0x8E, 0x0F, 0x19, 0x5F, 0x1F,
+ 0x38, 0xBA, 0x6E, 0x31, 0x92, 0x54, 0xD4, 0xB4, 0xE5, 0x50, 0x6D, 0x39, 0xB8, 0xB4, 0xEF, 0xCD,
+ 0x24, 0x94, 0x57, 0x96, 0xBB, 0x1D, 0xED, 0xFA, 0x4F, 0x06, 0x9F, 0x34, 0x7A, 0x75, 0xB2, 0xCD,
+ 0x70, 0x90, 0x18, 0x2D, 0x60, 0x52, 0x22, 0x46, 0x21, 0x02, 0xA2, 0x92, 0x70, 0x3A, 0x90, 0x39,
+ 0x03, 0xE8, 0x3A, 0x0E, 0x0C, 0x32, 0x84, 0xEB, 0x47, 0xDA, 0xBB, 0x46, 0xEA, 0xEE, 0xDD, 0x34,
+ 0xDB, 0xE5, 0xD3, 0xC9, 0x74, 0xB1, 0xE9, 0xE2, 0x63, 0x56, 0x8E, 0x0A, 0x4B, 0x09, 0x04, 0xE4,
+ 0xA3, 0x68, 0xC7, 0x44, 0x9B, 0x4A, 0xC9, 0x74, 0xF2, 0x5D, 0x2C, 0xBB, 0x5E, 0xC7, 0x95, 0xFC,
+ 0x1B, 0xF0, 0x3E, 0xAD, 0xE1, 0x79, 0xFC, 0x43, 0x7D, 0xAF, 0x08, 0x66, 0xD7, 0xFC, 0x4B, 0xA9,
+ 0x49, 0x7F, 0xAB, 0x5F, 0xD9, 0xDA, 0xC9, 0x74, 0xF6, 0x36, 0xAA, 0x00, 0x45, 0x52, 0xA3, 0x72,
+ 0x84, 0x50, 0xAA, 0xC4, 0x8C, 0x67, 0x92, 0x2B, 0xE9, 0x61, 0x8A, 0xA1, 0x5A, 0xAA, 0xA7, 0x29,
+ 0x28, 0xD2, 0x5A, 0xBD, 0x2E, 0xE2, 0x97, 0x58, 0xEC, 0xEC, 0x96, 0xB6, 0xD1, 0x5D, 0xB5, 0x7B,
+ 0x2D, 0x3C, 0x3A, 0x58, 0x79, 0xF2, 0xC7, 0x96, 0x0F, 0x96, 0x14, 0xD4, 0x20, 0x9D, 0xAF, 0xB7,
+ 0x34, 0xE5, 0x24, 0x97, 0xBA, 0xE5, 0x36, 0xDB, 0x49, 0xDB, 0x95, 0x45, 0x35, 0xA5, 0x9E, 0xDF,
+ 0x8F, 0xAF, 0x3C, 0x3B, 0xAA, 0x69, 0xFA, 0xDE, 0x99, 0x79, 0xAA, 0xDB, 0xDA, 0xE9, 0x77, 0x96,
+ 0xAF, 0x6F, 0x1C, 0x5A, 0xA6, 0xA9, 0x16, 0xE8, 0xD0, 0x26, 0x17, 0x71, 0x24, 0x0C, 0x02, 0xB9,
+ 0x00, 0x01, 0x80, 0x05, 0x72, 0xD6, 0xC7, 0xAA, 0xB8, 0xE5, 0x59, 0x37, 0xEC, 0xEF, 0xCB, 0x14,
+ 0xDD, 0xDA, 0x8D, 0xAD, 0x65, 0xBD, 0x9D, 0x9B, 0xD1, 0x5E, 0xD7, 0x7E, 0x64, 0xFB, 0x2A, 0xF2,
+ 0xA2, 0xE3, 0x06, 0xA3, 0x51, 0x59, 0xC5, 0xEA, 0x94, 0x65, 0x16, 0xA5, 0x16, 0xBA, 0xA4, 0xA4,
+ 0x97, 0x4D, 0xFA, 0x1F, 0x22, 0x7C, 0x37, 0xF1, 0x0D, 0xAF, 0xC3, 0x3F, 0x14, 0x6A, 0xBE, 0x28,
+ 0xF1, 0xEF, 0xC5, 0x6D, 0x0F, 0x5A, 0xD6, 0x2D, 0x74, 0xC5, 0xF0, 0xEF, 0x86, 0x6E, 0x57, 0x5D,
+ 0x3E, 0x21, 0xBE, 0xB0, 0xD3, 0xA3, 0x66, 0x0B, 0x02, 0xAB, 0x83, 0xB5, 0x02, 0xC8, 0x42, 0xA8,
+ 0xC8, 0x1C, 0xE0, 0x8C, 0x71, 0xE7, 0xD3, 0xC4, 0x61, 0x30, 0x94, 0x65, 0x4A, 0xAE, 0x26, 0x1C,
+ 0xAE, 0x5E, 0xED, 0xF9, 0x63, 0xCB, 0x0B, 0x5F, 0x95, 0xDE, 0xD7, 0x6B, 0x4D, 0x77, 0xB2, 0x8F,
+ 0x56, 0xAF, 0xEE, 0x66, 0x58, 0xAC, 0xD7, 0x3D, 0xC4, 0x61, 0x6A, 0xE0, 0x70, 0x95, 0x22, 0xA0,
+ 0xA5, 0x29, 0xB7, 0x1E, 0x64, 0xEA, 0xCA, 0x2A, 0x37, 0x8B, 0x57, 0x8D, 0x94, 0x6E, 0xB5, 0xB6,
+ 0xEA, 0xD1, 0xBE, 0xDE, 0x5B, 0xE2, 0x9F, 0x8A, 0x1E, 0x15, 0x1E, 0x2D, 0x49, 0xAC, 0x35, 0x6B,
+ 0x4D, 0x43, 0xC1, 0x51, 0xEB, 0xEB, 0xE2, 0xD7, 0xD1, 0xEC, 0xF4, 0x04, 0x8F, 0x54, 0x9B, 0x52,
+ 0x8E, 0xDC, 0xC7, 0x14, 0x86, 0xE9, 0xA3, 0x0C, 0x63, 0x00, 0x8F, 0x94, 0xC9, 0x81, 0xB4, 0x71,
+ 0x93, 0x91, 0xE7, 0x57, 0xCF, 0xB2, 0x78, 0x66, 0x10, 0xC6, 0x4B, 0x11, 0xCD, 0x05, 0x18, 0xDE,
+ 0x0A, 0x32, 0x77, 0x94, 0x53, 0x51, 0x6B, 0x68, 0xE9, 0xD6, 0xFA, 0xA6, 0x93, 0x8A, 0x56, 0x3A,
+ 0x70, 0x99, 0x27, 0x10, 0xD6, 0xE1, 0x8A, 0xD9, 0x1C, 0x30, 0xCE, 0x9D, 0x59, 0x73, 0x42, 0x33,
+ 0x9C, 0xA3, 0x65, 0x4A, 0x52, 0x52, 0x94, 0x74, 0x6E, 0x49, 0xEE, 0x92, 0x4A, 0xCD, 0x6E, 0xB4,
+ 0x45, 0xCF, 0x1B, 0xFE, 0xD4, 0xEB, 0xE2, 0xA3, 0x78, 0x8B, 0xF0, 0xF3, 0xC2, 0xD7, 0x76, 0x77,
+ 0x1A, 0x3A, 0xE8, 0xF0, 0x69, 0xDA, 0xAD, 0xAC, 0xB6, 0xDA, 0x3D, 0x88, 0x48, 0xD5, 0x52, 0xE6,
+ 0x1B, 0x4B, 0x69, 0x93, 0x6C, 0xC0, 0xA0, 0x70, 0x43, 0xED, 0xDF, 0x92, 0x54, 0xF4, 0x1C, 0x78,
+ 0xDE, 0x37, 0xC2, 0x3A, 0x12, 0xA1, 0x81, 0xC3, 0xB7, 0x76, 0x9B, 0xE7, 0x6A, 0xCD, 0xAE, 0xE9,
+ 0x5D, 0xCA, 0x3A, 0x27, 0x6B, 0xA6, 0xDF, 0x54, 0x75, 0xE4, 0xBE, 0x1F, 0x62, 0xB0, 0x99, 0x95,
+ 0x2C, 0xD3, 0x31, 0xC4, 0x43, 0x9A, 0x9C, 0x79, 0x63, 0x0A, 0x71, 0x6A, 0x31, 0xD2, 0xD7, 0x8D,
+ 0xEC, 0x93, 0xB6, 0xF7, 0x8B, 0x4D, 0x68, 0xD3, 0xDC, 0xF0, 0xA3, 0xF1, 0x13, 0x50, 0x6F, 0x04,
+ 0xDD, 0x78, 0x22, 0xEB, 0x45, 0xD0, 0x2E, 0xE0, 0xB9, 0xD6, 0x06, 0xB1, 0x3F, 0x88, 0x64, 0x7B,
+ 0xA3, 0xE2, 0x65, 0x73, 0x20, 0x66, 0x48, 0xA5, 0x17, 0x1E, 0x46, 0xD3, 0x82, 0x0E, 0x61, 0x73,
+ 0xCF, 0x5C, 0x81, 0x8F, 0x93, 0xC4, 0x71, 0x36, 0x61, 0x8D, 0xC2, 0x3C, 0x05, 0x4B, 0x2A, 0x53,
+ 0x94, 0xA6, 0xD4, 0x62, 0xE2, 0xFD, 0xE9, 0x73, 0x34, 0xDB, 0x6D, 0x59, 0x3D, 0xAE, 0xAF, 0x6B,
+ 0x2D, 0x52, 0x3E, 0xF6, 0x97, 0x0C, 0x65, 0xB8, 0x4C, 0xCA, 0x59, 0xBD, 0x38, 0x2F, 0x6F, 0x18,
+ 0x46, 0x9A, 0xB4, 0xE2, 0xE2, 0xA0, 0x95, 0x92, 0x8C, 0x56, 0x9B, 0x68, 0xDA, 0xBA, 0x5B, 0x69,
+ 0xD7, 0x6A, 0x5F, 0x89, 0xF6, 0x0B, 0xE2, 0x0F, 0x0F, 0x6A, 0xD6, 0x5E, 0x0A, 0xB3, 0x6D, 0x0B,
+ 0xC2, 0x9A, 0x6A, 0x59, 0x69, 0x3E, 0x16, 0xD6, 0x3C, 0x41, 0xAA, 0x6A, 0xFA, 0x47, 0xDA, 0x15,
+ 0x08, 0xFB, 0x6C, 0xAE, 0xD3, 0x89, 0x16, 0x52, 0x4A, 0x3E, 0xD8, 0x1A, 0x05, 0xDD, 0x1C, 0x78,
+ 0x5C, 0x29, 0x06, 0x16, 0x63, 0x4D, 0xD7, 0xA7, 0x56, 0x95, 0x38, 0x45, 0xC2, 0x36, 0xB6, 0xAA,
+ 0xFC, 0xAD, 0x5A, 0x57, 0x94, 0xA5, 0x79, 0xB4, 0x96, 0xB1, 0x50, 0x57, 0xD9, 0x69, 0xAE, 0x98,
+ 0x8C, 0x1B, 0xAB, 0xCD, 0x4E, 0x55, 0x5B, 0x72, 0x6E, 0xF7, 0xD1, 0xB8, 0xBD, 0x2D, 0xEE, 0xB8,
+ 0xBB, 0x25, 0x65, 0xAB, 0x93, 0xB6, 0x97, 0x30, 0x17, 0xC4, 0x3A, 0x4E, 0xA7, 0x63, 0x77, 0x79,
+ 0xAE, 0x68, 0x9A, 0x86, 0xA7, 0xE3, 0x1B, 0xDF, 0x12, 0xA6, 0xB9, 0x3F, 0x8B, 0x2F, 0xF5, 0xE9,
+ 0xAE, 0x60, 0xBB, 0xB4, 0x54, 0x22, 0x4B, 0x19, 0x6D, 0x1D, 0x0E, 0xF2, 0xD2, 0x95, 0x63, 0x31,
+ 0x94, 0xB6, 0x17, 0x6E, 0x39, 0xCD, 0x7D, 0x87, 0x0A, 0xE0, 0xF0, 0x79, 0xD5, 0x7C, 0x45, 0x7C,
+ 0x64, 0xA5, 0x49, 0x28, 0xF3, 0x54, 0x96, 0xEA, 0x51, 0x96, 0x8A, 0x31, 0xBA, 0x5C, 0xB1, 0xE6,
+ 0x49, 0x37, 0xAD, 0xA0, 0x9A, 0xBF, 0x6C, 0xAA, 0xC6, 0x74, 0x22, 0xA8, 0xD0, 0x71, 0xE5, 0x49,
+ 0x25, 0x1B, 0x7C, 0x2F, 0xBB, 0xB3, 0xED, 0xB2, 0xF4, 0x38, 0xFD, 0x56, 0xEE, 0xE3, 0x50, 0xBE,
+ 0xB8, 0xBC, 0xBB, 0x65, 0x33, 0xDC, 0x31, 0x96, 0x41, 0x1A, 0x04, 0x8D, 0x49, 0x3F, 0x2A, 0xAA,
+ 0xF6, 0x00, 0x60, 0x0E, 0xBC, 0x57, 0x8F, 0xC4, 0xB4, 0x2B, 0x51, 0xC4, 0x7D, 0x5F, 0x19, 0x52,
+ 0xF2, 0x84, 0x36, 0x5A, 0xD9, 0x26, 0xD4, 0x12, 0x57, 0x49, 0x45, 0x2B, 0x45, 0x36, 0xDB, 0x51,
+ 0xD5, 0x27, 0xD3, 0xAB, 0x0A, 0xA3, 0x1A, 0x71, 0x85, 0x3B, 0xD9, 0x24, 0x95, 0xDB, 0x7A, 0x24,
+ 0x95, 0xAE, 0xEE, 0xF4, 0x5A, 0x25, 0xB2, 0x49, 0x25, 0x64, 0x91, 0x99, 0x5F, 0x1E, 0x76, 0x8B,
+ 0xF2, 0xE0, 0x00, 0x31, 0x80, 0x07, 0x6C, 0x74, 0xEC, 0x31, 0xEC, 0x2B, 0x69, 0x3C, 0x37, 0xB2,
+ 0x4A, 0x9C, 0x64, 0xA7, 0xA6, 0xED, 0x34, 0xF4, 0xD6, 0xC9, 0x45, 0x35, 0xE5, 0xAB, 0xD3, 0x4E,
+ 0x84, 0x25, 0x24, 0xFA, 0x58, 0x9A, 0xDA, 0xDD, 0xA7, 0x75, 0x45, 0x1F, 0x2F, 0x00, 0xF4, 0x00,
+ 0x71, 0xC0, 0x1F, 0x95, 0x7D, 0x0F, 0x0A, 0xF0, 0xC6, 0x33, 0x89, 0x73, 0x0A, 0x78, 0x5C, 0x3C,
+ 0x3F, 0x77, 0x74, 0xA4, 0xF6, 0xE9, 0x7B, 0x27, 0x6B, 0x6C, 0xB5, 0xEC, 0xBE, 0x49, 0xE5, 0x5E,
+ 0xB4, 0x68, 0x43, 0x5D, 0xED, 0xA1, 0xE8, 0x1A, 0x6E, 0x9E, 0xB6, 0xF1, 0x20, 0x0B, 0x81, 0xB4,
+ 0x63, 0x20, 0x60, 0x71, 0xD7, 0x1F, 0xFD, 0x6A, 0xFF, 0x00, 0x4C, 0x3C, 0x2C, 0xF0, 0xDF, 0x0D,
+ 0xC3, 0xD9, 0x55, 0x0A, 0x74, 0xE1, 0x68, 0x59, 0x59, 0xCB, 0x55, 0x17, 0x64, 0xAF, 0xB2, 0x76,
+ 0x8F, 0x5D, 0x35, 0xEF, 0xD4, 0xF8, 0xDC, 0x66, 0x29, 0xD4, 0x93, 0xEF, 0xE4, 0x4F, 0xA9, 0xDC,
+ 0x9B, 0x68, 0x7C, 0xB4, 0x8B, 0x32, 0xE3, 0x0B, 0x81, 0xF2, 0x8C, 0x0E, 0x01, 0x1E, 0xF8, 0xAF,
+ 0x73, 0xC5, 0x5E, 0x2C, 0xAD, 0xC2, 0xF9, 0x27, 0xD4, 0x30, 0x98, 0x57, 0x2C, 0x63, 0x56, 0x8A,
+ 0x4B, 0xDD, 0x56, 0xDB, 0x9A, 0x37, 0x4D, 0xF3, 0xFD, 0x94, 0x9A, 0xB5, 0xD2, 0xE9, 0xA6, 0x58,
+ 0x1A, 0x0A, 0xBC, 0xD4, 0x9C, 0xBD, 0xDF, 0xEB, 0x6F, 0x43, 0x92, 0x39, 0x0F, 0x15, 0xC3, 0x09,
+ 0xD0, 0x46, 0x37, 0x4D, 0x3C, 0x41, 0x92, 0x58, 0xB9, 0xFF, 0x00, 0x55, 0xB7, 0x38, 0x07, 0xA5,
+ 0x7F, 0x19, 0xE2, 0x61, 0x5E, 0x8E, 0x61, 0x85, 0xE2, 0x5C, 0x62, 0xC4, 0x52, 0x8D, 0x2B, 0xCF,
+ 0x11, 0x88, 0xA5, 0xED, 0xA1, 0x5A, 0x8D, 0xE4, 0x9F, 0xD4, 0xF9, 0x1C, 0xDC, 0x54, 0xAC, 0xD3,
+ 0xBB, 0xF7, 0x5A, 0xD1, 0x45, 0x3B, 0x35, 0xF4, 0x10, 0xE5, 0xE4, 0x74, 0x69, 0xA8, 0xBB, 0xE8,
+ 0xA2, 0xEC, 0xD3, 0xD3, 0xE2, 0xDB, 0x6F, 0x4D, 0x8E, 0xD6, 0xDE, 0x7B, 0x7B, 0xA8, 0xE1, 0x96,
+ 0xD9, 0xC3, 0xC6, 0xA8, 0x15, 0x73, 0xF7, 0x94, 0xE3, 0xB8, 0xF5, 0x18, 0xAF, 0xEF, 0x2E, 0x1B,
+ 0xE2, 0x0E, 0x1C, 0xE2, 0xEC, 0x06, 0x0F, 0x39, 0xE1, 0x8C, 0x52, 0xAD, 0x86, 0x85, 0x3E, 0x58,
+ 0xF3, 0x36, 0xE7, 0x17, 0xA2, 0x7C, 0xDA, 0xB6, 0xAA, 0x45, 0xAB, 0x74, 0x51, 0xD5, 0x38, 0xB3,
+ 0xE6, 0x6A, 0xD1, 0xAB, 0x41, 0xCA, 0x95, 0x68, 0xDA, 0x57, 0xF9, 0x7C, 0xB6, 0xD0, 0xA8, 0xCA,
+ 0x2C, 0x66, 0x6B, 0xC6, 0x59, 0x1E, 0xCE, 0x62, 0x12, 0xE5, 0x21, 0xC0, 0x2A, 0xD8, 0xF9, 0x24,
+ 0x23, 0xA7, 0x04, 0x00, 0x7D, 0xAB, 0xE0, 0x73, 0x8C, 0x2D, 0x6E, 0x01, 0xCF, 0xA7, 0xC7, 0x74,
+ 0x69, 0x4A, 0xAE, 0x53, 0x89, 0x94, 0x69, 0xE2, 0xE3, 0x4D, 0x7B, 0xCA, 0x76, 0xF7, 0x71, 0x12,
+ 0xD9, 0x29, 0x5D, 0x46, 0x13, 0x93, 0x4D, 0x72, 0xD9, 0x5A, 0x36, 0x3B, 0x68, 0x3A, 0x78, 0x9A,
+ 0x4B, 0x0B, 0x51, 0xDA, 0x71, 0x4D, 0xC7, 0xB6, 0xDA, 0x2F, 0x4F, 0x24, 0x5D, 0x29, 0xF2, 0x2B,
+ 0x80, 0xBC, 0xE0, 0x80, 0xA0, 0x70, 0xA7, 0xA0, 0xFE, 0x55, 0xFA, 0x5D, 0x4C, 0x2C, 0xDE, 0x16,
+ 0x9E, 0x32, 0xE9, 0xB9, 0x59, 0xD9, 0x25, 0xA4, 0x25, 0xAC, 0x13, 0xDF, 0x5D, 0xB9, 0x9D, 0xBD,
+ 0x12, 0xB1, 0xC0, 0x9A, 0x5E, 0xEA, 0x5A, 0x7E, 0xAB, 0xFA, 0xD0, 0x88, 0xAF, 0x03, 0x80, 0x31,
+ 0x81, 0xC6, 0x71, 0xD3, 0x8E, 0x3F, 0x0A, 0xF2, 0x31, 0x18, 0x6A, 0x89, 0x45, 0x34, 0x92, 0xF2,
+ 0xBD, 0xBC, 0xBD, 0x3E, 0xE5, 0xDB, 0xA6, 0xBA, 0x45, 0xAD, 0x91, 0x0B, 0x46, 0x40, 0xE3, 0xF0,
+ 0x1C, 0x7E, 0x9F, 0x90, 0xAF, 0x0B, 0x11, 0x84, 0xA9, 0x05, 0xA2, 0xD1, 0xF4, 0xD3, 0x7D, 0x36,
+ 0xB7, 0x4B, 0x7E, 0x46, 0x91, 0x69, 0x59, 0x5B, 0x4F, 0xD0, 0x83, 0x68, 0xE9, 0x8E, 0x06, 0x30,
+ 0x00, 0x00, 0x0C, 0x76, 0xC5, 0x78, 0x9F, 0x57, 0x71, 0x4E, 0x9C, 0xF6, 0xD1, 0xAB, 0x6D, 0xA6,
+ 0x96, 0xB7, 0x4D, 0xD2, 0xE9, 0x7F, 0x2B, 0x58, 0xD1, 0x34, 0xED, 0xCA, 0x87, 0xB2, 0x92, 0xB1,
+ 0xB4, 0x6C, 0x62, 0x9E, 0x06, 0x59, 0x6D, 0xE6, 0x84, 0xEC, 0x96, 0x27, 0x46, 0x05, 0x19, 0x4F,
+ 0x6C, 0x10, 0x2B, 0x8B, 0x8A, 0xB8, 0x6B, 0x2F, 0xE2, 0xEC, 0x8E, 0xA6, 0x4F, 0x8D, 0x86, 0xF1,
+ 0x4A, 0x32, 0x86, 0x93, 0x4D, 0x34, 0xE3, 0xAE, 0xBA, 0x5D, 0x25, 0xB6, 0xDA, 0x7A, 0x3A, 0x15,
+ 0xA5, 0x42, 0x6A, 0x71, 0xDB, 0xB7, 0x4D, 0x8F, 0xE8, 0x0B, 0xF6, 0x16, 0xFD, 0xAB, 0x2C, 0x75,
+ 0xBD, 0x27, 0x4E, 0xB5, 0xD5, 0xAE, 0xE2, 0x8B, 0x57, 0xB1, 0x86, 0x3D, 0x37, 0xC4, 0x1A, 0x71,
+ 0x65, 0x49, 0x15, 0x90, 0xFC, 0xB3, 0xA2, 0x93, 0xF7, 0x5B, 0xEF, 0x2F, 0x6E, 0xA0, 0xF2, 0x31,
+ 0x5F, 0xC6, 0x38, 0xCC, 0xAB, 0x17, 0xC3, 0x78, 0xDA, 0x9C, 0x2B, 0x9E, 0x47, 0x92, 0xA4, 0x5B,
+ 0x74, 0xE5, 0xD2, 0x49, 0xDE, 0xCA, 0xFD, 0x1F, 0x4B, 0x24, 0xBA, 0x59, 0x6C, 0x8E, 0x3C, 0x6E,
+ 0x1F, 0xD9, 0x57, 0x58, 0xDC, 0x2A, 0xF7, 0x6D, 0xEF, 0x2B, 0x5F, 0x64, 0xAD, 0x6D, 0x3C, 0xAD,
+ 0xD7, 0x64, 0xDE, 0x88, 0xFD, 0x4F, 0xBC, 0xF0, 0x27, 0xC3, 0x5F, 0x88, 0xF7, 0x3A, 0x77, 0x89,
+ 0x5E, 0xDA, 0xCE, 0xF2, 0xF6, 0xD9, 0x52, 0x4B, 0x6B, 0x9B, 0x3B, 0xA3, 0x0D, 0xC4, 0x47, 0x00,
+ 0x85, 0x25, 0x09, 0x3C, 0x64, 0x70, 0x7A, 0x71, 0x9E, 0xBC, 0x14, 0x73, 0x1C, 0xD3, 0x2A, 0x84,
+ 0xB0, 0xF4, 0xDD, 0xA3, 0xE6, 0x93, 0x56, 0xEE, 0xAE, 0xB6, 0x76, 0xE9, 0x64, 0xED, 0xA2, 0xD0,
+ 0xE0, 0xAB, 0x96, 0xE5, 0xF9, 0x8C, 0x95, 0x48, 0xE9, 0x2F, 0x27, 0x6E, 0x9B, 0x69, 0x7D, 0x3D,
+ 0x34, 0x7A, 0xBB, 0x6E, 0x7A, 0x03, 0x78, 0x5F, 0x41, 0x97, 0x4B, 0x93, 0x45, 0x7D, 0x3A, 0x29,
+ 0x34, 0xD9, 0x62, 0x11, 0x4B, 0x6F, 0x22, 0x86, 0xF3, 0x50, 0x60, 0x01, 0x26, 0x73, 0xC0, 0x00,
+ 0x0E, 0x87, 0xA7, 0x3E, 0xFE, 0x6A, 0xC6, 0x62, 0x61, 0x56, 0x35, 0x94, 0xDF, 0x3A, 0xD9, 0xAE,
+ 0x8F, 0xCA, 0xD6, 0xDF, 0xCA, 0xDE, 0x5A, 0x6D, 0xDE, 0xB0, 0x38, 0x47, 0x45, 0xE1, 0xB9, 0x3D,
+ 0xC6, 0xB4, 0xEF, 0x6D, 0x16, 0xFB, 0x25, 0xDF, 0xD1, 0xF6, 0x39, 0xA8, 0xFC, 0x3D, 0xE0, 0x7F,
+ 0x03, 0xD8, 0x2B, 0xAC, 0x76, 0xFA, 0x75, 0x9D, 0xB0, 0x06, 0x38, 0x64, 0x94, 0x18, 0xA2, 0xE3,
+ 0xA4, 0x68, 0x7D, 0x48, 0x1E, 0xBF, 0x90, 0xAE, 0xB9, 0x62, 0xF3, 0x0C, 0xC6, 0x7C, 0xB2, 0x7C,
+ 0xCD, 0xF5, 0xB2, 0x5A, 0x2D, 0x35, 0x7A, 0x2B, 0x25, 0xA5, 0xB6, 0x56, 0xE8, 0x71, 0x47, 0x03,
+ 0x96, 0xE0, 0x60, 0xA2, 0x95, 0xA2, 0x96, 0x89, 0xB5, 0xFA, 0xD9, 0x5A, 0xFE, 0x8B, 0x6D, 0xF7,
+ 0x7F, 0x98, 0xBF, 0xB7, 0x17, 0xED, 0x59, 0xA0, 0xF8, 0x2B, 0xC2, 0xD7, 0xC2, 0xDE, 0xF2, 0x2F,
+ 0xB5, 0x35, 0xBB, 0x5A, 0x68, 0x9A, 0x54, 0x52, 0x01, 0x3D, 0xCC, 0xCC, 0xA4, 0x21, 0x31, 0xF6,
+ 0xC7, 0x3C, 0x9E, 0x80, 0x1E, 0x99, 0xE3, 0xC5, 0xCE, 0xB3, 0x2C, 0x3E, 0x07, 0x07, 0x3C, 0x1D,
+ 0x39, 0x5E, 0x6F, 0xE3, 0x92, 0xED, 0x67, 0xEE, 0xAD, 0xB5, 0x7F, 0xF0, 0x76, 0x8A, 0x3D, 0x1C,
+ 0xB7, 0x05, 0x5B, 0x1B, 0x8A, 0x8D, 0x6A, 0x8A, 0xD1, 0xD3, 0x95, 0x5A, 0xDA, 0x25, 0x6B, 0x3D,
+ 0x34, 0xB6, 0xB6, 0xD2, 0xDB, 0x68, 0xB6, 0x5F, 0x87, 0x7F, 0xB1, 0x36, 0xA3, 0x77, 0xAB, 0xFE,
+ 0xDD, 0xBF, 0xB2, 0x46, 0xAB, 0x7F, 0x29, 0x9A, 0xF7, 0x51, 0xFD, 0xAC, 0x3C, 0x05, 0x7B, 0x75,
+ 0x29, 0xFE, 0x39, 0x25, 0xF1, 0x75, 0x8B, 0x39, 0xC7, 0xD4, 0x9E, 0x2B, 0xF3, 0x4C, 0x15, 0x47,
+ 0x57, 0x35, 0xA3, 0x52, 0x5B, 0xBA, 0x91, 0x7E, 0x9E, 0xF2, 0xD1, 0x79, 0x25, 0xA2, 0xEC, 0x91,
+ 0xF7, 0x15, 0xA1, 0x1A, 0x78, 0x39, 0xC2, 0x2A, 0xC9, 0x45, 0xFE, 0x47, 0xFA, 0x04, 0x57, 0xE9,
+ 0xE7, 0xC8, 0x05, 0x00, 0x14, 0x00, 0x50, 0x07, 0xF2, 0x31, 0xFF, 0x00, 0x05, 0x5D, 0xFD, 0x9F,
+ 0xFE, 0x31, 0x7C, 0x5A, 0xFD, 0xB9, 0x3E, 0x2B, 0xEB, 0xDF, 0x0E, 0x7E, 0x1F, 0x6B, 0xBE, 0x2D,
+ 0xD1, 0x74, 0xDD, 0x17, 0xC2, 0xDA, 0x1D, 0xEE, 0xA1, 0xA5, 0xC7, 0x17, 0xD9, 0x6D, 0xEE, 0xD3,
+ 0xC2, 0xDA, 0x7C, 0xAF, 0x6E, 0x59, 0xDD, 0x7E, 0x71, 0x15, 0xCD, 0xB3, 0x10, 0x3A, 0x09, 0x13,
+ 0xD6, 0xBD, 0x3C, 0x9F, 0x34, 0xC9, 0xF0, 0x58, 0x5C, 0x4E, 0x1B, 0x31, 0xAA, 0xA3, 0x27, 0x55,
+ 0xB4, 0x9A, 0x6F, 0xDD, 0x74, 0xA9, 0x24, 0xD5, 0x93, 0xB6, 0xA9, 0xAE, 0x9D, 0x7D, 0x0F, 0x5F,
+ 0x0B, 0x09, 0xBA, 0x10, 0x70, 0x5A, 0x25, 0xFA, 0xB3, 0xF3, 0x7E, 0x4F, 0xD8, 0xB3, 0xF6, 0xA2,
+ 0x65, 0x0B, 0xFF, 0x00, 0x0A, 0x5B, 0xC5, 0x98, 0xDA, 0x08, 0x1E, 0x5D, 0xAE, 0x30, 0x07, 0x6F,
+ 0xDE, 0xFF, 0x00, 0xB2, 0x78, 0xF6, 0xAC, 0xF3, 0x4C, 0xD3, 0x87, 0x71, 0x74, 0x9D, 0x07, 0x5A,
+ 0x2E, 0x29, 0x24, 0x97, 0x2C, 0x9F, 0x6E, 0xF1, 0xFB, 0xD5, 0x92, 0xED, 0xAA, 0x3A, 0xA0, 0xAA,
+ 0x53, 0x69, 0xF2, 0xFD, 0xDF, 0xF0, 0x3F, 0xA5, 0xF2, 0x33, 0x65, 0xFD, 0x8A, 0x3F, 0x6A, 0x44,
+ 0x20, 0x27, 0xC1, 0x6F, 0x16, 0xE3, 0x03, 0x8D, 0xB6, 0xBD, 0xFA, 0x00, 0x3C, 0xDE, 0x9C, 0x0F,
+ 0xD2, 0xBF, 0x2E, 0xCD, 0x70, 0x79, 0x7C, 0x67, 0x1F, 0xEC, 0xC9, 0xA7, 0x1D, 0x5B, 0xF8, 0x96,
+ 0xEF, 0x44, 0x93, 0x56, 0xB2, 0x5B, 0x6B, 0xEB, 0xB1, 0xD7, 0x4B, 0x11, 0x14, 0xAD, 0x3F, 0xCB,
+ 0xFE, 0x07, 0xF5, 0xD0, 0x8F, 0xFE, 0x18, 0xAB, 0xF6, 0xA7, 0xFF, 0x00, 0xA2, 0x29, 0xE2, 0xEF,
+ 0xFB, 0xE6, 0xD7, 0xFF, 0x00, 0x8E, 0xD7, 0x8D, 0xEC, 0x2A, 0x7F, 0x29, 0xB7, 0xB7, 0xA3, 0xDF,
+ 0xF0, 0x7F, 0xE4, 0x1F, 0xF0, 0xC5, 0x5F, 0xB5, 0x3F, 0xFD, 0x11, 0x4F, 0x17, 0x7F, 0xDF, 0x36,
+ 0xBF, 0xFC, 0x76, 0x8F, 0x61, 0x53, 0xF9, 0x43, 0xDB, 0xD1, 0xEF, 0xF8, 0x3F, 0xF2, 0x35, 0x34,
+ 0xFF, 0x00, 0xD8, 0xF7, 0xF6, 0xAB, 0xB2, 0x60, 0x0F, 0xC1, 0x6F, 0x17, 0xF9, 0x43, 0x18, 0x2A,
+ 0xB6, 0xA1, 0xA3, 0xC7, 0x42, 0x08, 0x97, 0xB6, 0x2B, 0xF6, 0x2F, 0x0E, 0xBC, 0x4E, 0xCC, 0x78,
+ 0x4A, 0x6F, 0x01, 0x98, 0xAE, 0x6C, 0x14, 0x92, 0x8B, 0xF7, 0x53, 0x71, 0x5A, 0x2D, 0x2C, 0xB6,
+ 0x4B, 0xEE, 0xD3, 0x46, 0xB6, 0xF3, 0xB1, 0x54, 0x30, 0xF5, 0x92, 0x95, 0x37, 0x69, 0x2F, 0x54,
+ 0x7E, 0xA4, 0x7C, 0x2C, 0xF0, 0xBF, 0xC6, 0x7F, 0x8A, 0x5F, 0x07, 0xEF, 0x7E, 0x00, 0xFE, 0xD4,
+ 0x9F, 0x0A, 0x3C, 0x77, 0x3D, 0xB5, 0xBD, 0xAB, 0x1F, 0x86, 0x3F, 0x13, 0x64, 0xB1, 0x8F, 0x50,
+ 0xBE, 0xF0, 0x55, 0xD4, 0x51, 0x95, 0x83, 0xED, 0x29, 0x0C, 0x9E, 0x64, 0xC8, 0x37, 0x15, 0xCB,
+ 0x02, 0x00, 0x20, 0xB6, 0x71, 0x5F, 0xD3, 0x9C, 0x3D, 0xC6, 0xDC, 0x1B, 0x57, 0x1B, 0x86, 0xCC,
+ 0xF8, 0x67, 0x1F, 0x4E, 0x9E, 0x2A, 0x32, 0x4E, 0x51, 0x92, 0x70, 0x5A, 0x6A, 0xED, 0x2A, 0x89,
+ 0x45, 0x37, 0x64, 0xB9, 0x61, 0x6D, 0x13, 0x5A, 0x69, 0x6F, 0xCD, 0xF3, 0x0C, 0x87, 0x31, 0xCB,
+ 0x31, 0x6F, 0x31, 0xC0, 0xD1, 0x95, 0x4A, 0x5D, 0x69, 0xA9, 0x5B, 0x96, 0xFB, 0xB8, 0xAB, 0xDE,
+ 0xCD, 0xA5, 0xCD, 0x15, 0x17, 0xD6, 0xF6, 0x4A, 0xCB, 0xE3, 0x2B, 0x2F, 0xD8, 0xCB, 0xF6, 0x96,
+ 0xB7, 0xF1, 0x0B, 0xE8, 0x8F, 0xF0, 0x9F, 0xC4, 0x77, 0x90, 0x49, 0x7C, 0xBA, 0x20, 0xD5, 0x2D,
+ 0xAC, 0x93, 0x53, 0x82, 0x44, 0x32, 0x84, 0x8E, 0x78, 0x6D, 0x92, 0x5D, 0xD2, 0xE0, 0x88, 0xD9,
+ 0x50, 0x2B, 0x13, 0xF2, 0x85, 0x52, 0x48, 0x07, 0xFB, 0x2A, 0x9F, 0x8C, 0x1C, 0x13, 0x89, 0xC1,
+ 0xC6, 0x78, 0xAC, 0xC2, 0x95, 0x3C, 0x5D, 0x38, 0x27, 0x38, 0xDA, 0x51, 0x4D, 0xB5, 0x78, 0xA5,
+ 0x51, 0x45, 0xD3, 0x84, 0x93, 0xB5, 0xDB, 0x6D, 0x26, 0xED, 0xA5, 0x82, 0xAE, 0x07, 0x1D, 0x3C,
+ 0x1A, 0xC4, 0x61, 0xA8, 0xB5, 0x24, 0x9C, 0x94, 0x3D, 0xD4, 0xEF, 0x6D, 0x62, 0xDB, 0x4D, 0xC6,
+ 0xFA, 0xAB, 0xA4, 0x9A, 0x5A, 0xDD, 0x6B, 0x6F, 0xE8, 0x1F, 0xC3, 0x5F, 0xB3, 0x67, 0x8E, 0xFF,
+ 0x00, 0xE0, 0x96, 0xBF, 0x0E, 0x7C, 0x3B, 0xA4, 0xE8, 0xFE, 0x19, 0xB7, 0xF8, 0xC9, 0xFF, 0x00,
+ 0x05, 0x0E, 0xF1, 0xF6, 0x8E, 0x1B, 0xC0, 0xBE, 0x2D, 0x97, 0x48, 0x17, 0x5F, 0x0B, 0x7F, 0x63,
+ 0x9F, 0x0F, 0xEA, 0xD1, 0x03, 0x1B, 0xC6, 0x5C, 0xB3, 0x5C, 0xF8, 0x8A, 0xE0, 0x3A, 0x91, 0x23,
+ 0xA0, 0x5B, 0x34, 0x72, 0xE9, 0x24, 0x52, 0x5B, 0xED, 0x97, 0xF9, 0x53, 0x36, 0xE3, 0x0C, 0x9F,
+ 0xC6, 0x4C, 0xEE, 0x75, 0x73, 0x27, 0x0C, 0x27, 0x0D, 0xE1, 0xAA, 0x45, 0xCA, 0x9D, 0xA4, 0xEB,
+ 0xE3, 0xA5, 0x09, 0x24, 0xD3, 0x95, 0xAD, 0x1A, 0x71, 0x8D, 0xEE, 0xA2, 0xEC, 0xF4, 0xE7, 0x84,
+ 0xF9, 0xBD, 0xCC, 0x29, 0xBC, 0xD3, 0x26, 0xCA, 0xB1, 0x15, 0xB0, 0x94, 0xEA, 0x39, 0x54, 0x51,
+ 0x75, 0x29, 0xC2, 0xAA, 0x70, 0x8B, 0x8A, 0x95, 0xAA, 0x72, 0xBB, 0x41, 0xCA, 0x11, 0xD5, 0x5A,
+ 0x17, 0x77, 0x49, 0x5E, 0xEE, 0xFF, 0x00, 0x91, 0xBE, 0x32, 0xF8, 0x37, 0xFB, 0x59, 0xDA, 0xF8,
+ 0x9B, 0xC4, 0x5A, 0x9C, 0x1E, 0x0B, 0xF1, 0x6F, 0x8D, 0xAE, 0x75, 0xFD, 0x5A, 0xE3, 0x56, 0xD5,
+ 0xBC, 0x51, 0xE2, 0x9B, 0x53, 0xAB, 0xEA, 0x9A, 0xAE, 0xA1, 0x73, 0x2E, 0xFB, 0xA2, 0x6F, 0x0D,
+ 0xD1, 0x79, 0xF7, 0x4B, 0x28, 0xCC, 0xD2, 0x28, 0x2D, 0x85, 0x20, 0x1D, 0xA0, 0x57, 0xEC, 0xD9,
+ 0x1E, 0x75, 0xE1, 0x46, 0x26, 0x82, 0xA7, 0x5A, 0xB4, 0x70, 0x94, 0x29, 0xA5, 0x18, 0x72, 0x3B,
+ 0x45, 0xA5, 0x75, 0x65, 0x17, 0x07, 0x64, 0x92, 0x76, 0x51, 0x6A, 0x29, 0x3B, 0x68, 0xB6, 0xFA,
+ 0x2E, 0x18, 0xE3, 0xEE, 0x34, 0xA5, 0x97, 0x61, 0xF0, 0x78, 0x8C, 0x14, 0x1C, 0x29, 0x45, 0x25,
+ 0x15, 0x68, 0xB7, 0x1F, 0xE6, 0x96, 0xBA, 0x49, 0xDD, 0xCA, 0xD7, 0xB3, 0x6D, 0xDD, 0x2B, 0xDD,
+ 0xF2, 0x53, 0xFC, 0x29, 0xFD, 0xAB, 0x5C, 0xB4, 0xF0, 0x7C, 0x19, 0xD7, 0xAD, 0x6E, 0xE5, 0xB9,
+ 0x32, 0x4D, 0x2A, 0x69, 0xB6, 0xAD, 0x1C, 0x25, 0x93, 0x25, 0x8B, 0x09, 0x10, 0x12, 0xA4, 0x9C,
+ 0x15, 0x63, 0xCA, 0xE4, 0x7D, 0xE1, 0x8F, 0x57, 0xEB, 0x9E, 0x15, 0x53, 0x5F, 0x57, 0xA9, 0x9C,
+ 0x27, 0x18, 0xC5, 0x2B, 0x25, 0x35, 0xD5, 0x59, 0x25, 0xCA, 0xDA, 0xD2, 0xD6, 0x8B, 0x8E, 0xD6,
+ 0x4E, 0xC8, 0xFB, 0x08, 0x78, 0x87, 0xC5, 0x0A, 0x2E, 0x1F, 0xD9, 0x94, 0xDC, 0x54, 0x5D, 0xAF,
+ 0x39, 0x6E, 0xB4, 0xD2, 0x29, 0xBD, 0xD5, 0x9A, 0x4F, 0x96, 0xE9, 0xA5, 0xA3, 0x5A, 0xB3, 0xC2,
+ 0x9F, 0xB3, 0xCF, 0xED, 0xC3, 0xE3, 0xFF, 0x00, 0x11, 0xD8, 0xF8, 0x76, 0xDB, 0xE1, 0xFE, 0xA3,
+ 0xE1, 0xB8, 0x6E, 0x1C, 0xCB, 0x7B, 0xAE, 0x6A, 0x16, 0x76, 0xD6, 0xDA, 0x3E, 0x83, 0x6A, 0x8C,
+ 0x0C, 0x97, 0x37, 0x6C, 0x8E, 0xED, 0x1C, 0x49, 0xB4, 0x92, 0xAA, 0xA4, 0x9C, 0x6D, 0x00, 0x9C,
+ 0x0A, 0xE6, 0xC6, 0x66, 0xFE, 0x0B, 0xE5, 0x38, 0x6F, 0xAD, 0x51, 0xC6, 0xC6, 0xBE, 0x25, 0x5F,
+ 0x92, 0x9A, 0xE7, 0x6E, 0x5A, 0x5A, 0xFA, 0xF2, 0xAD, 0xEC, 0xBB, 0x5E, 0xD6, 0xB3, 0x68, 0x78,
+ 0x8E, 0x3E, 0xE2, 0x25, 0x49, 0xB5, 0x87, 0xA7, 0x04, 0xAC, 0x9B, 0x49, 0xBE, 0x9A, 0xA4, 0xDC,
+ 0x9E, 0xB6, 0x5B, 0xAD, 0x56, 0xDA, 0x68, 0x7B, 0xA7, 0x8B, 0xF4, 0x3F, 0xDA, 0x17, 0xE1, 0x46,
+ 0x8F, 0x37, 0x80, 0x3F, 0x67, 0x9F, 0x85, 0xBE, 0x35, 0xD4, 0xF5, 0x9B, 0xCB, 0x59, 0xF4, 0x9F,
+ 0x88, 0x9F, 0x1E, 0x35, 0x26, 0x4B, 0x3D, 0x47, 0xC7, 0x6B, 0x2A, 0x6C, 0x96, 0xDF, 0x46, 0xB7,
+ 0x2F, 0x14, 0x96, 0x3A, 0x78, 0xC1, 0x00, 0x9D, 0xAE, 0xE0, 0x65, 0x80, 0xDC, 0xDB, 0xBE, 0x43,
+ 0x2A, 0xAD, 0xE1, 0xD6, 0x37, 0x16, 0xF3, 0x7E, 0x26, 0xC7, 0x51, 0xA6, 0xDB, 0x4E, 0x9D, 0x08,
+ 0xC1, 0xC9, 0x41, 0x47, 0xA4, 0xA4, 0xA2, 0xD4, 0xE7, 0x7D, 0x74, 0xBC, 0x63, 0x2B, 0x59, 0x4B,
+ 0x46, 0xBE, 0x5B, 0x38, 0xC7, 0x71, 0x36, 0x79, 0x08, 0x2C, 0x65, 0x69, 0x46, 0x29, 0x27, 0x18,
+ 0xC7, 0x96, 0x2E, 0x2D, 0x49, 0x49, 0x34, 0x95, 0xA2, 0x9A, 0x57, 0x8E, 0xB0, 0xE6, 0x69, 0xA4,
+ 0xDA, 0xB2, 0x8A, 0xF8, 0x3B, 0x4E, 0xFD, 0x94, 0x3F, 0x69, 0x9D, 0x3E, 0x61, 0x70, 0x3E, 0x09,
+ 0x6B, 0xF7, 0xB2, 0xBC, 0x32, 0x44, 0x53, 0x53, 0xB4, 0xB3, 0xBD, 0x81, 0x0B, 0x2E, 0x15, 0xA3,
+ 0x47, 0x90, 0xE1, 0x97, 0x2B, 0xC9, 0xCE, 0x08, 0x1E, 0x95, 0xFA, 0x55, 0x7F, 0x11, 0x7C, 0x3F,
+ 0x78, 0x49, 0x60, 0x70, 0xD9, 0x9D, 0x18, 0xD1, 0x49, 0x24, 0xB9, 0x67, 0xA6, 0xDD, 0xA2, 0xF4,
+ 0xB2, 0x7B, 0xBB, 0xBD, 0xAE, 0xA2, 0x71, 0x62, 0x70, 0x53, 0xC6, 0xC6, 0x9B, 0xC4, 0x4E, 0xAF,
+ 0x3A, 0xD6, 0x4D, 0x54, 0x8E, 0xB6, 0x56, 0x8A, 0x77, 0x4E, 0xF1, 0xB5, 0x93, 0x4F, 0xA2, 0xD2,
+ 0xCE, 0xD6, 0x4D, 0x33, 0xF6, 0x56, 0xFD, 0xAA, 0x74, 0x91, 0x2C, 0x70, 0xFC, 0x14, 0xD6, 0x6E,
+ 0xA1, 0x96, 0x64, 0x9D, 0xAD, 0x75, 0x1D, 0x2E, 0xC2, 0xFE, 0x04, 0x78, 0xF3, 0xB7, 0x62, 0x33,
+ 0xFC, 0x9C, 0xB1, 0x24, 0x2E, 0x01, 0xDA, 0xB9, 0x18, 0x5A, 0xF2, 0x71, 0x1C, 0x7B, 0xE1, 0xEB,
+ 0xA6, 0xD4, 0x73, 0x3A, 0x49, 0x2B, 0x3F, 0xB4, 0xEC, 0x95, 0xAC, 0xAE, 0xE0, 0xAE, 0xBF, 0x2E,
+ 0x89, 0x3D, 0x5E, 0x33, 0xCA, 0x7D, 0xAC, 0xA3, 0x27, 0x4D, 0xF3, 0x25, 0x64, 0xD4, 0xAC, 0xDA,
+ 0x6A, 0xD6, 0x6D, 0x3D, 0x74, 0xEF, 0x7E, 0xEB, 0x5D, 0x47, 0xA7, 0xEC, 0xB9, 0xFB, 0x56, 0x41,
+ 0x64, 0x96, 0xB6, 0x7F, 0x05, 0xB5, 0xAD, 0x3A, 0x48, 0xE6, 0x7B, 0x85, 0xD4, 0x74, 0xDB, 0x3B,
+ 0x3B, 0x0D, 0x4C, 0x09, 0x24, 0x0E, 0x53, 0xCF, 0x49, 0x81, 0xD8, 0x0A, 0x28, 0x0B, 0xFC, 0x20,
+ 0x00, 0x31, 0x8A, 0xF2, 0x6A, 0xF1, 0xEF, 0x00, 0x43, 0x9A, 0x3F, 0xDA, 0x70, 0x57, 0x6A, 0xEB,
+ 0x96, 0x4E, 0xFA, 0x59, 0x25, 0xEE, 0x5B, 0x6D, 0xAD, 0xAD, 0xB6, 0xD3, 0x62, 0xA6, 0x4D, 0xED,
+ 0x6A, 0xB9, 0x55, 0x8C, 0x9C, 0x6D, 0x67, 0x16, 0xEF, 0x06, 0xAD, 0x6B, 0x38, 0xB6, 0xD3, 0xD1,
+ 0xF5, 0xEB, 0xBB, 0xD1, 0x5A, 0x9D, 0xC7, 0xEC, 0xB3, 0xFB, 0x5A, 0xCD, 0x0C, 0x91, 0x37, 0xC2,
+ 0x9F, 0x1C, 0x01, 0x32, 0xFF, 0x00, 0xA4, 0xC8, 0x2F, 0x15, 0xA4, 0xB9, 0x0C, 0x41, 0x60, 0xE0,
+ 0xDC, 0x11, 0xCB, 0x80, 0x48, 0x00, 0x7C, 0xDE, 0x9D, 0x2B, 0xC4, 0xAD, 0xE2, 0x0F, 0x87, 0xB1,
+ 0x5C, 0x93, 0xCC, 0xA9, 0xBA, 0x6F, 0xDD, 0xE5, 0xE5, 0x97, 0x5B, 0x6F, 0x68, 0x27, 0xA2, 0x56,
+ 0x4D, 0xBB, 0x28, 0xDA, 0xDA, 0x1A, 0x53, 0xC9, 0xF9, 0x5D, 0xFD, 0x9A, 0x6B, 0xA2, 0xB4, 0x6C,
+ 0xB5, 0xBA, 0xB2, 0x49, 0x6D, 0xA7, 0x7B, 0x5B, 0x5D, 0x51, 0x97, 0x1F, 0xEC, 0x93, 0xFB, 0x5A,
+ 0xC0, 0x58, 0xDB, 0x7C, 0x2E, 0xF1, 0xE5, 0xBB, 0x15, 0x68, 0x4F, 0x93, 0x7D, 0x14, 0x25, 0xD5,
+ 0x80, 0x46, 0x43, 0x89, 0xC6, 0x41, 0x1B, 0x57, 0x1E, 0x9E, 0xC2, 0xBE, 0x5B, 0x19, 0xC7, 0xBC,
+ 0x03, 0x56, 0x2A, 0x94, 0x31, 0xF0, 0xB4, 0x75, 0x8A, 0x51, 0xA9, 0xB2, 0x57, 0x57, 0x4D, 0x59,
+ 0xD9, 0x75, 0xB2, 0xB7, 0xA2, 0x3B, 0xA1, 0x96, 0xA8, 0xC1, 0x25, 0x45, 0x72, 0xAE, 0x96, 0x8E,
+ 0xEB, 0xAA, 0x49, 0x7F, 0x4B, 0x63, 0x11, 0xFF, 0x00, 0x63, 0x1F, 0xDA, 0x87, 0x00, 0x8F, 0x82,
+ 0xFE, 0x2C, 0xC2, 0x83, 0x92, 0x16, 0xD7, 0x00, 0x0E, 0xBF, 0xF2, 0xD7, 0xB6, 0x2B, 0xE6, 0xAB,
+ 0x71, 0xFF, 0x00, 0x06, 0x24, 0x93, 0xC7, 0x42, 0xC9, 0x2F, 0xB3, 0x3F, 0x92, 0xB7, 0x2F, 0x9E,
+ 0x96, 0x5D, 0xED, 0xB3, 0x4B, 0xB1, 0x61, 0x6B, 0xBB, 0x25, 0x0D, 0x3E, 0x5D, 0x3F, 0xAF, 0xEB,
+ 0x42, 0x1F, 0xF8, 0x63, 0x4F, 0xDA, 0x8D, 0x0F, 0xEE, 0xFE, 0x0D, 0x78, 0xB9, 0x4F, 0x1C, 0xC7,
+ 0xF6, 0x55, 0x20, 0x13, 0x80, 0x09, 0x12, 0xF1, 0xCA, 0x91, 0x8F, 0x6F, 0x6A, 0xF9, 0xCC, 0x5F,
+ 0x1D, 0x70, 0x73, 0x72, 0x71, 0xC6, 0x45, 0xAB, 0xE9, 0x68, 0xCF, 0x6D, 0x1D, 0xAC, 0xA1, 0xDA,
+ 0xDA, 0x5B, 0x63, 0x78, 0xE1, 0x6B, 0x24, 0x93, 0x8E, 0xDE, 0x9F, 0x87, 0xFC, 0x0F, 0xC8, 0xEA,
+ 0x3C, 0x31, 0xFB, 0x1D, 0x7E, 0xD6, 0xFA, 0xAE, 0xB1, 0xA7, 0x69, 0x1F, 0xF0, 0x84, 0x78, 0xD3,
+ 0xC3, 0x90, 0x5E, 0x4C, 0xB6, 0xCB, 0xA9, 0x5E, 0x5E, 0x95, 0xB1, 0xB5, 0x62, 0x40, 0x51, 0x20,
+ 0x8A, 0x56, 0x65, 0x1C, 0x01, 0x9C, 0x60, 0x71, 0xD2, 0xBE, 0x7F, 0xFD, 0x61, 0xE0, 0xDC, 0xC3,
+ 0x10, 0xB0, 0x50, 0xC4, 0xD3, 0x4A, 0x56, 0xFB, 0x2D, 0x5D, 0x29, 0x46, 0xFA, 0xB8, 0xC5, 0x25,
+ 0xCB, 0xCC, 0xDB, 0x72, 0x49, 0x2D, 0xBA, 0x1C, 0x58, 0xBC, 0xBE, 0x94, 0x30, 0xB2, 0x75, 0x30,
+ 0xAA, 0xA4, 0x56, 0xAE, 0x36, 0x8B, 0xD3, 0xBD, 0x9E, 0x9A, 0x6F, 0xF2, 0xE8, 0xB5, 0x5E, 0xD3,
+ 0xE1, 0xAF, 0x80, 0x1F, 0xB6, 0xAF, 0x80, 0x75, 0x4B, 0x6B, 0x0B, 0x5D, 0x0F, 0xC6, 0xBA, 0x83,
+ 0xF8, 0x73, 0xE2, 0x14, 0x71, 0xDC, 0xCA, 0xD7, 0xD1, 0x5D, 0x69, 0x17, 0xF6, 0x4A, 0x55, 0x5E,
+ 0x54, 0xCB, 0x79, 0xD2, 0x44, 0x59, 0x98, 0x00, 0xAE, 0x4E, 0x06, 0xE0, 0xA0, 0x1E, 0x79, 0x5E,
+ 0x6D, 0xC2, 0x71, 0xE1, 0x9C, 0x56, 0x03, 0x19, 0x89, 0xA5, 0x1A, 0xB4, 0x73, 0x17, 0x3A, 0x4E,
+ 0x29, 0xC9, 0xBC, 0x3B, 0xA6, 0xE0, 0x9C, 0x7D, 0xD5, 0x17, 0x28, 0xC9, 0xDE, 0x50, 0x92, 0xB2,
+ 0xE5, 0xF7, 0xAE, 0x95, 0xA3, 0xE6, 0x4F, 0x2D, 0x4A, 0xAC, 0x1E, 0x1F, 0x08, 0xA3, 0x09, 0x51,
+ 0xB7, 0xBA, 0xB4, 0x52, 0x4E, 0xF1, 0x8B, 0x49, 0x72, 0xC7, 0x4B, 0xD9, 0xF5, 0x6D, 0xA5, 0x7D,
+ 0x19, 0x53, 0xC4, 0x3E, 0x0D, 0xFF, 0x00, 0x82, 0x83, 0xDA, 0x78, 0x8B, 0x58, 0x6D, 0x2B, 0xC2,
+ 0xBE, 0x2D, 0xBB, 0xB3, 0x3A, 0x9C, 0xD3, 0x5A, 0xCF, 0x6B, 0x61, 0x63, 0x3D, 0x91, 0x8E, 0x47,
+ 0xDE, 0x89, 0x17, 0x9A, 0x77, 0x61, 0x41, 0x03, 0xE6, 0xC9, 0x1D, 0x33, 0xC5, 0x7E, 0x67, 0x8F,
+ 0xAB, 0xC1, 0x34, 0xEA, 0x4A, 0x32, 0xAF, 0x79, 0x73, 0x36, 0xDF, 0xBC, 0xEF, 0x6B, 0xE9, 0x64,
+ 0xAC, 0x96, 0xDC, 0xC9, 0x2E, 0x5B, 0xDD, 0x47, 0x45, 0xAF, 0xB5, 0x82, 0xCA, 0x94, 0x30, 0x90,
+ 0x55, 0x20, 0xD3, 0xE5, 0x57, 0x5A, 0xAB, 0x3B, 0x2B, 0xE9, 0xA5, 0xAD, 0xB2, 0x5E, 0x47, 0xA5,
+ 0xFC, 0x3A, 0xB3, 0xFD, 0xB9, 0xB4, 0xCD, 0x27, 0x5C, 0xD6, 0xBC, 0x57, 0xF0, 0xC7, 0x5A, 0xD5,
+ 0xE2, 0xD1, 0xF5, 0x7D, 0x2A, 0x54, 0xF0, 0xC3, 0x69, 0x36, 0x70, 0x5D, 0xF8, 0x82, 0x09, 0x0C,
+ 0x82, 0xE0, 0xC7, 0x20, 0x73, 0x1A, 0xF9, 0x60, 0x46, 0xD9, 0x6D, 0xBC, 0x1E, 0x33, 0x92, 0x06,
+ 0x9C, 0x3D, 0xC4, 0x5C, 0x37, 0x94, 0xE5, 0xB9, 0xA4, 0xE8, 0x54, 0xFD, 0xF2, 0xAD, 0x85, 0xA9,
+ 0x49, 0x72, 0xC9, 0x45, 0xD3, 0x83, 0x92, 0xAB, 0x77, 0x67, 0xB5, 0xD7, 0x2C, 0x53, 0x8B, 0x6D,
+ 0x75, 0xD2, 0xDE, 0x5E, 0x69, 0x91, 0x57, 0xC4, 0xD5, 0xA3, 0x4B, 0x0A, 0x9A, 0x87, 0x24, 0xD4,
+ 0xA4, 0xDA, 0xD1, 0xD9, 0x38, 0xF6, 0x96, 0xBB, 0x5E, 0x29, 0xD9, 0x36, 0xAC, 0x91, 0x06, 0x9D,
+ 0x37, 0xED, 0x85, 0x19, 0x57, 0xBC, 0xFD, 0x9F, 0x3C, 0x50, 0x64, 0x69, 0x67, 0x73, 0x1D, 0x96,
+ 0x9B, 0xA5, 0x2C, 0x69, 0x13, 0x37, 0xEE, 0x02, 0x31, 0x91, 0x4E, 0x54, 0x10, 0x1B, 0xA0, 0xF4,
+ 0xEB, 0xC7, 0xCC, 0xCF, 0x17, 0xC3, 0x70, 0x6A, 0x4B, 0x15, 0x52, 0x49, 0xAE, 0x69, 0x59, 0xD9,
+ 0x5D, 0xB6, 0xED, 0x14, 0xE1, 0x65, 0x6B, 0x6B, 0x76, 0xFA, 0x25, 0x75, 0x76, 0x77, 0xC7, 0x25,
+ 0xE5, 0x51, 0x54, 0x92, 0x4A, 0xCA, 0xEA, 0xCD, 0x59, 0xA5, 0xD2, 0xC9, 0xDD, 0x37, 0xDD, 0x26,
+ 0x97, 0x7D, 0x0D, 0x19, 0x75, 0x4F, 0xDB, 0x58, 0x0B, 0x58, 0xB4, 0xBF, 0xD9, 0xC3, 0x5C, 0x9A,
+ 0x34, 0x85, 0xBE, 0xD0, 0x75, 0x38, 0x6D, 0xA2, 0xF9, 0xC8, 0x1B, 0x44, 0x62, 0x3B, 0x8C, 0x60,
+ 0x0E, 0xC7, 0x9A, 0xF6, 0x72, 0xAC, 0xB7, 0x86, 0x33, 0x5A, 0xF0, 0xA3, 0x2C, 0x45, 0x58, 0xB7,
+ 0x16, 0xDB, 0x6A, 0x09, 0x37, 0x18, 0xB7, 0x64, 0xDA, 0x82, 0x57, 0xB3, 0xF7, 0x5B, 0xBD, 0xAC,
+ 0xB7, 0x57, 0x2E, 0x79, 0x5D, 0x7A, 0x71, 0x4E, 0x12, 0x4B, 0x6D, 0x2D, 0x7E, 0xDB, 0x2B, 0xA6,
+ 0xB4, 0xD2, 0xFA, 0xFA, 0x25, 0xA0, 0xE8, 0x35, 0xCF, 0xDB, 0x41, 0x2D, 0xEE, 0x3E, 0xD3, 0xFB,
+ 0x2F, 0xDF, 0x49, 0x20, 0xDA, 0xB6, 0xD1, 0xAC, 0xB1, 0x34, 0x72, 0xB3, 0x30, 0xDC, 0xAE, 0xDE,
+ 0x78, 0xDB, 0xF2, 0x9C, 0x83, 0x86, 0x07, 0x81, 0x81, 0x9C, 0x8F, 0x26, 0xAD, 0x0E, 0x1D, 0xA3,
+ 0xC9, 0x37, 0x56, 0xA4, 0xA0, 0xEC, 0xD2, 0x4A, 0x29, 0xDA, 0xF6, 0xF7, 0x6F, 0x2B, 0x5E, 0xEB,
+ 0x76, 0xD5, 0x92, 0xBD, 0xAC, 0x8D, 0xBF, 0xB2, 0xAA, 0x37, 0x18, 0xDF, 0x47, 0xA5, 0xF6, 0xB2,
+ 0x49, 0xDB, 0x44, 0xAC, 0xF6, 0x4B, 0x4B, 0x77, 0xEC, 0x89, 0xE2, 0xD7, 0xBF, 0x6C, 0xA5, 0xE1,
+ 0xBF, 0x65, 0x0D, 0x46, 0x28, 0xCC, 0x04, 0xC4, 0xB1, 0x6A, 0xF0, 0xE4, 0xB0, 0x18, 0x48, 0xD8,
+ 0x19, 0x38, 0xE7, 0xA9, 0xC7, 0x00, 0xD7, 0x1E, 0x2D, 0xE4, 0x90, 0x49, 0xE0, 0x69, 0xD7, 0xE5,
+ 0xB6, 0x89, 0xCA, 0x83, 0x77, 0xFF, 0x00, 0xB7, 0x65, 0xA2, 0x4A, 0xDB, 0xA5, 0x6E, 0xD6, 0xB0,
+ 0xD6, 0x52, 0xF6, 0xE6, 0x76, 0xDB, 0x45, 0x64, 0xBC, 0xFE, 0x1D, 0x52, 0xD3, 0x4D, 0xDE, 0xD7,
+ 0xDA, 0xDE, 0x37, 0xF1, 0x73, 0xC0, 0x7F, 0xB5, 0xFF, 0x00, 0xC5, 0x5D, 0x1E, 0x3B, 0x0B, 0xDF,
+ 0xD9, 0xCF, 0x58, 0xD2, 0x06, 0xD5, 0x42, 0x6D, 0xAE, 0x21, 0xBA, 0x95, 0x48, 0x60, 0xC5, 0x46,
+ 0xE9, 0x02, 0xFF, 0x00, 0x08, 0xE7, 0xA7, 0x6E, 0xBD, 0x3E, 0x97, 0x0F, 0x5F, 0x86, 0x72, 0x4C,
+ 0xA6, 0x95, 0x78, 0x62, 0xDD, 0x5A, 0xD5, 0x21, 0x17, 0x3A, 0x4D, 0x72, 0x3A, 0x72, 0x69, 0x2E,
+ 0x55, 0x26, 0x9C, 0x24, 0x96, 0xD7, 0x8B, 0xB6, 0x9A, 0x6C, 0xCF, 0x32, 0x7C, 0x35, 0xED, 0x73,
+ 0x5A, 0x39, 0x85, 0x49, 0xBE, 0x5A, 0x5C, 0xDC, 0xA9, 0x2D, 0x1F, 0x32, 0xE5, 0x57, 0x7B, 0xD9,
+ 0x2B, 0x24, 0x92, 0x5D, 0x3A, 0x1D, 0xF7, 0x82, 0x47, 0xED, 0x57, 0xE0, 0xDF, 0x03, 0xAE, 0x83,
+ 0x17, 0xEC, 0xBF, 0xE2, 0x9B, 0xED, 0x6E, 0xCA, 0xE2, 0x2F, 0xB3, 0x5E, 0xB6, 0xA5, 0x6D, 0x6F,
+ 0xA5, 0xC9, 0x6E, 0x10, 0x09, 0x51, 0xE0, 0x04, 0xB8, 0x93, 0x76, 0xD2, 0x18, 0x30, 0x5C, 0x64,
+ 0x11, 0xEB, 0xE0, 0xF1, 0x0E, 0x6B, 0xC2, 0xD8, 0xF9, 0xAC, 0x46, 0x57, 0x3A, 0xB1, 0x94, 0x62,
+ 0xF9, 0xA3, 0x34, 0xA4, 0xA5, 0x25, 0xB2, 0x87, 0x2C, 0x52, 0x4B, 0xB3, 0x95, 0xBE, 0x57, 0x49,
+ 0x4E, 0x57, 0xC3, 0x71, 0xCB, 0x29, 0x3C, 0x32, 0xA9, 0xCD, 0x07, 0x26, 0xD3, 0x6B, 0x54, 0x9B,
+ 0x6E, 0xCF, 0xA3, 0x4B, 0xC9, 0x27, 0xB6, 0x87, 0xD4, 0xFF, 0x00, 0x09, 0x3E, 0x0A, 0x7E, 0xD9,
+ 0xDF, 0x16, 0x3E, 0x1E, 0x78, 0xB3, 0xE2, 0x19, 0xF0, 0x27, 0x82, 0x7E, 0x1D, 0xC1, 0xE1, 0x0B,
+ 0x99, 0xED, 0x2E, 0xBC, 0x39, 0xE2, 0xD5, 0xD5, 0xEE, 0xB5, 0x5B, 0xF5, 0x8A, 0xCB, 0xCE, 0x8E,
+ 0x58, 0x66, 0xB5, 0xB6, 0x92, 0x00, 0x24, 0x60, 0x22, 0x55, 0x67, 0x04, 0x36, 0x09, 0x01, 0x4D,
+ 0x7C, 0xBA, 0xAE, 0xAA, 0x51, 0x95, 0x6C, 0x34, 0x63, 0xC9, 0x1D, 0xD4, 0x9A, 0x8C, 0xAD, 0xA6,
+ 0xAA, 0x36, 0x77, 0x8E, 0xA9, 0x2E, 0xBE, 0x5A, 0x5C, 0xF6, 0x16, 0x53, 0x47, 0x48, 0xA9, 0xBD,
+ 0x7E, 0x5F, 0x24, 0xBC, 0xAD, 0xD2, 0xD6, 0xFC, 0x17, 0x90, 0xFC, 0x2A, 0xF8, 0xF1, 0xFF, 0x00,
+ 0x05, 0x25, 0xF8, 0x1F, 0xE3, 0x7D, 0x23, 0xE2, 0x2F, 0xC3, 0x2F, 0x81, 0x17, 0xBE, 0x1C, 0xF1,
+ 0x0D, 0x8D, 0xBB, 0xD9, 0x5C, 0x21, 0x78, 0xEF, 0x74, 0xED, 0x7A, 0xC6, 0xE5, 0x76, 0xDE, 0x69,
+ 0x5A, 0x9D, 0xA9, 0x98, 0x47, 0x73, 0x65, 0x3C, 0x65, 0x92, 0x5B, 0x79, 0x55, 0x91, 0x94, 0x9C,
+ 0x8C, 0x1C, 0x57, 0x4C, 0xEA, 0x61, 0x29, 0xE1, 0xE9, 0xD5, 0x55, 0xE3, 0xED, 0x1A, 0x4F, 0x95,
+ 0x6B, 0xCA, 0xEC, 0xAD, 0x19, 0x5A, 0x3A, 0x6B, 0xBA, 0xBF, 0x46, 0xD3, 0xE8, 0x4C, 0x72, 0xB5,
+ 0x4A, 0x49, 0xAA, 0x9E, 0xEF, 0x9C, 0x5B, 0xBA, 0xF9, 0x49, 0x59, 0x76, 0x56, 0x5E, 0x5D, 0x2D,
+ 0xF7, 0x57, 0xED, 0x1B, 0xF0, 0x9F, 0xE2, 0x8F, 0xC6, 0x9F, 0x83, 0x1A, 0x8F, 0xED, 0x87, 0xFB,
+ 0x1D, 0x7C, 0x16, 0xBA, 0xF0, 0x3D, 0xD6, 0x9F, 0x1C, 0x36, 0x9F, 0xB4, 0x7F, 0xEC, 0x85, 0xAD,
+ 0xE9, 0x12, 0x6A, 0x3A, 0x97, 0xC0, 0x7D, 0x56, 0xF9, 0x0A, 0xDB, 0x6B, 0x5E, 0x17, 0xD4, 0x84,
+ 0x8A, 0x35, 0x1D, 0x06, 0xEE, 0x68, 0x26, 0x65, 0x5C, 0x17, 0xB5, 0x3B, 0xCC, 0xBE, 0x4C, 0x61,
+ 0x11, 0x7D, 0xBE, 0x1A, 0xCD, 0x72, 0x3C, 0x0F, 0xD6, 0xEB, 0x66, 0x33, 0x77, 0x95, 0x0A, 0xB0,
+ 0x82, 0x8A, 0x6A, 0xD5, 0x64, 0xAD, 0x4B, 0x97, 0x7B, 0xC6, 0xFA, 0x36, 0xD4, 0x52, 0x5E, 0xF5,
+ 0xD3, 0xF7, 0x4E, 0x2C, 0x46, 0x59, 0xED, 0x2B, 0x28, 0x4E, 0x2D, 0x46, 0x4F, 0x46, 0xB9, 0x6D,
+ 0x65, 0x6B, 0xA7, 0x17, 0x14, 0x96, 0x9A, 0xD9, 0x75, 0x69, 0x45, 0x1F, 0x90, 0xF7, 0x30, 0xFF,
+ 0x00, 0xC1, 0x44, 0x6E, 0x31, 0xE5, 0xFC, 0x21, 0xBF, 0xB5, 0x50, 0xA0, 0x6D, 0x83, 0x45, 0xB4,
+ 0xC1, 0xC0, 0xF7, 0xB8, 0x3D, 0x78, 0xAF, 0x83, 0x79, 0x9E, 0x35, 0xC5, 0x46, 0x34, 0xE2, 0x97,
+ 0xA7, 0xA5, 0xBA, 0xF4, 0x6A, 0xEB, 0xFC, 0xB4, 0x3D, 0x3A, 0x59, 0x26, 0x55, 0x4D, 0x5B, 0x99,
+ 0xDF, 0xA6, 0xEA, 0xDF, 0x72, 0xFF, 0x00, 0x81, 0xF7, 0x23, 0xD3, 0xBE, 0x18, 0x6B, 0xFF, 0x00,
+ 0xB7, 0x25, 0x9B, 0xA7, 0x83, 0xBE, 0x31, 0x7C, 0x19, 0xF1, 0x97, 0x8C, 0x3E, 0x17, 0xDF, 0x07,
+ 0x87, 0xC8, 0xD3, 0x6C, 0xEC, 0x6C, 0xBC, 0x49, 0xE0, 0x39, 0xA5, 0xC8, 0x3A, 0xA6, 0x89, 0x38,
+ 0x94, 0x1F, 0x31, 0x0B, 0x06, 0x68, 0x18, 0x98, 0xE5, 0x0A, 0x54, 0x85, 0x27, 0x70, 0xDA, 0x86,
+ 0x6F, 0x8D, 0x52, 0xE5, 0xC4, 0xC5, 0xBA, 0x69, 0x5A, 0xC9, 0xDB, 0xB6, 0xD7, 0x7E, 0x56, 0xD7,
+ 0xBB, 0xB7, 0x44, 0x6D, 0x1C, 0xA7, 0x2B, 0x85, 0x17, 0x4D, 0xB7, 0x24, 0xD6, 0xCF, 0x4B, 0x7A,
+ 0x59, 0x2B, 0x69, 0xDA, 0xCB, 0x6E, 0xCA, 0xDE, 0x6D, 0xF1, 0x8F, 0xF6, 0x67, 0xFD, 0xBA, 0x7C,
+ 0x2B, 0xAD, 0x45, 0x2F, 0x84, 0xAE, 0x7C, 0x75, 0xF1, 0x13, 0xC0, 0x9A, 0xD4, 0x6D, 0x77, 0xE1,
+ 0x5F, 0x15, 0xE8, 0xB6, 0xF0, 0xE8, 0x4F, 0x2C, 0x41, 0xF8, 0xB7, 0xBF, 0xB4, 0x6D, 0x8F, 0x05,
+ 0xD2, 0x0C, 0xAB, 0xC6, 0x72, 0x32, 0x19, 0x94, 0xB2, 0x90, 0x4A, 0xAD, 0x8E, 0xCC, 0xE8, 0xCA,
+ 0x2E, 0x8D, 0x44, 0xE9, 0xDE, 0xE9, 0x59, 0x6C, 0xAD, 0xA6, 0x96, 0xB2, 0x5B, 0x69, 0xD3, 0x45,
+ 0x6D, 0x05, 0x0C, 0x9F, 0x26, 0xF6, 0x3C, 0x95, 0xA8, 0xEB, 0x6B, 0x27, 0xCD, 0x25, 0x65, 0x65,
+ 0x6B, 0xDB, 0x7D, 0x2E, 0xB9, 0x6F, 0xA3, 0xD7, 0x54, 0x8F, 0x2A, 0xF0, 0xE7, 0xC2, 0x7F, 0xF8,
+ 0x28, 0x17, 0x85, 0x5F, 0x58, 0x9F, 0x46, 0xF0, 0x67, 0xC4, 0xA8, 0xAE, 0xF5, 0xFF, 0x00, 0x0F,
+ 0x5F, 0xF8, 0x57, 0x55, 0xBA, 0xB9, 0xBC, 0x82, 0xFA, 0x5B, 0x8B, 0x0D, 0x4A, 0x25, 0x4B, 0xA8,
+ 0x00, 0x92, 0x76, 0x55, 0xCA, 0xA7, 0x0C, 0xA0, 0x32, 0xEE, 0x6C, 0x11, 0x93, 0x99, 0xFE, 0xD6,
+ 0xCC, 0x7E, 0xAE, 0xA8, 0xDB, 0xDE, 0xBB, 0x69, 0xE8, 0xAC, 0xAC, 0xAC, 0x92, 0x56, 0x5A, 0x35,
+ 0x77, 0x7B, 0xDF, 0x4D, 0x34, 0x46, 0xD0, 0xCB, 0xF2, 0xBA, 0x72, 0x52, 0xA3, 0x05, 0x17, 0x64,
+ 0x9D, 0xA3, 0xAB, 0x4B, 0xA3, 0xBA, 0x77, 0x4F, 0x66, 0xB6, 0xB1, 0xE4, 0xD3, 0x7E, 0xC6, 0xBF,
+ 0xB5, 0x8D, 0xC1, 0xCC, 0xFF, 0x00, 0x07, 0x7C, 0x6B, 0x39, 0xC6, 0x33, 0x34, 0x96, 0xF2, 0x1C,
+ 0x63, 0xA6, 0x4C, 0xD5, 0xE5, 0x4B, 0xEB, 0x73, 0x4A, 0x32, 0x94, 0x9A, 0xF3, 0x7F, 0xF0, 0x4E,
+ 0xEA, 0x7F, 0x52, 0xA4, 0x92, 0xA7, 0x18, 0xA5, 0xE5, 0x1B, 0x7E, 0x48, 0xAF, 0xFF, 0x00, 0x0C,
+ 0x55, 0xFB, 0x53, 0xFF, 0x00, 0xD1, 0x14, 0xF1, 0x77, 0xFD, 0xF3, 0x6B, 0xFF, 0x00, 0xC7, 0x6B,
+ 0x1F, 0x61, 0x53, 0xF9, 0x4D, 0x7D, 0xBD, 0x1E, 0xFF, 0x00, 0x83, 0xFF, 0x00, 0x20, 0xFF, 0x00,
+ 0x86, 0x2A, 0xFD, 0xA9, 0xFF, 0x00, 0xE8, 0x8A, 0x78, 0xBB, 0xFE, 0xF9, 0xB5, 0xFF, 0x00, 0xE3,
+ 0xB4, 0x7B, 0x0A, 0x9F, 0xCA, 0x1E, 0xDE, 0x8F, 0x7F, 0xC1, 0xFF, 0x00, 0x90, 0x7F, 0xC3, 0x15,
+ 0x7E, 0xD4, 0xFF, 0x00, 0xF4, 0x45, 0x3C, 0x5D, 0xFF, 0x00, 0x7C, 0xDA, 0xFF, 0x00, 0xF1, 0xDA,
+ 0x3D, 0x85, 0x4F, 0xE5, 0x0F, 0x6F, 0x47, 0xBF, 0xE0, 0xFF, 0x00, 0xC8, 0x3F, 0xE1, 0x8A, 0xBF,
+ 0x6A, 0x7F, 0xFA, 0x22, 0x9E, 0x2E, 0xFF, 0x00, 0xBE, 0x6D, 0x7F, 0xF8, 0xED, 0x1E, 0xC2, 0xA7,
+ 0xF2, 0x87, 0xB7, 0xA3, 0xDF, 0xF0, 0x7F, 0xE4, 0x3E, 0x2F, 0xD8, 0xA3, 0xF6, 0xA5, 0x77, 0x44,
+ 0x6F, 0x83, 0x1E, 0x2A, 0x85, 0x49, 0x00, 0xC8, 0xEB, 0x6D, 0xB2, 0x30, 0x07, 0x24, 0x85, 0x94,
+ 0x9E, 0xDD, 0x81, 0xAD, 0x21, 0x4A, 0x5C, 0xAA, 0x9C, 0xA0, 0x92, 0x6D, 0x6A, 0xEE, 0x9A, 0x4B,
+ 0xA6, 0x9A, 0x24, 0xFD, 0x1E, 0xCB, 0xA6, 0x84, 0xBA, 0xF4, 0x56, 0xB7, 0xD1, 0x74, 0x49, 0xFF,
+ 0x00, 0x91, 0xD4, 0xEB, 0xDF, 0xB1, 0x77, 0xED, 0x1B, 0x62, 0xB6, 0x3A, 0x66, 0x81, 0xF0, 0x97,
+ 0xC4, 0xBA, 0xCD, 0xBD, 0xBD, 0xB8, 0x96, 0x7D, 0x5E, 0x2D, 0x31, 0x74, 0xC6, 0xB8, 0x92, 0x4E,
+ 0x5A, 0x26, 0x8A, 0x59, 0xB2, 0x7C, 0xB2, 0x0A, 0x86, 0x00, 0x02, 0x30, 0x47, 0xBF, 0xDB, 0x50,
+ 0xE2, 0x8A, 0xB9, 0x6E, 0x55, 0x1C, 0xAF, 0x2D, 0x83, 0x71, 0xBE, 0xBC, 0xD6, 0xB3, 0xB6, 0x89,
+ 0xAB, 0x59, 0xAB, 0x2B, 0x2B, 0x5A, 0xDB, 0x6B, 0xEE, 0xA4, 0x71, 0x42, 0x95, 0x19, 0x55, 0x95,
+ 0x79, 0x4D, 0xEB, 0xD1, 0xAD, 0x12, 0x5B, 0x59, 0x6B, 0x6B, 0xF5, 0xDB, 0xB5, 0xB4, 0x39, 0x33,
+ 0xFB, 0x15, 0xFE, 0xD4, 0xE7, 0x9F, 0xF8, 0x52, 0xBE, 0x2E, 0xFF, 0x00, 0xBE, 0x6D, 0x7D, 0x38,
+ 0x00, 0x79, 0xDE, 0xC2, 0xBE, 0x32, 0xBB, 0xC4, 0xE2, 0x6A, 0xCA, 0xB5, 0x54, 0xDC, 0x9F, 0xF5,
+ 0x65, 0xE4, 0xB6, 0x4B, 0xA2, 0xD0, 0xEE, 0x85, 0x5A, 0x10, 0x8A, 0x8A, 0x7A, 0x2F, 0x2F, 0xF8,
+ 0x01, 0xFF, 0x00, 0x0C, 0x55, 0xFB, 0x53, 0xFF, 0x00, 0xD1, 0x14, 0xF1, 0x77, 0xFD, 0xF3, 0x6B,
+ 0xFF, 0x00, 0xC7, 0x6B, 0x0F, 0x61, 0x53, 0xF9, 0x47, 0xED, 0xE8, 0xF7, 0xFC, 0x1F, 0xF9, 0x02,
+ 0xFE, 0xC5, 0x3F, 0xB5, 0x39, 0x2A, 0xAB, 0xF0, 0x53, 0xC5, 0xD9, 0x38, 0x0A, 0x02, 0xDA, 0xFA,
+ 0x70, 0x00, 0xF3, 0x7D, 0xAA, 0xA1, 0x86, 0xA9, 0x29, 0x46, 0x16, 0xB5, 0xEC, 0xB5, 0xB2, 0x4B,
+ 0xA7, 0xF5, 0xE4, 0x1E, 0xDE, 0x8A, 0x49, 0x27, 0xF8, 0x3F, 0xF2, 0x3B, 0x4D, 0x2B, 0xF6, 0x21,
+ 0xFD, 0xA7, 0x6D, 0xA1, 0x43, 0x27, 0xC1, 0x9F, 0x16, 0x23, 0x30, 0x0E, 0xE0, 0xAD, 0xA9, 0xC6,
+ 0x00, 0xE9, 0xFB, 0xDE, 0xD9, 0x1F, 0x4A, 0xFE, 0xDF, 0xF0, 0x73, 0x07, 0xE1, 0xDE, 0x41, 0x91,
+ 0xD2, 0xC4, 0xE2, 0xF3, 0x08, 0x46, 0xAC, 0x9C, 0x5D, 0x45, 0xCB, 0x26, 0xD4, 0x9A, 0xB2, 0xB7,
+ 0xBB, 0x76, 0xB4, 0xB7, 0xBA, 0xAD, 0xA7, 0xDF, 0xF3, 0x98, 0xF9, 0xE2, 0x6A, 0x54, 0x71, 0x8C,
+ 0x34, 0xD9, 0x6D, 0xF7, 0x7E, 0x1B, 0x76, 0x47, 0x48, 0xBF, 0xB1, 0xDF, 0xED, 0x2F, 0x6A, 0x9E,
+ 0x6B, 0xFC, 0x19, 0xF1, 0x6B, 0x2C, 0x63, 0x6E, 0xD4, 0x8E, 0xD1, 0x8A, 0x92, 0xBF, 0x29, 0xDA,
+ 0x64, 0x20, 0x81, 0x8C, 0x9E, 0x3A, 0x0A, 0xFE, 0x9C, 0xCD, 0x7C, 0x59, 0xF0, 0xD3, 0x87, 0x72,
+ 0x9F, 0x6C, 0xB3, 0x28, 0x4A, 0x6E, 0x29, 0x45, 0x28, 0xD4, 0x6D, 0x5E, 0xC9, 0x4F, 0xDD, 0x8D,
+ 0xFD, 0xCD, 0x65, 0xBA, 0xBF, 0x2D, 0x92, 0x68, 0xF2, 0xF0, 0xF8, 0x2C, 0x44, 0xEB, 0x24, 0xE0,
+ 0xED, 0xE5, 0x6E, 0xDB, 0x6A, 0x9A, 0xED, 0xA5, 0xBE, 0xE3, 0x90, 0x97, 0xF6, 0x37, 0xFD, 0xA9,
+ 0xE5, 0x95, 0xA4, 0x6F, 0x82, 0xFE, 0x30, 0x56, 0x97, 0xF7, 0x45, 0xB6, 0xDB, 0x61, 0x63, 0x07,
+ 0x02, 0x6D, 0x9E, 0x6F, 0xD0, 0x00, 0x31, 0x8A, 0xFE, 0x2D, 0xCF, 0x3C, 0x44, 0xFE, 0xDD, 0xE2,
+ 0x58, 0xE7, 0x0F, 0x32, 0xF6, 0x70, 0xAC, 0xEA, 0xD0, 0xAB, 0x78, 0xD5, 0x9F, 0x35, 0x08, 0xA6,
+ 0xE1, 0x8E, 0x51, 0x4A, 0xCB, 0x95, 0x45, 0xDA, 0x9A, 0x8F, 0x3A, 0x4D, 0xDE, 0xCA, 0x37, 0x3D,
+ 0xBA, 0x78, 0x5F, 0x65, 0x4E, 0x34, 0xD4, 0x55, 0x92, 0xE6, 0x4A, 0xCB, 0x7B, 0x2F, 0x76, 0xFA,
+ 0x5B, 0xF2, 0x7A, 0x24, 0x49, 0x6B, 0xFB, 0x1A, 0x7E, 0xD4, 0x71, 0x8B, 0x58, 0x8F, 0xC1, 0xDF,
+ 0x1B, 0x47, 0x1D, 0xBC, 0xE1, 0xF1, 0x11, 0xB6, 0x12, 0xC6, 0x49, 0x01, 0xA5, 0x45, 0x32, 0xE0,
+ 0x96, 0x05, 0x06, 0x39, 0xC0, 0xC5, 0x63, 0x82, 0xE2, 0xBE, 0x1D, 0xA1, 0x94, 0x61, 0x30, 0x78,
+ 0x0C, 0xC9, 0xD3, 0xAB, 0x4A, 0xAF, 0x32, 0x9B, 0xF6, 0xD3, 0x9C, 0x1C, 0x54, 0xB9, 0xF1, 0x5E,
+ 0xCD, 0x46, 0xD5, 0x3E, 0xB1, 0x1E, 0x58, 0xBA, 0x49, 0xB7, 0x49, 0x2B, 0xD9, 0x37, 0x63, 0x49,
+ 0x47, 0x18, 0xAE, 0xE8, 0xAD, 0x52, 0xF7, 0x56, 0xC9, 0x5D, 0x2D, 0x34, 0x69, 0xAB, 0x77, 0x56,
+ 0xBA, 0xF2, 0x1B, 0xA2, 0xFE, 0xC7, 0xFF, 0x00, 0xB5, 0x45, 0xBC, 0xE2, 0xD1, 0xFE, 0x0A, 0xF8,
+ 0xA4, 0xDB, 0xEE, 0x67, 0x69, 0x59, 0x2D, 0x54, 0x82, 0x4F, 0x20, 0x9F, 0x3B, 0xDE, 0xBE, 0x9B,
+ 0xC0, 0xCF, 0x19, 0xBF, 0xD5, 0x8C, 0xF2, 0x8F, 0x06, 0xE3, 0xE7, 0x45, 0xE5, 0xD3, 0xA9, 0x39,
+ 0x7B, 0x69, 0xC6, 0x51, 0x97, 0x35, 0x49, 0xCA, 0x4D, 0x49, 0xDB, 0x5D, 0x5D, 0xD3, 0xB2, 0x4B,
+ 0x45, 0xBA, 0x39, 0xB3, 0x0C, 0x0C, 0x2B, 0x41, 0xD5, 0xA7, 0x7E, 0x74, 0xB6, 0x5B, 0x59, 0x24,
+ 0xBD, 0x11, 0xD5, 0xCF, 0xFB, 0x18, 0x7E, 0xD3, 0x4E, 0xB2, 0xC2, 0xDF, 0x06, 0x7C, 0x56, 0x23,
+ 0x64, 0x11, 0x3F, 0xCD, 0x68, 0xD1, 0xE0, 0x9C, 0x00, 0x3F, 0x7B, 0xEC, 0x31, 0xED, 0xED, 0x5F,
+ 0xD6, 0x79, 0xF7, 0x1D, 0xF8, 0x61, 0x9B, 0xC3, 0x13, 0x90, 0x55, 0xCC, 0x23, 0xEC, 0xAB, 0xC5,
+ 0xD1, 0x9A, 0x6D, 0xCA, 0x0D, 0x3B, 0x49, 0xD9, 0x28, 0x68, 0xD5, 0x95, 0xDB, 0xDB, 0x6B, 0xDF,
+ 0x43, 0xC4, 0xA3, 0x87, 0xC5, 0x53, 0xE5, 0xA8, 0xA3, 0xAA, 0xDB, 0x6E, 0xDF, 0x75, 0xBF, 0x0E,
+ 0x85, 0x0B, 0x4F, 0xD8, 0xDF, 0xF6, 0xA2, 0x0D, 0xF6, 0x39, 0x3E, 0x0C, 0xF8, 0xB3, 0xF7, 0x20,
+ 0x24, 0x6E, 0x12, 0xDB, 0x12, 0xA6, 0x7E, 0x42, 0xC7, 0xCD, 0xC0, 0xF4, 0xC7, 0xB5, 0x7C, 0x07,
+ 0x08, 0xF8, 0xA5, 0xC3, 0x18, 0x4C, 0x45, 0x5E, 0x0E, 0xCE, 0xB3, 0x18, 0xF3, 0x61, 0x14, 0xA3,
+ 0x09, 0xA5, 0x36, 0xAB, 0x51, 0x8A, 0xE6, 0x84, 0xE5, 0x25, 0x0E, 0x55, 0x28, 0xC6, 0xD0, 0xE5,
+ 0xBB, 0x6F, 0x97, 0x6D, 0x51, 0xD5, 0x5F, 0x07, 0x55, 0xC6, 0x35, 0xE9, 0xC3, 0x47, 0x6B, 0xAD,
+ 0x15, 0x9D, 0xB5, 0x4B, 0xBF, 0xCB, 0x62, 0x76, 0xFD, 0x8D, 0xBF, 0x69, 0xD0, 0x31, 0xFF, 0x00,
+ 0x0A, 0x6B, 0xC5, 0x43, 0x68, 0x1F, 0x2E, 0x2D, 0x46, 0x30, 0x3A, 0x63, 0xCD, 0x1D, 0xB1, 0xC7,
+ 0xA6, 0x2B, 0xE8, 0xEB, 0x78, 0x9F, 0xC0, 0x73, 0x84, 0x79, 0x33, 0x08, 0xF4, 0x4A, 0xD1, 0xA9,
+ 0xE9, 0x67, 0x68, 0xAF, 0x4B, 0x37, 0xF3, 0xDC, 0xCE, 0x38, 0x2C, 0x4A, 0x4B, 0xDC, 0xD3, 0xE5,
+ 0xFD, 0x7C, 0xAD, 0xB7, 0x90, 0xC3, 0xFB, 0x19, 0xFE, 0xD3, 0xF9, 0x20, 0x7C, 0x19, 0xF1, 0x57,
+ 0xCB, 0x90, 0x57, 0xFD, 0x10, 0x30, 0x00, 0xE3, 0x21, 0x7C, 0xEE, 0x9E, 0xF8, 0xC7, 0x07, 0xD3,
+ 0x8F, 0x23, 0x11, 0xE2, 0x5F, 0x03, 0x2F, 0x7D, 0x66, 0x10, 0xB3, 0x5A, 0x7B, 0xB3, 0xEB, 0xE4,
+ 0xA1, 0xA5, 0xBB, 0x5A, 0x36, 0x56, 0xD1, 0x68, 0x5A, 0xC2, 0xD6, 0x51, 0xD2, 0x3A, 0x2F, 0x4E,
+ 0x8B, 0xB7, 0xF5, 0xDB, 0xC8, 0x83, 0xFE, 0x18, 0xCB, 0xF6, 0xA1, 0x24, 0x2A, 0xFC, 0x18, 0xF1,
+ 0x6F, 0xCA, 0x07, 0xCB, 0xB2, 0xDB, 0x80, 0x46, 0x47, 0x1E, 0x6F, 0x70, 0x2B, 0xE7, 0xAB, 0x78,
+ 0x8F, 0xC1, 0x13, 0x92, 0x8C, 0x71, 0xF0, 0xB6, 0xAB, 0xE1, 0x9F, 0x7E, 0x96, 0x8A, 0x5D, 0x35,
+ 0xED, 0xA7, 0x95, 0xF5, 0x8E, 0x13, 0x11, 0x15, 0xF0, 0x69, 0xA7, 0x6F, 0xEB, 0xFE, 0x1A, 0xC2,
+ 0xAF, 0xEC, 0x65, 0xFB, 0x4F, 0xE0, 0x2F, 0xFC, 0x29, 0x9F, 0x15, 0x8D, 0xA7, 0x18, 0x02, 0xD7,
+ 0x3C, 0x11, 0xD0, 0x79, 0xBD, 0x3E, 0x61, 0x5D, 0x31, 0xF1, 0x1B, 0x81, 0x54, 0x23, 0x2A, 0x99,
+ 0x8C, 0x54, 0x55, 0xAD, 0xEE, 0xCD, 0xD9, 0xAD, 0x56, 0xD1, 0x7A, 0x75, 0xE9, 0x6F, 0x42, 0x56,
+ 0x0F, 0x11, 0xA5, 0xA1, 0xF9, 0x7C, 0xBF, 0x2F, 0xCB, 0xBA, 0x35, 0xB4, 0x7F, 0xD9, 0x6B, 0xF6,
+ 0xC4, 0xF0, 0x86, 0xA7, 0x6D, 0xE2, 0x4F, 0x0A, 0xFC, 0x2E, 0xF1, 0x96, 0x93, 0xAC, 0x59, 0x9D,
+ 0x91, 0x49, 0x6C, 0xD6, 0xBB, 0x25, 0x03, 0x19, 0x8A, 0x54, 0xF3, 0xB0, 0xC0, 0xE0, 0x0D, 0xA4,
+ 0x7A, 0x63, 0x9C, 0x57, 0xE6, 0x3E, 0x34, 0xE6, 0x3C, 0x19, 0xC6, 0x59, 0x42, 0xCC, 0xE9, 0x66,
+ 0x10, 0x58, 0xEA, 0x49, 0x7B, 0x34, 0xA3, 0x26, 0x9A, 0xB2, 0xD1, 0xBE, 0x54, 0x92, 0x76, 0xD7,
+ 0x6B, 0x6F, 0x75, 0xA3, 0x3A, 0x70, 0x54, 0x2A, 0x42, 0x4A, 0x94, 0xE9, 0xDE, 0x1F, 0x2B, 0xAF,
+ 0x4F, 0xEB, 0x6E, 0x87, 0xE8, 0x47, 0xC2, 0x7F, 0x8C, 0x1F, 0xB5, 0xEF, 0x86, 0x6D, 0x2D, 0xED,
+ 0x3C, 0x65, 0xFB, 0x3B, 0xFC, 0x45, 0x8A, 0xEE, 0xDD, 0x04, 0x4F, 0xAA, 0x78, 0x5E, 0xE6, 0xCD,
+ 0xD2, 0x72, 0xAB, 0x82, 0x5A, 0xDA, 0x49, 0xD7, 0x6E, 0x4A, 0x8E, 0x8C, 0xDD, 0xBF, 0x0F, 0xE5,
+ 0x4C, 0x2F, 0x15, 0xE2, 0xF0, 0xB0, 0xF6, 0x35, 0x63, 0xCF, 0x14, 0xED, 0x66, 0x94, 0x96, 0x8E,
+ 0xDA, 0x3D, 0x1B, 0x56, 0xD9, 0x34, 0xAC, 0xBA, 0xBD, 0x08, 0xC4, 0xF0, 0xFE, 0x0E, 0xAC, 0xB9,
+ 0xE8, 0xCF, 0x92, 0x5D, 0x5A, 0xBA, 0x7A, 0x2B, 0x2B, 0xD9, 0x34, 0xFB, 0x76, 0xB6, 0xDA, 0x33,
+ 0xE9, 0xA5, 0xFD, 0xA6, 0xBE, 0x3A, 0x2D, 0xBA, 0xAF, 0xFC, 0x29, 0xEF, 0x8E, 0x45, 0x92, 0x35,
+ 0x0B, 0x11, 0xF0, 0xEE, 0x96, 0xDC, 0xAA, 0xE0, 0x0F, 0x30, 0xDD, 0xFB, 0x01, 0xC6, 0x3E, 0xBC,
+ 0x66, 0xBD, 0x4F, 0xF5, 0xBB, 0x02, 0xE9, 0xB6, 0xF0, 0xD1, 0xE7, 0xD7, 0x4F, 0x7B, 0x7E, 0xC9,
+ 0x25, 0x6B, 0x75, 0xF8, 0x92, 0xFD, 0x38, 0x7F, 0xB0, 0x2B, 0xD9, 0x47, 0xEB, 0x12, 0xB5, 0xB7,
+ 0xD3, 0x4F, 0x35, 0xDB, 0xC9, 0x2B, 0x5A, 0xFA, 0x2D, 0x11, 0xF3, 0xD7, 0xC5, 0x1F, 0x8D, 0x5F,
+ 0xB5, 0x8E, 0xB9, 0x67, 0x71, 0x6F, 0xE0, 0xCF, 0xD9, 0xDB, 0xE2, 0x5D, 0xDD, 0xF4, 0x91, 0xEC,
+ 0x87, 0x54, 0xF1, 0x4C, 0xF6, 0x30, 0x43, 0x01, 0x20, 0x02, 0xEB, 0x6F, 0x1C, 0xEF, 0xD0, 0x0C,
+ 0x60, 0x10, 0x0F, 0x1C, 0xFA, 0x79, 0x78, 0xAE, 0x2D, 0xC5, 0x56, 0xA6, 0xE9, 0x50, 0x87, 0x2C,
+ 0x76, 0x6A, 0x29, 0x45, 0x7A, 0x5F, 0x57, 0x6F, 0x97, 0x96, 0xCC, 0xEE, 0xC1, 0xE4, 0x18, 0x3A,
+ 0x13, 0xF6, 0x95, 0x67, 0xCC, 0xF4, 0xD5, 0xA6, 0xFD, 0x6C, 0xAC, 0x92, 0xED, 0xA2, 0x7A, 0x5A,
+ 0xDD, 0x2D, 0xF9, 0x77, 0xE3, 0xAF, 0xD9, 0xB3, 0xF6, 0xD3, 0xF8, 0x91, 0xAD, 0xCD, 0xAF, 0xF8,
+ 0xBB, 0xE1, 0x57, 0x8D, 0x75, 0x3B, 0xE9, 0x32, 0xB1, 0x2B, 0xFD, 0x95, 0x6D, 0xAD, 0x10, 0x9C,
+ 0x88, 0xE1, 0x8F, 0xCE, 0xC2, 0xA8, 0xE0, 0x7A, 0xF0, 0x32, 0x78, 0xAF, 0x8D, 0xAF, 0x3C, 0x56,
+ 0x26, 0x4A, 0x55, 0x16, 0x9D, 0x17, 0x45, 0xFD, 0x7F, 0x92, 0xD9, 0x24, 0xBE, 0x92, 0x82, 0xC2,
+ 0x61, 0xE0, 0xA1, 0x4B, 0x45, 0xB6, 0xDF, 0xF0, 0x0D, 0x1F, 0xD9, 0x5B, 0xE1, 0x77, 0xC4, 0x0F,
+ 0x84, 0xFF, 0x00, 0xB7, 0xA7, 0xEC, 0x63, 0xE1, 0xFF, 0x00, 0x88, 0xBE, 0x13, 0xD5, 0x7C, 0x23,
+ 0xAB, 0xDE, 0x7E, 0xD2, 0xDF, 0x0F, 0x35, 0x3B, 0x3B, 0x1D, 0x56, 0x15, 0x8D, 0xEE, 0x6D, 0x9F,
+ 0xC5, 0xF6, 0x48, 0xB2, 0xC6, 0xCA, 0x4A, 0xB2, 0xEE, 0x8A, 0x45, 0xE0, 0xF0, 0x54, 0x83, 0xD2,
+ 0xAB, 0x2E, 0x83, 0x86, 0x63, 0x86, 0x4D, 0x5B, 0xDF, 0x87, 0xFE, 0x94, 0x8B, 0xAF, 0x28, 0x4B,
+ 0x09, 0x51, 0xC1, 0xE9, 0xCA, 0xFF, 0x00, 0x23, 0xFB, 0xD8, 0xAF, 0xD4, 0x4F, 0x90, 0x0A, 0x00,
+ 0x28, 0x00, 0xA0, 0x0F, 0x67, 0xFD, 0x85, 0xFF, 0x00, 0x64, 0xDD, 0x37, 0xE3, 0xD8, 0xFD, 0xAE,
+ 0xBC, 0x5F, 0x75, 0xA5, 0xC5, 0x7D, 0x36, 0x93, 0xFB, 0x58, 0xDB, 0xF8, 0x50, 0x31, 0x85, 0x5D,
+ 0x91, 0x20, 0xF8, 0x31, 0xF0, 0xF2, 0xE1, 0x53, 0x3B, 0x49, 0x03, 0x3A, 0x83, 0x90, 0x3E, 0xB8,
+ 0xAF, 0x83, 0xCE, 0xEA, 0xAA, 0x79, 0x8D, 0x48, 0xDD, 0xAF, 0x87, 0x67, 0x65, 0xF0, 0xAE, 0xDF,
+ 0xD6, 0xC7, 0xD1, 0x65, 0xFF, 0x00, 0xEE, 0x90, 0x5C, 0xAB, 0xAF, 0x7E, 0xFE, 0x47, 0xDE, 0xA7,
+ 0xFE, 0x09, 0xAF, 0xE1, 0xE5, 0xDA, 0x06, 0x8D, 0x1F, 0x0B, 0x82, 0xEB, 0x65, 0x11, 0x19, 0x03,
+ 0xE5, 0x07, 0x81, 0xEC, 0x38, 0x1D, 0xBF, 0x2F, 0x29, 0x62, 0x22, 0x97, 0xC5, 0x2B, 0x5B, 0xBF,
+ 0xF5, 0xFD, 0x74, 0xD0, 0xEA, 0x53, 0x6E, 0xCA, 0x34, 0xD5, 0xBD, 0x5A, 0xB7, 0x6E, 0xBF, 0xF0,
+ 0xD6, 0x23, 0x6F, 0xF8, 0x26, 0xB7, 0x87, 0xB1, 0xB8, 0x68, 0x96, 0xED, 0x85, 0xC7, 0xCD, 0xA7,
+ 0xC2, 0x3A, 0x8E, 0x41, 0x3B, 0x4F, 0xBF, 0xA5, 0x4F, 0xB7, 0x85, 0xB4, 0x72, 0xD3, 0xCF, 0xF2,
+ 0xFF, 0x00, 0x80, 0x52, 0xA8, 0xD5, 0x97, 0xB3, 0x4B, 0xD1, 0xBB, 0x7E, 0x6B, 0xF4, 0xEC, 0x56,
+ 0x4F, 0xF8, 0x26, 0xBE, 0x81, 0x95, 0x5F, 0xF8, 0x47, 0x2D, 0xC0, 0xE0, 0x64, 0xD8, 0x42, 0x02,
+ 0x8E, 0x9D, 0x3C, 0xBF, 0x6A, 0x9F, 0xAC, 0x45, 0x2D, 0x1C, 0xBE, 0xFF, 0x00, 0xF8, 0x06, 0x8A,
+ 0x4D, 0x24, 0xB9, 0x57, 0xDF, 0x2F, 0xF3, 0x27, 0x1F, 0xF0, 0x4D, 0x3F, 0x0E, 0x71, 0x8D, 0x06,
+ 0xDB, 0x00, 0x76, 0xD3, 0xA2, 0xC7, 0x03, 0x80, 0x3F, 0x77, 0xF4, 0xFA, 0x54, 0xFD, 0x61, 0x2D,
+ 0x13, 0x7F, 0x7F, 0xFC, 0x02, 0x79, 0xDD, 0x92, 0x50, 0x5F, 0x7C, 0xBF, 0xCC, 0x6B, 0x7F, 0xC1,
+ 0x35, 0x3C, 0x3C, 0xA9, 0x95, 0xF0, 0xFD, 0xB1, 0xE8, 0x15, 0x7F, 0xB3, 0xA2, 0x53, 0x8E, 0x31,
+ 0xC7, 0x97, 0xC7, 0x51, 0xE9, 0x4E, 0x38, 0x85, 0xA2, 0xBB, 0xFB, 0xFF, 0x00, 0xE0, 0x02, 0xA8,
+ 0xF4, 0x5C, 0xAA, 0xDE, 0xB2, 0xFF, 0x00, 0x3F, 0x21, 0xD6, 0xFF, 0x00, 0xF0, 0x4D, 0xDD, 0x11,
+ 0x4E, 0x3F, 0xB0, 0x6D, 0xD5, 0x40, 0x0D, 0xFB, 0xCB, 0x28, 0xF0, 0x31, 0x8C, 0x00, 0x02, 0x2F,
+ 0xA0, 0x1C, 0xF6, 0xE3, 0xE9, 0xD1, 0x47, 0x1A, 0xE9, 0x49, 0x3A, 0x73, 0x69, 0xF7, 0xBE, 0xDE,
+ 0x9E, 0x7B, 0x79, 0xE8, 0xAC, 0x4B, 0x49, 0x46, 0xFC, 0x8B, 0x4E, 0xD7, 0xFF, 0x00, 0x35, 0xB1,
+ 0xEA, 0xDF, 0x0F, 0xBF, 0x60, 0xBF, 0x0D, 0xF8, 0x0A, 0xF0, 0xF8, 0xCA, 0xD7, 0x40, 0xB4, 0xB9,
+ 0xF1, 0x3E, 0x9A, 0x4C, 0x3E, 0x13, 0x8A, 0xEB, 0x4E, 0x82, 0xEE, 0xDB, 0x4C, 0x9D, 0xD7, 0x03,
+ 0x50, 0x96, 0x06, 0x5C, 0x33, 0x44, 0xAC, 0xDE, 0x59, 0xC8, 0x2B, 0x26, 0xC7, 0x1F, 0x74, 0x57,
+ 0xB9, 0x1E, 0x21, 0xAD, 0x52, 0x2A, 0x9C, 0xEB, 0x49, 0xAB, 0x25, 0x2B, 0xB6, 0xAE, 0xBA, 0xAD,
+ 0x1E, 0xCD, 0xF4, 0xB5, 0xAC, 0xB6, 0x38, 0xAA, 0xD2, 0xA9, 0x38, 0x25, 0xCB, 0xA3, 0xE8, 0x9B,
+ 0xB7, 0x4B, 0x6A, 0xDD, 0x96, 0x8A, 0xDA, 0x6A, 0xB6, 0xE8, 0x71, 0x97, 0xDF, 0xF0, 0x4F, 0x3D,
+ 0x3B, 0x51, 0xBF, 0xB8, 0xD5, 0x6F, 0x34, 0xEF, 0xB7, 0xEA, 0x9A, 0x85, 0xE3, 0xDE, 0xDF, 0x5E,
+ 0xEA, 0x10, 0x06, 0xBD, 0xBD, 0x9E, 0x57, 0x2F, 0x34, 0xF2, 0xCC, 0x41, 0x2E, 0xEC, 0xE7, 0x25,
+ 0x89, 0xC9, 0x27, 0x35, 0xEA, 0x47, 0x8A, 0x15, 0x2A, 0x71, 0x84, 0x26, 0xAD, 0x15, 0x64, 0xB6,
+ 0x49, 0x25, 0x65, 0x64, 0x93, 0x49, 0xE9, 0x65, 0x64, 0xB4, 0xEC, 0xB4, 0x08, 0xD3, 0x97, 0x2B,
+ 0x84, 0xE2, 0x94, 0x74, 0x56, 0x4D, 0xB5, 0x6D, 0xAD, 0x6B, 0xED, 0x6E, 0x9A, 0xEB, 0xE4, 0x32,
+ 0x2F, 0xF8, 0x27, 0x7E, 0x86, 0xE0, 0xC6, 0xFE, 0x1F, 0xB6, 0x48, 0xD9, 0x41, 0x78, 0xC5, 0x9A,
+ 0xC8, 0x91, 0xC8, 0x83, 0x0A, 0xF1, 0xA8, 0x00, 0x00, 0x40, 0x50, 0x71, 0xE8, 0xB8, 0xE8, 0x33,
+ 0xA5, 0x0E, 0x2E, 0x94, 0x1D, 0xE3, 0x51, 0xC6, 0x2F, 0x59, 0x2D, 0x34, 0x69, 0x68, 0xD7, 0x4D,
+ 0x6D, 0x67, 0xAA, 0xBE, 0xED, 0x6A, 0xCC, 0x6A, 0x61, 0x1A, 0x8A, 0x7C, 0xA9, 0xBD, 0x95, 0xDB,
+ 0xF8, 0x5F, 0x47, 0xBB, 0xF7, 0x7A, 0x25, 0xA6, 0xB6, 0x4A, 0xC3, 0x47, 0xFC, 0x13, 0xA3, 0xC3,
+ 0xFB, 0x4A, 0x0D, 0x19, 0x5B, 0x72, 0x88, 0xA2, 0x59, 0x34, 0xB8, 0x7C, 0x94, 0x19, 0xE4, 0x90,
+ 0x38, 0xE3, 0x91, 0xE9, 0xCF, 0xE7, 0xBA, 0xE3, 0x39, 0xA8, 0xBF, 0xDE, 0xBE, 0xE9, 0x72, 0xDB,
+ 0x7B, 0x74, 0xFC, 0xF4, 0x5B, 0x68, 0x9A, 0x12, 0xC2, 0xB7, 0x67, 0xEC, 0x63, 0x65, 0xFD, 0xE6,
+ 0xF4, 0xD3, 0x6F, 0xE9, 0x6D, 0x6D, 0x36, 0x34, 0xE6, 0xFF, 0x00, 0x82, 0x7D, 0xE8, 0xD6, 0x5A,
+ 0x71, 0xD2, 0x34, 0xDD, 0x0E, 0x14, 0xB7, 0xBB, 0x1B, 0xB5, 0x79, 0xC5, 0xA2, 0xA4, 0xBA, 0x87,
+ 0xCB, 0x8F, 0x29, 0x98, 0x03, 0x88, 0x4E, 0x4F, 0xC8, 0x00, 0x04, 0xF2, 0x41, 0x20, 0x63, 0x9A,
+ 0x3C, 0x59, 0x3A, 0x69, 0x35, 0x57, 0xDE, 0x7E, 0x6D, 0x25, 0xB6, 0xC9, 0xDF, 0xD2, 0xCA, 0xDA,
+ 0x68, 0xAC, 0x8D, 0x61, 0x42, 0x53, 0x6E, 0x55, 0x23, 0xB7, 0xC2, 0x95, 0xEC, 0xB4, 0xDD, 0x6D,
+ 0xAE, 0x9F, 0x2D, 0xBD, 0x31, 0x57, 0xFE, 0x09, 0xD7, 0xA2, 0x49, 0xF3, 0x49, 0xA3, 0x44, 0x8D,
+ 0x9E, 0x02, 0x59, 0x46, 0x5E, 0x31, 0x9C, 0xAE, 0xD3, 0x81, 0x8C, 0x64, 0x00, 0x01, 0x1D, 0x0E,
+ 0x08, 0xA7, 0xFE, 0xB6, 0x56, 0x92, 0x72, 0xA9, 0x57, 0xCA, 0xC9, 0xB7, 0xA2, 0x49, 0x74, 0xB7,
+ 0x65, 0xD1, 0xE9, 0xD9, 0x68, 0x57, 0xB0, 0x74, 0xEC, 0xA9, 0xC1, 0x25, 0xEA, 0xD7, 0xE0, 0x9D,
+ 0xAE, 0xDF, 0xF5, 0xA0, 0xA3, 0xFE, 0x09, 0xCD, 0xA0, 0x63, 0x3F, 0xD8, 0xC7, 0xB8, 0xC7, 0xF6,
+ 0x6C, 0x6B, 0x80, 0x7A, 0x0C, 0x76, 0x1F, 0x77, 0xB0, 0xEE, 0x3B, 0x52, 0x5C, 0x55, 0xAA, 0x8A,
+ 0xA8, 0xED, 0xE8, 0xFA, 0x25, 0x6F, 0xB5, 0x6D, 0x3D, 0x76, 0xB6, 0xDD, 0x05, 0x1A, 0xC9, 0x25,
+ 0xC8, 0x95, 0x97, 0xF3, 0x3B, 0x7A, 0x6C, 0x8A, 0xF2, 0x7F, 0xC1, 0x39, 0xF4, 0x54, 0x24, 0x0D,
+ 0x06, 0x07, 0x5D, 0xA7, 0x05, 0x6C, 0xD0, 0x6E, 0x07, 0xAE, 0x72, 0xBE, 0xC0, 0x63, 0xD8, 0x74,
+ 0xAE, 0x5A, 0xBC, 0x4D, 0x51, 0x7B, 0xAE, 0xA5, 0xD6, 0x8D, 0x59, 0xB5, 0x6B, 0x2B, 0x2D, 0x2F,
+ 0xD9, 0x25, 0xA6, 0xBF, 0x76, 0x9A, 0xC2, 0x9B, 0xB2, 0xD3, 0x5D, 0x36, 0x6D, 0xF9, 0xDB, 0x7E,
+ 0xFF, 0x00, 0xD2, 0xD0, 0x91, 0x7F, 0xE0, 0x9C, 0x9A, 0x17, 0x97, 0xB9, 0xB4, 0x38, 0xC3, 0x1C,
+ 0xE1, 0x52, 0xC1, 0x5C, 0x29, 0x00, 0x63, 0xE6, 0xE3, 0x81, 0xB7, 0x19, 0xC7, 0x7C, 0x7A, 0x54,
+ 0x2E, 0x21, 0x76, 0x4D, 0xD5, 0x76, 0x7B, 0xA5, 0x7F, 0xBA, 0xDC, 0xD1, 0x49, 0x6D, 0xA5, 0xB4,
+ 0xB6, 0x9A, 0x24, 0x94, 0xDA, 0xAC, 0x5A, 0x50, 0x8A, 0xB2, 0xB5, 0xBD, 0xE6, 0xAD, 0xA5, 0xAC,
+ 0x96, 0xB6, 0xD1, 0x58, 0x07, 0xFC, 0x13, 0x8B, 0xC3, 0xD8, 0x50, 0xBA, 0x2C, 0x4B, 0xC6, 0x33,
+ 0xF6, 0x08, 0xC2, 0x21, 0x00, 0x6D, 0x0A, 0x07, 0x61, 0x93, 0xD3, 0x18, 0xED, 0xC7, 0x35, 0x9F,
+ 0xF6, 0xEB, 0x6A, 0xCA, 0x6F, 0xA2, 0xEB, 0x6B, 0x5E, 0xFF, 0x00, 0xCD, 0xFA, 0x74, 0x5D, 0x6E,
+ 0x17, 0xAB, 0xD1, 0x2B, 0x7F, 0x89, 0xFF, 0x00, 0x4B, 0xA7, 0xCB, 0xB1, 0x55, 0xBF, 0xE0, 0x9C,
+ 0xBA, 0x12, 0x9C, 0x0F, 0x0E, 0xDB, 0x95, 0x52, 0x40, 0x3F, 0x66, 0x4C, 0x15, 0x1D, 0x80, 0xDB,
+ 0xD3, 0x1E, 0xDC, 0x7A, 0x57, 0x24, 0xF3, 0xD9, 0xB8, 0xB8, 0x39, 0x6D, 0xA2, 0xB3, 0xD3, 0x45,
+ 0xA7, 0x5E, 0x9D, 0xB6, 0xF2, 0xED, 0xB4, 0x61, 0x37, 0x15, 0xA3, 0xDB, 0x6B, 0xBD, 0x3F, 0x1E,
+ 0x9A, 0x6D, 0xE9, 0xB0, 0xF5, 0xFF, 0x00, 0x82, 0x6F, 0x78, 0x7B, 0xCB, 0x50, 0x74, 0x08, 0xB3,
+ 0xC0, 0x3B, 0x6C, 0x23, 0x28, 0x08, 0x1C, 0x0C, 0x9C, 0x1E, 0xCB, 0x9E, 0x0F, 0xE4, 0x6B, 0x29,
+ 0x66, 0x70, 0x92, 0x49, 0xCD, 0xED, 0xD3, 0xA6, 0x8B, 0xAE, 0x9F, 0x87, 0x6F, 0x24, 0x45, 0xEA,
+ 0x27, 0x68, 0xC3, 0x4F, 0x56, 0xBB, 0x74, 0xBF, 0x65, 0xA6, 0xDD, 0x3A, 0x00, 0xFF, 0x00, 0x82,
+ 0x6E, 0xF8, 0x77, 0x03, 0x67, 0x87, 0xA1, 0x52, 0x08, 0xE5, 0xF4, 0xF8, 0x99, 0x50, 0x02, 0x71,
+ 0x80, 0x07, 0x3D, 0x08, 0xE4, 0x7A, 0x66, 0xB9, 0x9E, 0x32, 0x12, 0x6D, 0x73, 0xBF, 0xC3, 0xFA,
+ 0xF3, 0x4B, 0xBF, 0x61, 0xC5, 0xCF, 0x4B, 0xD3, 0xFC, 0x5F, 0x6E, 0xC9, 0xFE, 0x5F, 0x81, 0x4C,
+ 0x7F, 0xC1, 0x38, 0x74, 0x5C, 0x04, 0x3E, 0x1D, 0xB4, 0xC1, 0xC2, 0x12, 0xD6, 0x80, 0xAA, 0xF2,
+ 0x01, 0xC6, 0x07, 0x0A, 0x39, 0xE9, 0xE9, 0xF9, 0xE0, 0xF1, 0x69, 0xDD, 0x5D, 0xDB, 0xCA, 0xDE,
+ 0x5F, 0xD7, 0x4E, 0xDB, 0x68, 0x6C, 0x96, 0xC9, 0x45, 0x7E, 0x3F, 0xD6, 0x9A, 0x7D, 0xDE, 0x96,
+ 0x97, 0xFE, 0x1D, 0xB1, 0xE1, 0xBD, 0xA8, 0xA7, 0x41, 0xB6, 0x50, 0x80, 0xFC, 0xA9, 0x60, 0x9D,
+ 0x08, 0xE0, 0x01, 0xC8, 0x1D, 0x00, 0x3D, 0x3F, 0x4A, 0x97, 0x88, 0xA7, 0x1D, 0x39, 0x9B, 0xB7,
+ 0x6D, 0xBE, 0x4D, 0xFF, 0x00, 0x49, 0x5A, 0xD7, 0x25, 0x4A, 0x56, 0xD2, 0x9A, 0x5F, 0x37, 0xF9,
+ 0x2F, 0xEB, 0xC9, 0x74, 0x63, 0x7F, 0xC1, 0x36, 0x7C, 0x3C, 0xAA, 0x4A, 0xE8, 0x51, 0x39, 0x03,
+ 0x84, 0x7B, 0x28, 0xD5, 0x70, 0x07, 0x0A, 0x40, 0x1D, 0x3A, 0x0F, 0xE5, 0xD6, 0xA7, 0xEB, 0x11,
+ 0x4B, 0x95, 0x49, 0xD9, 0x69, 0xAB, 0x6B, 0xA7, 0xF4, 0xBD, 0x3E, 0xE4, 0xE1, 0x37, 0xA2, 0xF6,
+ 0x6B, 0xE4, 0xDB, 0xFF, 0x00, 0x80, 0x97, 0xFC, 0x37, 0x6B, 0xB6, 0x1F, 0xF8, 0x26, 0xFE, 0x88,
+ 0x03, 0x47, 0xFD, 0x83, 0x6C, 0x11, 0xD5, 0x73, 0xE6, 0x5A, 0x28, 0x5E, 0x07, 0x00, 0x80, 0xA3,
+ 0xDC, 0x7F, 0xFA, 0xE8, 0x8E, 0x2F, 0x91, 0x38, 0xDD, 0xD9, 0xAB, 0x6E, 0xFF, 0x00, 0x0F, 0xD3,
+ 0xB7, 0x42, 0x9B, 0x8A, 0x49, 0xF2, 0x2B, 0x2F, 0x52, 0x55, 0xFF, 0x00, 0x82, 0x6D, 0xF8, 0x75,
+ 0x42, 0x81, 0xE1, 0xFB, 0x35, 0x03, 0x8D, 0x82, 0xC0, 0x04, 0x51, 0x9E, 0x00, 0x00, 0xE3, 0xD3,
+ 0xD2, 0x94, 0x71, 0x51, 0x56, 0xDE, 0xDE, 0xAF, 0xFC, 0xD7, 0xCA, 0xD6, 0xF4, 0xB2, 0x15, 0xE5,
+ 0xAF, 0xB8, 0xB6, 0xEF, 0xE4, 0xBC, 0x9D, 0xBF, 0x1D, 0x2D, 0xE8, 0x36, 0x4F, 0xF8, 0x26, 0xE6,
+ 0x80, 0xAA, 0x0C, 0x5A, 0x05, 0x91, 0x00, 0x11, 0xB3, 0xFB, 0x38, 0x8E, 0xAB, 0xC0, 0x03, 0x24,
+ 0x0C, 0x7C, 0xC3, 0x8C, 0x70, 0x07, 0xE1, 0xA4, 0x71, 0x6A, 0x09, 0x72, 0xB7, 0x6D, 0xAD, 0x76,
+ 0xBA, 0x5B, 0x6B, 0xBE, 0x9B, 0x59, 0x68, 0xBC, 0xF5, 0x14, 0x5F, 0x47, 0x04, 0xBD, 0x1B, 0xF2,
+ 0xED, 0x6F, 0xBB, 0xF3, 0x4A, 0xC3, 0x22, 0xFF, 0x00, 0x82, 0x6E, 0xE8, 0x4C, 0x76, 0x1F, 0x0F,
+ 0xDA, 0x22, 0xED, 0x18, 0x26, 0xC4, 0x12, 0x72, 0x41, 0x23, 0x18, 0x03, 0x3F, 0x40, 0x3D, 0x3B,
+ 0xD6, 0x71, 0xC5, 0x24, 0xB9, 0x53, 0x76, 0xF5, 0x7D, 0x2D, 0xFF, 0x00, 0x00, 0xA7, 0x64, 0x93,
+ 0x50, 0xD7, 0xB2, 0x6D, 0x79, 0x7C, 0xBF, 0x4D, 0x2C, 0x89, 0x87, 0xFC, 0x13, 0x67, 0xC3, 0x78,
+ 0x38, 0xD0, 0xAD, 0x41, 0x2A, 0x54, 0x63, 0x4E, 0x50, 0x79, 0xFC, 0x48, 0xEC, 0x07, 0x4A, 0x7F,
+ 0x5A, 0x8F, 0x46, 0xFF, 0x00, 0xAF, 0x9F, 0xF4, 0xBE, 0x44, 0xA9, 0x4D, 0x59, 0x7B, 0x35, 0x65,
+ 0xD2, 0xEE, 0xDF, 0x82, 0xF9, 0x69, 0x6E, 0x9E, 0x76, 0x85, 0xFF, 0x00, 0xE0, 0x9B, 0x7A, 0x12,
+ 0x84, 0xC6, 0x85, 0x6E, 0xEB, 0x8D, 0xA6, 0x35, 0xB2, 0x54, 0x18, 0x03, 0x39, 0xFB, 0xA7, 0xAE,
+ 0x0F, 0xF8, 0x0E, 0x00, 0x1E, 0x29, 0x59, 0x26, 0xDD, 0xBA, 0x6B, 0xFD, 0x7C, 0xBC, 0xBA, 0x58,
+ 0xA8, 0x35, 0xAA, 0x54, 0xD2, 0x7F, 0x3F, 0x2D, 0xBF, 0x2D, 0x3F, 0x30, 0x4F, 0xF8, 0x26, 0xCF,
+ 0x87, 0xE5, 0x50, 0x5B, 0xC3, 0xB6, 0x70, 0x95, 0x21, 0x1B, 0xCB, 0xD3, 0x93, 0x74, 0x80, 0xE3,
+ 0x25, 0xB7, 0x29, 0xCF, 0x4E, 0x9D, 0x28, 0xFA, 0xCC, 0x5C, 0x54, 0x6C, 0xD2, 0x5D, 0x9B, 0xBB,
+ 0xF5, 0xBB, 0xE9, 0xE4, 0x90, 0x73, 0x59, 0x24, 0xA3, 0x75, 0xD3, 0x57, 0xA7, 0xE5, 0x6E, 0xDF,
+ 0xA1, 0x20, 0xFF, 0x00, 0x82, 0x6C, 0xE8, 0x22, 0x36, 0x45, 0xD2, 0x63, 0x44, 0x60, 0x33, 0x0C,
+ 0x76, 0x51, 0xC7, 0x13, 0x60, 0x71, 0x94, 0x0B, 0x8E, 0xC3, 0xB7, 0x61, 0xE9, 0x50, 0xAB, 0xC1,
+ 0x25, 0x67, 0x2F, 0xBF, 0xCB, 0xFA, 0xFE, 0xB4, 0x05, 0x39, 0x68, 0x95, 0x35, 0x6F, 0x57, 0xF8,
+ 0x6B, 0xFD, 0x76, 0x2B, 0x4B, 0xFF, 0x00, 0x04, 0xD8, 0xD0, 0x54, 0xA2, 0xFF, 0x00, 0x60, 0x42,
+ 0xE0, 0x28, 0xC6, 0x2C, 0x62, 0xDA, 0xA3, 0x3C, 0x00, 0x0C, 0x67, 0x1D, 0x3F, 0x9F, 0xE0, 0x2C,
+ 0x44, 0x76, 0xBB, 0xB7, 0xAF, 0xA7, 0xF5, 0xFA, 0x0D, 0x4B, 0x4D, 0x20, 0x97, 0x4E, 0xBE, 0x5E,
+ 0x67, 0x79, 0xF0, 0xF7, 0xF6, 0x18, 0x97, 0xE1, 0xB6, 0xAE, 0x35, 0xEF, 0x0D, 0x58, 0x45, 0x6B,
+ 0x25, 0xD5, 0x9C, 0x9A, 0x46, 0xB1, 0xA6, 0x3D, 0x82, 0x4B, 0xA6, 0x6B, 0xFA, 0x74, 0xCB, 0xB6,
+ 0xEB, 0x4F, 0xBF, 0xB7, 0xDA, 0x12, 0x7B, 0x69, 0x54, 0xA8, 0x68, 0x9C, 0x6D, 0x38, 0x5C, 0x8E,
+ 0x29, 0xFD, 0x62, 0x2A, 0x0D, 0x6B, 0xF7, 0xEC, 0xBF, 0x4E, 0x9A, 0x75, 0x5D, 0x6C, 0x65, 0x36,
+ 0xA6, 0xD4, 0x1C, 0x16, 0x96, 0xB3, 0xBB, 0xDF, 0x4B, 0x35, 0xAF, 0x4E, 0x8D, 0x6D, 0xF2, 0x31,
+ 0xBC, 0x4B, 0xFF, 0x00, 0x04, 0xD1, 0xF0, 0x29, 0xD5, 0xA5, 0xB8, 0xD0, 0x34, 0x18, 0x53, 0x48,
+ 0xBF, 0x02, 0xF6, 0xD2, 0xD2, 0x5D, 0x36, 0xDC, 0x4F, 0xA5, 0x89, 0x0E, 0x5A, 0xD6, 0x40, 0x91,
+ 0x85, 0xF9, 0x3A, 0x02, 0xA0, 0x0C, 0x63, 0x1D, 0x2A, 0x3E, 0xB1, 0x15, 0xB3, 0x76, 0xF2, 0x7F,
+ 0xA7, 0x4F, 0x4F, 0xD2, 0xC5, 0xC2, 0x75, 0x14, 0x23, 0xCD, 0x15, 0x7E, 0xBA, 0xBF, 0xC3, 0x54,
+ 0xAC, 0x73, 0x27, 0xFE, 0x09, 0xB1, 0xA0, 0x03, 0x81, 0xE1, 0xB8, 0x08, 0x07, 0x03, 0x1A, 0x7C,
+ 0x40, 0x11, 0xD8, 0xE3, 0xCA, 0xFA, 0x55, 0x2A, 0xF1, 0xB5, 0xB9, 0x9F, 0xDF, 0xFF, 0x00, 0x02,
+ 0xC5, 0xA9, 0x3B, 0x2F, 0x75, 0x5B, 0xD6, 0x5F, 0xE6, 0x6C, 0xD8, 0x7F, 0xC1, 0x39, 0xB4, 0x1B,
+ 0x7B, 0x79, 0x6C, 0x2E, 0x34, 0x28, 0xA6, 0xD3, 0x6E, 0x80, 0x69, 0xAD, 0x05, 0x84, 0x72, 0x2C,
+ 0x0E, 0x07, 0xCB, 0x34, 0x69, 0xB0, 0x00, 0xE3, 0xA6, 0x46, 0x32, 0x38, 0xEF, 0x4A, 0x38, 0x88,
+ 0xA6, 0xAE, 0xDD, 0xB4, 0x57, 0xBE, 0xC9, 0x79, 0x69, 0xF7, 0x7F, 0xC3, 0x12, 0xE7, 0x24, 0xAD,
+ 0x18, 0xAB, 0xFA, 0xBD, 0x7C, 0xB7, 0xD3, 0xFC, 0xBC, 0xB4, 0x28, 0x49, 0xFF, 0x00, 0x04, 0xD0,
+ 0xF0, 0xDC, 0x72, 0x14, 0x4D, 0x0E, 0xD9, 0x93, 0xFE, 0x59, 0xB9, 0xD3, 0x22, 0x04, 0xAE, 0x46,
+ 0x32, 0xA2, 0x33, 0x83, 0xC8, 0xE0, 0x7F, 0x4E, 0x07, 0x5E, 0x29, 0xDA, 0x2D, 0xDB, 0xD6, 0xDF,
+ 0xA6, 0x82, 0x55, 0x65, 0xCA, 0x9B, 0x82, 0xDB, 0xA3, 0x93, 0xB7, 0x96, 0xE8, 0xAB, 0xFF, 0x00,
+ 0x0E, 0xD8, 0xF0, 0xF8, 0x6D, 0xA3, 0xC3, 0x96, 0xD8, 0x1C, 0x67, 0xEC, 0x11, 0x05, 0xC0, 0x1C,
+ 0x63, 0xF7, 0x7E, 0x98, 0xA1, 0x57, 0x8D, 0x97, 0xBC, 0xFE, 0xFF, 0x00, 0xF8, 0x06, 0xAA, 0x4F,
+ 0x44, 0xA0, 0xAD, 0xEB, 0x2F, 0xF3, 0x27, 0xFF, 0x00, 0x87, 0x69, 0xF8, 0x70, 0x00, 0x06, 0x83,
+ 0x6B, 0xD0, 0x63, 0x1A, 0x74, 0x40, 0x74, 0x18, 0x03, 0xF7, 0x63, 0xB1, 0x15, 0x3F, 0x58, 0xB2,
+ 0xDD, 0xDB, 0xD7, 0xFE, 0x01, 0x0A, 0xA3, 0xB6, 0x90, 0x56, 0xF5, 0x97, 0xE5, 0x71, 0xA7, 0xFE,
+ 0x09, 0xA9, 0xE1, 0xD0, 0xA7, 0x1A, 0x05, 0xB7, 0xCA, 0x38, 0x53, 0xA7, 0xC2, 0xA0, 0x91, 0xD1,
+ 0x41, 0xF2, 0xFE, 0x94, 0x2C, 0x46, 0x9A, 0x37, 0xF7, 0xFF, 0x00, 0xC0, 0x05, 0x51, 0xE8, 0xB9,
+ 0x15, 0xBC, 0x9C, 0xBF, 0xCC, 0x89, 0x3F, 0xE0, 0x9B, 0x1E, 0x1F, 0x24, 0x2F, 0xFC, 0x23, 0x96,
+ 0xCA, 0x38, 0x19, 0x36, 0x11, 0x60, 0x74, 0xE0, 0x01, 0x17, 0xB8, 0xE9, 0xFD, 0x2A, 0xBE, 0xB1,
+ 0x14, 0x95, 0xA4, 0xFE, 0xFB, 0x7E, 0x9A, 0x15, 0xCC, 0xD6, 0x9C, 0xAB, 0xE4, 0xE5, 0xFE, 0x64,
+ 0xE3, 0xFE, 0x09, 0xA7, 0xE1, 0xCC, 0x0C, 0x78, 0x7E, 0x0E, 0xC0, 0x01, 0xA6, 0xC4, 0x3A, 0x8E,
+ 0x01, 0x1E, 0x5F, 0x1D, 0xAA, 0x7E, 0xB0, 0x96, 0x97, 0x76, 0xF5, 0xFF, 0x00, 0x80, 0x4A, 0xA8,
+ 0xEC, 0xBD, 0xD5, 0x6F, 0x59, 0x7F, 0x9F, 0x41, 0x8D, 0xFF, 0x00, 0x04, 0xD5, 0xF0, 0xEA, 0x26,
+ 0x57, 0xC3, 0xF6, 0xCD, 0x8C, 0x00, 0xA3, 0x4E, 0x88, 0x1C, 0x63, 0xFE, 0xB9, 0xFB, 0x0A, 0xA5,
+ 0x5D, 0x75, 0x6E, 0xDE, 0xBF, 0xF0, 0x3F, 0xAF, 0xB8, 0x6A, 0x6F, 0x6E, 0x45, 0xF7, 0xCA, 0xDF,
+ 0x9F, 0xF5, 0xF2, 0x1B, 0x1F, 0xFC, 0x13, 0x5F, 0xC3, 0xCD, 0xC1, 0xF0, 0xED, 0xB4, 0x60, 0x28,
+ 0x3F, 0x35, 0x84, 0x20, 0x75, 0xC0, 0x03, 0xF7, 0x7E, 0xD4, 0x7B, 0x78, 0xE8, 0x94, 0x9F, 0xDF,
+ 0xFF, 0x00, 0x00, 0x39, 0xDA, 0x8D, 0xF9, 0x55, 0xBD, 0x65, 0xFE, 0x64, 0xBF, 0xF0, 0xED, 0x3F,
+ 0x0E, 0x05, 0xCF, 0xF6, 0x05, 0xB8, 0x00, 0x1E, 0x06, 0x99, 0x17, 0x18, 0x38, 0xC7, 0xFA, 0xBF,
+ 0x61, 0xFE, 0x45, 0x25, 0x88, 0x49, 0x25, 0x77, 0xF7, 0xFF, 0x00, 0xC0, 0x12, 0xA8, 0xF6, 0xE4,
+ 0x5F, 0x7C, 0xBF, 0xCF, 0xFA, 0xF2, 0x23, 0x7F, 0xF8, 0x26, 0xAF, 0x87, 0x90, 0x0D, 0xBE, 0x1E,
+ 0xB6, 0x6E, 0x71, 0xB4, 0x69, 0xD1, 0x29, 0x00, 0x0E, 0x0E, 0x3C, 0xBA, 0x6A, 0xBA, 0xB2, 0xD5,
+ 0xDB, 0xD7, 0xFE, 0x00, 0x2A, 0x8D, 0xE8, 0xA0, 0xAD, 0x6E, 0xF2, 0xB7, 0x6E, 0xFF, 0x00, 0xD7,
+ 0xE5, 0x25, 0xBF, 0xFC, 0x13, 0x5B, 0xC3, 0x83, 0x12, 0x3F, 0x87, 0xED, 0xD4, 0x47, 0x82, 0x10,
+ 0x69, 0xF0, 0x92, 0x71, 0xD3, 0x23, 0x60, 0xC7, 0x41, 0xDF, 0xB5, 0x6F, 0x87, 0xAB, 0x4F, 0x99,
+ 0x39, 0x49, 0xF2, 0xAB, 0x3D, 0xF7, 0xF2, 0x4B, 0x6B, 0x7E, 0x16, 0xD0, 0x9A, 0x93, 0x94, 0x62,
+ 0x94, 0x62, 0xB6, 0xEE, 0xD2, 0xB5, 0xBD, 0x7A, 0x79, 0x1A, 0xC3, 0xFE, 0x09, 0xC3, 0xE1, 0xC5,
+ 0x04, 0x1D, 0x05, 0x14, 0x70, 0x46, 0xDD, 0x32, 0x2D, 0x8A, 0x40, 0xEC, 0x09, 0x03, 0xBE, 0x07,
+ 0x1F, 0xCB, 0x8F, 0xA3, 0xC3, 0xE7, 0xD4, 0xF0, 0xF4, 0xE3, 0x4E, 0x35, 0x1F, 0x22, 0xE8, 0x93,
+ 0xD6, 0xCA, 0xCB, 0xED, 0x79, 0x2B, 0xE8, 0xBE, 0x6A, 0xC7, 0x27, 0xEF, 0xAE, 0x9C, 0x60, 0xBB,
+ 0x7C, 0x4F, 0x6F, 0xBB, 0xD2, 0xDD, 0xEC, 0x67, 0xDD, 0x7F, 0xC1, 0x38, 0x74, 0x49, 0x24, 0x5F,
+ 0xF8, 0xA7, 0xE0, 0x60, 0xA0, 0x61, 0xBE, 0xC6, 0xAA, 0xD9, 0x04, 0xE3, 0x23, 0x69, 0xC7, 0x45,
+ 0xC6, 0x00, 0xC7, 0xE3, 0xC7, 0x97, 0x99, 0x67, 0x13, 0xC6, 0xD6, 0x5C, 0xD3, 0x7C, 0x89, 0x2B,
+ 0x59, 0xF6, 0x4B, 0x7F, 0xBB, 0x66, 0xF7, 0xBB, 0x37, 0xA3, 0x1E, 0x4A, 0x69, 0x38, 0x6B, 0xB6,
+ 0xF2, 0x6A, 0xDE, 0x5E, 0x9D, 0x34, 0x5A, 0x5B, 0x4B, 0x09, 0x1F, 0xFC, 0x13, 0x6F, 0x41, 0x31,
+ 0xE5, 0xB4, 0x2B, 0x75, 0x7D, 0xC7, 0xE5, 0x16, 0x2A, 0xC5, 0x80, 0x1C, 0x28, 0x18, 0x5F, 0x97,
+ 0x83, 0xC6, 0x7B, 0x0E, 0x6B, 0xCE, 0x8E, 0x25, 0x24, 0x92, 0x93, 0xED, 0xA3, 0xFC, 0x3D, 0x2D,
+ 0xF2, 0xE8, 0x5B, 0x97, 0x2D, 0x92, 0x82, 0xB7, 0x6B, 0xBF, 0xEB, 0xEE, 0x5F, 0x86, 0xD2, 0x0F,
+ 0xF8, 0x26, 0xD7, 0x87, 0x78, 0x0B, 0xA1, 0xC0, 0xA8, 0x09, 0x21, 0x05, 0x8A, 0xE5, 0x46, 0x06,
+ 0x76, 0x91, 0xF4, 0x00, 0x71, 0x8E, 0x3A, 0x75, 0xC9, 0x1C, 0x5C, 0x39, 0x79, 0x5B, 0x76, 0xF5,
+ 0xED, 0x6D, 0x9E, 0x9D, 0x9A, 0xB6, 0xDB, 0x69, 0x72, 0x5B, 0x92, 0x8D, 0xF9, 0x15, 0xEC, 0xBA,
+ 0xBF, 0x4B, 0x5B, 0x65, 0x6D, 0x3E, 0xEE, 0xC4, 0x71, 0xFF, 0x00, 0xC1, 0x37, 0xF4, 0x18, 0xE6,
+ 0x59, 0x0E, 0x81, 0x6F, 0x22, 0xC4, 0x36, 0xC7, 0xB6, 0xD1, 0x00, 0x00, 0x0C, 0x80, 0xA7, 0x6E,
+ 0x47, 0x7E, 0x33, 0xFF, 0x00, 0xD6, 0xDB, 0x09, 0x8A, 0xA7, 0x4A, 0xB4, 0x6B, 0x54, 0x93, 0xB4,
+ 0x5A, 0x69, 0x39, 0x75, 0x5B, 0x7E, 0x2B, 0xD3, 0x42, 0x9D, 0xF9, 0x14, 0x61, 0x0B, 0x7A, 0x5F,
+ 0xFC, 0xD2, 0xFB, 0xBE, 0x5E, 0x57, 0x57, 0xFE, 0x09, 0xC9, 0xA1, 0x37, 0xCE, 0xDA, 0x15, 0xBA,
+ 0x39, 0x39, 0x0A, 0x96, 0x29, 0xB5, 0x47, 0x4C, 0x64, 0x80, 0x47, 0x40, 0x38, 0xFE, 0x95, 0xF4,
+ 0x12, 0xE2, 0x29, 0xA5, 0xED, 0x63, 0x51, 0xDD, 0xEA, 0x92, 0x6E, 0xD7, 0xFF, 0x00, 0xC0, 0x96,
+ 0xBE, 0x89, 0x5A, 0xCA, 0xD6, 0xD8, 0xE6, 0x94, 0x6A, 0x69, 0x15, 0x1B, 0xAB, 0x6B, 0x79, 0x3F,
+ 0xC9, 0x7F, 0x5B, 0x21, 0xC9, 0xFF, 0x00, 0x04, 0xE0, 0xF0, 0xE6, 0x49, 0xFE, 0xC3, 0x45, 0x2E,
+ 0x0E, 0x0B, 0x69, 0xD1, 0xB0, 0x00, 0x8E, 0x41, 0x3C, 0xF6, 0x1F, 0xC8, 0x74, 0xC5, 0x73, 0x50,
+ 0xCE, 0x21, 0x4A, 0xAC, 0xEB, 0xFB, 0x46, 0xA7, 0x25, 0x67, 0xA6, 0x96, 0xDB, 0x74, 0xEE, 0xAC,
+ 0xAD, 0x6D, 0x5E, 0xBA, 0xDA, 0xE9, 0xD8, 0x97, 0xB5, 0xB2, 0x5C, 0x8A, 0xDD, 0x7D, 0xE7, 0x7D,
+ 0x36, 0xF2, 0xE9, 0xE5, 0xB7, 0x62, 0xA7, 0xFC, 0x3B, 0x97, 0x45, 0x18, 0x51, 0xE1, 0xEB, 0x70,
+ 0xAA, 0x7E, 0x5C, 0x5B, 0x2A, 0x85, 0xF9, 0x7A, 0x8F, 0x97, 0x8E, 0x83, 0xF2, 0xFC, 0xA2, 0xA6,
+ 0x7B, 0x51, 0xB6, 0xA5, 0x37, 0x6D, 0xB7, 0xD1, 0xF4, 0xEF, 0x7D, 0x3A, 0x5A, 0xCD, 0x76, 0xE8,
+ 0x6D, 0x1A, 0x6F, 0x49, 0x24, 0xD6, 0x96, 0xDD, 0xF9, 0x79, 0xF4, 0xD8, 0x9C, 0xFF, 0x00, 0xC1,
+ 0x37, 0xFC, 0x38, 0x02, 0xAF, 0xF6, 0x1C, 0x38, 0x00, 0x1C, 0x2D, 0x84, 0x7C, 0x81, 0xD3, 0x1D,
+ 0x3A, 0xFC, 0xA3, 0xB7, 0x4A, 0xA9, 0xE7, 0x3C, 0xD1, 0xB4, 0xEA, 0xB6, 0xFB, 0xAF, 0xF3, 0x76,
+ 0x7D, 0x6C, 0xAC, 0x95, 0xAD, 0x7B, 0x2B, 0x69, 0x9F, 0x35, 0x4D, 0x94, 0x55, 0xBF, 0xC4, 0xD7,
+ 0xE1, 0x7F, 0xEB, 0x6E, 0xC3, 0x1B, 0xFE, 0x09, 0xBB, 0xE1, 0xD0, 0x98, 0x5D, 0x09, 0x37, 0x28,
+ 0x1B, 0x73, 0x63, 0x1A, 0x82, 0x06, 0x32, 0x06, 0x07, 0x19, 0xDA, 0x3B, 0x7A, 0xE3, 0xAD, 0x72,
+ 0xAC, 0xC6, 0x2B, 0x9B, 0x96, 0xA3, 0x5A, 0x6D, 0xA2, 0x5F, 0x87, 0x6E, 0xDD, 0x76, 0x7B, 0x21,
+ 0xC5, 0xD4, 0xD1, 0x72, 0x2B, 0x79, 0x37, 0x7F, 0x2E, 0xDA, 0x7F, 0xC3, 0x2E, 0xC4, 0x43, 0xFE,
+ 0x09, 0xC5, 0xA1, 0x13, 0xB7, 0xFE, 0x11, 0xEB, 0x65, 0x52, 0x73, 0xF2, 0xDB, 0x28, 0x0B, 0x81,
+ 0xC0, 0x03, 0x68, 0xFE, 0xF1, 0xF4, 0xC7, 0x1E, 0x94, 0xA3, 0x9B, 0x5D, 0x28, 0xA9, 0xB4, 0xBB,
+ 0xBB, 0x7E, 0x9F, 0x76, 0x8B, 0x5D, 0x0B, 0x71, 0x94, 0x55, 0xD2, 0xE9, 0xD1, 0xCB, 0xFC, 0xFC,
+ 0xAD, 0xD9, 0x7A, 0x13, 0x8F, 0xF8, 0x26, 0xFF, 0x00, 0x87, 0x70, 0x33, 0xA0, 0x46, 0x48, 0x18,
+ 0x03, 0xFB, 0x3E, 0x1C, 0x70, 0x06, 0x38, 0xE3, 0x00, 0x10, 0x6B, 0x65, 0x9A, 0x41, 0x5A, 0x2E,
+ 0x4E, 0xDF, 0x2F, 0xB9, 0x6A, 0xBE, 0xED, 0x17, 0x97, 0x6C, 0xBF, 0x7B, 0x74, 0xB9, 0x17, 0x92,
+ 0xE6, 0x7F, 0xD7, 0x96, 0x9F, 0x79, 0x9F, 0x27, 0xFC, 0x13, 0x57, 0xC3, 0xAA, 0x18, 0xA7, 0x87,
+ 0xED, 0xDB, 0x04, 0x61, 0x0D, 0x84, 0x21, 0xB9, 0xC7, 0x03, 0xE4, 0x3C, 0x0C, 0x7F, 0x9E, 0x2B,
+ 0xC5, 0x9D, 0x68, 0xC6, 0x76, 0x8B, 0x76, 0xF5, 0xFD, 0x2D, 0xD0, 0xEA, 0x85, 0x49, 0x72, 0xA5,
+ 0xC8, 0xBE, 0xF7, 0xD3, 0xD1, 0xFF, 0x00, 0x5E, 0x5D, 0x22, 0x8F, 0xFE, 0x09, 0xAF, 0xE1, 0xF6,
+ 0x21, 0x4F, 0x87, 0x6D, 0xA3, 0x18, 0x1C, 0xB5, 0x84, 0x40, 0x0C, 0x8E, 0x00, 0x1E, 0x57, 0xD2,
+ 0x97, 0xB7, 0x8A, 0x4A, 0xCE, 0x5F, 0x7F, 0xFC, 0x02, 0xF9, 0x9D, 0xB4, 0x8A, 0xFB, 0xE5, 0xFE,
+ 0x64, 0xBF, 0xF0, 0xED, 0x3F, 0x0E, 0xED, 0x18, 0xD0, 0x2D, 0xF3, 0xD0, 0x2F, 0xF6, 0x6C, 0x5C,
+ 0x0C, 0xE0, 0x67, 0xF7, 0x7C, 0x7F, 0xF5, 0xBD, 0xB8, 0x85, 0x88, 0x4A, 0xDA, 0xBB, 0x7A, 0xFF,
+ 0x00, 0xC0, 0x21, 0x55, 0x76, 0x56, 0x82, 0xB7, 0xAC, 0xBF, 0xCC, 0x6B, 0xFF, 0x00, 0xC1, 0x35,
+ 0x7C, 0x3A, 0x8A, 0x36, 0xF8, 0x7E, 0xD9, 0xF8, 0xFB, 0xAB, 0xA7, 0xC4, 0x08, 0x00, 0x75, 0xFF,
+ 0x00, 0x57, 0x8E, 0xC2, 0xA9, 0x57, 0x49, 0x2D, 0x5D, 0xBD, 0x7F, 0xE0, 0x15, 0x19, 0xC9, 0xE9,
+ 0xC8, 0xAD, 0xEB, 0x2B, 0x7E, 0x67, 0xF2, 0x2B, 0xFF, 0x00, 0x05, 0xB0, 0xF8, 0x05, 0x65, 0xFB,
+ 0x3F, 0x7F, 0xC1, 0x64, 0xFF, 0x00, 0xE0, 0x95, 0x5E, 0x1F, 0xB1, 0xB0, 0x8F, 0x4F, 0x8F, 0x5E,
+ 0xBF, 0xF8, 0x7B, 0xAE, 0x3C, 0x51, 0xC2, 0xB0, 0x6E, 0x65, 0xF8, 0xAF, 0x3C, 0x3B, 0x8A, 0x85,
+ 0x51, 0xD2, 0x10, 0x3A, 0x76, 0xAD, 0xB0, 0x32, 0x53, 0xCC, 0xB0, 0xF6, 0x6E, 0xDC, 0xF0, 0xDF,
+ 0xFC, 0x48, 0x8A, 0xDA, 0xE1, 0x6A, 0x69, 0x6F, 0x75, 0xF7, 0xEC, 0xFB, 0x9F, 0xB2, 0xF5, 0xFA,
+ 0x79, 0xF2, 0x21, 0x40, 0x05, 0x00, 0x14, 0x01, 0xFA, 0xF5, 0xFF, 0x00, 0x04, 0x4A, 0xB4, 0xB7,
+ 0xBA, 0xF0, 0x27, 0xED, 0xD0, 0x27, 0x8F, 0x78, 0x8F, 0xF6, 0xE7, 0x84, 0x20, 0x0E, 0xC9, 0xB4,
+ 0x1F, 0x80, 0xFF, 0x00, 0x0C, 0x72, 0x38, 0x23, 0xD0, 0x57, 0xE7, 0x5C, 0x41, 0xFF, 0x00, 0x23,
+ 0x49, 0xFA, 0x47, 0xFF, 0x00, 0x49, 0x47, 0xD4, 0x65, 0x7F, 0xEE, 0x51, 0xF9, 0xFE, 0x67, 0xED,
+ 0x6F, 0xF6, 0x4E, 0x9F, 0xFF, 0x00, 0x3C, 0x0F, 0xFD, 0xFE, 0x93, 0xFC, 0x6B, 0xC4, 0xB2, 0xD3,
+ 0x43, 0xD1, 0x0F, 0xEC, 0x9D, 0x3F, 0xFE, 0x78, 0x1F, 0xFB, 0xFD, 0x27, 0xF8, 0xD1, 0x65, 0x64,
+ 0xAD, 0xA0, 0x07, 0xF6, 0x4E, 0x9F, 0xFF, 0x00, 0x3C, 0x0F, 0xFD, 0xFE, 0x93, 0xFC, 0x69, 0x80,
+ 0x7F, 0x64, 0xE9, 0xFF, 0x00, 0xF3, 0xC0, 0xFF, 0x00, 0xDF, 0xE9, 0x3F, 0xC6, 0x80, 0x0F, 0xEC,
+ 0x9D, 0x3F, 0xFE, 0x78, 0x1F, 0xFB, 0xFD, 0x27, 0xF8, 0xD2, 0x49, 0x2D, 0x90, 0xAC, 0xBB, 0x07,
+ 0xF6, 0x4E, 0x9F, 0xFF, 0x00, 0x3C, 0x0F, 0xFD, 0xFE, 0x93, 0xFC, 0x69, 0x82, 0x49, 0x24, 0x92,
+ 0xD0, 0x3F, 0xB2, 0x74, 0xFF, 0x00, 0xF9, 0xE0, 0x7F, 0xEF, 0xF4, 0x9F, 0xE3, 0x4A, 0xCB, 0x4D,
+ 0x06, 0x1F, 0xD9, 0x3A, 0x7F, 0xFC, 0xF0, 0x3F, 0xF7, 0xFA, 0x4F, 0xF1, 0xA2, 0xCB, 0x4D, 0x00,
+ 0x3F, 0xB2, 0x74, 0xFF, 0x00, 0xF9, 0xE0, 0x7F, 0xEF, 0xF4, 0x9F, 0xE3, 0x45, 0x96, 0x9A, 0x09,
+ 0x24, 0xB6, 0x41, 0xFD, 0x93, 0xA7, 0xFF, 0x00, 0xCF, 0x03, 0xFF, 0x00, 0x7F, 0xA4, 0xFF, 0x00,
+ 0x1A, 0x12, 0x49, 0x59, 0x2D, 0x06, 0x1F, 0xD9, 0x3A, 0x7F, 0xFC, 0xF0, 0x3F, 0xF7, 0xFA, 0x4F,
+ 0xF1, 0xA6, 0x01, 0xFD, 0x93, 0xA7, 0xFF, 0x00, 0xCF, 0x03, 0xFF, 0x00, 0x7F, 0xA4, 0xFF, 0x00,
+ 0x1A, 0x49, 0x24, 0xAC, 0x96, 0x82, 0x49, 0x25, 0x64, 0xB4, 0x0F, 0xEC, 0x9D, 0x3F, 0xFE, 0x78,
+ 0x1F, 0xFB, 0xFD, 0x27, 0xF8, 0xD1, 0x65, 0xA6, 0x83, 0x0F, 0xEC, 0x9D, 0x3F, 0xFE, 0x78, 0x1F,
+ 0xFB, 0xFD, 0x27, 0xF8, 0xD3, 0x15, 0x96, 0x9A, 0x07, 0xF6, 0x4E, 0x9F, 0xFF, 0x00, 0x3C, 0x0F,
+ 0xFD, 0xFE, 0x93, 0xFC, 0x69, 0x24, 0x92, 0xB2, 0x5A, 0x0C, 0x3F, 0xB2, 0x74, 0xFF, 0x00, 0xF9,
+ 0xE0, 0x7F, 0xEF, 0xF4, 0x9F, 0xE3, 0x45, 0x95, 0xAD, 0x6D, 0x00, 0x3F, 0xB2, 0x74, 0xFF, 0x00,
+ 0xF9, 0xE0, 0x7F, 0xEF, 0xF4, 0x9F, 0xE3, 0x4C, 0x56, 0x5D, 0x83, 0xFB, 0x27, 0x4F, 0xFF, 0x00,
+ 0x9E, 0x07, 0xFE, 0xFF, 0x00, 0x49, 0xFE, 0x34, 0x0C, 0x3F, 0xB2, 0x74, 0xFF, 0x00, 0xF9, 0xE0,
+ 0x7F, 0xEF, 0xF4, 0x9F, 0xE3, 0x40, 0x07, 0xF6, 0x4E, 0x9F, 0xFF, 0x00, 0x3C, 0x0F, 0xFD, 0xFE,
+ 0x93, 0xFC, 0x68, 0x15, 0x95, 0xAD, 0x6D, 0x03, 0xFB, 0x27, 0x4F, 0xFF, 0x00, 0x9E, 0x07, 0xFE,
+ 0xFF, 0x00, 0x49, 0xFE, 0x34, 0x92, 0x4B, 0x64, 0x30, 0xFE, 0xC9, 0xD3, 0xFF, 0x00, 0xE7, 0x81,
+ 0xFF, 0x00, 0xBF, 0xD2, 0x7F, 0x8D, 0x09, 0x25, 0x6B, 0x20, 0x0F, 0xEC, 0x9D, 0x3F, 0xFE, 0x78,
+ 0x1F, 0xFB, 0xFD, 0x27, 0xF8, 0xD1, 0x65, 0x64, 0xAD, 0xA0, 0x92, 0x4B, 0x64, 0x1F, 0xD9, 0x3A,
+ 0x7F, 0xFC, 0xF0, 0x3F, 0xF7, 0xFA, 0x4F, 0xF1, 0xA6, 0x30, 0xFE, 0xC9, 0xD3, 0xFF, 0x00, 0xE7,
+ 0x81, 0xFF, 0x00, 0xBF, 0xD2, 0x7F, 0x8D, 0x02, 0xB2, 0xD3, 0x40, 0xFE, 0xC9, 0xD3, 0xFF, 0x00,
+ 0xE7, 0x81, 0xFF, 0x00, 0xBF, 0xD2, 0x7F, 0x8D, 0x00, 0x92, 0x5B, 0x20, 0xFE, 0xC9, 0xD3, 0xFF,
+ 0x00, 0xE7, 0x81, 0xFF, 0x00, 0xBF, 0xD2, 0x7F, 0x8D, 0x03, 0x0F, 0xEC, 0x9D, 0x3F, 0xFE, 0x78,
+ 0x1F, 0xFB, 0xFD, 0x27, 0xF8, 0xD0, 0x01, 0xFD, 0x93, 0xA7, 0xFF, 0x00, 0xCF, 0x03, 0xFF, 0x00,
+ 0x7F, 0xA4, 0xFF, 0x00, 0x1A, 0x00, 0x3F, 0xB2, 0x74, 0xFF, 0x00, 0xF9, 0xE0, 0x7F, 0xEF, 0xF4,
+ 0x9F, 0xE3, 0x40, 0x07, 0xF6, 0x4E, 0x9F, 0xFF, 0x00, 0x3C, 0x0F, 0xFD, 0xFE, 0x93, 0xFC, 0x69,
+ 0x24, 0x96, 0xC8, 0x56, 0x5D, 0x83, 0xFB, 0x27, 0x4F, 0xFF, 0x00, 0x9E, 0x07, 0xFE, 0xFF, 0x00,
+ 0x49, 0xFE, 0x34, 0x59, 0x76, 0x04, 0x92, 0x56, 0x4B, 0x40, 0xFE, 0xC9, 0xD3, 0xFF, 0x00, 0xE7,
+ 0x81, 0xFF, 0x00, 0xBF, 0xD2, 0x7F, 0x8D, 0x31, 0x87, 0xF6, 0x4E, 0x9F, 0xFF, 0x00, 0x3C, 0x0F,
+ 0xFD, 0xFE, 0x93, 0xFC, 0x68, 0x15, 0x95, 0x92, 0xB6, 0x81, 0xFD, 0x93, 0xA7, 0xFF, 0x00, 0xCF,
+ 0x03, 0xFF, 0x00, 0x7F, 0xA4, 0xFF, 0x00, 0x1A, 0x49, 0x25, 0xB2, 0x18, 0x7F, 0x64, 0xE9, 0xFF,
+ 0x00, 0xF3, 0xC0, 0xFF, 0x00, 0xDF, 0xE9, 0x3F, 0xC6, 0x98, 0x07, 0xF6, 0x4E, 0x9F, 0xFF, 0x00,
+ 0x3C, 0x0F, 0xFD, 0xFE, 0x93, 0xFC, 0x68, 0x15, 0x95, 0xAD, 0x6D, 0x03, 0xFB, 0x27, 0x4F, 0xFF,
+ 0x00, 0x9E, 0x07, 0xFE, 0xFF, 0x00, 0x49, 0xFE, 0x34, 0x0C, 0x3F, 0xB2, 0x74, 0xFF, 0x00, 0xF9,
+ 0xE0, 0x7F, 0xEF, 0xF4, 0x9F, 0xE3, 0x49, 0x24, 0xB6, 0x42, 0x49, 0x2D, 0x90, 0x7F, 0x64, 0xE9,
+ 0xFF, 0x00, 0xF3, 0xC0, 0xFF, 0x00, 0xDF, 0xE9, 0x3F, 0xC6, 0x8B, 0x2B, 0x5A, 0xDA, 0x05, 0x95,
+ 0xAD, 0x6D, 0x03, 0xFB, 0x27, 0x4F, 0xFF, 0x00, 0x9E, 0x07, 0xFE, 0xFF, 0x00, 0x49, 0xFE, 0x34,
+ 0xC6, 0x1F, 0xD9, 0x3A, 0x7F, 0xFC, 0xF0, 0x3F, 0xF7, 0xFA, 0x4F, 0xF1, 0xA0, 0x03, 0xFB, 0x27,
+ 0x4F, 0xFF, 0x00, 0x9E, 0x07, 0xFE, 0xFF, 0x00, 0x49, 0xFE, 0x34, 0xAC, 0xAD, 0x6B, 0x68, 0x24,
+ 0x92, 0xD9, 0x07, 0xF6, 0x4E, 0x9F, 0xFF, 0x00, 0x3C, 0x0F, 0xFD, 0xFE, 0x93, 0xFC, 0x68, 0x49,
+ 0x24, 0x92, 0x5A, 0x0C, 0x3F, 0xB2, 0x74, 0xFF, 0x00, 0xF9, 0xE0, 0x7F, 0xEF, 0xF4, 0x9F, 0xE3,
+ 0x42, 0x49, 0x6C, 0x84, 0x92, 0x5B, 0x20, 0xFE, 0xC9, 0xD3, 0xFF, 0x00, 0xE7, 0x81, 0xFF, 0x00,
+ 0xBF, 0xD2, 0x7F, 0x8D, 0x16, 0x5A, 0x68, 0x09, 0x25, 0xB2, 0x0F, 0xEC, 0x9D, 0x3F, 0xFE, 0x78,
+ 0x1F, 0xFB, 0xFD, 0x27, 0xF8, 0xD3, 0x18, 0x7F, 0x64, 0xE9, 0xFF, 0x00, 0xF3, 0xC0, 0xFF, 0x00,
+ 0xDF, 0xE9, 0x3F, 0xC6, 0x80, 0x0F, 0xEC, 0x9D, 0x3F, 0xFE, 0x78, 0x1F, 0xFB, 0xFD, 0x27, 0xF8,
+ 0xD2, 0xB2, 0xD3, 0x41, 0x24, 0x92, 0x49, 0x2D, 0x03, 0xFB, 0x27, 0x4F, 0xFF, 0x00, 0x9E, 0x07,
+ 0xFE, 0xFF, 0x00, 0x49, 0xFE, 0x34, 0x59, 0x5A, 0xD6, 0xD0, 0x2C, 0xAD, 0x6B, 0x68, 0x1F, 0xD9,
+ 0x3A, 0x7F, 0xFC, 0xF0, 0x3F, 0xF7, 0xFA, 0x4F, 0xF1, 0xA6, 0x16, 0x56, 0xB5, 0xB4, 0x0F, 0xEC,
+ 0x9D, 0x3F, 0xFE, 0x78, 0x1F, 0xFB, 0xFD, 0x27, 0xF8, 0xD2, 0x49, 0x2D, 0x90, 0xC3, 0xFB, 0x27,
+ 0x4F, 0xFF, 0x00, 0x9E, 0x07, 0xFE, 0xFF, 0x00, 0x49, 0xFE, 0x34, 0xC0, 0x3F, 0xB2, 0x74, 0xFF,
+ 0x00, 0xF9, 0xE0, 0x7F, 0xEF, 0xF4, 0x9F, 0xE3, 0x40, 0xAC, 0xB4, 0xD0, 0x3F, 0xB2, 0x74, 0xFF,
+ 0x00, 0xF9, 0xE0, 0x7F, 0xEF, 0xF4, 0x9F, 0xE3, 0x49, 0x24, 0xB6, 0x43, 0x0F, 0xEC, 0x9D, 0x3F,
+ 0xFE, 0x78, 0x1F, 0xFB, 0xFD, 0x27, 0xF8, 0xD0, 0x92, 0x5B, 0x20, 0x0F, 0xEC, 0x9D, 0x3F, 0xFE,
+ 0x78, 0x1F, 0xFB, 0xFD, 0x27, 0xF8, 0xD3, 0x00, 0xFE, 0xC9, 0xD3, 0xFF, 0x00, 0xE7, 0x81, 0xFF,
+ 0x00, 0xBF, 0xD2, 0x7F, 0x8D, 0x2B, 0x2D, 0x34, 0x00, 0xFE, 0xC9, 0xD3, 0xFF, 0x00, 0xE7, 0x81,
+ 0xFF, 0x00, 0xBF, 0xD2, 0x7F, 0x8D, 0x16, 0x5D, 0x85, 0x65, 0x64, 0xAD, 0xA0, 0x7F, 0x64, 0xE9,
+ 0xFF, 0x00, 0xF3, 0xC0, 0xFF, 0x00, 0xDF, 0xE9, 0x3F, 0xC6, 0x8B, 0x2B, 0x5A, 0xDA, 0x02, 0x49,
+ 0x24, 0x92, 0xD0, 0x3F, 0xB2, 0x74, 0xFF, 0x00, 0xF9, 0xE0, 0x7F, 0xEF, 0xF4, 0x9F, 0xE3, 0x4C,
+ 0x61, 0xFD, 0x93, 0xA7, 0xFF, 0x00, 0xCF, 0x03, 0xFF, 0x00, 0x7F, 0xA4, 0xFF, 0x00, 0x1A, 0x05,
+ 0x65, 0x6B, 0x5B, 0x43, 0xF8, 0x00, 0xFF, 0x00, 0x83, 0x9D, 0xE1, 0x8A, 0xDF, 0xFE, 0x0B, 0x97,
+ 0xFF, 0x00, 0x04, 0x86, 0x8A, 0x14, 0xD8, 0x89, 0xA5, 0x7C, 0x3D, 0x0A, 0xB9, 0x2D, 0x80, 0x7E,
+ 0x2F, 0xDD, 0x1C, 0x64, 0xFD, 0x4D, 0x76, 0x65, 0x9F, 0xF2, 0x30, 0xC3, 0xFF, 0x00, 0x8E, 0x1F,
+ 0xFA, 0x52, 0x30, 0xC4, 0xA4, 0xB0, 0xB5, 0x2C, 0xBE, 0xCB, 0xFC, 0x8F, 0xB6, 0x2B, 0xF5, 0x33,
+ 0xE3, 0x82, 0x80, 0x0A, 0x00, 0x28, 0x03, 0xF6, 0x0B, 0xFE, 0x08, 0x85, 0xFF, 0x00, 0x22, 0x27,
+ 0xED, 0xD7, 0xFF, 0x00, 0x67, 0xCF, 0x07, 0xFE, 0xA8, 0x6F, 0x86, 0x55, 0xF9, 0xD7, 0x10, 0x7F,
+ 0xC8, 0xD2, 0x7E, 0x91, 0xFF, 0x00, 0xD2, 0x51, 0xF5, 0x19, 0x5F, 0xFB, 0x94, 0x7E, 0x7F, 0x99,
+ 0xFB, 0x6D, 0x5E, 0x29, 0xE8, 0x85, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05,
+ 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14,
+ 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40,
+ 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x7F, 0x9F, 0x9F, 0xFC, 0x1C, 0xFB, 0xFF, 0x00, 0x29, 0xCF, 0xFF, 0x00, 0x82, 0x43, 0xFF, 0x00,
+ 0xD8, 0x2B, 0xE1, 0xEF, 0xFE, 0xAD, 0xEB, 0x9A, 0xEC, 0xCB, 0x3F, 0xE4, 0x61, 0x87, 0xFF, 0x00,
+ 0x1C, 0x3F, 0xF4, 0xA4, 0x73, 0xE2, 0x7F, 0xDD, 0x6A, 0x7F, 0x85, 0xFE, 0x47, 0xDA, 0x95, 0xFA,
+ 0x99, 0xF1, 0xC1, 0x40, 0x05, 0x00, 0x14, 0x01, 0xFB, 0x05, 0xFF, 0x00, 0x04, 0x42, 0xFF, 0x00,
+ 0x91, 0x13, 0xF6, 0xEB, 0xFF, 0x00, 0xB3, 0xE7, 0x83, 0xFF, 0x00, 0x54, 0x37, 0xC3, 0x2A, 0xFC,
+ 0xEB, 0x88, 0x3F, 0xE4, 0x69, 0x3F, 0x48, 0xFF, 0x00, 0xE9, 0x28, 0xFA, 0x8C, 0xAF, 0xFD, 0xCA,
+ 0x3F, 0x3F, 0xCC, 0xFD, 0xB6, 0xAF, 0x14, 0xF4, 0x42, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02,
+ 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A,
+ 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28,
+ 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0,
+ 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80,
+ 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00,
+ 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00,
+ 0xA0, 0x02, 0x80, 0x3F, 0xCF, 0xCF, 0xFE, 0x0E, 0x7D, 0xFF, 0x00, 0x94, 0xE7, 0xFF, 0x00, 0xC1,
+ 0x21, 0xFF, 0x00, 0xEC, 0x15, 0xF0, 0xF7, 0xFF, 0x00, 0x56, 0xF5, 0xCD, 0x76, 0x65, 0x9F, 0xF2,
+ 0x30, 0xC3, 0xFF, 0x00, 0x8E, 0x1F, 0xFA, 0x52, 0x39, 0xF1, 0x3F, 0xEE, 0xB5, 0x3F, 0xC2, 0xFF,
+ 0x00, 0x23, 0xED, 0x4A, 0xFD, 0x4C, 0xF8, 0xE0, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0xFD, 0x82, 0xFF,
+ 0x00, 0x82, 0x21, 0x7F, 0xC8, 0x89, 0xFB, 0x75, 0xFF, 0x00, 0xD9, 0xF3, 0xC1, 0xFF, 0x00, 0xAA,
+ 0x1B, 0xE1, 0x95, 0x7E, 0x75, 0xC4, 0x1F, 0xF2, 0x34, 0x9F, 0xA4, 0x7F, 0xF4, 0x94, 0x7D, 0x46,
+ 0x57, 0xFE, 0xE5, 0x1F, 0x9F, 0xE6, 0x7E, 0xDB, 0x57, 0x8A, 0x7A, 0x21, 0x40, 0x05, 0x00, 0x14,
+ 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40,
+ 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05,
+ 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x1F, 0xE7, 0xE7, 0xFF, 0x00, 0x07, 0x3E, 0xFF, 0x00, 0xCA,
+ 0x73, 0xFF, 0x00, 0xE0, 0x90, 0xFF, 0x00, 0xF6, 0x0A, 0xF8, 0x7B, 0xFF, 0x00, 0xAB, 0x7A, 0xE6,
+ 0xBB, 0x32, 0xCF, 0xF9, 0x18, 0x61, 0xFF, 0x00, 0xC7, 0x0F, 0xFD, 0x29, 0x1C, 0xF8, 0x9F, 0xF7,
+ 0x5A, 0x9F, 0xE1, 0x7F, 0x91, 0xF6, 0xA5, 0x7E, 0xA6, 0x7C, 0x70, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x7E, 0xC1, 0x7F, 0xC1, 0x10, 0xBF, 0xE4, 0x44, 0xFD, 0xBA, 0xFF, 0x00, 0xEC, 0xF9, 0xE0, 0xFF,
+ 0x00, 0xD5, 0x0D, 0xF0, 0xCA, 0xBF, 0x3A, 0xE2, 0x0F, 0xF9, 0x1A, 0x4F, 0xD2, 0x3F, 0xFA, 0x4A,
+ 0x3E, 0xA3, 0x2B, 0xFF, 0x00, 0x72, 0x8F, 0xCF, 0xF3, 0x3F, 0x6D, 0xAB, 0xC5, 0x3D, 0x10, 0xA0,
+ 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80,
+ 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00,
+ 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00,
+ 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02,
+ 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A,
+ 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28,
+ 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x0F, 0xF3, 0xF3, 0xFF, 0x00, 0x83, 0x9F,
+ 0x7F, 0xE5, 0x39, 0xFF, 0x00, 0xF0, 0x48, 0x7F, 0xFB, 0x05, 0x7C, 0x3D, 0xFF, 0x00, 0xD5, 0xBD,
+ 0x73, 0x5D, 0x99, 0x67, 0xFC, 0x8C, 0x30, 0xFF, 0x00, 0xE3, 0x87, 0xFE, 0x94, 0x8E, 0x7C, 0x4F,
+ 0xFB, 0xAD, 0x4F, 0xF0, 0xBF, 0xC8, 0xFB, 0x52, 0xBF, 0x53, 0x3E, 0x38, 0x28, 0x00, 0xA0, 0x02,
+ 0x80, 0x3F, 0x60, 0xBF, 0xE0, 0x88, 0x5F, 0xF2, 0x22, 0x7E, 0xDD, 0x7F, 0xF6, 0x7C, 0xF0, 0x7F,
+ 0xEA, 0x86, 0xF8, 0x65, 0x5F, 0x9D, 0x71, 0x07, 0xFC, 0x8D, 0x27, 0xE9, 0x1F, 0xFD, 0x25, 0x1F,
+ 0x51, 0x95, 0xFF, 0x00, 0xB9, 0x47, 0xE7, 0xF9, 0x9F, 0xB6, 0xD5, 0xE2, 0x9E, 0x88, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05,
+ 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14,
+ 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40,
+ 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x07, 0xF9, 0xF9, 0xFF, 0x00, 0xC1, 0xCF, 0xBF,
+ 0xF2, 0x9C, 0xFF, 0x00, 0xF8, 0x24, 0x3F, 0xFD, 0x82, 0xBE, 0x1E, 0xFF, 0x00, 0xEA, 0xDE, 0xB9,
+ 0xAE, 0xCC, 0xB3, 0xFE, 0x46, 0x18, 0x7F, 0xF1, 0xC3, 0xFF, 0x00, 0x4A, 0x47, 0x3E, 0x27, 0xFD,
+ 0xD6, 0xA7, 0xF8, 0x5F, 0xE4, 0x7D, 0xA9, 0x5F, 0xA9, 0x9F, 0x1C, 0x14, 0x00, 0x50, 0x01, 0x40,
+ 0x1F, 0xB0, 0x5F, 0xF0, 0x44, 0x2F, 0xF9, 0x11, 0x3F, 0x6E, 0xBF, 0xFB, 0x3E, 0x78, 0x3F, 0xF5,
+ 0x43, 0x7C, 0x32, 0xAF, 0xCE, 0xB8, 0x83, 0xFE, 0x46, 0x93, 0xF4, 0x8F, 0xFE, 0x92, 0x8F, 0xA8,
+ 0xCA, 0xFF, 0x00, 0xDC, 0xA3, 0xF3, 0xFC, 0xCF, 0xDB, 0x6A, 0xF1, 0x4F, 0x44, 0x28, 0x00, 0xA0,
+ 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80,
+ 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00,
+ 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00,
+ 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02,
+ 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A,
+ 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28,
+ 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x03, 0xFC, 0xFC, 0xFF, 0x00, 0xE0, 0xE7, 0xDF, 0xF9,
+ 0x4E, 0x7F, 0xFC, 0x12, 0x1F, 0xFE, 0xC1, 0x5F, 0x0F, 0x7F, 0xF5, 0x6F, 0x5C, 0xD7, 0x66, 0x59,
+ 0xFF, 0x00, 0x23, 0x0C, 0x3F, 0xF8, 0xE1, 0xFF, 0x00, 0xA5, 0x23, 0x9F, 0x13, 0xFE, 0xEB, 0x53,
+ 0xFC, 0x2F, 0xF2, 0x3E, 0xD4, 0xAF, 0xD4, 0xCF, 0x8E, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x0F, 0xD8,
+ 0x2F, 0xF8, 0x22, 0x17, 0xFC, 0x88, 0x9F, 0xB7, 0x5F, 0xFD, 0x9F, 0x3C, 0x1F, 0xFA, 0xA1, 0xBE,
+ 0x19, 0x57, 0xE7, 0x5C, 0x41, 0xFF, 0x00, 0x23, 0x49, 0xFA, 0x47, 0xFF, 0x00, 0x49, 0x47, 0xD4,
+ 0x65, 0x7F, 0xEE, 0x51, 0xF9, 0xFE, 0x67, 0xED, 0xB5, 0x78, 0xA7, 0xA2, 0x14, 0x00, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05,
+ 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14,
+ 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40,
+ 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x01, 0xFE, 0x7E, 0x7F, 0xF0, 0x73, 0xEF, 0xFC, 0xA7, 0x3F,
+ 0xFE, 0x09, 0x0F, 0xFF, 0x00, 0x60, 0xAF, 0x87, 0xBF, 0xFA, 0xB7, 0xAE, 0x6B, 0xB3, 0x2C, 0xFF,
+ 0x00, 0x91, 0x86, 0x1F, 0xFC, 0x70, 0xFF, 0x00, 0xD2, 0x91, 0xCF, 0x89, 0xFF, 0x00, 0x75, 0xA9,
+ 0xFE, 0x17, 0xF9, 0x1F, 0x6A, 0x57, 0xEA, 0x67, 0xC7, 0x05, 0x00, 0x14, 0x00, 0x50, 0x07, 0xEC,
+ 0x17, 0xFC, 0x11, 0x0B, 0xFE, 0x44, 0x4F, 0xDB, 0xAF, 0xFE, 0xCF, 0x9E, 0x0F, 0xFD, 0x50, 0xDF,
+ 0x0C, 0xAB, 0xF3, 0xAE, 0x20, 0xFF, 0x00, 0x91, 0xA4, 0xFD, 0x23, 0xFF, 0x00, 0xA4, 0xA3, 0xEA,
+ 0x32, 0xBF, 0xF7, 0x28, 0xFC, 0xFF, 0x00, 0x33, 0xF6, 0xDA, 0xBC, 0x53, 0xD1, 0x0A, 0x00, 0x28,
+ 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0,
+ 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80,
+ 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00,
+ 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00,
+ 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02,
+ 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A,
+ 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0xFF, 0x00, 0x3F, 0x3F, 0xF8, 0x39, 0xF7, 0xFE,
+ 0x53, 0x9F, 0xFF, 0x00, 0x04, 0x87, 0xFF, 0x00, 0xB0, 0x57, 0xC3, 0xDF, 0xFD, 0x5B, 0xD7, 0x35,
+ 0xD9, 0x96, 0x7F, 0xC8, 0xC3, 0x0F, 0xFE, 0x38, 0x7F, 0xE9, 0x48, 0xE7, 0xC4, 0xFF, 0x00, 0xBA,
+ 0xD4, 0xFF, 0x00, 0x0B, 0xFC, 0x8F, 0xB5, 0x2B, 0xF5, 0x33, 0xE3, 0x82, 0x80, 0x0A, 0x00, 0x28,
+ 0x03, 0xF6, 0x0B, 0xFE, 0x08, 0x85, 0xFF, 0x00, 0x22, 0x27, 0xED, 0xD7, 0xFF, 0x00, 0x67, 0xCF,
+ 0x07, 0xFE, 0xA8, 0x6F, 0x86, 0x55, 0xF9, 0xD7, 0x10, 0x7F, 0xC8, 0xD2, 0x7E, 0x91, 0xFF, 0x00,
+ 0xD2, 0x51, 0xF5, 0x19, 0x5F, 0xFB, 0x94, 0x7E, 0x7F, 0x99, 0xFB, 0x6D, 0x5E, 0x29, 0xE8, 0x85,
+ 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x08, 0x7E, 0xE9,
+ 0xFF, 0x00, 0x77, 0xFA, 0x50, 0x04, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40,
+ 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x05, 0x8A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00,
+ 0x28, 0x03, 0xFC, 0xFC, 0xFF, 0x00, 0xE0, 0xE7, 0xDF, 0xF9, 0x4E, 0x7F, 0xFC, 0x12, 0x1F, 0xFE,
+ 0xC1, 0x5F, 0x0F, 0x7F, 0xF5, 0x6F, 0x5C, 0xD7, 0x66, 0x59, 0xFF, 0x00, 0x23, 0x0C, 0x3F, 0xF8,
+ 0xE1, 0xFF, 0x00, 0xA5, 0x23, 0x9F, 0x13, 0xFE, 0xEB, 0x53, 0xFC, 0x2F, 0xF2, 0x3E, 0xD4, 0xAF,
+ 0xD4, 0xCF, 0x8E, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x0F, 0xD8, 0x2F, 0xF8, 0x22, 0x17, 0xFC, 0x88,
+ 0x9F, 0xB7, 0x5F, 0xFD, 0x9F, 0x3C, 0x1F, 0xFA, 0xA1, 0xBE, 0x19, 0x57, 0xE7, 0x5C, 0x41, 0xFF,
+ 0x00, 0x23, 0x49, 0xFA, 0x47, 0xFF, 0x00, 0x49, 0x47, 0xD4, 0x65, 0x7F, 0xEE, 0x51, 0xF9, 0xFE,
+ 0x67, 0xED, 0xB5, 0x78, 0xA7, 0xA2, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x21, 0xFB, 0xA7, 0xFD, 0xDF, 0xE9, 0x40, 0x10, 0x50, 0x01, 0x40, 0x05,
+ 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14,
+ 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x03, 0x8C, 0x70, 0x38, 0xC7, 0x18, 0xE3, 0x8E, 0xD8, 0xFC,
+ 0x28, 0x03, 0xE6, 0x3F, 0x87, 0xBE, 0x3E, 0xF1, 0x87, 0xC3, 0xCF, 0x17, 0xE9, 0x7F, 0x02, 0xFE,
+ 0x39, 0x6A, 0xAF, 0xAE, 0x6B, 0x1A, 0xC7, 0xDA, 0xBF, 0xE1, 0x4A, 0x7C, 0x6A, 0x7D, 0x3D, 0x34,
+ 0xFD, 0x37, 0xE3, 0x5D, 0x9D, 0xA4, 0x72, 0xDC, 0x4D, 0xA4, 0xEB, 0x31, 0xDB, 0xDB, 0xC7, 0x63,
+ 0xA6, 0xF8, 0xB2, 0xCA, 0xCE, 0x20, 0xD3, 0xDA, 0xA1, 0x8E, 0x1D, 0x56, 0x0B, 0x7B, 0x9D, 0x57,
+ 0x4E, 0x8A, 0x38, 0xE1, 0xD5, 0x34, 0xDF, 0x0E, 0x80, 0x7D, 0x39, 0x40, 0x19, 0xDA, 0xBC, 0xD2,
+ 0xDA, 0xE9, 0x1A, 0x9D, 0xC5, 0xBB, 0x79, 0x73, 0x5B, 0xE9, 0xB3, 0xCD, 0x0B, 0x85, 0x53, 0xE5,
+ 0xBA, 0x44, 0x4A, 0x90, 0x08, 0x23, 0x82, 0x07, 0x04, 0x62, 0x80, 0x3C, 0x7F, 0xF6, 0x61, 0xF1,
+ 0x5F, 0x88, 0x7C, 0x79, 0xFB, 0x35, 0x7E, 0xCF, 0x1E, 0x38, 0xF1, 0x76, 0xA6, 0xFA, 0xD7, 0x8B,
+ 0x3C, 0x67, 0xF0, 0x33, 0xC2, 0x3E, 0x2B, 0xF1, 0x3E, 0xB3, 0x25, 0xAC, 0x16, 0x52, 0x6A, 0xDA,
+ 0x8E, 0xA3, 0xE1, 0xFB, 0x4B, 0x8B, 0xDB, 0xA6, 0x86, 0x04, 0x8E, 0x18, 0xCC, 0x93, 0x4D, 0x2B,
+ 0xEC, 0x8E, 0x34, 0x45, 0xDD, 0x85, 0x55, 0x00, 0x00, 0x01, 0xEE, 0x34, 0x01, 0xF2, 0xF7, 0xC4,
+ 0x3F, 0x88, 0xDE, 0x2F, 0xF1, 0xF7, 0x8C, 0xF5, 0x5F, 0x80, 0x5F, 0x01, 0x75, 0x65, 0xD1, 0xFC,
+ 0x4F, 0xA2, 0x0B, 0x43, 0xF1, 0xB3, 0xE3, 0x4A, 0xE9, 0x96, 0xBA, 0xF6, 0x89, 0xF0, 0x06, 0xCA,
+ 0xF2, 0x18, 0x2E, 0x61, 0xD2, 0x2C, 0x6D, 0xA6, 0x26, 0x0B, 0xCF, 0x19, 0x6A, 0x1A, 0x7D, 0xCA,
+ 0xCD, 0x63, 0x6B, 0x24, 0x57, 0x16, 0xBA, 0x64, 0x13, 0x5B, 0x6B, 0x1A, 0xA4, 0x32, 0xC3, 0x2E,
+ 0x95, 0xA4, 0xF8, 0xA0, 0x03, 0xE9, 0xC8, 0x23, 0x30, 0xC1, 0x0C, 0x2D, 0x2C, 0x93, 0xB4, 0x51,
+ 0x2C, 0x46, 0x79, 0xB6, 0x79, 0xD3, 0x15, 0x50, 0x0B, 0xBE, 0xD5, 0x55, 0xC9, 0xC6, 0x4E, 0xD5,
+ 0x51, 0xE8, 0x00, 0xE0, 0x00, 0x4B, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x01, 0x62, 0x80,
+ 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0xFF, 0x00, 0x3F, 0x3F, 0xF8, 0x39, 0xF7,
+ 0xFE, 0x53, 0x9F, 0xFF, 0x00, 0x04, 0x87, 0xFF, 0x00, 0xB0, 0x57, 0xC3, 0xDF, 0xFD, 0x5B, 0xD7,
+ 0x35, 0xD9, 0x96, 0x7F, 0xC8, 0xC3, 0x0F, 0xFE, 0x38, 0x7F, 0xE9, 0x48, 0xE7, 0xC4, 0xFF, 0x00,
+ 0xBA, 0xD4, 0xFF, 0x00, 0x0B, 0xFC, 0x8F, 0xB5, 0x2B, 0xF5, 0x33, 0xE3, 0x82, 0x80, 0x0A, 0x00,
+ 0x28, 0x03, 0xF6, 0x0B, 0xFE, 0x08, 0x85, 0xFF, 0x00, 0x22, 0x27, 0xED, 0xD7, 0xFF, 0x00, 0x67,
+ 0xCF, 0x07, 0xFE, 0xA8, 0x6F, 0x86, 0x55, 0xF9, 0xD7, 0x10, 0x7F, 0xC8, 0xD2, 0x7E, 0x91, 0xFF,
+ 0x00, 0xD2, 0x51, 0xF5, 0x19, 0x5F, 0xFB, 0x94, 0x7E, 0x7F, 0x99, 0xFB, 0x6D, 0x5E, 0x29, 0xE8,
+ 0x85, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x08, 0x7E,
+ 0xE9, 0xFF, 0x00, 0x77, 0xFA, 0x50, 0x04, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x71, 0xDE, 0x3D, 0xF0, 0x07, 0x84, 0x3E, 0x27, 0x78, 0x53, 0x51, 0xF0, 0x4F,
+ 0x8E, 0x74, 0x58, 0x75, 0xDF, 0x0E, 0x6A, 0x72, 0xDA, 0x5E, 0x3D, 0xA9, 0xB8, 0x9F, 0x4E, 0xBD,
+ 0xD3, 0xEF, 0x34, 0xEB, 0xC8, 0xAF, 0x34, 0xAD, 0x4F, 0x4E, 0xBE, 0xB7, 0x78, 0xEE, 0xAC, 0x75,
+ 0x0B, 0x2B, 0xDB, 0x3B, 0x2B, 0xBB, 0x4B, 0xDB, 0x59, 0x61, 0xB8, 0xB4, 0xB9, 0xB6, 0xB6, 0xB9,
+ 0x82, 0x58, 0xA6, 0x82, 0x39, 0x10, 0x02, 0x8F, 0xC3, 0x1F, 0x0F, 0xF8, 0xE3, 0xC2, 0x9E, 0x11,
+ 0xB1, 0xF0, 0xDF, 0x8F, 0xBC, 0x71, 0x17, 0xC4, 0x9D, 0x67, 0x45, 0x96, 0x4D, 0x36, 0xC7, 0xC7,
+ 0x12, 0x68, 0x11, 0x78, 0x6F, 0x5E, 0xF1, 0x1E, 0x9D, 0x11, 0xDB, 0xA7, 0xDC, 0x6B, 0x76, 0xF0,
+ 0xB9, 0xB4, 0x7D, 0x54, 0xC2, 0x23, 0x17, 0x73, 0xDA, 0x45, 0x69, 0x6D, 0x3C, 0xE2, 0x59, 0xE0,
+ 0xB2, 0xB1, 0x8E, 0x54, 0xB4, 0xB7, 0x00, 0xF1, 0x1F, 0x1C, 0xFE, 0xD6, 0xDF, 0x07, 0x34, 0x48,
+ 0x2E, 0x34, 0x78, 0x6C, 0xFE, 0x38, 0xF8, 0xC0, 0x6A, 0x9A, 0x6E, 0xA5, 0x6F, 0x69, 0xAE, 0x7C,
+ 0x26, 0xFD, 0x94, 0x3E, 0x2B, 0x7C, 0x6E, 0xF0, 0x6F, 0x9B, 0x65, 0xAA, 0xDF, 0xE9, 0x37, 0x96,
+ 0xEF, 0xAD, 0xF8, 0x73, 0xC3, 0x7A, 0x85, 0x82, 0x4F, 0x15, 0xF6, 0x8F, 0x7E, 0x8F, 0x01, 0x9B,
+ 0xCD, 0x08, 0xB0, 0xCD, 0xB3, 0xCA, 0xB8, 0x82, 0x49, 0x40, 0x3C, 0x4B, 0xF6, 0x76, 0xFD, 0xA9,
+ 0x7E, 0x11, 0xFC, 0x2D, 0xF8, 0x15, 0xF0, 0x2F, 0xE1, 0x6F, 0x8D, 0xAC, 0x3E, 0x3F, 0xF8, 0x77,
+ 0x51, 0xF8, 0x6F, 0xF0, 0x8F, 0xC3, 0x1E, 0x02, 0xF1, 0x77, 0x8C, 0xBC, 0x4B, 0xFB, 0x16, 0x7C,
+ 0x6F, 0xF0, 0x07, 0xC2, 0x8D, 0x12, 0x7D, 0x1B, 0x45, 0xB6, 0xB4, 0xD4, 0x35, 0x2B, 0xEF, 0x13,
+ 0xEB, 0x5E, 0x0F, 0xB0, 0xB0, 0xD3, 0xF4, 0xA8, 0xDA, 0xDA, 0x59, 0x5E, 0xFB, 0x50, 0x92, 0xCE,
+ 0x18, 0x61, 0x53, 0x2C, 0xCD, 0x0A, 0xAB, 0x6C, 0x00, 0xFB, 0x83, 0xE2, 0x4E, 0x83, 0xE3, 0x4F,
+ 0x13, 0xF8, 0x2B, 0x59, 0xF0, 0xEF, 0xC3, 0xEF, 0x1C, 0xB7, 0xC3, 0x3F, 0x13, 0x6B, 0x4B, 0x06,
+ 0x9B, 0x07, 0x8F, 0xAD, 0x34, 0x0B, 0x2F, 0x12, 0xEB, 0x5E, 0x12, 0xB4, 0x96, 0xE2, 0x35, 0xD4,
+ 0x6F, 0x74, 0x8B, 0x3B, 0xC4, 0x92, 0xC0, 0xEA, 0x69, 0x68, 0x6E, 0x8D, 0x9B, 0xDE, 0xDB, 0xDE,
+ 0xDA, 0x45, 0x75, 0xF6, 0x69, 0x6E, 0x6C, 0xAF, 0x60, 0x8E, 0x4B, 0x4B, 0x80, 0x09, 0x7E, 0x1D,
+ 0xFC, 0x3B, 0xF0, 0x6F, 0xC2, 0x9F, 0x08, 0x69, 0x7E, 0x06, 0xF0, 0x16, 0x89, 0x1E, 0x83, 0xE1,
+ 0xBD, 0x2A, 0x5B, 0xBB, 0xD8, 0xED, 0xBE, 0xD7, 0x73, 0xAA, 0x5F, 0x6A, 0x17, 0xBA, 0x8D, 0xEC,
+ 0xB7, 0x9A, 0xAE, 0xA9, 0xA8, 0xDF, 0xDC, 0xC9, 0x2D, 0xDD, 0xF6, 0xA1, 0x7B, 0x7D, 0x79, 0x7B,
+ 0x79, 0x77, 0x7B, 0x75, 0x2C, 0xD7, 0x37, 0x77, 0x57, 0x37, 0x37, 0x33, 0xCB, 0x2C, 0xD3, 0x49,
+ 0x23, 0x80, 0x76, 0xB4, 0x00, 0x50, 0x07, 0x01, 0xF1, 0x07, 0xE2, 0x7F, 0x82, 0x3E, 0x16, 0xD8,
+ 0xE8, 0x37, 0xBE, 0x34, 0xD5, 0xAE, 0x2C, 0x5F, 0xC5, 0x5E, 0x24, 0x83, 0xC1, 0xDE, 0x12, 0xD1,
+ 0x74, 0x8D, 0x0B, 0x50, 0xF1, 0x6F, 0x8A, 0xFC, 0x5F, 0xAA, 0x4D, 0x6F, 0x35, 0xC0, 0xD3, 0xF4,
+ 0x7D, 0x13, 0x4F, 0x82, 0x7B, 0xFB, 0xE9, 0xA3, 0xB3, 0xB0, 0xD4, 0x6F, 0x25, 0x4B, 0x68, 0x25,
+ 0x30, 0x59, 0xD8, 0xDF, 0xDE, 0x4B, 0xE5, 0xDB, 0xD9, 0xCF, 0x2C, 0x40, 0x1F, 0x3E, 0x7F, 0xC3,
+ 0x72, 0x7C, 0x15, 0xFF, 0x00, 0xA1, 0x27, 0xF6, 0xC3, 0xFF, 0x00, 0xC5, 0x77, 0x7E, 0xD0, 0x3F,
+ 0xFC, 0xC5, 0xD0, 0x01, 0xFF, 0x00, 0x0D, 0xC9, 0xF0, 0x57, 0xFE, 0x84, 0x9F, 0xDB, 0x0F, 0xFF,
+ 0x00, 0x15, 0xDD, 0xFB, 0x40, 0xFF, 0x00, 0xF3, 0x17, 0x40, 0x07, 0xFC, 0x37, 0x27, 0xC1, 0x5F,
+ 0xFA, 0x12, 0x7F, 0x6C, 0x3F, 0xFC, 0x57, 0x77, 0xED, 0x03, 0xFF, 0x00, 0xCC, 0x5D, 0x00, 0x1F,
+ 0xF0, 0xDC, 0x9F, 0x05, 0x7F, 0xE8, 0x49, 0xFD, 0xB0, 0xFF, 0x00, 0xF1, 0x5D, 0xDF, 0xB4, 0x0F,
+ 0xFF, 0x00, 0x31, 0x74, 0x00, 0x7F, 0xC3, 0x72, 0x7C, 0x15, 0xFF, 0x00, 0xA1, 0x27, 0xF6, 0xC3,
+ 0xFF, 0x00, 0xC5, 0x77, 0x7E, 0xD0, 0x3F, 0xFC, 0xC5, 0xD0, 0x01, 0xFF, 0x00, 0x0D, 0xC9, 0xF0,
+ 0x57, 0xFE, 0x84, 0x9F, 0xDB, 0x0F, 0xFF, 0x00, 0x15, 0xDD, 0xFB, 0x40, 0xFF, 0x00, 0xF3, 0x17,
+ 0x40, 0x07, 0xFC, 0x37, 0x27, 0xC1, 0x5F, 0xFA, 0x12, 0x7F, 0x6C, 0x3F, 0xFC, 0x57, 0x77, 0xED,
+ 0x03, 0xFF, 0x00, 0xCC, 0x5D, 0x00, 0x1F, 0xF0, 0xDC, 0x9F, 0x05, 0x7F, 0xE8, 0x49, 0xFD, 0xB0,
+ 0xFF, 0x00, 0xF1, 0x5D, 0xDF, 0xB4, 0x0F, 0xFF, 0x00, 0x31, 0x74, 0x00, 0x7F, 0xC3, 0x72, 0x7C,
+ 0x15, 0xFF, 0x00, 0xA1, 0x27, 0xF6, 0xC3, 0xFF, 0x00, 0xC5, 0x77, 0x7E, 0xD0, 0x3F, 0xFC, 0xC5,
+ 0xD0, 0x01, 0xFF, 0x00, 0x0D, 0xC9, 0xF0, 0x57, 0xFE, 0x84, 0x9F, 0xDB, 0x0F, 0xFF, 0x00, 0x15,
+ 0xDD, 0xFB, 0x40, 0xFF, 0x00, 0xF3, 0x17, 0x40, 0x07, 0xFC, 0x37, 0x27, 0xC1, 0x5F, 0xFA, 0x12,
+ 0x7F, 0x6C, 0x3F, 0xFC, 0x57, 0x77, 0xED, 0x03, 0xFF, 0x00, 0xCC, 0x5D, 0x00, 0x1F, 0xF0, 0xDC,
+ 0x9F, 0x05, 0x7F, 0xE8, 0x49, 0xFD, 0xB0, 0xFF, 0x00, 0xF1, 0x5D, 0xDF, 0xB4, 0x0F, 0xFF, 0x00,
+ 0x31, 0x74, 0x01, 0xEB, 0x7F, 0x09, 0xFE, 0x3C, 0xF8, 0x1F, 0xE3, 0x34, 0xFA, 0xE5, 0xAF, 0x83,
+ 0xF4, 0x2F, 0x8D, 0x1A, 0x34, 0x9E, 0x1D, 0x86, 0xDA, 0x7B, 0xF6, 0xF8, 0xB1, 0xFB, 0x36, 0xFC,
+ 0x45, 0xF8, 0x09, 0x6F, 0x3A, 0xDD, 0x34, 0xA2, 0x21, 0x61, 0x37, 0x89, 0xB4, 0x3D, 0x36, 0x3B,
+ 0xD6, 0x1F, 0x66, 0x93, 0x7A, 0xDA, 0xB4, 0xCD, 0x10, 0x31, 0x19, 0x02, 0x09, 0x63, 0xDE, 0x01,
+ 0xEC, 0xF4, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x58,
+ 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x3F, 0xCF, 0xCF, 0xFE, 0x0E, 0x7D,
+ 0xFF, 0x00, 0x94, 0xE7, 0xFF, 0x00, 0xC1, 0x21, 0xFF, 0x00, 0xEC, 0x15, 0xF0, 0xF7, 0xFF, 0x00,
+ 0x56, 0xF5, 0xCD, 0x76, 0x65, 0x9F, 0xF2, 0x30, 0xC3, 0xFF, 0x00, 0x8E, 0x1F, 0xFA, 0x52, 0x39,
+ 0xF1, 0x3F, 0xEE, 0xB5, 0x3F, 0xC2, 0xFF, 0x00, 0x23, 0xED, 0x4A, 0xFD, 0x4C, 0xF8, 0xE0, 0xA0,
+ 0x02, 0x80, 0x0A, 0x00, 0xFD, 0x82, 0xFF, 0x00, 0x82, 0x21, 0x7F, 0xC8, 0x89, 0xFB, 0x75, 0xFF,
+ 0x00, 0xD9, 0xF3, 0xC1, 0xFF, 0x00, 0xAA, 0x1B, 0xE1, 0x95, 0x7E, 0x75, 0xC4, 0x1F, 0xF2, 0x34,
+ 0x9F, 0xA4, 0x7F, 0xF4, 0x94, 0x7D, 0x46, 0x57, 0xFE, 0xE5, 0x1F, 0x9F, 0xE6, 0x7E, 0xDB, 0x57,
+ 0x8A, 0x7A, 0x21, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x02, 0x1F, 0xBA, 0x7F, 0xDD, 0xFE, 0x94, 0x01, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05,
+ 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14,
+ 0x00, 0x50, 0x01, 0x40, 0x00, 0x1D, 0x00, 0x1E, 0x80, 0x00, 0x3F, 0x20, 0x07, 0xE5, 0x40, 0x1F,
+ 0x24, 0x6A, 0x9A, 0xB5, 0xFF, 0x00, 0xED, 0x45, 0xA8, 0x6A, 0x3E, 0x10, 0xF0, 0x6E, 0xA7, 0x71,
+ 0xA6, 0xFE, 0xCE, 0x5A, 0x5D, 0xDC, 0xFA, 0x2F, 0xC4, 0x1F, 0x88, 0x9A, 0x1D, 0xEC, 0x49, 0x73,
+ 0xF1, 0xAE, 0x78, 0x4C, 0x4B, 0x73, 0xE1, 0x9F, 0x0C, 0x5D, 0xA0, 0x71, 0xFD, 0x8E, 0x37, 0x5E,
+ 0x5B, 0x6A, 0x5A, 0x8C, 0x4D, 0x1C, 0x9E, 0x64, 0x52, 0x59, 0x5A, 0x38, 0x91, 0x6E, 0x2E, 0x2D,
+ 0x00, 0x3E, 0xA7, 0xD2, 0x34, 0x8D, 0x27, 0x40, 0xD2, 0x74, 0xBD, 0x07, 0x41, 0xD3, 0x34, 0xED,
+ 0x13, 0x43, 0xD1, 0x34, 0xE8, 0x34, 0x8D, 0x1B, 0x46, 0xD2, 0x2C, 0xA2, 0xD3, 0x74, 0x9D, 0x22,
+ 0xD2, 0xDA, 0x25, 0x8E, 0xDA, 0xD6, 0xD6, 0xDA, 0x35, 0x58, 0xE2, 0x86, 0x38, 0xE3, 0x8D, 0x12,
+ 0x34, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x00, 0xB3, 0x73, 0x6B, 0x6B, 0x7B, 0x6B, 0x71,
+ 0x63, 0x7B, 0x6D, 0x6F, 0x77, 0x65, 0x77, 0x6E, 0xF6, 0x97, 0x76, 0x77, 0x50, 0xA5, 0xC5, 0xAD,
+ 0xD4, 0x52, 0x21, 0x59, 0x22, 0x92, 0x36, 0x05, 0x59, 0x19, 0x49, 0x05, 0x48, 0x20, 0x82, 0x41,
+ 0x18, 0xA0, 0x0F, 0x90, 0xD2, 0xE6, 0x6F, 0xD9, 0x0E, 0x61, 0x6F, 0xA8, 0xCF, 0xE6, 0xFE, 0xC9,
+ 0x37, 0x37, 0x01, 0x6C, 0x75, 0x5B, 0x87, 0x82, 0x0F, 0xF8, 0x65, 0x29, 0xAE, 0x6E, 0x98, 0x25,
+ 0xA5, 0xDC, 0x8D, 0x22, 0xE7, 0xC1, 0x4C, 0xF7, 0x36, 0xB0, 0x5B, 0x08, 0xA2, 0x3F, 0xD8, 0x01,
+ 0x42, 0x39, 0xFE, 0xC7, 0x0A, 0xDE, 0x1C, 0x00, 0xFB, 0x0F, 0xDB, 0xD3, 0x8C, 0x7A, 0x63, 0xB6,
+ 0x3F, 0x0A, 0x00, 0x28, 0x03, 0xCC, 0x3E, 0x2C, 0x7C, 0x57, 0xF0, 0xEF, 0xC2, 0x1F, 0x0C, 0xDA,
+ 0xEB, 0x7A, 0xC5, 0x8E, 0xB7, 0xE2, 0x2D, 0x67, 0x5D, 0xD6, 0xAD, 0xFC, 0x23, 0xE0, 0x1F, 0x87,
+ 0xFE, 0x10, 0xB3, 0x87, 0x52, 0xF1, 0xD7, 0xC4, 0xBD, 0x7A, 0xF1, 0x24, 0x6B, 0x1D, 0x0F, 0x44,
+ 0xB4, 0x96, 0x58, 0x61, 0x69, 0xDD, 0x2D, 0xAE, 0x66, 0x92, 0x7B, 0x89, 0xAD, 0xED, 0x2C, 0xED,
+ 0x6D, 0xAF, 0xAF, 0xEF, 0x6E, 0x6D, 0x2C, 0x6C, 0x6E, 0xAE, 0xED, 0x80, 0x38, 0x7F, 0x84, 0x9F,
+ 0x09, 0xFC, 0x47, 0x6B, 0xAF, 0xDD, 0xFC, 0x69, 0xF8, 0xD5, 0x75, 0xA3, 0xEB, 0xFF, 0x00, 0x1D,
+ 0x7C, 0x49, 0xA2, 0xB6, 0x83, 0x1D, 0xA6, 0x81, 0x73, 0x75, 0x7B, 0xF0, 0xFF, 0x00, 0xE0, 0xA6,
+ 0x81, 0x2D, 0xC2, 0xDC, 0x27, 0x84, 0x3C, 0x22, 0x97, 0x01, 0x4B, 0x2E, 0xF8, 0xED, 0x1B, 0x52,
+ 0xD6, 0x0C, 0x16, 0xD7, 0x5A, 0xE5, 0xCD, 0xA5, 0xAC, 0xF3, 0xC3, 0x6B, 0x67, 0x63, 0xA4, 0x69,
+ 0x1A, 0x18, 0x07, 0xD0, 0xF4, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40,
+ 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x01, 0x62, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0,
+ 0x02, 0x80, 0x0A, 0x00, 0xFF, 0x00, 0x3F, 0x3F, 0xF8, 0x39, 0xF7, 0xFE, 0x53, 0x9F, 0xFF, 0x00,
+ 0x04, 0x87, 0xFF, 0x00, 0xB0, 0x57, 0xC3, 0xDF, 0xFD, 0x5B, 0xD7, 0x35, 0xD9, 0x96, 0x7F, 0xC8,
+ 0xC3, 0x0F, 0xFE, 0x38, 0x7F, 0xE9, 0x48, 0xE7, 0xC4, 0xFF, 0x00, 0xBA, 0xD4, 0xFF, 0x00, 0x0B,
+ 0xFC, 0x8F, 0xB5, 0x2B, 0xF5, 0x33, 0xE3, 0x82, 0x80, 0x0A, 0x00, 0x28, 0x03, 0xF6, 0x0B, 0xFE,
+ 0x08, 0x85, 0xFF, 0x00, 0x22, 0x27, 0xED, 0xD7, 0xFF, 0x00, 0x67, 0xCF, 0x07, 0xFE, 0xA8, 0x6F,
+ 0x86, 0x55, 0xF9, 0xD7, 0x10, 0x7F, 0xC8, 0xD2, 0x7E, 0x91, 0xFF, 0x00, 0xD2, 0x51, 0xF5, 0x19,
+ 0x5F, 0xFB, 0x94, 0x7E, 0x7F, 0x99, 0xFB, 0x6D, 0x5E, 0x29, 0xE8, 0x85, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x08, 0x7E, 0xE9, 0xFF, 0x00, 0x77, 0xFA,
+ 0x50, 0x04, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0xC0, 0x1D, 0x80, 0x03, 0xD8,
+ 0x00, 0x00, 0xA0, 0x05, 0xDA, 0x7F, 0xBA, 0x7F, 0x2A, 0x00, 0xF0, 0x9F, 0xDA, 0x17, 0xE2, 0x0E,
+ 0xA5, 0xE0, 0x2F, 0x03, 0xE9, 0x5A, 0x7F, 0x87, 0x3C, 0x33, 0xA4, 0x78, 0xC3, 0xC6, 0xBF, 0x13,
+ 0xFC, 0x6B, 0xA4, 0xFC, 0x23, 0xF0, 0x4F, 0x86, 0x7C, 0x45, 0x84, 0xF0, 0xC5, 0xDD, 0xD6, 0xB9,
+ 0x71, 0xB2, 0xFA, 0xF7, 0x55, 0x2C, 0x55, 0x1E, 0xC7, 0x4F, 0xD2, 0xE2, 0xD6, 0x35, 0x29, 0xED,
+ 0xFC, 0xC8, 0xA4, 0xBA, 0x8B, 0x4F, 0x92, 0xCE, 0x06, 0x37, 0x37, 0x50, 0x23, 0x80, 0x51, 0xF1,
+ 0xBC, 0xBF, 0x1C, 0x7C, 0x16, 0xFF, 0x00, 0x00, 0x3C, 0x33, 0xF0, 0x5B, 0xC0, 0x7F, 0x0D, 0x3C,
+ 0x41, 0xE1, 0x8F, 0xF8, 0x4B, 0xB4, 0xFF, 0x00, 0x0B, 0xFC, 0x5E, 0x7B, 0xA9, 0x5B, 0xC0, 0xBA,
+ 0x27, 0x83, 0x7C, 0x33, 0x6F, 0x65, 0xB6, 0xE6, 0xEB, 0x45, 0xB3, 0x49, 0x64, 0x6B, 0x34, 0x8A,
+ 0x38, 0x65, 0x6B, 0x68, 0xE2, 0x8F, 0x54, 0x66, 0xB9, 0x8B, 0x4B, 0xD3, 0x1E, 0xDE, 0xDE, 0xD7,
+ 0x52, 0xBB, 0xF1, 0x07, 0x86, 0xC0, 0x31, 0xFE, 0x39, 0x7E, 0xD1, 0xD6, 0xBF, 0xB3, 0xF7, 0x8E,
+ 0xBE, 0x12, 0xDB, 0x78, 0xE7, 0xC2, 0x9A, 0xFB, 0x7C, 0x1F, 0xF8, 0x91, 0x67, 0xAE, 0xF8, 0x66,
+ 0xFB, 0xE2, 0x47, 0x85, 0x7C, 0x2F, 0xAF, 0xFC, 0x44, 0xD6, 0x7C, 0x3D, 0xE3, 0x58, 0x64, 0xD3,
+ 0x25, 0xF0, 0x87, 0x86, 0x8F, 0x87, 0xB4, 0x6D, 0x3A, 0xF2, 0xF4, 0xC3, 0xAA, 0xD8, 0x7F, 0xC2,
+ 0x69, 0x20, 0xBF, 0x91, 0x62, 0xB7, 0x86, 0xE3, 0x48, 0xB0, 0xB2, 0x2E, 0x6E, 0x35, 0x6B, 0x38,
+ 0xA5, 0x00, 0x8B, 0xE0, 0x7F, 0xED, 0x27, 0x65, 0xF1, 0xEB, 0xE2, 0x77, 0xC6, 0x8F, 0x0E, 0xF8,
+ 0x2F, 0xC2, 0x9E, 0x22, 0xB7, 0xF8, 0x69, 0xF0, 0x8B, 0x4B, 0xF0, 0xAE, 0x85, 0x2F, 0x8E, 0x7C,
+ 0x5B, 0xE1, 0x4F, 0x10, 0x7C, 0x37, 0xF1, 0x1D, 0xEF, 0x8D, 0x35, 0x6B, 0x7B, 0xFD, 0x43, 0xC4,
+ 0x1E, 0x18, 0xB8, 0xF0, 0xD6, 0xB5, 0xA7, 0x59, 0x5F, 0x40, 0x96, 0x1A, 0x1D, 0xCF, 0xC3, 0xDD,
+ 0x41, 0x2E, 0xC2, 0x3C, 0x37, 0x2B, 0xE2, 0x4D, 0x88, 0xDB, 0xAC, 0xE5, 0x00, 0x03, 0xB5, 0xF8,
+ 0x6F, 0xAC, 0xFC, 0x74, 0xD4, 0xFE, 0x20, 0x7C, 0x6B, 0xD3, 0xBE, 0x27, 0x78, 0x33, 0xC1, 0x9E,
+ 0x1E, 0xF8, 0x69, 0xA2, 0xF8, 0x87, 0x4F, 0xB3, 0xF8, 0x23, 0xAF, 0xE8, 0x3A, 0xDB, 0xDD, 0xF8,
+ 0x8F, 0xC5, 0x96, 0x32, 0x58, 0x97, 0xD4, 0x9E, 0xFE, 0xD3, 0x74, 0x89, 0xE4, 0xC6, 0xED, 0x64,
+ 0x63, 0xB9, 0x73, 0x63, 0x33, 0x5C, 0x4D, 0xAA, 0xD8, 0x9D, 0x3B, 0xEC, 0xDA, 0x55, 0x9E, 0xB7,
+ 0xE2, 0x60, 0x0E, 0x0F, 0xF6, 0x60, 0xF8, 0x99, 0xA6, 0x6A, 0x3F, 0x0D, 0x7C, 0x5D, 0xE0, 0x4F,
+ 0x10, 0x68, 0xBE, 0x08, 0xF8, 0x6F, 0xE2, 0x9F, 0xD9, 0x4B, 0xC5, 0xD7, 0x3F, 0x00, 0x7E, 0x29,
+ 0xF8, 0x5F, 0xC1, 0xBA, 0x29, 0xF0, 0x57, 0xC3, 0x0F, 0x08, 0x1D, 0x0B, 0x46, 0xB0, 0xD4, 0xB4,
+ 0x1B, 0xED, 0x12, 0xD5, 0x9E, 0x4B, 0x5B, 0x1D, 0x22, 0xFF, 0x00, 0xC2, 0x7A, 0xDF, 0x84, 0x75,
+ 0x98, 0x2C, 0xE2, 0xBB, 0xBC, 0x5D, 0x32, 0x0D, 0x56, 0x3D, 0x36, 0x7B, 0x86, 0xBA, 0xD3, 0xAE,
+ 0x96, 0x30, 0x07, 0x78, 0x43, 0xF6, 0x98, 0x8F, 0xE3, 0x16, 0xBF, 0xE1, 0x08, 0x3F, 0x67, 0xAF,
+ 0x00, 0xEB, 0x5F, 0x13, 0x7E, 0x1A, 0xEA, 0xD1, 0xA6, 0xBF, 0xE2, 0x1F, 0x8F, 0x9A, 0xE7, 0xDB,
+ 0x7E, 0x1B, 0xFC, 0x13, 0x1A, 0x0C, 0x86, 0x1F, 0xB0, 0xDE, 0xF8, 0x3B, 0x56, 0xB8, 0xB1, 0x96,
+ 0x4F, 0x17, 0x4D, 0xA8, 0x45, 0x72, 0x6E, 0xB4, 0xF9, 0x74, 0x98, 0x25, 0xD2, 0x27, 0xB4, 0xB6,
+ 0xB8, 0x9E, 0x5D, 0x62, 0xD4, 0x4F, 0xA6, 0xA6, 0xA8, 0x01, 0xF4, 0x3D, 0xC7, 0x85, 0x7C, 0x2F,
+ 0x77, 0xE2, 0x7D, 0x1F, 0xC6, 0xD7, 0x5E, 0x1C, 0xD0, 0xAE, 0x7C, 0x67, 0xE1, 0xED, 0x03, 0x52,
+ 0xF0, 0xAE, 0x81, 0xE2, 0xD9, 0xF4, 0x8B, 0x79, 0xBC, 0x4D, 0xA1, 0xE9, 0x7A, 0xC5, 0xC5, 0x8C,
+ 0xFA, 0xBE, 0x9B, 0x67, 0x7E, 0x50, 0xCF, 0x0D, 0xAD, 0xD4, 0xFA, 0x16, 0x89, 0x2C, 0xF0, 0xA3,
+ 0x2A, 0x4C, 0xFA, 0x75, 0x83, 0xBA, 0xB3, 0x5B, 0x44, 0x50, 0x03, 0xF3, 0x7F, 0xE2, 0x77, 0xED,
+ 0xB5, 0xFB, 0x50, 0x78, 0x5B, 0xC7, 0x9F, 0x0C, 0xFC, 0x31, 0xA3, 0x7E, 0xC0, 0x5F, 0x15, 0x7E,
+ 0x1E, 0x78, 0x77, 0xC7, 0x9E, 0x3A, 0x9F, 0xE1, 0x6D, 0xB7, 0xC4, 0xBF, 0xDA, 0x6F, 0xE2, 0x7F,
+ 0xC3, 0x2F, 0x06, 0xFC, 0x0D, 0x93, 0x5D, 0xBD, 0x8C, 0xB7, 0x85, 0xE3, 0xD4, 0xBC, 0x53, 0xE0,
+ 0xFF, 0x00, 0x15, 0x78, 0xAF, 0x58, 0xD0, 0x6D, 0xB5, 0x19, 0x2C, 0xAE, 0xEC, 0x6C, 0xE5, 0xB9,
+ 0xF0, 0xCD, 0xCF, 0xDB, 0x35, 0x6D, 0x47, 0xC3, 0x5A, 0x48, 0x16, 0xD3, 0x6A, 0x89, 0x24, 0x60,
+ 0x1F, 0x78, 0xFC, 0x24, 0xF8, 0x97, 0x67, 0xF1, 0x5F, 0xC2, 0x17, 0xDE, 0x2E, 0xB2, 0xD2, 0xAE,
+ 0x74, 0x7B, 0x7B, 0x1F, 0x88, 0x5E, 0x31, 0xF8, 0x7F, 0xF6, 0x2B, 0x89, 0xD6, 0xEE, 0x69, 0x1F,
+ 0xC1, 0xFE, 0x2E, 0xD4, 0xF4, 0x19, 0xAE, 0x43, 0x2A, 0x80, 0x16, 0x77, 0xD0, 0xDE, 0x65, 0x4C,
+ 0x12, 0xAB, 0x2A, 0xA1, 0x24, 0xAE, 0x48, 0x07, 0xC8, 0xBF, 0x16, 0x3F, 0x6B, 0x9F, 0x8B, 0xB7,
+ 0x1E, 0x24, 0xFD, 0x92, 0xF4, 0x9F, 0xD9, 0x47, 0xE0, 0x4D, 0xAF, 0xC5, 0xDF, 0x0D, 0x7E, 0xD2,
+ 0xAD, 0x2F, 0x8A, 0x2D, 0x7E, 0x2B, 0x7C, 0x4E, 0xF1, 0xB6, 0x9B, 0xF0, 0x8B, 0xE0, 0xB4, 0x7A,
+ 0x18, 0xF0, 0x66, 0xB3, 0xAA, 0xC1, 0xA6, 0x5C, 0x5D, 0x89, 0xEE, 0xFC, 0x5F, 0xA7, 0x6A, 0xEF,
+ 0x2E, 0x9F, 0xA2, 0x4C, 0x8D, 0x1F, 0x84, 0x75, 0x6B, 0x63, 0x0C, 0x93, 0x5B, 0xCA, 0xD6, 0xD2,
+ 0x48, 0xD7, 0x16, 0x20, 0x1E, 0xAD, 0xE3, 0x0F, 0xDA, 0xAF, 0xC3, 0x36, 0x3F, 0x06, 0xFE, 0x26,
+ 0x7C, 0x53, 0xF0, 0x87, 0xFC, 0x23, 0x5E, 0x1F, 0x1F, 0x0B, 0x2D, 0x2C, 0x75, 0x0F, 0x12, 0xEA,
+ 0x5F, 0xB5, 0xAC, 0xDE, 0x2F, 0xFD, 0x8C, 0x3E, 0x0F, 0x69, 0x16, 0xB3, 0xDD, 0x2A, 0xDE, 0xDD,
+ 0xDF, 0x78, 0xBF, 0x5B, 0xF0, 0xBC, 0xA6, 0x28, 0x21, 0xB7, 0x8E, 0xED, 0xC4, 0xB0, 0xD8, 0xDC,
+ 0x21, 0x91, 0x2D, 0xA2, 0x95, 0xAD, 0xD6, 0xE0, 0x4A, 0x80, 0x1F, 0x02, 0xFE, 0xC5, 0x9F, 0xF0,
+ 0x55, 0x0D, 0x5F, 0xF6, 0xAA, 0xFD, 0xA1, 0xBE, 0x37, 0xFC, 0x1B, 0xB1, 0xF1, 0x6F, 0xFC, 0x13,
+ 0x67, 0xC7, 0x76, 0x5E, 0x02, 0xF8, 0x9C, 0xFA, 0x2F, 0x82, 0xB4, 0x5F, 0xD9, 0xBB, 0xF6, 0xFE,
+ 0x4F, 0x8A, 0xBF, 0x18, 0x3C, 0x57, 0xE1, 0xCB, 0x7F, 0x86, 0x3E, 0x1D, 0xD7, 0x2E, 0x35, 0x2F,
+ 0x0D, 0x68, 0x72, 0x78, 0x72, 0xDE, 0xDF, 0xC5, 0x10, 0x2E, 0xB9, 0xAE, 0x6A, 0xB6, 0x52, 0xEA,
+ 0x22, 0xE7, 0x43, 0xB6, 0xB6, 0x30, 0x5D, 0x5A, 0x3C, 0x4F, 0x2E, 0x93, 0x25, 0xCE, 0xA2, 0x01,
+ 0xF4, 0x25, 0xAF, 0xED, 0x8B, 0xFB, 0x4E, 0xEB, 0x7F, 0x1F, 0x7E, 0x08, 0xFC, 0x32, 0x97, 0xF6,
+ 0x1C, 0xF1, 0xD7, 0xC0, 0x1F, 0x06, 0xFC, 0x4B, 0xD3, 0xF5, 0xEB, 0x3B, 0xEF, 0x10, 0xFE, 0xD6,
+ 0x9F, 0x16, 0xBE, 0x1A, 0x78, 0x5A, 0x2F, 0x11, 0x6A, 0xFA, 0x6C, 0xBA, 0x65, 0xDC, 0x1A, 0x57,
+ 0x83, 0xEF, 0xBC, 0x11, 0xE2, 0x7F, 0x18, 0x35, 0xE6, 0xB1, 0x1E, 0x85, 0x17, 0x8D, 0xB5, 0x01,
+ 0xA4, 0x5D, 0xD8, 0x59, 0x8B, 0xB8, 0x74, 0xAB, 0x89, 0xD3, 0x50, 0xB6, 0x8B, 0x4E, 0xBA, 0xDE,
+ 0x01, 0xF5, 0x07, 0xC1, 0x0F, 0xDA, 0x23, 0x41, 0xF8, 0xC5, 0xFB, 0x27, 0x7C, 0x21, 0xFD, 0xAC,
+ 0xA4, 0xF0, 0xFE, 0xB7, 0xE1, 0x9F, 0x0C, 0x7C, 0x53, 0xFD, 0x9D, 0xBC, 0x3F, 0xFB, 0x44, 0xBF,
+ 0x85, 0x2D, 0x6D, 0x67, 0xF1, 0x8F, 0x88, 0xFC, 0x3F, 0x61, 0xAE, 0x78, 0x66, 0xDF, 0x59, 0x3A,
+ 0x74, 0x70, 0x59, 0xC2, 0x66, 0xBE, 0xB9, 0x86, 0x1B, 0xAF, 0x28, 0x25, 0xBC, 0x25, 0xE6, 0x74,
+ 0x01, 0x23, 0xCB, 0xAA, 0xD0, 0x07, 0x80, 0xFC, 0x49, 0xFD, 0xAF, 0x7E, 0x2A, 0x5A, 0xFE, 0xD0,
+ 0xFF, 0x00, 0x04, 0xBE, 0x0E, 0xFC, 0x11, 0xF8, 0x1D, 0x67, 0xE3, 0x7F, 0x05, 0xFC, 0x44, 0xF8,
+ 0x3F, 0xAF, 0x7E, 0xD0, 0xFA, 0xA7, 0xC6, 0x1F, 0x1D, 0x78, 0xDA, 0xCB, 0xC3, 0x5F, 0x0E, 0x3C,
+ 0x51, 0xE0, 0xBD, 0x01, 0xB4, 0x38, 0x35, 0x29, 0x7C, 0x1E, 0xFA, 0x33, 0xEB, 0x1E, 0x23, 0xB8,
+ 0xD6, 0x6D, 0xAE, 0x3C, 0x69, 0xE1, 0xA2, 0x2C, 0x6E, 0xFC, 0x39, 0x6F, 0x6F, 0x79, 0x1D, 0xE1,
+ 0x10, 0xEA, 0x08, 0xD0, 0xB0, 0x60, 0x0E, 0xDF, 0xE2, 0xEF, 0xED, 0x7D, 0xA0, 0x78, 0x2B, 0xE0,
+ 0x76, 0xA7, 0xF1, 0xD7, 0xC2, 0x97, 0x7F, 0x09, 0x7C, 0x27, 0xE0, 0xDF, 0x0A, 0xF8, 0xD6, 0xD7,
+ 0xC2, 0xBE, 0x37, 0xF1, 0x37, 0xED, 0xC3, 0xE3, 0xFF, 0x00, 0x13, 0xFE, 0xC0, 0xBF, 0x0F, 0xBC,
+ 0x37, 0x05, 0xD4, 0x28, 0xB0, 0xDC, 0xAE, 0xB1, 0xAE, 0x78, 0x4E, 0xEE, 0x69, 0x64, 0x92, 0xF2,
+ 0xFF, 0x00, 0x46, 0xB6, 0x85, 0x4D, 0x9C, 0x76, 0xF3, 0x3D, 0xC4, 0xE8, 0xB7, 0x5E, 0x75, 0xBF,
+ 0xD9, 0xE5, 0x00, 0xF9, 0x47, 0xFE, 0x09, 0xB5, 0xFF, 0x00, 0x05, 0x28, 0xD5, 0xBF, 0x6E, 0x1D,
+ 0x4F, 0xC5, 0x3E, 0x1F, 0xBE, 0xF1, 0x7F, 0xFC, 0x13, 0xE3, 0xC4, 0x5A, 0xBF, 0x86, 0x3C, 0x73,
+ 0xF1, 0x32, 0xD2, 0xFB, 0x43, 0xFD, 0x99, 0x7F, 0x6D, 0x49, 0x7E, 0x2F, 0xFC, 0x54, 0xD3, 0x7C,
+ 0x3B, 0xE1, 0x5F, 0x88, 0xFA, 0x9E, 0x83, 0xE1, 0x8D, 0x66, 0x5F, 0x04, 0x9F, 0x0F, 0xC4, 0xED,
+ 0xA5, 0x5D, 0xE9, 0xF6, 0x9A, 0x24, 0xCB, 0xAC, 0xB6, 0xA3, 0x0C, 0x37, 0xAB, 0x7B, 0x69, 0x7B,
+ 0x0D, 0x9D, 0xAA, 0x6A, 0x11, 0x59, 0x5A, 0x80, 0x7E, 0x91, 0x5F, 0x7C, 0x4B, 0x9E, 0xCB, 0xE3,
+ 0xB7, 0x85, 0x7E, 0x0E, 0x2E, 0x8D, 0x0B, 0xDA, 0x78, 0x8B, 0xE1, 0x26, 0xBF, 0xF1, 0x2D, 0xF5,
+ 0xFF, 0x00, 0xB6, 0xB2, 0x4F, 0x67, 0x26, 0x89, 0xAC, 0x68, 0xD6, 0x29, 0x64, 0xB6, 0xBE, 0x5E,
+ 0xD6, 0x59, 0x17, 0x5F, 0x77, 0x2F, 0xBC, 0x15, 0x30, 0x2A, 0x85, 0x3B, 0xF2, 0xA0, 0x1E, 0xB5,
+ 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05,
+ 0x00, 0x14, 0x01, 0x62, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0xFF, 0x00,
+ 0x3F, 0x3F, 0xF8, 0x39, 0xF7, 0xFE, 0x53, 0x9F, 0xFF, 0x00, 0x04, 0x87, 0xFF, 0x00, 0xB0, 0x57,
+ 0xC3, 0xDF, 0xFD, 0x5B, 0xD7, 0x35, 0xD9, 0x96, 0x7F, 0xC8, 0xC3, 0x0F, 0xFE, 0x38, 0x7F, 0xE9,
+ 0x48, 0xE7, 0xC4, 0xFF, 0x00, 0xBA, 0xD4, 0xFF, 0x00, 0x0B, 0xFC, 0x8F, 0xB5, 0x2B, 0xF5, 0x33,
+ 0xE3, 0x82, 0x80, 0x0A, 0x00, 0x28, 0x03, 0xF6, 0x0B, 0xFE, 0x08, 0x85, 0xFF, 0x00, 0x22, 0x27,
+ 0xED, 0xD7, 0xFF, 0x00, 0x67, 0xCF, 0x07, 0xFE, 0xA8, 0x6F, 0x86, 0x55, 0xF9, 0xD7, 0x10, 0x7F,
+ 0xC8, 0xD2, 0x7E, 0x91, 0xFF, 0x00, 0xD2, 0x51, 0xF5, 0x19, 0x5F, 0xFB, 0x94, 0x7E, 0x7F, 0x99,
+ 0xFB, 0x6D, 0x5E, 0x29, 0xE8, 0x85, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x08, 0x7E, 0xE9, 0xFF, 0x00, 0x77, 0xFA, 0x50, 0x04, 0x14, 0x00, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05,
+ 0x00, 0x14, 0x00, 0x50, 0x00, 0x38, 0x00, 0x0E, 0x30, 0x00, 0x18, 0xE3, 0x18, 0x1C, 0x63, 0xF2,
+ 0x14, 0x01, 0xF2, 0x3C, 0xBF, 0xB0, 0x07, 0xEC, 0x1D, 0x71, 0x2C, 0x93, 0xCF, 0xFB, 0x12, 0xFE,
+ 0xC8, 0xB3, 0x4F, 0x34, 0x8D, 0x2C, 0xD3, 0x4B, 0xFB, 0x36, 0x78, 0x32, 0x49, 0x65, 0x76, 0x39,
+ 0x66, 0x66, 0x3A, 0x76, 0x49, 0x24, 0x92, 0x49, 0xA0, 0x0C, 0x4F, 0x1F, 0x7E, 0xC9, 0x9E, 0x02,
+ 0xF0, 0x2F, 0xC3, 0x9B, 0x46, 0xFD, 0x93, 0x7E, 0x16, 0xFC, 0x06, 0xF8, 0x23, 0xE3, 0x3F, 0x00,
+ 0xFC, 0x4B, 0xD1, 0xFE, 0x37, 0xE8, 0x1A, 0x16, 0x87, 0xE0, 0x3D, 0x3F, 0xE1, 0x8F, 0xC3, 0x8F,
+ 0x1E, 0x6A, 0x3A, 0x1A, 0xBC, 0x57, 0x7A, 0x4F, 0x88, 0x26, 0xD2, 0x6D, 0x51, 0xED, 0x52, 0xFB,
+ 0x49, 0xBB, 0xD5, 0x74, 0xF4, 0xD4, 0xC4, 0x17, 0x8F, 0xA7, 0x3D, 0xD4, 0x17, 0xDF, 0x63, 0xBF,
+ 0x5B, 0x33, 0x61, 0x76, 0x01, 0xF6, 0x46, 0x9F, 0x74, 0x2F, 0xEC, 0x2C, 0x6F, 0x84, 0x2F, 0x6E,
+ 0x2F, 0x2C, 0xE2, 0xBA, 0x16, 0xF2, 0x49, 0x0C, 0xD2, 0x40, 0x24, 0x8C, 0x30, 0x46, 0x78, 0x5E,
+ 0x48, 0x98, 0x8C, 0xE0, 0x98, 0xDD, 0xD4, 0xE3, 0xE5, 0x66, 0x18, 0x24, 0x03, 0xCA, 0xBE, 0x3C,
+ 0x7C, 0x24, 0x83, 0xE3, 0x67, 0xC2, 0xCF, 0x11, 0xF8, 0x01, 0x3C, 0x43, 0xAB, 0x78, 0x2B, 0x5F,
+ 0x9D, 0xAC, 0xFC, 0x47, 0xE0, 0x0F, 0x88, 0x1E, 0x1F, 0xF2, 0x8E, 0xBB, 0xF0, 0xDB, 0xC5, 0x1A,
+ 0x1D, 0xEC, 0x3A, 0x87, 0x85, 0xFC, 0x47, 0x67, 0x0C, 0xA9, 0x25, 0xB5, 0xC3, 0xD8, 0x6A, 0x96,
+ 0x1A, 0x75, 0xC9, 0xB4, 0xBB, 0x86, 0xE2, 0xCE, 0xE9, 0x61, 0x7B, 0x5B, 0xBB, 0x7B, 0x8B, 0x5B,
+ 0x89, 0xED, 0xE5, 0x00, 0xA5, 0xFB, 0x3C, 0x7C, 0x29, 0x9F, 0xE0, 0xF7, 0xC2, 0xAF, 0x0F, 0xF8,
+ 0x6B, 0x5B, 0x9E, 0xD7, 0x54, 0xF8, 0x83, 0xAB, 0xBC, 0xFE, 0x39, 0xF8, 0xC3, 0xE2, 0x8B, 0x5D,
+ 0x46, 0xEF, 0x57, 0x8F, 0xC6, 0xBE, 0x34, 0xD7, 0x24, 0x37, 0x9E, 0x29, 0xD5, 0xE3, 0xB8, 0xB9,
+ 0x02, 0x61, 0x6F, 0x2D, 0xFC, 0xF7, 0x22, 0xDA, 0xDC, 0x24, 0x30, 0x5A, 0x5A, 0x25, 0x9D, 0x95,
+ 0xAD, 0xBD, 0xAD, 0xAD, 0xA5, 0xBD, 0xAD, 0xB8, 0x07, 0xB6, 0x8C, 0x70, 0x38, 0x03, 0x81, 0xD3,
+ 0xA7, 0xA0, 0x03, 0xF2, 0xA0, 0x0F, 0x8E, 0x3E, 0x09, 0xFE, 0xCF, 0xFA, 0x0F, 0x88, 0x7E, 0x1C,
+ 0xFC, 0x5C, 0xD6, 0xBE, 0x39, 0xF8, 0x6F, 0xE1, 0xF7, 0xC4, 0x4D, 0x43, 0xF6, 0xB8, 0xF8, 0xA3,
+ 0x1F, 0xED, 0x03, 0xF1, 0x3B, 0xC1, 0x33, 0xE9, 0x76, 0x5E, 0x32, 0xF8, 0x5D, 0x62, 0xD1, 0xE8,
+ 0xBA, 0x26, 0x95, 0xE1, 0x1D, 0x26, 0xD2, 0x29, 0x9A, 0xE6, 0xDE, 0xF0, 0xE9, 0xDA, 0x0F, 0x82,
+ 0xBC, 0x19, 0x1C, 0xB7, 0xCA, 0xED, 0x1D, 0xDE, 0xA3, 0x67, 0x79, 0xA9, 0x5B, 0xC7, 0x69, 0x1D,
+ 0xCC, 0x36, 0xB6, 0x80, 0x1D, 0x47, 0x84, 0xBE, 0x02, 0xF8, 0xE3, 0xE1, 0x57, 0x8A, 0x2D, 0xA4,
+ 0xF8, 0x4B, 0xF1, 0xBB, 0xC4, 0x16, 0xBF, 0x0A, 0x6F, 0xB5, 0xE3, 0xA8, 0xEB, 0xFF, 0x00, 0x06,
+ 0x7E, 0x2F, 0xE9, 0x57, 0x1F, 0x19, 0x34, 0x4F, 0x0E, 0x5A, 0xCB, 0x71, 0x24, 0xD7, 0x76, 0xBE,
+ 0x06, 0xD6, 0xE4, 0xBF, 0xB4, 0xD6, 0x34, 0x61, 0x2C, 0x97, 0x0C, 0xB1, 0xDB, 0xDE, 0xDD, 0xEB,
+ 0x1A, 0x6D, 0x94, 0x31, 0x5B, 0x5B, 0x58, 0x69, 0xB6, 0x50, 0x42, 0x22, 0x20, 0x1F, 0x49, 0x3E,
+ 0xA5, 0xA6, 0xC3, 0xA8, 0xD9, 0xE8, 0xF2, 0xDF, 0xD8, 0xC7, 0xAB, 0x5F, 0x59, 0x5C, 0x6A, 0x56,
+ 0x3A, 0x53, 0xDD, 0x46, 0x9A, 0x8D, 0xE5, 0xB5, 0xA4, 0x90, 0x47, 0x75, 0x71, 0x0C, 0x04, 0xEF,
+ 0x78, 0xA2, 0x7B, 0xDB, 0x25, 0x77, 0x50, 0x55, 0x0C, 0xF0, 0x82, 0x41, 0x91, 0x41, 0x00, 0xFC,
+ 0x9F, 0xF0, 0xC7, 0xFC, 0x13, 0xFD, 0x6D, 0x7C, 0x7B, 0xE1, 0xAF, 0x0A, 0xFC, 0x54, 0xFD, 0x97,
+ 0x3F, 0x63, 0x3F, 0x8D, 0x9E, 0x05, 0x83, 0x50, 0xB4, 0xD7, 0xFC, 0x4D, 0xFB, 0x6B, 0xDC, 0x78,
+ 0xB3, 0x5A, 0xF8, 0x61, 0xFB, 0x72, 0x6B, 0x5A, 0x8E, 0x8B, 0x2A, 0xEA, 0x1E, 0x1E, 0xD5, 0x35,
+ 0x6D, 0x36, 0xD7, 0xC3, 0x37, 0x2D, 0xAB, 0x6B, 0x71, 0xEA, 0xDA, 0x4F, 0x87, 0xE7, 0x9F, 0x56,
+ 0x4F, 0x17, 0xE9, 0x6A, 0xF3, 0xA3, 0x5F, 0xC1, 0xA7, 0xDA, 0x9B, 0x4B, 0x7B, 0x26, 0x00, 0xFB,
+ 0x3B, 0xF6, 0x7F, 0xF8, 0x6B, 0xF1, 0x77, 0xE1, 0x5E, 0xB9, 0xF1, 0x2B, 0xC2, 0x9E, 0x22, 0xBD,
+ 0xF8, 0x7D, 0x73, 0xF0, 0x73, 0xFE, 0x13, 0x8F, 0x12, 0xF8, 0xDF, 0xE1, 0x8D, 0xE6, 0x89, 0x75,
+ 0xA8, 0x5D, 0xFC, 0x41, 0xD7, 0xEE, 0x7C, 0x67, 0xE2, 0xDD, 0x4F, 0xC4, 0x5A, 0xAB, 0x6B, 0x96,
+ 0xB2, 0xDB, 0x45, 0x6B, 0xA6, 0xA5, 0x8C, 0xBA, 0xE3, 0x69, 0xF0, 0xC5, 0x6F, 0x71, 0xA8, 0xFD,
+ 0xB1, 0x2D, 0xC5, 0xEB, 0xC9, 0x64, 0xD2, 0xFD, 0x86, 0x20, 0x0F, 0x16, 0xF0, 0xBF, 0xEC, 0x4F,
+ 0xA9, 0xF8, 0x07, 0xE2, 0xA7, 0x8C, 0x7C, 0x61, 0xF0, 0xE3, 0xC6, 0xD6, 0xDE, 0x0B, 0xB2, 0xD2,
+ 0xBE, 0x10, 0xFC, 0x5A, 0xD2, 0xBE, 0x02, 0xF8, 0xB2, 0x7B, 0x08, 0xFC, 0x5F, 0xE3, 0x3F, 0x03,
+ 0xF8, 0xDF, 0xF6, 0x82, 0xF8, 0xA7, 0x7D, 0xE3, 0x9F, 0x8A, 0xFA, 0xC6, 0xB1, 0xA6, 0x4F, 0x0C,
+ 0x56, 0x17, 0xDA, 0x6D, 0xBE, 0xAB, 0xA4, 0xFC, 0x39, 0x7D, 0x22, 0xD8, 0x3A, 0x32, 0xA5, 0xB6,
+ 0xB7, 0x05, 0xD3, 0x4C, 0x25, 0x82, 0x55, 0x00, 0xED, 0x6C, 0xEF, 0x7F, 0x6F, 0xDF, 0x18, 0x7C,
+ 0x3D, 0xF8, 0xA5, 0xA0, 0x78, 0x9F, 0xE1, 0xF7, 0xEC, 0xD3, 0xF0, 0x37, 0xC7, 0x03, 0xC2, 0x69,
+ 0x07, 0xC2, 0x5F, 0x1B, 0x7C, 0x33, 0xFD, 0xA6, 0xB5, 0xDF, 0x8E, 0x17, 0xBA, 0xB6, 0xA5, 0xE6,
+ 0x62, 0xE1, 0x35, 0x18, 0xB5, 0x5F, 0x86, 0x7A, 0x4D, 0x96, 0x88, 0xEF, 0x02, 0x6D, 0x86, 0xFB,
+ 0xEC, 0x7E, 0x21, 0x86, 0xDA, 0x79, 0x96, 0x79, 0x74, 0x8B, 0xF8, 0xAD, 0x8D, 0x95, 0xE0, 0x07,
+ 0x84, 0x7E, 0xC8, 0xDF, 0xB2, 0xDF, 0xED, 0xA3, 0xF0, 0x8E, 0xDF, 0xE2, 0xFE, 0xB3, 0xF1, 0x93,
+ 0xE3, 0xA7, 0x83, 0x3C, 0x55, 0xAD, 0xFE, 0xD4, 0x1F, 0x15, 0x6F, 0xFE, 0x22, 0x7C, 0x64, 0xD3,
+ 0xE3, 0x96, 0x1F, 0x13, 0xFC, 0x42, 0xF8, 0x79, 0x2C, 0x7F, 0x0F, 0xB4, 0x3F, 0x09, 0xE8, 0x57,
+ 0xDE, 0x19, 0xF8, 0x83, 0xA5, 0x78, 0x77, 0xC2, 0xBA, 0x5E, 0xA3, 0x71, 0x15, 0xBF, 0x81, 0xF4,
+ 0x8B, 0x87, 0x8A, 0x4F, 0x05, 0x69, 0x28, 0xA2, 0xED, 0x60, 0x59, 0x1E, 0x5D, 0x36, 0x4B, 0xED,
+ 0x74, 0x02, 0x2F, 0x83, 0x3F, 0xB0, 0x9D, 0x9F, 0x86, 0xBE, 0x26, 0xF8, 0x6C, 0x7C, 0x50, 0xFD,
+ 0x92, 0xFF, 0x00, 0x62, 0x31, 0x65, 0xF0, 0xBF, 0x52, 0xB0, 0xF8, 0x87, 0xE0, 0xAF, 0xDB, 0x1B,
+ 0xE0, 0x76, 0xBF, 0xAE, 0x7C, 0x2C, 0xFD, 0xA7, 0x3C, 0x73, 0xE2, 0xFD, 0x36, 0x58, 0x5E, 0x0D,
+ 0x47, 0x5B, 0xF0, 0xAC, 0x5E, 0x1F, 0x13, 0x59, 0x9B, 0x88, 0xEE, 0xF5, 0xCB, 0x6B, 0xF9, 0xDF,
+ 0xC6, 0xDA, 0xBF, 0xF6, 0x8C, 0x32, 0x5E, 0x47, 0x73, 0x6C, 0xF6, 0xDA, 0xD5, 0xDD, 0x9D, 0xB8,
+ 0x07, 0xD3, 0x1F, 0xB1, 0xDF, 0xC1, 0xCF, 0x8A, 0x9F, 0xB3, 0xDF, 0xC3, 0x1D, 0x0F, 0xE0, 0x57,
+ 0x8B, 0x2F, 0xBE, 0x1F, 0xCB, 0xF0, 0x97, 0xE0, 0x57, 0x82, 0xBC, 0x3D, 0xF0, 0x37, 0xF6, 0x75,
+ 0x87, 0xC2, 0xF7, 0x5A, 0x8E, 0xB7, 0xE3, 0x2D, 0x63, 0xC2, 0x9E, 0x14, 0xB2, 0x7B, 0x3D, 0x33,
+ 0x5D, 0xF1, 0x6D, 0xF5, 0xC4, 0x16, 0xB0, 0xC3, 0xAA, 0xCF, 0x60, 0x34, 0x6B, 0x49, 0xB4, 0xFB,
+ 0x58, 0x27, 0x82, 0x29, 0x74, 0xAB, 0x8B, 0xD4, 0xBE, 0x90, 0x6A, 0xC2, 0xC3, 0x48, 0x00, 0xF3,
+ 0xEF, 0x04, 0xFE, 0xC8, 0x5E, 0x27, 0xF8, 0x39, 0x69, 0xF1, 0x9F, 0x50, 0xF8, 0x2F, 0xE2, 0xFD,
+ 0x3B, 0xC3, 0x1E, 0x35, 0xBB, 0xFD, 0x97, 0xFE, 0x1B, 0xFE, 0xCA, 0x3F, 0xB3, 0xEF, 0x88, 0xB5,
+ 0x76, 0x4D, 0x6C, 0x68, 0x1E, 0x1D, 0xF8, 0x55, 0xA5, 0x6B, 0x52, 0x78, 0x5A, 0x7F, 0x11, 0x43,
+ 0x2D, 0x83, 0xC2, 0xD7, 0xE7, 0x58, 0xF1, 0xCF, 0x8A, 0x8C, 0xF3, 0xC5, 0x0C, 0xF0, 0xB5, 0xA9,
+ 0xD3, 0xF6, 0xDA, 0x89, 0x21, 0x91, 0x67, 0x00, 0xD2, 0xF1, 0x29, 0xFF, 0x00, 0x82, 0x84, 0xFC,
+ 0x43, 0xF8, 0x1F, 0xF1, 0x37, 0x49, 0x8F, 0xC2, 0x9F, 0xB3, 0xBF, 0xEC, 0xE1, 0xF1, 0xBC, 0x5C,
+ 0x69, 0x67, 0xE1, 0x6E, 0xAB, 0xF0, 0xA7, 0xF6, 0x97, 0xD4, 0xFE, 0x32, 0x69, 0x5A, 0xBD, 0xB2,
+ 0x5E, 0x23, 0xEB, 0x10, 0xDE, 0xEB, 0x5A, 0xFF, 0x00, 0xC2, 0xB8, 0x2D, 0xF4, 0x3B, 0x87, 0xB7,
+ 0x89, 0xA1, 0x86, 0x76, 0xF0, 0xF7, 0x88, 0xE3, 0x53, 0x33, 0x48, 0xD6, 0xD9, 0x8D, 0x55, 0x80,
+ 0x30, 0x3F, 0x61, 0xBF, 0xD9, 0xDF, 0xF6, 0xA0, 0xFD, 0x99, 0x7E, 0x1E, 0x78, 0x6B, 0xC0, 0x9F,
+ 0x14, 0xFE, 0x2C, 0x7C, 0x38, 0xF8, 0xB3, 0xA5, 0xEB, 0xFE, 0x34, 0xF8, 0x81, 0xF1, 0x5B, 0xE2,
+ 0x3C, 0x27, 0xC3, 0xB2, 0x58, 0xF8, 0xF3, 0xC2, 0xFE, 0x23, 0xF8, 0x87, 0xE3, 0x8D, 0x6F, 0xC5,
+ 0xB7, 0xED, 0x65, 0xE2, 0x9B, 0x3B, 0x6D, 0x3F, 0x4C, 0xD7, 0xAD, 0xED, 0xEF, 0x3C, 0x49, 0x2D,
+ 0x83, 0x11, 0xE1, 0x9F, 0x0E, 0x0B, 0x81, 0xBF, 0x50, 0x8E, 0x2B, 0x15, 0x0B, 0xA4, 0x80, 0x0F,
+ 0xA6, 0xB5, 0x5F, 0x04, 0x78, 0xAA, 0xE3, 0xF6, 0x8B, 0xF0, 0x17, 0xC4, 0x6B, 0x2D, 0x17, 0xC0,
+ 0x32, 0x78, 0x23, 0x46, 0xF8, 0x2B, 0xE2, 0xDF, 0x04, 0x78, 0x8B, 0xC4, 0x17, 0xDA, 0xCE, 0xB7,
+ 0x17, 0xC5, 0x0B, 0x2D, 0x53, 0x52, 0xD7, 0x3C, 0x39, 0x75, 0xA3, 0x59, 0x69, 0x7A, 0x74, 0x7F,
+ 0xF1, 0x27, 0x93, 0x4B, 0x96, 0x0D, 0x27, 0x5C, 0x7B, 0xB9, 0xAE, 0x00, 0xBA, 0x8E, 0x68, 0x34,
+ 0x94, 0xB7, 0xFD, 0xD4, 0xD7, 0x58, 0x00, 0xF6, 0xBA, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A,
+ 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x0B, 0x14, 0x00, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x07, 0xF9, 0xF9, 0xFF, 0x00, 0xC1, 0xCF, 0xBF, 0xF2, 0x9C,
+ 0xFF, 0x00, 0xF8, 0x24, 0x3F, 0xFD, 0x82, 0xBE, 0x1E, 0xFF, 0x00, 0xEA, 0xDE, 0xB9, 0xAE, 0xCC,
+ 0xB3, 0xFE, 0x46, 0x18, 0x7F, 0xF1, 0xC3, 0xFF, 0x00, 0x4A, 0x47, 0x3E, 0x27, 0xFD, 0xD6, 0xA7,
+ 0xF8, 0x5F, 0xE4, 0x7D, 0xA9, 0x5F, 0xA9, 0x9F, 0x1C, 0x14, 0x00, 0x50, 0x01, 0x40, 0x1F, 0xB0,
+ 0x5F, 0xF0, 0x44, 0x2F, 0xF9, 0x11, 0x3F, 0x6E, 0xBF, 0xFB, 0x3E, 0x78, 0x3F, 0xF5, 0x43, 0x7C,
+ 0x32, 0xAF, 0xCE, 0xB8, 0x83, 0xFE, 0x46, 0x93, 0xF4, 0x8F, 0xFE, 0x92, 0x8F, 0xA8, 0xCA, 0xFF,
+ 0x00, 0xDC, 0xA3, 0xF3, 0xFC, 0xCF, 0xDB, 0x6A, 0xF1, 0x4F, 0x44, 0x28, 0x00, 0xA0, 0x02, 0x80,
+ 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x43, 0xF7, 0x4F, 0xFB, 0xBF, 0xD2, 0x80,
+ 0x20, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0,
+ 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x01, 0x0A, 0xAB, 0x29,
+ 0x42, 0xA0, 0xA9, 0x5D, 0xA5, 0x48, 0x1B, 0x48, 0x23, 0x90, 0x45, 0x00, 0x7C, 0x52, 0x73, 0xFB,
+ 0x14, 0xEE, 0x75, 0x56, 0x7F, 0xD8, 0xB4, 0xE3, 0x31, 0xC6, 0x92, 0x4D, 0x2F, 0xEC, 0x62, 0x71,
+ 0x2B, 0xCD, 0x34, 0x92, 0x34, 0xAC, 0x4F, 0xC3, 0xB3, 0x8B, 0x68, 0xE3, 0x86, 0x28, 0xC7, 0xFC,
+ 0x22, 0xDC, 0xF5, 0xF0, 0xE9, 0xFF, 0x00, 0x8A, 0x28, 0x03, 0xED, 0x71, 0x8C, 0x71, 0x8C, 0x0E,
+ 0x38, 0x18, 0xC6, 0x3B, 0x63, 0xF0, 0xA0, 0x03, 0xA0, 0xE0, 0x70, 0x07, 0x00, 0x0E, 0xC0, 0x70,
+ 0x00, 0xFC, 0xA8, 0x03, 0xE3, 0x02, 0xE3, 0xF6, 0xCE, 0x02, 0x3B, 0x77, 0x82, 0x4F, 0xD8, 0xC5,
+ 0xD0, 0xAD, 0xC5, 0xC2, 0x7D, 0x9E, 0xFE, 0xD3, 0xF6, 0xCD, 0x89, 0xE3, 0x85, 0x92, 0x38, 0x72,
+ 0xB2, 0x45, 0x27, 0xC3, 0xB7, 0x49, 0x6E, 0x23, 0x93, 0xEE, 0x3F, 0x88, 0x99, 0x30, 0xB8, 0xD0,
+ 0x79, 0xF1, 0x68, 0x07, 0xD9, 0x91, 0xC7, 0x1C, 0x31, 0xC7, 0x0C, 0x48, 0xB1, 0xC5, 0x14, 0x6B,
+ 0x14, 0x51, 0xA2, 0x85, 0x48, 0xD5, 0x46, 0x15, 0x54, 0x76, 0x00, 0x00, 0x31, 0x40, 0x0F, 0xA0,
+ 0x0F, 0x2E, 0xF8, 0xA9, 0xF0, 0xAB, 0x47, 0xF8, 0xA5, 0xA4, 0x69, 0x51, 0x4B, 0xA9, 0xEA, 0x9E,
+ 0x13, 0xF1, 0x77, 0x84, 0xB5, 0x43, 0xE2, 0x3F, 0x87, 0x5F, 0x11, 0x7C, 0x34, 0x96, 0xDF, 0xF0,
+ 0x96, 0x7C, 0x3B, 0xD5, 0xBE, 0xCD, 0x25, 0xB8, 0xBF, 0xD3, 0xCD, 0xC4, 0x52, 0xDB, 0xB8, 0x7B,
+ 0x7B, 0x9B, 0x98, 0x26, 0x82, 0x78, 0xA5, 0x82, 0xE2, 0x09, 0xA7, 0x82, 0x68, 0xDE, 0x39, 0x19,
+ 0x48, 0x07, 0x39, 0xF0, 0xAF, 0xE2, 0xA6, 0xAD, 0xAD, 0x6A, 0xD7, 0xFF, 0x00, 0x0B, 0x7E, 0x29,
+ 0xE9, 0xBA, 0x4F, 0x84, 0xBE, 0x36, 0xF8, 0x63, 0x4D, 0xFE, 0xD1, 0xD4, 0xB4, 0x8D, 0x22, 0x4B,
+ 0x83, 0xE1, 0x2F, 0x88, 0x5A, 0x64, 0x62, 0x05, 0x6F, 0x13, 0xF8, 0x4A, 0x5B, 0x85, 0x59, 0xAE,
+ 0x34, 0xE1, 0x25, 0xED, 0xAC, 0x37, 0x10, 0xB6, 0xE9, 0x74, 0xFB, 0x99, 0x16, 0xDA, 0x66, 0x91,
+ 0x24, 0xB4, 0xBA, 0xBE, 0x00, 0xF7, 0x4A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28,
+ 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0,
+ 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0xB1, 0x40, 0x05, 0x00, 0x14,
+ 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x7F, 0x9F, 0x9F, 0xFC, 0x1C, 0xFB, 0xFF, 0x00, 0x29, 0xCF,
+ 0xFF, 0x00, 0x82, 0x43, 0xFF, 0x00, 0xD8, 0x2B, 0xE1, 0xEF, 0xFE, 0xAD, 0xEB, 0x9A, 0xEC, 0xCB,
+ 0x3F, 0xE4, 0x61, 0x87, 0xFF, 0x00, 0x1C, 0x3F, 0xF4, 0xA4, 0x73, 0xE2, 0x7F, 0xDD, 0x6A, 0x7F,
+ 0x85, 0xFE, 0x47, 0xDA, 0x95, 0xFA, 0x99, 0xF1, 0xC1, 0x40, 0x05, 0x00, 0x14, 0x01, 0xFB, 0x05,
+ 0xFF, 0x00, 0x04, 0x42, 0xFF, 0x00, 0x91, 0x13, 0xF6, 0xEB, 0xFF, 0x00, 0xB3, 0xE7, 0x83, 0xFF,
+ 0x00, 0x54, 0x37, 0xC3, 0x2A, 0xFC, 0xEB, 0x88, 0x3F, 0xE4, 0x69, 0x3F, 0x48, 0xFF, 0x00, 0xE9,
+ 0x28, 0xFA, 0x8C, 0xAF, 0xFD, 0xCA, 0x3F, 0x3F, 0xCC, 0xFD, 0xB6, 0xAF, 0x14, 0xF4, 0x42, 0x80,
+ 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x04, 0x3F, 0x74, 0xFF,
+ 0x00, 0xBB, 0xFD, 0x28, 0x02, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00,
+ 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02,
+ 0x80, 0x30, 0x3C, 0x55, 0xE2, 0xAF, 0x0C, 0xF8, 0x17, 0xC3, 0x1A, 0xF7, 0x8C, 0xFC, 0x65, 0xAF,
+ 0x69, 0x3E, 0x16, 0xF0, 0x8F, 0x85, 0x74, 0x89, 0xF5, 0xEF, 0x12, 0x78, 0x8F, 0x5D, 0xBD, 0x8F,
+ 0x4C, 0xD1, 0x74, 0x2B, 0x1B, 0x48, 0x8C, 0x97, 0x37, 0x57, 0x57, 0x0E, 0x42, 0x47, 0x14, 0x68,
+ 0x8C, 0xCC, 0xCC, 0x40, 0x00, 0x50, 0x07, 0x3B, 0xF0, 0xD3, 0xC5, 0xFA, 0xFF, 0x00, 0x8F, 0x3C,
+ 0x36, 0xDE, 0x28, 0xD6, 0xFC, 0x05, 0xAD, 0x7C, 0x3A, 0xB3, 0xD4, 0xB5, 0x09, 0x1F, 0xC2, 0xBA,
+ 0x17, 0x8A, 0xA7, 0x58, 0xBC, 0x69, 0x75, 0xA5, 0x2A, 0x20, 0xB6, 0xD4, 0x35, 0x7D, 0x35, 0x53,
+ 0x1A, 0x64, 0xF3, 0xB8, 0x9E, 0x44, 0xB2, 0x69, 0x65, 0x9A, 0x28, 0x0D, 0xA9, 0xB9, 0x16, 0xD7,
+ 0x4F, 0x3D, 0x95, 0x90, 0x07, 0xCC, 0xDE, 0x31, 0xFD, 0x92, 0xB5, 0xFD, 0x23, 0x48, 0xD1, 0x74,
+ 0xBF, 0x80, 0x7F, 0xB5, 0xBF, 0xED, 0x2B, 0xFB, 0x26, 0x7C, 0x31, 0xF0, 0x27, 0x84, 0x64, 0xD1,
+ 0xF4, 0x0F, 0x83, 0x1F, 0x02, 0xB4, 0x0F, 0x84, 0x1E, 0x20, 0xF8, 0x77, 0xA6, 0xA4, 0x77, 0xB7,
+ 0x77, 0x6A, 0x6C, 0x7F, 0xE1, 0x32, 0xF0, 0x2F, 0x88, 0xB5, 0x0B, 0x08, 0x23, 0x8E, 0xF2, 0x1B,
+ 0x3B, 0x7D, 0x3E, 0xCE, 0xEE, 0xDF, 0x4D, 0xB2, 0xB3, 0xB1, 0xB0, 0xB6, 0xB4, 0xB2, 0xB7, 0x8E,
+ 0x12, 0x1C, 0x03, 0xC9, 0x7E, 0x07, 0xFE, 0xCD, 0xDE, 0x36, 0xF8, 0xE3, 0xF0, 0xA7, 0xE1, 0x2F,
+ 0xC4, 0x4F, 0x8C, 0x5F, 0xB6, 0xCF, 0xED, 0x85, 0xF1, 0x9F, 0xE1, 0x77, 0xC5, 0x9F, 0x86, 0xBA,
+ 0x27, 0x8F, 0x3C, 0x5D, 0xFB, 0x3B, 0x7C, 0x4B, 0xB0, 0xF8, 0x23, 0xA2, 0x7C, 0x3D, 0xF1, 0x65,
+ 0xAE, 0xB9, 0xA3, 0xC5, 0x78, 0x9A, 0x1E, 0xBB, 0xA9, 0xF8, 0x4B, 0xE1, 0xBF, 0x87, 0xF5, 0xCB,
+ 0xAB, 0x18, 0xE4, 0xB9, 0x87, 0xCE, 0xB7, 0x86, 0xFE, 0xD6, 0xDE, 0xF9, 0x21, 0x6B, 0x5B, 0xC8,
+ 0x2E, 0x6C, 0xAE, 0xAE, 0xAC, 0xAE, 0x00, 0x3F, 0x40, 0x3C, 0x7F, 0xE2, 0x0F, 0x11, 0xF8, 0x53,
+ 0xC2, 0xB7, 0xDA, 0xFF, 0x00, 0x85, 0x3C, 0x13, 0x77, 0xF1, 0x07, 0x53, 0xD3, 0x6E, 0x6D, 0x26,
+ 0x9F, 0xC2, 0x7A, 0x5E, 0xAD, 0x6F, 0xA2, 0xEB, 0x17, 0xF6, 0x2D, 0x79, 0x12, 0xEA, 0x52, 0xD8,
+ 0x3C, 0xE0, 0x41, 0x2D, 0xD4, 0x36, 0xAF, 0x73, 0x34, 0x56, 0xF2, 0x3C, 0x2B, 0x3B, 0xC4, 0x90,
+ 0xF9, 0xD1, 0x79, 0x9E, 0x62, 0x80, 0x5A, 0xF0, 0x47, 0x8D, 0x7C, 0x2F, 0xF1, 0x1B, 0xC2, 0x7A,
+ 0x17, 0x8D, 0xFC, 0x17, 0xAA, 0xC7, 0xAD, 0x78, 0x63, 0xC4, 0x76, 0x0B, 0x7F, 0xA5, 0x5F, 0xA5,
+ 0xB4, 0xD6, 0x12, 0x95, 0xDC, 0x56, 0x48, 0x6E, 0x2D, 0x66, 0x44, 0x9E, 0xDA, 0xE2, 0x29, 0x23,
+ 0x92, 0x29, 0x6D, 0xE7, 0x8E, 0x39, 0xA1, 0x96, 0x39, 0x62, 0x91, 0x12, 0x48, 0xD9, 0x14, 0x03,
+ 0xAA, 0xA0, 0x02, 0x80, 0x3C, 0xE3, 0xE2, 0x3F, 0xC2, 0xEF, 0x0E, 0x7C, 0x4B, 0xB1, 0xD2, 0x57,
+ 0x54, 0x9F, 0x59, 0xD0, 0x7C, 0x43, 0xE1, 0x7D, 0x40, 0xEB, 0x9E, 0x07, 0xF1, 0xD7, 0x84, 0xF5,
+ 0x01, 0xA3, 0x78, 0xCB, 0xC0, 0xDA, 0x88, 0x89, 0xA3, 0x4B, 0xDD, 0x3E, 0xE4, 0xAB, 0xC4, 0xE3,
+ 0x6B, 0x95, 0x96, 0xD6, 0xE6, 0x2B, 0x8B, 0x3B, 0xA8, 0xCB, 0x5B, 0xDD, 0x5B, 0x5C, 0xC1, 0x24,
+ 0x90, 0xB8, 0x07, 0xCA, 0x3F, 0xF0, 0xC7, 0xDF, 0xB4, 0x27, 0xFD, 0x25, 0x57, 0xF6, 0xF6, 0xFF,
+ 0x00, 0xC3, 0x75, 0xFB, 0x2E, 0x7F, 0xF3, 0x9D, 0xA0, 0x03, 0xFE, 0x18, 0xFB, 0xF6, 0x84, 0xFF,
+ 0x00, 0xA4, 0xAA, 0xFE, 0xDE, 0xDF, 0xF8, 0x6E, 0xBF, 0x65, 0xCF, 0xFE, 0x73, 0xB4, 0x00, 0x7F,
+ 0xC3, 0x1F, 0x7E, 0xD0, 0x9F, 0xF4, 0x95, 0x5F, 0xDB, 0xDB, 0xFF, 0x00, 0x0D, 0xD7, 0xEC, 0xB9,
+ 0xFF, 0x00, 0xCE, 0x76, 0x80, 0x0F, 0xF8, 0x63, 0xEF, 0xDA, 0x13, 0xFE, 0x92, 0xAB, 0xFB, 0x7B,
+ 0x7F, 0xE1, 0xBA, 0xFD, 0x97, 0x3F, 0xF9, 0xCE, 0xD0, 0x01, 0xFF, 0x00, 0x0C, 0x7D, 0xFB, 0x42,
+ 0x7F, 0xD2, 0x55, 0x7F, 0x6F, 0x6F, 0xFC, 0x37, 0x5F, 0xB2, 0xE7, 0xFF, 0x00, 0x39, 0xDA, 0x00,
+ 0x3F, 0xE1, 0x8F, 0xBF, 0x68, 0x4F, 0xFA, 0x4A, 0xAF, 0xED, 0xED, 0xFF, 0x00, 0x86, 0xEB, 0xF6,
+ 0x5C, 0xFF, 0x00, 0xE7, 0x3B, 0x40, 0x07, 0xFC, 0x31, 0xF7, 0xED, 0x09, 0xFF, 0x00, 0x49, 0x55,
+ 0xFD, 0xBD, 0xBF, 0xF0, 0xDD, 0x7E, 0xCB, 0x9F, 0xFC, 0xE7, 0x68, 0x00, 0xFF, 0x00, 0x86, 0x3E,
+ 0xFD, 0xA1, 0x3F, 0xE9, 0x2A, 0xBF, 0xB7, 0xB7, 0xFE, 0x1B, 0xAF, 0xD9, 0x73, 0xFF, 0x00, 0x9C,
+ 0xED, 0x00, 0x1F, 0xF0, 0xC7, 0xDF, 0xB4, 0x27, 0xFD, 0x25, 0x57, 0xF6, 0xF6, 0xFF, 0x00, 0xC3,
+ 0x75, 0xFB, 0x2E, 0x7F, 0xF3, 0x9D, 0xA0, 0x03, 0xFE, 0x18, 0xFB, 0xF6, 0x84, 0xFF, 0x00, 0xA4,
+ 0xAA, 0xFE, 0xDE, 0xDF, 0xF8, 0x6E, 0xBF, 0x65, 0xCF, 0xFE, 0x73, 0xB4, 0x00, 0x7F, 0xC3, 0x1F,
+ 0x7E, 0xD0, 0x9F, 0xF4, 0x95, 0x5F, 0xDB, 0xDB, 0xFF, 0x00, 0x0D, 0xD7, 0xEC, 0xB9, 0xFF, 0x00,
+ 0xCE, 0x76, 0x80, 0x0F, 0xF8, 0x63, 0xEF, 0xDA, 0x13, 0xFE, 0x92, 0xAB, 0xFB, 0x7B, 0x7F, 0xE1,
+ 0xBA, 0xFD, 0x97, 0x3F, 0xF9, 0xCE, 0xD0, 0x07, 0xBA, 0x7C, 0x11, 0xF8, 0x33, 0xF1, 0x17, 0xE1,
+ 0x44, 0xFE, 0x23, 0x9B, 0xC7, 0x7F, 0xB5, 0x9F, 0xED, 0x03, 0xFB, 0x4C, 0x45, 0xAD, 0xC1, 0x69,
+ 0x16, 0x97, 0x67, 0xF1, 0xBB, 0xC3, 0x7F, 0x0A, 0x74, 0x0B, 0x6F, 0x06, 0xB5, 0xB3, 0x4A, 0x66,
+ 0x93, 0x4D, 0x3E, 0x0E, 0xF0, 0x67, 0x87, 0xA4, 0x76, 0x9C, 0x4D, 0x10, 0x90, 0x5E, 0x3D, 0xDA,
+ 0x81, 0x6F, 0x17, 0x94, 0xB1, 0x13, 0x21, 0x94, 0x03, 0xE8, 0x1A, 0x00, 0x28, 0x00, 0xA0, 0x02,
+ 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x2C, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x1F, 0xE7, 0xE7, 0xFF, 0x00, 0x07, 0x3E, 0xFF, 0x00, 0xCA, 0x73, 0xFF, 0x00,
+ 0xE0, 0x90, 0xFF, 0x00, 0xF6, 0x0A, 0xF8, 0x7B, 0xFF, 0x00, 0xAB, 0x7A, 0xE6, 0xBB, 0x32, 0xCF,
+ 0xF9, 0x18, 0x61, 0xFF, 0x00, 0xC7, 0x0F, 0xFD, 0x29, 0x1C, 0xF8, 0x9F, 0xF7, 0x5A, 0x9F, 0xE1,
+ 0x7F, 0x91, 0xF6, 0xA5, 0x7E, 0xA6, 0x7C, 0x70, 0x50, 0x01, 0x40, 0x05, 0x00, 0x7E, 0xC1, 0x7F,
+ 0xC1, 0x10, 0xBF, 0xE4, 0x44, 0xFD, 0xBA, 0xFF, 0x00, 0xEC, 0xF9, 0xE0, 0xFF, 0x00, 0xD5, 0x0D,
+ 0xF0, 0xCA, 0xBF, 0x3A, 0xE2, 0x0F, 0xF9, 0x1A, 0x4F, 0xD2, 0x3F, 0xFA, 0x4A, 0x3E, 0xA3, 0x2B,
+ 0xFF, 0x00, 0x72, 0x8F, 0xCF, 0xF3, 0x3F, 0x6D, 0xAB, 0xC5, 0x3D, 0x10, 0xA0, 0x02, 0x80, 0x0A,
+ 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x01, 0x0F, 0xDD, 0x3F, 0xEE, 0xFF, 0x00,
+ 0x4A, 0x00, 0x82, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0,
+ 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xE0, 0x0E, 0x9C,
+ 0x01, 0xD3, 0x81, 0xC0, 0x1D, 0x3D, 0x3B, 0x0A, 0x00, 0xF9, 0x57, 0xC2, 0x5E, 0x1A, 0xF1, 0x17,
+ 0xC7, 0xAF, 0x10, 0x78, 0x77, 0xE2, 0xCF, 0xC5, 0x0D, 0x13, 0x55, 0xF0, 0xC7, 0xC3, 0x7F, 0x0D,
+ 0xEA, 0x36, 0xBE, 0x28, 0xF8, 0x21, 0xF0, 0x5F, 0xC4, 0x16, 0x32, 0x69, 0x9A, 0xC4, 0xB7, 0x90,
+ 0x2C, 0x86, 0xC7, 0xC6, 0xDE, 0x34, 0xD3, 0xE7, 0xB7, 0x86, 0xE6, 0xDB, 0x53, 0x09, 0x72, 0x0D,
+ 0x96, 0x89, 0x3E, 0xE5, 0xD3, 0x4C, 0x71, 0x5E, 0x5C, 0xAF, 0xF6, 0x9F, 0x93, 0x0E, 0x82, 0x01,
+ 0xF5, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x07, 0xE0, 0x28,
+ 0x03, 0x2F, 0x5C, 0x46, 0x7D, 0x13, 0x57, 0x8E, 0x34, 0x2C, 0xCD, 0xA5, 0x5C, 0x22, 0x22, 0x29,
+ 0x66, 0x62, 0x61, 0x60, 0x15, 0x40, 0xFC, 0x06, 0x05, 0x00, 0x78, 0x67, 0xEC, 0x87, 0xA7, 0xDF,
+ 0x69, 0x3F, 0xB2, 0x6F, 0xEC, 0xBD, 0xA5, 0x6A, 0x96, 0x37, 0x9A, 0x5E, 0xA7, 0xA6, 0x7E, 0xCE,
+ 0xDE, 0x08, 0xD3, 0xF5, 0x1D, 0x33, 0x51, 0xB5, 0x92, 0xC7, 0x50, 0xD3, 0xAE, 0x20, 0xF0, 0xCD,
+ 0x92, 0x4D, 0x6F, 0x3C, 0x0E, 0x15, 0xE3, 0x91, 0x1D, 0x19, 0x59, 0x18, 0x02, 0xA4, 0x10, 0x40,
+ 0x23, 0x00, 0x03, 0xE8, 0x7A, 0x00, 0xF9, 0x87, 0xC6, 0xDE, 0x09, 0xF1, 0x2F, 0xC2, 0x6F, 0x12,
+ 0xEB, 0x9F, 0x1A, 0x3E, 0x0B, 0xE8, 0x57, 0x1A, 0xED, 0xBE, 0xB9, 0x39, 0xD5, 0xFE, 0x35, 0x7C,
+ 0x14, 0xD1, 0xD6, 0xD6, 0xD0, 0x7C, 0x4B, 0x10, 0xDA, 0xB2, 0xB7, 0x88, 0x3C, 0x3C, 0x8C, 0xA8,
+ 0x89, 0xE2, 0xA5, 0x48, 0x6C, 0x61, 0x06, 0x59, 0xA2, 0xB7, 0xBF, 0xB7, 0x85, 0x2D, 0xA7, 0x64,
+ 0x92, 0x3B, 0x5B, 0xAB, 0x40, 0x0F, 0xA5, 0xED, 0x6E, 0x23, 0xBB, 0xB5, 0xB6, 0xBA, 0x85, 0x27,
+ 0x48, 0xAE, 0x6D, 0xD2, 0xE2, 0x24, 0xB9, 0xB4, 0x96, 0xC6, 0xE5, 0x15, 0xD4, 0x15, 0x59, 0x20,
+ 0x91, 0x56, 0x48, 0xD8, 0x02, 0x01, 0x47, 0x55, 0x65, 0x3C, 0x10, 0x08, 0xC0, 0x00, 0x9E, 0x80,
+ 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00,
+ 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00,
+ 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x02, 0xC5, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x14, 0x01, 0xFE, 0x7E, 0x7F, 0xF0, 0x73, 0xEF, 0xFC, 0xA7, 0x3F, 0xFE, 0x09, 0x0F, 0xFF, 0x00,
+ 0x60, 0xAF, 0x87, 0xBF, 0xFA, 0xB7, 0xAE, 0x6B, 0xB3, 0x2C, 0xFF, 0x00, 0x91, 0x86, 0x1F, 0xFC,
+ 0x70, 0xFF, 0x00, 0xD2, 0x91, 0xCF, 0x89, 0xFF, 0x00, 0x75, 0xA9, 0xFE, 0x17, 0xF9, 0x1F, 0x6A,
+ 0x57, 0xEA, 0x67, 0xC7, 0x05, 0x00, 0x14, 0x00, 0x50, 0x07, 0xEC, 0x17, 0xFC, 0x11, 0x0B, 0xFE,
+ 0x44, 0x4F, 0xDB, 0xAF, 0xFE, 0xCF, 0x9E, 0x0F, 0xFD, 0x50, 0xDF, 0x0C, 0xAB, 0xF3, 0xAE, 0x20,
+ 0xFF, 0x00, 0x91, 0xA4, 0xFD, 0x23, 0xFF, 0x00, 0xA4, 0xA3, 0xEA, 0x32, 0xBF, 0xF7, 0x28, 0xFC,
+ 0xFF, 0x00, 0x33, 0xF6, 0xDA, 0xBC, 0x53, 0xD1, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A,
+ 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x10, 0xFD, 0xD3, 0xFE, 0xEF, 0xF4, 0xA0, 0x08, 0x28, 0x00,
+ 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02,
+ 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x3E,
+ 0x5C, 0xFD, 0xA2, 0xFC, 0x4D, 0xF1, 0x38, 0xEB, 0x9F, 0x06, 0x3E, 0x0F, 0xFC, 0x2A, 0xF1, 0xB5,
+ 0x8F, 0xC2, 0xED, 0x5B, 0xE3, 0x57, 0x89, 0xF5, 0xAD, 0x03, 0xC4, 0x5F, 0x13, 0x7F, 0xE1, 0x12,
+ 0xB6, 0xF1, 0xA7, 0x8A, 0xBC, 0x15, 0xA3, 0x69, 0xBE, 0x18, 0xBE, 0xBB, 0xB9, 0xB8, 0xF0, 0xBD,
+ 0x9D, 0xDB, 0x9D, 0x32, 0x2D, 0x6F, 0xCF, 0x8E, 0xC0, 0xDA, 0xDC, 0xEA, 0x56, 0x9A, 0xA5, 0x8C,
+ 0x26, 0x37, 0x33, 0xE9, 0xB7, 0xA8, 0xDE, 0x49, 0x00, 0xA1, 0xFB, 0x29, 0xFC, 0x40, 0xF1, 0xF7,
+ 0x88, 0x1B, 0xF6, 0x82, 0xF8, 0x49, 0xF1, 0x2F, 0xC5, 0x29, 0xF1, 0x13, 0xC5, 0x7F, 0xB2, 0xDF,
+ 0xC7, 0x38, 0x7E, 0x06, 0x49, 0xF1, 0x52, 0x4F, 0x0E, 0xDA, 0x78, 0x47, 0x59, 0xF8, 0xA5, 0x63,
+ 0x75, 0xE0, 0x0F, 0x0B, 0xF8, 0xAF, 0x49, 0xD6, 0x35, 0x9D, 0x32, 0xCF, 0x16, 0x11, 0x6A, 0xCB,
+ 0x63, 0xE3, 0xBB, 0x2B, 0x4B, 0xE9, 0x2C, 0x61, 0xB2, 0xB3, 0xB9, 0xBB, 0xB2, 0xBA, 0xBB, 0xB5,
+ 0xB0, 0xD3, 0x6D, 0xEE, 0xA2, 0xD3, 0xAC, 0x80, 0x39, 0x1F, 0xDB, 0x2F, 0xC6, 0xDF, 0x15, 0xB1,
+ 0xF0, 0xD7, 0xE0, 0xAF, 0xEC, 0xF5, 0xE2, 0x38, 0xF4, 0x2F, 0x8E, 0x3E, 0x37, 0x5D, 0x7F, 0xE3,
+ 0x16, 0x91, 0x1C, 0x76, 0x66, 0xF2, 0xE6, 0x6D, 0x13, 0xE1, 0x9D, 0x8C, 0x3A, 0x97, 0x97, 0x71,
+ 0x1B, 0x4D, 0x04, 0x72, 0xE9, 0x37, 0xBE, 0x2A, 0xBF, 0xF8, 0x6D, 0xA0, 0xEA, 0x90, 0x2C, 0xD1,
+ 0x5C, 0x4F, 0xA6, 0x78, 0x93, 0x51, 0x86, 0xDA, 0x5B, 0x49, 0x64, 0x5D, 0x47, 0x4E, 0x00, 0xFA,
+ 0x97, 0xE1, 0x67, 0xC4, 0x3F, 0x0F, 0x7C, 0x5D, 0xF8, 0x61, 0xF0, 0xE3, 0xE2, 0xC7, 0x84, 0x6E,
+ 0x63, 0xBC, 0xF0, 0x9F, 0xC4, 0xFF, 0x00, 0x01, 0x68, 0xFF, 0x00, 0x11, 0x3C, 0x2F, 0x79, 0x16,
+ 0xF3, 0x15, 0xDE, 0x9D, 0xAD, 0xE9, 0xD0, 0xDE, 0x58, 0xCA, 0x85, 0xD1, 0x1F, 0x0D, 0x0D, 0xCC,
+ 0x44, 0x6E, 0x44, 0x3C, 0xF2, 0xAA, 0x78, 0x00, 0x0B, 0xF1, 0x43, 0xE2, 0x17, 0x86, 0xFE, 0x11,
+ 0x7C, 0x32, 0xF8, 0x89, 0xF1, 0x63, 0xC6, 0x17, 0x71, 0x69, 0xDE, 0x10, 0xF8, 0x5F, 0xE0, 0x4D,
+ 0x5F, 0xE2, 0x1F, 0x8A, 0xB5, 0x09, 0x7C, 0xC1, 0x0D, 0x86, 0x99, 0xA2, 0x69, 0xF2, 0xDE, 0x5F,
+ 0x4C, 0xFE, 0x5A, 0x3B, 0xED, 0x48, 0x2D, 0x65, 0x63, 0xB5, 0x1C, 0xE0, 0x70, 0xA4, 0xE0, 0x10,
+ 0x0F, 0x95, 0xFF, 0x00, 0x63, 0x1F, 0x1B, 0x7C, 0x59, 0xC7, 0xC4, 0x8F, 0x83, 0x1F, 0xB4, 0x27,
+ 0x88, 0x13, 0x59, 0xF8, 0xDD, 0xE0, 0xB8, 0xBC, 0x3F, 0xF1, 0x9F, 0x55, 0x82, 0x5B, 0x53, 0x6B,
+ 0x79, 0x65, 0xA2, 0xFC, 0x4D, 0xB2, 0x9F, 0x51, 0x36, 0xF0, 0xA2, 0xCD, 0x3C, 0x49, 0xA5, 0x58,
+ 0x78, 0xAB, 0x4E, 0xF8, 0x8F, 0xA1, 0x69, 0x70, 0x99, 0xA4, 0x9E, 0x0D, 0x33, 0xC3, 0xBA, 0x6C,
+ 0x17, 0x12, 0x5D, 0xCB, 0x13, 0x6A, 0x3A, 0x88, 0x07, 0xDC, 0x54, 0x00, 0x50, 0x07, 0xCB, 0xDF,
+ 0x11, 0x7E, 0x22, 0xF8, 0xBB, 0xC7, 0xFE, 0x2F, 0xD6, 0x3E, 0x00, 0xFC, 0x05, 0xD6, 0x1F, 0x45,
+ 0xF1, 0x36, 0x92, 0xB1, 0x5A, 0x7C, 0x6D, 0xF8, 0xDB, 0x65, 0x69, 0x6B, 0xA9, 0xD9, 0x7E, 0xCE,
+ 0x96, 0xB7, 0xB6, 0x31, 0x5C, 0xDB, 0x58, 0xE9, 0x50, 0xDD, 0x5A, 0xDC, 0xE9, 0xDA, 0x87, 0x8D,
+ 0x6E, 0x6D, 0x6F, 0xB4, 0xFB, 0x9B, 0x3D, 0x36, 0xEE, 0x29, 0x6D, 0xAC, 0x2D, 0x2E, 0x6D, 0xF5,
+ 0x7D, 0x4A, 0x29, 0x60, 0x97, 0x4B, 0xD2, 0xFC, 0x4C, 0x01, 0x36, 0xA1, 0xFB, 0x22, 0xFC, 0x1E,
+ 0xD5, 0x27, 0x86, 0xE6, 0xF7, 0x53, 0xF8, 0xF6, 0xD3, 0xC3, 0xA6, 0x58, 0xE9, 0x21, 0xAD, 0xBF,
+ 0x6B, 0x5F, 0x8B, 0x16, 0x09, 0x24, 0x5A, 0x75, 0x8C, 0x36, 0x96, 0xEF, 0x22, 0x45, 0xE2, 0x45,
+ 0x57, 0x98, 0xC5, 0x69, 0x11, 0x96, 0x66, 0x0D, 0x2C, 0xF2, 0x99, 0x67, 0x99, 0xE4, 0x96, 0x59,
+ 0x24, 0x70, 0x0A, 0x3F, 0xF0, 0xC6, 0x9F, 0x05, 0x3F, 0xE8, 0x23, 0xFB, 0x41, 0x7F, 0xE2, 0x61,
+ 0x7C, 0x5E, 0xFF, 0x00, 0xE6, 0x9A, 0x80, 0x0F, 0xF8, 0x63, 0x4F, 0x82, 0x9F, 0xF4, 0x11, 0xFD,
+ 0xA0, 0xBF, 0xF1, 0x30, 0xBE, 0x2F, 0x7F, 0xF3, 0x4D, 0x40, 0x07, 0xFC, 0x31, 0xA7, 0xC1, 0x4F,
+ 0xFA, 0x08, 0xFE, 0xD0, 0x5F, 0xF8, 0x98, 0x5F, 0x17, 0xBF, 0xF9, 0xA6, 0xA0, 0x03, 0xFE, 0x18,
+ 0xD3, 0xE0, 0xA7, 0xFD, 0x04, 0x7F, 0x68, 0x2F, 0xFC, 0x4C, 0x2F, 0x8B, 0xDF, 0xFC, 0xD3, 0x50,
+ 0x01, 0xFF, 0x00, 0x0C, 0x69, 0xF0, 0x53, 0xFE, 0x82, 0x3F, 0xB4, 0x17, 0xFE, 0x26, 0x17, 0xC5,
+ 0xEF, 0xFE, 0x69, 0xA8, 0x00, 0xFF, 0x00, 0x86, 0x34, 0xF8, 0x29, 0xFF, 0x00, 0x41, 0x1F, 0xDA,
+ 0x0B, 0xFF, 0x00, 0x13, 0x0B, 0xE2, 0xF7, 0xFF, 0x00, 0x34, 0xD4, 0x00, 0x7F, 0xC3, 0x1A, 0x7C,
+ 0x14, 0xFF, 0x00, 0xA0, 0x8F, 0xED, 0x05, 0xFF, 0x00, 0x89, 0x85, 0xF1, 0x7B, 0xFF, 0x00, 0x9A,
+ 0x6A, 0x00, 0x3F, 0xE1, 0x8D, 0x3E, 0x0A, 0x7F, 0xD0, 0x47, 0xF6, 0x82, 0xFF, 0x00, 0xC4, 0xC2,
+ 0xF8, 0xBD, 0xFF, 0x00, 0xCD, 0x35, 0x00, 0x1F, 0xF0, 0xC6, 0x9F, 0x05, 0x3F, 0xE8, 0x23, 0xFB,
+ 0x41, 0x7F, 0xE2, 0x61, 0x7C, 0x5E, 0xFF, 0x00, 0xE6, 0x9A, 0x80, 0x0F, 0xF8, 0x63, 0x4F, 0x82,
+ 0x9F, 0xF4, 0x11, 0xFD, 0xA0, 0xBF, 0xF1, 0x30, 0xBE, 0x2F, 0x7F, 0xF3, 0x4D, 0x40, 0x07, 0xFC,
+ 0x31, 0xA7, 0xC1, 0x4F, 0xFA, 0x08, 0xFE, 0xD0, 0x5F, 0xF8, 0x98, 0x5F, 0x17, 0xBF, 0xF9, 0xA6,
+ 0xA0, 0x03, 0xFE, 0x18, 0xD3, 0xE0, 0xA7, 0xFD, 0x04, 0x7F, 0x68, 0x2F, 0xFC, 0x4C, 0x2F, 0x8B,
+ 0xDF, 0xFC, 0xD3, 0x50, 0x01, 0xFF, 0x00, 0x0C, 0x69, 0xF0, 0x53, 0xFE, 0x82, 0x3F, 0xB4, 0x17,
+ 0xFE, 0x26, 0x17, 0xC5, 0xEF, 0xFE, 0x69, 0xA8, 0x03, 0xDF, 0x7C, 0x0D, 0xE0, 0x9D, 0x0B, 0xE1,
+ 0xD7, 0x85, 0xB4, 0xCF, 0x07, 0x78, 0x6E, 0x4F, 0x11, 0x4D, 0xA2, 0xE9, 0x0D, 0x70, 0xD6, 0x72,
+ 0x78, 0xB3, 0xC6, 0x7A, 0xCF, 0xC4, 0x1D, 0x7C, 0x9B, 0xAB, 0xA9, 0x2E, 0x25, 0x13, 0xEA, 0xFA,
+ 0xAD, 0xD5, 0xD5, 0xFC, 0xE0, 0x49, 0x71, 0x20, 0x41, 0x2C, 0xEE, 0x23, 0x40, 0x91, 0x26, 0xD8,
+ 0xE3, 0x44, 0x50, 0x0E, 0xB2, 0x80, 0x0A, 0x00, 0x28, 0x02, 0xC5, 0x00, 0x14, 0x00, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x14, 0x01, 0xFE, 0x7E, 0x7F, 0xF0, 0x73, 0xEF, 0xFC, 0xA7, 0x3F, 0xFE, 0x09,
+ 0x0F, 0xFF, 0x00, 0x60, 0xAF, 0x87, 0xBF, 0xFA, 0xB7, 0xAE, 0x6B, 0xB3, 0x2C, 0xFF, 0x00, 0x91,
+ 0x86, 0x1F, 0xFC, 0x70, 0xFF, 0x00, 0xD2, 0x91, 0xCF, 0x89, 0xFF, 0x00, 0x75, 0xA9, 0xFE, 0x17,
+ 0xF9, 0x1F, 0x6A, 0x57, 0xEA, 0x67, 0xC7, 0x05, 0x00, 0x14, 0x00, 0x50, 0x07, 0xEC, 0x17, 0xFC,
+ 0x11, 0x0B, 0xFE, 0x44, 0x4F, 0xDB, 0xAF, 0xFE, 0xCF, 0x9E, 0x0F, 0xFD, 0x50, 0xDF, 0x0C, 0xAB,
+ 0xF3, 0xAE, 0x20, 0xFF, 0x00, 0x91, 0xA4, 0xFD, 0x23, 0xFF, 0x00, 0xA4, 0xA3, 0xEA, 0x32, 0xBF,
+ 0xF7, 0x28, 0xFC, 0xFF, 0x00, 0x33, 0xF6, 0xDA, 0xBC, 0x53, 0xD1, 0x0A, 0x00, 0x28, 0x00, 0xA0,
+ 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x10, 0xFD, 0xD3, 0xFE, 0xEF, 0xF4, 0xA0,
+ 0x0F, 0x2B, 0xF8, 0xA3, 0xE3, 0xCF, 0x14, 0xFC, 0x3F, 0xD1, 0xF4, 0xDD, 0x4B, 0xC2, 0x7F, 0x04,
+ 0xFE, 0x26, 0xFC, 0x71, 0xBC, 0xBD, 0xD5, 0x06, 0x9D, 0x73, 0xE1, 0xDF, 0x85, 0x9A, 0xAF, 0x82,
+ 0xF4, 0x8D, 0x5F, 0x46, 0x84, 0xC1, 0x23, 0x9B, 0xEB, 0x97, 0xF1, 0x26, 0xBF, 0xA3, 0x5A, 0x18,
+ 0x03, 0x45, 0x1C, 0x5B, 0x61, 0x9E, 0x59, 0x77, 0x4B, 0x19, 0x11, 0x6C, 0x0E, 0xE8, 0x01, 0xE2,
+ 0x1F, 0xF0, 0xD2, 0x7F, 0x19, 0x7F, 0xE9, 0x1F, 0x1F, 0xB5, 0xEF, 0xFE, 0x16, 0x9F, 0x00, 0x7F,
+ 0xF9, 0xE5, 0xD0, 0x01, 0xFF, 0x00, 0x0D, 0x27, 0xF1, 0x97, 0xFE, 0x91, 0xF1, 0xFB, 0x5E, 0xFF,
+ 0x00, 0xE1, 0x69, 0xF0, 0x07, 0xFF, 0x00, 0x9E, 0x5D, 0x00, 0x1F, 0xF0, 0xD2, 0x7F, 0x19, 0x7F,
+ 0xE9, 0x1F, 0x1F, 0xB5, 0xEF, 0xFE, 0x16, 0x9F, 0x00, 0x7F, 0xF9, 0xE5, 0xD0, 0x01, 0xFF, 0x00,
+ 0x0D, 0x27, 0xF1, 0x97, 0xFE, 0x91, 0xF1, 0xFB, 0x5E, 0xFF, 0x00, 0xE1, 0x69, 0xF0, 0x07, 0xFF,
+ 0x00, 0x9E, 0x5D, 0x00, 0x1F, 0xF0, 0xD2, 0x7F, 0x19, 0x7F, 0xE9, 0x1F, 0x1F, 0xB5, 0xEF, 0xFE,
+ 0x16, 0x9F, 0x00, 0x7F, 0xF9, 0xE5, 0xD0, 0x01, 0xFF, 0x00, 0x0D, 0x27, 0xF1, 0x97, 0xFE, 0x91,
+ 0xF1, 0xFB, 0x5E, 0xFF, 0x00, 0xE1, 0x69, 0xF0, 0x07, 0xFF, 0x00, 0x9E, 0x5D, 0x00, 0x1F, 0xF0,
+ 0xD2, 0x7F, 0x19, 0x7F, 0xE9, 0x1F, 0x1F, 0xB5, 0xEF, 0xFE, 0x16, 0x9F, 0x00, 0x7F, 0xF9, 0xE5,
+ 0xD0, 0x01, 0xFF, 0x00, 0x0D, 0x27, 0xF1, 0x97, 0xFE, 0x91, 0xF1, 0xFB, 0x5E, 0xFF, 0x00, 0xE1,
+ 0x69, 0xF0, 0x07, 0xFF, 0x00, 0x9E, 0x5D, 0x00, 0x1F, 0xF0, 0xD2, 0x7F, 0x19, 0x7F, 0xE9, 0x1F,
+ 0x1F, 0xB5, 0xEF, 0xFE, 0x16, 0x9F, 0x00, 0x7F, 0xF9, 0xE5, 0xD0, 0x01, 0xFF, 0x00, 0x0D, 0x27,
+ 0xF1, 0x97, 0xFE, 0x91, 0xF1, 0xFB, 0x5E, 0xFF, 0x00, 0xE1, 0x69, 0xF0, 0x07, 0xFF, 0x00, 0x9E,
+ 0x5D, 0x00, 0x55, 0xBC, 0xFD, 0xA9, 0xFE, 0x25, 0x68, 0x96, 0x93, 0x6A, 0xFE, 0x26, 0xFD, 0x83,
+ 0x7F, 0x6C, 0x6D, 0x07, 0xC3, 0x5A, 0x62, 0x0B, 0xDF, 0x10, 0xEB, 0xB6, 0x72, 0xFC, 0x22, 0xF8,
+ 0x81, 0x73, 0xA0, 0xD8, 0x44, 0x41, 0xBC, 0xBE, 0x8F, 0x40, 0xD0, 0x3C, 0x77, 0xA8, 0xEB, 0xDA,
+ 0x99, 0x86, 0x11, 0x24, 0xBF, 0x62, 0xD2, 0xB4, 0xED, 0x42, 0xFE, 0xE3, 0x67, 0x93, 0x6B, 0x69,
+ 0x73, 0x3C, 0x91, 0x41, 0x20, 0x07, 0xD5, 0xDE, 0x1E, 0xF1, 0x06, 0x81, 0xE2, 0xDD, 0x03, 0x43,
+ 0xF1, 0x57, 0x85, 0x75, 0xBD, 0x1F, 0xC4, 0xBE, 0x17, 0xF1, 0x2E, 0x8F, 0x6B, 0xE2, 0x0F, 0x0E,
+ 0x78, 0x8B, 0xC3, 0xFA, 0x94, 0x1A, 0xCE, 0x83, 0xAF, 0xD8, 0x5E, 0xC0, 0x93, 0x59, 0x5E, 0xD8,
+ 0xDE, 0x42, 0xCD, 0x0C, 0xF6, 0xF2, 0xC3, 0x2C, 0x52, 0x47, 0x2C, 0x6C, 0xC8, 0xE8, 0xCA, 0xCA,
+ 0x48, 0x20, 0x90, 0x0E, 0x3F, 0xE2, 0x47, 0xC6, 0x2F, 0x84, 0x9F, 0x06, 0xF4, 0xFD, 0x3F, 0x55,
+ 0xF8, 0xB5, 0xF1, 0x3B, 0xC0, 0x1F, 0x0C, 0xB4, 0xDD, 0x56, 0xE5, 0xAC, 0xB4, 0x9B, 0xCF, 0x1E,
+ 0x78, 0xBB, 0x4F, 0xF0, 0x95, 0xBE, 0xA9, 0x34, 0x6A, 0x0C, 0x90, 0xDA, 0xB5, 0xCC, 0xB1, 0xF9,
+ 0xAE, 0xAA, 0xCA, 0x4A, 0xA6, 0xE2, 0xA0, 0x82, 0x40, 0x14, 0x01, 0xD9, 0xE8, 0x5A, 0xEE, 0x87,
+ 0xE2, 0x7D, 0x17, 0x4A, 0xF1, 0x1F, 0x86, 0x75, 0x8D, 0x27, 0xC4, 0x3E, 0x1D, 0xD7, 0x74, 0xF8,
+ 0x75, 0x5D, 0x0F, 0x5E, 0xD0, 0xB5, 0x08, 0x75, 0x6D, 0x17, 0x58, 0xB4, 0xB8, 0x8C, 0x3D, 0xBD,
+ 0xCD, 0xA5, 0xD4, 0x4C, 0xD1, 0x4B, 0x13, 0xA3, 0x2B, 0x2B, 0xA3, 0x15, 0x60, 0x41, 0x04, 0x83,
+ 0x40, 0x1C, 0x97, 0x8C, 0xFE, 0x2A, 0x78, 0x0B, 0xE1, 0xEE, 0xBF, 0xF0, 0xCB, 0xC2, 0xDE, 0x2E,
+ 0xD7, 0x57, 0x48, 0xD6, 0xFE, 0x30, 0x78, 0xC6, 0x5F, 0x00, 0xFC, 0x3D, 0xB3, 0xFE, 0xCE, 0xBB,
+ 0xBD, 0x4D, 0x63, 0x54, 0x87, 0x48, 0xBC, 0xD4, 0x9E, 0x19, 0xA6, 0x86, 0x27, 0x8A, 0xCE, 0x2F,
+ 0xB2, 0xE9, 0x37, 0x4A, 0xB7, 0x17, 0x4D, 0x04, 0x0D, 0x3B, 0xD9, 0xDA, 0x2C, 0x86, 0xE6, 0xF6,
+ 0xD6, 0x0B, 0x80, 0x0F, 0x42, 0xA0, 0x0A, 0x97, 0xD7, 0xD6, 0x3A, 0x55, 0x85, 0xE6, 0xA7, 0xA9,
+ 0x5D, 0xDA, 0xE9, 0xFA, 0x6E, 0x9B, 0x69, 0x25, 0xF5, 0xFD, 0xFD, 0xED, 0xC4, 0x76, 0x76, 0x56,
+ 0x30, 0x43, 0x19, 0x79, 0x66, 0x9A, 0x57, 0x21, 0x12, 0x34, 0x44, 0x66, 0x66, 0x62, 0x00, 0x00,
+ 0x92, 0x40, 0x14, 0x01, 0xC9, 0xFC, 0x33, 0xF8, 0x8D, 0xE0, 0xFF, 0x00, 0x8B, 0xFF, 0x00, 0x0F,
+ 0x3C, 0x11, 0xF1, 0x4F, 0xE1, 0xF6, 0xA5, 0x71, 0xAC, 0x78, 0x1F, 0xE2, 0x1F, 0x85, 0xAC, 0x7C,
+ 0x63, 0xE1, 0x4D, 0x4A, 0xF3, 0x45, 0xBE, 0xF0, 0xD6, 0xA1, 0x73, 0x61, 0xA8, 0x5B, 0xA4, 0xD6,
+ 0xC6, 0xEB, 0x4C, 0xBD, 0x86, 0x0B, 0xDB, 0x29, 0xC2, 0x48, 0xAB, 0x25, 0xAD, 0xD4, 0x10, 0xCF,
+ 0x03, 0x87, 0x8A, 0x58, 0xA3, 0x92, 0x36, 0x45, 0x00, 0xE6, 0x3E, 0x2D, 0xAF, 0x83, 0xBC, 0x33,
+ 0x63, 0xA3, 0x7C, 0x64, 0xF1, 0x37, 0x83, 0xFC, 0x49, 0xE2, 0xBB, 0xBF, 0x83, 0xB3, 0x5C, 0x6B,
+ 0x7A, 0x63, 0xF8, 0x45, 0x26, 0xBF, 0xD6, 0xFC, 0x37, 0x67, 0xA8, 0xC2, 0x2C, 0xB5, 0xDD, 0x52,
+ 0x3D, 0x31, 0x2E, 0x22, 0x17, 0xD1, 0xDB, 0x69, 0xD7, 0x17, 0x77, 0x12, 0xC0, 0x91, 0xDC, 0xDC,
+ 0xBC, 0x56, 0xF2, 0xAD, 0xA5, 0xB5, 0xC5, 0xD3, 0x41, 0x04, 0xC0, 0x1A, 0x1F, 0x0D, 0xBC, 0x21,
+ 0xF0, 0xC7, 0x4B, 0x97, 0xC7, 0x1F, 0x12, 0xFE, 0x19, 0x0D, 0x36, 0xF6, 0x1F, 0xDA, 0x1B, 0xC4,
+ 0xBA, 0x7F, 0xC6, 0x4F, 0x15, 0x78, 0xAB, 0x45, 0xF1, 0x14, 0xDE, 0x24, 0xD1, 0x3C, 0x7B, 0x7C,
+ 0x7C, 0x27, 0xA3, 0x68, 0x9A, 0x6E, 0xB1, 0x65, 0x29, 0x9E, 0x5B, 0x64, 0x81, 0xF4, 0x3F, 0x0B,
+ 0xF8, 0x6E, 0x24, 0x16, 0x9E, 0x5C, 0x0E, 0xB6, 0xEB, 0x38, 0x56, 0x92, 0x79, 0x65, 0x94, 0x03,
+ 0x8C, 0xBC, 0x97, 0xE1, 0x47, 0xC3, 0xFF, 0x00, 0xDA, 0x12, 0xC6, 0x76, 0x7B, 0xAB, 0xDF, 0x8D,
+ 0xDF, 0xB4, 0x87, 0x84, 0xED, 0xFC, 0x3D, 0x06, 0x95, 0x6A, 0xD0, 0x6A, 0x3A, 0xA2, 0xF8, 0x5F,
+ 0xE1, 0xC2, 0x5E, 0xDC, 0xC9, 0xA9, 0x3C, 0x1F, 0x2C, 0xD6, 0xFA, 0x35, 0x85, 0xE7, 0x8D, 0x96,
+ 0x19, 0x67, 0x25, 0xE2, 0x8E, 0xFB, 0xC4, 0x9A, 0x74, 0x58, 0x59, 0x35, 0x14, 0x12, 0x00, 0x79,
+ 0x67, 0x83, 0xBE, 0x2F, 0xFE, 0xCE, 0x1F, 0x02, 0xFC, 0x7F, 0xF1, 0xBB, 0xE0, 0xCE, 0x90, 0xFE,
+ 0x24, 0xF0, 0x9C, 0x9E, 0x1E, 0xF1, 0x5B, 0x7C, 0x63, 0xF1, 0xA4, 0x6F, 0xE1, 0x6B, 0xA9, 0x3C,
+ 0x1B, 0x65, 0xAD, 0x7C, 0x42, 0xD6, 0xAD, 0x6E, 0x35, 0x38, 0xF4, 0x98, 0x2D, 0x61, 0x32, 0xA7,
+ 0xDA, 0xF5, 0x6F, 0x14, 0xD8, 0x5E, 0xC9, 0x37, 0x90, 0xB6, 0xF7, 0x97, 0xBA, 0xCE, 0xAC, 0xD0,
+ 0x5C, 0xDD, 0xDD, 0x69, 0xDA, 0xE4, 0x7A, 0x50, 0x07, 0xB3, 0xFC, 0x6D, 0xD1, 0xBE, 0x14, 0xF8,
+ 0x8A, 0xCF, 0xE1, 0x7E, 0x8B, 0xF1, 0x66, 0x69, 0x1F, 0x4B, 0x9B, 0xE3, 0x67, 0x85, 0xF5, 0xAF,
+ 0x05, 0xE8, 0xED, 0x65, 0x2E, 0xA3, 0xA5, 0x6B, 0xBE, 0x2A, 0xD0, 0xEF, 0xBF, 0xB5, 0x7C, 0x2E,
+ 0x97, 0x90, 0xAC, 0x12, 0xC6, 0x56, 0xDF, 0x50, 0xD2, 0xAD, 0x2F, 0xA1, 0x79, 0x44, 0x6B, 0x15,
+ 0xD5, 0x8D, 0x94, 0xCB, 0x22, 0x49, 0x14, 0x46, 0x80, 0x3E, 0x7F, 0xF8, 0x53, 0xF1, 0xEB, 0xF6,
+ 0x7D, 0xFD, 0xA5, 0x3E, 0x33, 0xFC, 0x3A, 0xF1, 0xC7, 0x86, 0xF4, 0x4F, 0x88, 0x3A, 0x37, 0x8D,
+ 0x3C, 0x2B, 0xE0, 0xAF, 0x1A, 0x78, 0x7F, 0xE1, 0x8F, 0x8B, 0x3C, 0x49, 0xE1, 0x94, 0xF0, 0xF6,
+ 0x8B, 0xE2, 0xED, 0x2E, 0xEE, 0xFF, 0x00, 0x45, 0x3E, 0x2D, 0xD1, 0x63, 0x9D, 0x5A, 0x49, 0xA2,
+ 0x9D, 0x23, 0xB2, 0xF8, 0x7F, 0xA8, 0xCB, 0xA7, 0x5E, 0x0B, 0x39, 0xD1, 0xA6, 0x86, 0xDE, 0x58,
+ 0x06, 0xA3, 0xA0, 0x6B, 0x76, 0x3A, 0x00, 0x07, 0xDB, 0x5A, 0xD6, 0xB5, 0xA3, 0x78, 0x6B, 0x45,
+ 0xD5, 0xBC, 0x45, 0xE2, 0x2D, 0x5B, 0x4B, 0xF0, 0xFF, 0x00, 0x87, 0xBC, 0x3F, 0xA5, 0xDC, 0x6B,
+ 0x5A, 0xEE, 0xBB, 0xAD, 0x5F, 0xC3, 0xA4, 0xE8, 0xBA, 0x25, 0x95, 0xA4, 0x2D, 0x2D, 0xD5, 0xDD,
+ 0xDD, 0xD4, 0xAC, 0xB1, 0x43, 0x04, 0x51, 0x46, 0xEE, 0xF2, 0x3B, 0x2A, 0xA2, 0xAB, 0x31, 0x20,
+ 0x0E, 0x00, 0x38, 0xCD, 0x3B, 0xC4, 0xDE, 0x1C, 0xF8, 0xC9, 0xF0, 0xD2, 0xF7, 0x5B, 0xF8, 0x45,
+ 0xF1, 0x3F, 0x4C, 0xBA, 0xD1, 0x7C, 0x5D, 0xA3, 0xEA, 0x5A, 0x47, 0x85, 0x3E, 0x2A, 0xFC, 0x39,
+ 0xBE, 0xD2, 0x3C, 0x65, 0x69, 0xA5, 0xDD, 0x46, 0xF3, 0x59, 0xBE, 0xA1, 0xA6, 0x49, 0x2C, 0x77,
+ 0x5A, 0x75, 0xCC, 0xD6, 0xB7, 0x50, 0x4A, 0x02, 0x4D, 0x14, 0xF0, 0xF9, 0x90, 0x14, 0x92, 0x37,
+ 0x50, 0xC8, 0x40, 0x38, 0x18, 0xFC, 0x4D, 0xFB, 0x34, 0xFE, 0xC9, 0xDE, 0x15, 0xF0, 0x7F, 0xC3,
+ 0x9D, 0x6B, 0xE2, 0x37, 0xC3, 0x4F, 0x83, 0x9A, 0x34, 0xB6, 0xF7, 0x52, 0x78, 0x6A, 0xD3, 0xE2,
+ 0x77, 0xC5, 0x2B, 0x5D, 0x33, 0xC4, 0x7E, 0x30, 0x98, 0x4E, 0x25, 0xD5, 0xB5, 0x4B, 0xAD, 0x53,
+ 0x58, 0xBC, 0x3A, 0x86, 0xB3, 0xA8, 0x4D, 0x75, 0x7C, 0x6E, 0x2F, 0x75, 0x0B, 0x99, 0xAE, 0x6E,
+ 0xAE, 0x6E, 0x6E, 0xE4, 0xB8, 0xB9, 0x9A, 0x59, 0xAE, 0x1E, 0x49, 0x00, 0x33, 0xBF, 0x67, 0xDF,
+ 0xDA, 0xFB, 0xF6, 0x70, 0xFD, 0xA7, 0xBC, 0x2B, 0xF0, 0xDB, 0xC4, 0xFF, 0x00, 0x06, 0xBE, 0x2D,
+ 0x78, 0x1B, 0xC5, 0x32, 0xFC, 0x52, 0xF8, 0x70, 0xBF, 0x14, 0xFC, 0x31, 0xE1, 0x0B, 0x3F, 0x15,
+ 0x69, 0x97, 0x5E, 0x39, 0x8F, 0x49, 0x8E, 0xCF, 0x47, 0xB8, 0xD4, 0x5A, 0xEB, 0x4B, 0x86, 0xE2,
+ 0x49, 0x23, 0x92, 0xC4, 0x78, 0xC3, 0xC3, 0x11, 0xDE, 0x28, 0xDC, 0x2D, 0xA5, 0xD4, 0xEC, 0x63,
+ 0x90, 0x83, 0x3C, 0x7B, 0xC0, 0x3D, 0xEF, 0xC4, 0x3E, 0x24, 0xF0, 0xE7, 0x84, 0x34, 0x2D, 0x57,
+ 0xC4, 0xFE, 0x2C, 0xD7, 0xB4, 0x4F, 0x0B, 0xF8, 0x67, 0x40, 0xB0, 0x93, 0x53, 0xD7, 0x3C, 0x43,
+ 0xE2, 0x2D, 0x52, 0xDF, 0x44, 0xD0, 0xB4, 0x5B, 0x58, 0x57, 0x74, 0xB7, 0x17, 0x77, 0x73, 0x32,
+ 0x45, 0x0C, 0x48, 0xB8, 0x2C, 0xEE, 0xCA, 0xA0, 0x72, 0x48, 0x14, 0x01, 0xE4, 0xFF, 0x00, 0x01,
+ 0x7F, 0x69, 0x0F, 0x82, 0xBF, 0xB4, 0xC7, 0x86, 0x75, 0x5F, 0x15, 0xFC, 0x15, 0xF1, 0xFF, 0x00,
+ 0x86, 0xBC, 0x75, 0xA4, 0xE8, 0x1E, 0x24, 0xD4, 0x7C, 0x27, 0xAE, 0x8D, 0x07, 0x5B, 0xB2, 0xD5,
+ 0xEE, 0x34, 0x5B, 0xDD, 0x37, 0x51, 0xB9, 0xB2, 0x96, 0x3B, 0xA4, 0xB7, 0x96, 0x41, 0x18, 0x92,
+ 0x4D, 0x3E, 0x77, 0x88, 0xB1, 0x1B, 0xE2, 0x28, 0xE0, 0x61, 0xB8, 0x00, 0xF2, 0xEF, 0x88, 0x3F,
+ 0xB7, 0xE7, 0xEC, 0x75, 0xF0, 0xBF, 0xC6, 0xDE, 0x13, 0xF8, 0x77, 0xE2, 0xEF, 0xDA, 0x1B, 0xE1,
+ 0x26, 0x9F, 0xE2, 0xBF, 0x14, 0x7C, 0x47, 0xD4, 0x7E, 0x15, 0xDC, 0x69, 0x67, 0xE2, 0x16, 0x8B,
+ 0x1C, 0xBE, 0x0C, 0xD5, 0x74, 0xAD, 0x03, 0x58, 0xD5, 0x6F, 0x97, 0x5F, 0x47, 0xBA, 0x46, 0xB1,
+ 0x89, 0x22, 0xF0, 0xB6, 0xA1, 0x6C, 0x59, 0xD7, 0x3F, 0x6A, 0x96, 0xCE, 0xDF, 0x68, 0x69, 0x86,
+ 0x00, 0x24, 0xF8, 0xD5, 0xFB, 0x7A, 0xFE, 0xC8, 0x9F, 0x01, 0x3E, 0x11, 0xF8, 0xBF, 0xE3, 0x2F,
+ 0x8E, 0x3E, 0x3D, 0xFC, 0x2D, 0x7F, 0x0D, 0x78, 0x4B, 0xE0, 0xF6, 0xAD, 0xF1, 0xCE, 0xDB, 0x45,
+ 0xD0, 0xBE, 0x20, 0x68, 0x7A, 0x87, 0x8C, 0xFC, 0x6F, 0xE1, 0xED, 0x1E, 0xD2, 0xF6, 0x79, 0x67,
+ 0xF0, 0xDE, 0x96, 0xD7, 0x69, 0x26, 0xA2, 0xF3, 0x1D, 0x1F, 0x50, 0x82, 0xDD, 0x62, 0xCA, 0xCB,
+ 0x3C, 0x2F, 0x12, 0xB6, 0xE5, 0x6D, 0xA0, 0x1E, 0xE1, 0xF0, 0xFB, 0xE3, 0x67, 0xC1, 0xCF, 0x8B,
+ 0x17, 0xDA, 0xF6, 0x97, 0xF0, 0xB7, 0xE2, 0xAF, 0xC3, 0xAF, 0x88, 0xDA, 0x8F, 0x85, 0x6D, 0xAD,
+ 0x2F, 0x3C, 0x49, 0x61, 0xE0, 0x6F, 0x19, 0x69, 0xDE, 0x29, 0xBA, 0xD0, 0x60, 0xBE, 0xB9, 0xBC,
+ 0xB7, 0xB1, 0x9E, 0xEE, 0x3B, 0x69, 0x5C, 0xC5, 0x14, 0xD3, 0xE8, 0xBA, 0xBC, 0x51, 0x3B, 0x00,
+ 0xAE, 0xF6, 0x37, 0x6A, 0xA4, 0x98, 0x5C, 0x28, 0x07, 0x59, 0xE2, 0xCF, 0x18, 0xF8, 0x43, 0xC0,
+ 0x3A, 0x05, 0xDF, 0x8A, 0x7C, 0x73, 0xE2, 0xAF, 0x0D, 0x78, 0x2B, 0xC2, 0xFA, 0x7C, 0xD6, 0xD6,
+ 0xD7, 0xDE, 0x23, 0xF1, 0x6E, 0xB9, 0x6B, 0xE1, 0xBD, 0x02, 0xC6, 0x4B, 0xCB, 0xA8, 0xED, 0xAC,
+ 0xE3, 0x9A, 0xF2, 0xE1, 0xD2, 0x14, 0x69, 0x6E, 0x6E, 0x2D, 0xE1, 0x8C, 0x33, 0x02, 0xF2, 0x4B,
+ 0x1A, 0x2E, 0x59, 0x80, 0x20, 0x1E, 0x63, 0xFB, 0x38, 0x7E, 0xD1, 0x9F, 0x08, 0x3F, 0x6A, 0xFF,
+ 0x00, 0x83, 0x7E, 0x04, 0xF8, 0xEB, 0xF0, 0x3B, 0xC5, 0xDA, 0x5F, 0x8C, 0x7C, 0x01, 0xE3, 0xFF,
+ 0x00, 0x0C, 0xE9, 0x7E, 0x25, 0xD3, 0x6E, 0x74, 0xFB, 0xFB, 0x5B, 0xCB, 0xED, 0x1B, 0xFB, 0x53,
+ 0x4A, 0xB5, 0xD4, 0x22, 0xD3, 0x75, 0x48, 0xA0, 0x96, 0x45, 0xB5, 0xBF, 0x8A, 0xDF, 0x51, 0xB4,
+ 0xF3, 0xAD, 0xD9, 0xCB, 0x44, 0xCD, 0xB4, 0xFB, 0x80, 0x79, 0x26, 0xB5, 0xFF, 0x00, 0x05, 0x0C,
+ 0xFD, 0x89, 0xFC, 0x3F, 0xE3, 0x5F, 0x0F, 0xF8, 0x0B, 0x51, 0xFD, 0xA6, 0xBE, 0x0A, 0xC7, 0xAD,
+ 0x78, 0x82, 0xD3, 0x55, 0xB9, 0x8A, 0x68, 0xFE, 0x25, 0xE8, 0x6D, 0xA5, 0x69, 0x27, 0x46, 0x6B,
+ 0x75, 0xBA, 0x82, 0xFE, 0x7F, 0xB5, 0x0F, 0x22, 0x56, 0x37, 0xB1, 0x88, 0xD1, 0x86, 0x5B, 0xCB,
+ 0x98, 0x71, 0xB0, 0xD0, 0x06, 0xCF, 0xC4, 0xFF, 0x00, 0xDB, 0xA3, 0xF6, 0x46, 0xF8, 0x43, 0xA7,
+ 0xE8, 0xB7, 0x9E, 0x31, 0xFD, 0xA0, 0xFE, 0x10, 0x5B, 0xDC, 0x6B, 0xDE, 0x25, 0xF0, 0x57, 0x86,
+ 0x74, 0xDD, 0x0E, 0xD3, 0xE2, 0x5E, 0x81, 0x27, 0x88, 0xA4, 0x3E, 0x3E, 0xD6, 0x74, 0xBD, 0x3B,
+ 0xC3, 0x97, 0xE6, 0xC5, 0xEF, 0x12, 0x51, 0x62, 0xE7, 0xC4, 0x7A, 0x65, 0xD3, 0xCF, 0xB7, 0x6A,
+ 0xDA, 0x33, 0x5C, 0x0D, 0xC8, 0x06, 0xE0, 0x0F, 0x71, 0xF8, 0x73, 0xF1, 0x67, 0xE1, 0x6F, 0xC5,
+ 0xFD, 0x22, 0x6D, 0x7B, 0xE1, 0x4F, 0xC4, 0x4F, 0x04, 0x7C, 0x48, 0xD0, 0xED, 0xA6, 0xFB, 0x2D,
+ 0xC6, 0xAB, 0xE0, 0x6F, 0x13, 0xD9, 0x78, 0xA3, 0x4F, 0xB6, 0x90, 0x12, 0x04, 0x72, 0x4B, 0x6D,
+ 0x23, 0xAA, 0xB7, 0xEE, 0xDF, 0x82, 0x41, 0xF9, 0x4F, 0xA5, 0x00, 0x71, 0x9F, 0xB4, 0x9F, 0xED,
+ 0x1F, 0xF0, 0x8B, 0xF6, 0x4B, 0xF8, 0x2B, 0xF1, 0x07, 0xE3, 0xD7, 0xC6, 0xDF, 0x14, 0xE9, 0xFE,
+ 0x15, 0xF0, 0x1F, 0xC3, 0x9F, 0x07, 0x6B, 0x3E, 0x30, 0xBE, 0x59, 0xEF, 0xAD, 0x2D, 0xB5, 0xBF,
+ 0x11, 0xAE, 0x89, 0xA2, 0xDD, 0xEA, 0x97, 0x3A, 0x5E, 0x87, 0x6B, 0x3C, 0xD1, 0x0B, 0xDD, 0x4A,
+ 0x4B, 0x4D, 0x26, 0xF9, 0xA1, 0xB5, 0x8D, 0xB7, 0xC8, 0x62, 0x60, 0x30, 0x14, 0x95, 0x00, 0xF4,
+ 0x5F, 0x0B, 0x7C, 0x42, 0xF0, 0x17, 0x8D, 0xFC, 0x23, 0x17, 0x8F, 0xBC, 0x17, 0xE3, 0x4F, 0x0A,
+ 0x78, 0xB7, 0xC0, 0xB3, 0xA5, 0xEB, 0xDB, 0xF8, 0xCB, 0xC3, 0x3A, 0xFD, 0xA6, 0xB9, 0xE1, 0x5B,
+ 0x85, 0xD3, 0xAE, 0x65, 0xB7, 0xBF, 0x68, 0xB5, 0x08, 0x5D, 0xA0, 0x65, 0x86, 0x7B, 0x4B, 0xA8,
+ 0xDC, 0xAB, 0x10, 0xAD, 0x14, 0x8A, 0x70, 0x54, 0xE0, 0x03, 0xE5, 0x9B, 0xAF, 0xF8, 0x28, 0xC7,
+ 0xEC, 0x39, 0x65, 0xE3, 0x2D, 0x23, 0xC1, 0x12, 0xFE, 0xD4, 0x7F, 0x03, 0xBE, 0xDF, 0xAB, 0xF8,
+ 0x4B, 0x53, 0xF1, 0x8C, 0x3A, 0xAC, 0x7F, 0x14, 0x34, 0x26, 0xF0, 0xDD, 0xA5, 0xAE, 0x95, 0x77,
+ 0x63, 0x6F, 0x3C, 0x37, 0x17, 0x9F, 0x6A, 0xDB, 0x1D, 0xC3, 0xB6, 0xAF, 0x6E, 0xD1, 0xC6, 0x47,
+ 0xCE, 0x91, 0x5C, 0x30, 0x20, 0x44, 0x72, 0x01, 0xF4, 0xEF, 0xC4, 0x4F, 0x89, 0x3E, 0x0B, 0xF8,
+ 0x51, 0xE1, 0xFD, 0x3F, 0xC4, 0xFE, 0x3D, 0xD5, 0xCE, 0x85, 0xA1, 0xEA, 0x7E, 0x39, 0xF0, 0xBF,
+ 0xC3, 0x5B, 0x0B, 0xC4, 0xD3, 0x2E, 0xF5, 0x53, 0x3E, 0xB7, 0xE3, 0x3F, 0x12, 0xD8, 0x78, 0x7F,
+ 0xC3, 0x56, 0x5E, 0x55, 0xB4, 0x52, 0x48, 0xBF, 0x69, 0xD5, 0xF5, 0xDD, 0x2A, 0xDB, 0xCD, 0x65,
+ 0x11, 0x45, 0xE7, 0xF9, 0xB3, 0x3C, 0x51, 0x47, 0x24, 0x88, 0x01, 0xDC, 0xD0, 0x01, 0x40, 0x05,
+ 0x00, 0x58, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x3F, 0xCF, 0xCF, 0xFE,
+ 0x0E, 0x7D, 0xFF, 0x00, 0x94, 0xE7, 0xFF, 0x00, 0xC1, 0x21, 0xFF, 0x00, 0xEC, 0x15, 0xF0, 0xF7,
+ 0xFF, 0x00, 0x56, 0xF5, 0xCD, 0x76, 0x65, 0x9F, 0xF2, 0x30, 0xC3, 0xFF, 0x00, 0x8E, 0x1F, 0xFA,
+ 0x52, 0x39, 0xF1, 0x3F, 0xEE, 0xB5, 0x3F, 0xC2, 0xFF, 0x00, 0x23, 0xED, 0x4A, 0xFD, 0x4C, 0xF8,
+ 0xE0, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0xFD, 0x82, 0xFF, 0x00, 0x82, 0x21, 0x7F, 0xC8, 0x89, 0xFB,
+ 0x75, 0xFF, 0x00, 0xD9, 0xF3, 0xC1, 0xFF, 0x00, 0xAA, 0x1B, 0xE1, 0x95, 0x7E, 0x75, 0xC4, 0x1F,
+ 0xF2, 0x34, 0x9F, 0xA4, 0x7F, 0xF4, 0x94, 0x7D, 0x46, 0x57, 0xFE, 0xE5, 0x1F, 0x9F, 0xE6, 0x7E,
+ 0xDB, 0x57, 0x8A, 0x7A, 0x21, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14,
+ 0x00, 0x50, 0x02, 0x1F, 0xBA, 0x7F, 0xDD, 0xFE, 0x94, 0x01, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x1F,
+ 0x20, 0x6B, 0xFE, 0x13, 0xF1, 0x27, 0xEC, 0xD7, 0xE2, 0x5D, 0x67, 0xE2, 0x57, 0xC2, 0x4F, 0x0D,
+ 0x6A, 0xDE, 0x29, 0xF8, 0x27, 0xE2, 0xED, 0x7E, 0xEB, 0xC4, 0xFF, 0x00, 0x1B, 0x3E, 0x03, 0xF8,
+ 0x3B, 0x47, 0x1A, 0x8E, 0xBD, 0xE1, 0x1D, 0x57, 0x55, 0xBF, 0x6B, 0x9D, 0x67, 0xE2, 0x2F, 0x80,
+ 0xB4, 0xD8, 0x54, 0x49, 0x3D, 0xC4, 0xF7, 0x17, 0x77, 0xB7, 0xBA, 0xEE, 0x87, 0x08, 0x92, 0x4D,
+ 0x51, 0xCC, 0xFA, 0xA6, 0x99, 0x13, 0x6B, 0x4D, 0x7B, 0x63, 0xE3, 0x10, 0x0D, 0x3F, 0x0E, 0xC5,
+ 0x63, 0xF1, 0x13, 0xF6, 0x90, 0xF8, 0x7F, 0xF1, 0xDB, 0xC1, 0xD7, 0x1A, 0x37, 0x8E, 0xBE, 0x13,
+ 0xEA, 0xDF, 0xB2, 0x9D, 0xC4, 0x5F, 0x0E, 0xBE, 0x29, 0xF8, 0x6F, 0x51, 0xB4, 0xF1, 0x37, 0x83,
+ 0xF5, 0x18, 0x3C, 0x4B, 0xAE, 0xE9, 0xBA, 0x87, 0x99, 0xA1, 0x6A, 0x90, 0xBB, 0xC5, 0x25, 0xB6,
+ 0xA1, 0x67, 0xA6, 0xE8, 0xF7, 0x26, 0x5B, 0x76, 0x31, 0x5C, 0xC7, 0x69, 0x60, 0xE5, 0x9C, 0x41,
+ 0x09, 0x40, 0x0A, 0x7F, 0xB1, 0x17, 0x82, 0xFC, 0x67, 0xF0, 0xF3, 0xE0, 0x6E, 0xB3, 0xE1, 0x0F,
+ 0x1C, 0x69, 0x1A, 0xBE, 0x81, 0x75, 0xA4, 0xFE, 0xD2, 0xBF, 0x1B, 0x9B, 0xC1, 0xFA, 0x1E, 0xAF,
+ 0x2B, 0x38, 0xD1, 0xFC, 0x1B, 0x73, 0xF1, 0xA7, 0xC5, 0x53, 0xF8, 0x02, 0xD7, 0x4E, 0x8C, 0xB3,
+ 0x2C, 0x1A, 0x5C, 0x7E, 0x19, 0x9F, 0xC3, 0xA9, 0x61, 0x6D, 0x1E, 0xD8, 0xAD, 0xEC, 0x96, 0xCA,
+ 0x08, 0x92, 0x38, 0xE2, 0x48, 0xD0, 0x03, 0xC9, 0xFE, 0x29, 0xFC, 0x18, 0xF8, 0x83, 0xFB, 0x4E,
+ 0xF8, 0xF3, 0xE3, 0x86, 0xBB, 0x1C, 0x96, 0x9F, 0x0E, 0x17, 0xE1, 0x07, 0x85, 0xED, 0x7E, 0x16,
+ 0x7E, 0xCB, 0xBA, 0xAF, 0x8B, 0x7C, 0x1F, 0x7D, 0x7B, 0x63, 0xAC, 0x78, 0xB6, 0xDB, 0x56, 0xF0,
+ 0xFF, 0x00, 0x8B, 0xEF, 0xBC, 0x69, 0xAB, 0xDB, 0x9B, 0x88, 0x27, 0xBA, 0xD0, 0xA2, 0xD7, 0xFC,
+ 0x2B, 0xE0, 0x7B, 0x0B, 0x78, 0x2C, 0x1B, 0x4C, 0xBA, 0x3F, 0xD8, 0xBE, 0x23, 0x9D, 0x2F, 0xE4,
+ 0x17, 0xDA, 0x5C, 0xFA, 0x50, 0x07, 0xD9, 0xBF, 0x09, 0x7C, 0x6B, 0xAA, 0x7C, 0x46, 0xF8, 0x67,
+ 0xE0, 0x6F, 0x1B, 0xEB, 0xDE, 0x0A, 0xD7, 0xFE, 0x1B, 0xF8, 0x8B, 0xC4, 0x7E, 0x1B, 0xB5, 0xD4,
+ 0x3C, 0x4B, 0xF0, 0xF3, 0xC5, 0x11, 0x15, 0xD7, 0xBC, 0x0B, 0xAA, 0x18, 0xC2, 0xEA, 0x5A, 0x3D,
+ 0xCC, 0xBB, 0x12, 0x3B, 0x83, 0x6D, 0x72, 0x97, 0x10, 0x8B, 0x98, 0x41, 0x82, 0xE1, 0x63, 0x59,
+ 0xE0, 0x67, 0x86, 0x58, 0xDD, 0x80, 0x3C, 0x57, 0xF6, 0xB1, 0xD1, 0x3C, 0x4F, 0xF1, 0x2F, 0xC2,
+ 0x5E, 0x16, 0xFD, 0x9E, 0x3C, 0x35, 0xE1, 0xEB, 0x9D, 0x43, 0x4B, 0xF8, 0xFB, 0xE2, 0x41, 0xE0,
+ 0xEF, 0x8B, 0x1E, 0x26, 0xB8, 0xD1, 0x25, 0xD4, 0xFC, 0x2D, 0xE0, 0x5F, 0x00, 0x5A, 0xC0, 0x6E,
+ 0x7C, 0x61, 0x35, 0xF6, 0x5A, 0x3B, 0x69, 0x67, 0xD4, 0x2D, 0x62, 0x8F, 0x44, 0xB4, 0xB6, 0x91,
+ 0xE5, 0xCD, 0xC6, 0xB7, 0x15, 0xDC, 0xB6, 0x57, 0xD6, 0x3A, 0x76, 0xA1, 0x01, 0x00, 0x9F, 0xE0,
+ 0x46, 0x8D, 0xE2, 0xDF, 0x86, 0x3F, 0x11, 0xBE, 0x37, 0x7C, 0x1C, 0xD5, 0x74, 0xFB, 0xCD, 0x43,
+ 0xE1, 0xFC, 0x9E, 0x29, 0xB9, 0xF8, 0xF5, 0xF0, 0x8F, 0xC7, 0x0B, 0xA3, 0x5C, 0xC1, 0x6F, 0x25,
+ 0xB7, 0x8F, 0x75, 0xAD, 0x4B, 0x50, 0xF1, 0x37, 0x85, 0xF5, 0x2B, 0xDC, 0xB5, 0xAC, 0xB7, 0xFA,
+ 0x76, 0xBC, 0x75, 0x69, 0xE1, 0x68, 0x92, 0xD1, 0x7F, 0xB2, 0xF5, 0x7D, 0x0A, 0x03, 0x14, 0xF7,
+ 0x16, 0x57, 0xB7, 0xB7, 0x60, 0x1F, 0x53, 0x0E, 0x31, 0x8E, 0x31, 0x8C, 0x63, 0x8C, 0x63, 0xA6,
+ 0x3F, 0x21, 0x40, 0x1F, 0x28, 0x6B, 0x3A, 0x07, 0x88, 0x3F, 0x67, 0x3F, 0x10, 0x6A, 0xFE, 0x3C,
+ 0xF8, 0x7D, 0xA3, 0x6B, 0x3E, 0x28, 0xF8, 0x25, 0xE2, 0x9D, 0x6E, 0x7F, 0x10, 0x7C, 0x54, 0xF8,
+ 0x4D, 0xE1, 0xED, 0x3E, 0xEB, 0x5E, 0xF1, 0x27, 0x80, 0xB5, 0x4D, 0x4E, 0xFD, 0xE7, 0xD4, 0xBC,
+ 0x65, 0xE0, 0xAD, 0x2E, 0xDA, 0xDE, 0x5B, 0x9B, 0xBF, 0xB4, 0xDD, 0x5F, 0x4D, 0x71, 0xAA, 0xE9,
+ 0x28, 0xC3, 0xCD, 0x0B, 0x36, 0xA1, 0x63, 0x19, 0xBE, 0x37, 0x56, 0x9A, 0xE8, 0x07, 0x21, 0xA2,
+ 0x78, 0xA3, 0x4C, 0xD2, 0x7F, 0x6C, 0xCB, 0x2F, 0x88, 0x30, 0xDE, 0x69, 0xFE, 0x22, 0xF8, 0x59,
+ 0xFB, 0x5B, 0x7E, 0xCB, 0x9E, 0x0E, 0xF0, 0xB7, 0xC1, 0x9F, 0x89, 0x9E, 0x18, 0xD5, 0xAD, 0xB5,
+ 0xAF, 0x04, 0x5E, 0xEA, 0xFE, 0x02, 0xD5, 0xFC, 0x53, 0xAD, 0x5C, 0xE9, 0xB3, 0x5E, 0xAB, 0x88,
+ 0xDA, 0x5D, 0x5F, 0x46, 0xF8, 0x87, 0x69, 0x7F, 0xA5, 0x35, 0xA1, 0xBA, 0x4B, 0xAB, 0x7F, 0x0E,
+ 0xF8, 0x91, 0xE5, 0x6B, 0x61, 0x6B, 0x69, 0xFD, 0xA0, 0x01, 0xF5, 0x9F, 0x8E, 0x3C, 0x0D, 0xE1,
+ 0x2F, 0x89, 0x3E, 0x0C, 0xF1, 0x97, 0xC3, 0xDF, 0x1C, 0xE8, 0x36, 0x1E, 0x24, 0xF0, 0x67, 0xC4,
+ 0x1F, 0x09, 0xDF, 0xF8, 0x17, 0xC6, 0x7E, 0x1F, 0xD4, 0x23, 0x63, 0x63, 0xE2, 0x2D, 0x23, 0x53,
+ 0xB4, 0x96, 0xDA, 0xFF, 0x00, 0x4F, 0xB8, 0xDA, 0x55, 0x8C, 0x52, 0xC1, 0x75, 0x71, 0x19, 0x01,
+ 0x94, 0xE2, 0x46, 0xC1, 0x04, 0xE6, 0x80, 0x3F, 0x28, 0xFF, 0x00, 0x62, 0x8F, 0xD9, 0x33, 0xC4,
+ 0xBE, 0x1B, 0xF8, 0xD7, 0x63, 0xAF, 0x7C, 0x52, 0xF1, 0x0F, 0xED, 0x57, 0xE2, 0x79, 0xBF, 0x63,
+ 0xCF, 0x0C, 0xEA, 0x1F, 0x07, 0xBC, 0x21, 0xAC, 0x7C, 0x7D, 0xFD, 0xA2, 0x7E, 0x20, 0x7C, 0x5C,
+ 0xD0, 0x7E, 0x30, 0x78, 0xA7, 0x53, 0xB9, 0xBC, 0xB7, 0xFF, 0x00, 0x85, 0x91, 0x3D, 0x9E, 0xBF,
+ 0xAA, 0x5D, 0xE9, 0x97, 0x5A, 0xB1, 0xF0, 0x2A, 0xF8, 0x41, 0xA2, 0xD4, 0x74, 0x38, 0x2C, 0x6C,
+ 0xED, 0xEE, 0x3C, 0x6B, 0xE3, 0x9D, 0x36, 0x48, 0xCD, 0xCD, 0xBC, 0xB6, 0x3A, 0x10, 0x07, 0xD6,
+ 0x1F, 0x1C, 0xA1, 0x8F, 0xC7, 0x7F, 0xB5, 0x0F, 0xEC, 0x5B, 0xE0, 0x4F, 0x08, 0x5C, 0x58, 0xDD,
+ 0xEB, 0xFF, 0x00, 0x03, 0x7E, 0x2C, 0x6B, 0x3F, 0xB4, 0xF7, 0xC5, 0x7D, 0x3A, 0xDE, 0x47, 0x73,
+ 0xE1, 0x3F, 0x0A, 0xEA, 0x3F, 0x0B, 0xFC, 0x73, 0xE1, 0x0D, 0x1E, 0x6B, 0xE5, 0x85, 0x1F, 0xEC,
+ 0xF3, 0xEA, 0x5A, 0xE7, 0x8B, 0x47, 0xD8, 0x92, 0xE4, 0x40, 0x97, 0x91, 0xE8, 0x9E, 0x25, 0x78,
+ 0x64, 0x77, 0xD2, 0xE5, 0x88, 0x80, 0x70, 0xDF, 0x1B, 0xFE, 0x00, 0x7C, 0x60, 0x3F, 0x13, 0x6E,
+ 0x3E, 0x32, 0x35, 0x95, 0xB7, 0xED, 0x8D, 0xF0, 0xFB, 0xC3, 0x7A, 0xA6, 0x97, 0xE3, 0xFF, 0x00,
+ 0x0B, 0xFE, 0xCC, 0xBF, 0x10, 0xFC, 0x58, 0xFF, 0x00, 0x0E, 0xB5, 0x6F, 0x05, 0x6A, 0x7A, 0x25,
+ 0xF8, 0xBC, 0x88, 0xF8, 0x42, 0x08, 0x64, 0xB7, 0xF0, 0x56, 0xBB, 0x79, 0x6F, 0x2D, 0xA6, 0x9D,
+ 0x7B, 0xA2, 0xC7, 0xE2, 0x8D, 0x3E, 0x0B, 0xBB, 0x4D, 0x5E, 0xDC, 0x4D, 0x2F, 0x8A, 0xAD, 0xA0,
+ 0x96, 0xD2, 0x4D, 0x00, 0x03, 0xEE, 0x0F, 0x00, 0x78, 0xB6, 0x0F, 0x1D, 0x78, 0x43, 0x46, 0xF1,
+ 0x44, 0x1E, 0x1A, 0xF1, 0x77, 0x83, 0x86, 0xA3, 0x1C, 0xB0, 0xCD, 0xE1, 0x5F, 0x1D, 0xF8, 0x72,
+ 0x5F, 0x0A, 0x78, 0xAF, 0x40, 0x9E, 0xD6, 0xE1, 0xED, 0xEE, 0x2D, 0x6E, 0xEC, 0x9F, 0x2B, 0xF2,
+ 0x4B, 0x6F, 0x20, 0x49, 0x61, 0x79, 0x6D, 0xE7, 0x8F, 0xCB, 0x9E, 0xDE, 0x69, 0xA0, 0x96, 0x29,
+ 0x64, 0x00, 0xF9, 0x17, 0xF6, 0xBB, 0xD5, 0x3C, 0x76, 0x9E, 0x24, 0xF8, 0x77, 0xA1, 0xC1, 0xE3,
+ 0xFF, 0x00, 0x8D, 0xFF, 0x00, 0x04, 0xFE, 0x14, 0xCD, 0xA1, 0xEA, 0xDA, 0xBF, 0x88, 0xBE, 0x2D,
+ 0x7E, 0xCE, 0xBF, 0x02, 0xB4, 0xBF, 0x8F, 0x3F, 0x12, 0x1F, 0x5D, 0x82, 0x7B, 0x28, 0xB4, 0x7D,
+ 0x02, 0xE6, 0xCF, 0x50, 0xF0, 0xB7, 0x89, 0xAD, 0x6C, 0x34, 0x99, 0x6D, 0xAE, 0xB5, 0x79, 0xE5,
+ 0x94, 0xE9, 0x02, 0x59, 0x6E, 0x2D, 0xB4, 0xD4, 0x8E, 0xFA, 0xD9, 0x23, 0x9E, 0x0D, 0x40, 0x03,
+ 0xE2, 0xCF, 0x87, 0xDF, 0x0D, 0x7E, 0x30, 0x7E, 0xCB, 0x7E, 0x3D, 0xFD, 0x9D, 0x3F, 0x68, 0x2F,
+ 0x13, 0xDF, 0xF8, 0xC3, 0xF6, 0xA6, 0xF8, 0x4B, 0xE0, 0xBF, 0x86, 0xDF, 0x1F, 0x3E, 0x10, 0xFC,
+ 0x2B, 0xD2, 0xBE, 0x13, 0x7E, 0xCF, 0x3A, 0xBF, 0x81, 0x7F, 0x68, 0x0B, 0x5D, 0x3F, 0xE2, 0xE6,
+ 0xBB, 0xE0, 0x3F, 0x18, 0xF8, 0x2B, 0x49, 0xF1, 0x0F, 0x85, 0xAE, 0xA5, 0x8E, 0xCA, 0xDF, 0xEC,
+ 0xD7, 0x5F, 0x0C, 0xBC, 0x57, 0xA1, 0x9B, 0xE9, 0x0E, 0x8B, 0x6F, 0x0B, 0x6A, 0x5E, 0x10, 0x8E,
+ 0x6B, 0x3B, 0x68, 0xCE, 0xA1, 0x7B, 0x68, 0x01, 0xF6, 0x67, 0xED, 0x71, 0xE0, 0x5F, 0x8B, 0xDE,
+ 0x1B, 0xB9, 0xF1, 0xA7, 0xED, 0x09, 0xFB, 0x38, 0x5A, 0xE8, 0xF6, 0x3F, 0x17, 0x63, 0xFD, 0x96,
+ 0x7C, 0x63, 0xF0, 0x72, 0xCE, 0xE6, 0xD7, 0x49, 0xB9, 0xD5, 0xB5, 0x9F, 0x13, 0xF8, 0x92, 0xF6,
+ 0xEE, 0xC2, 0x5F, 0x85, 0x57, 0x5A, 0xB6, 0x9B, 0x05, 0x95, 0xC2, 0x6A, 0x7A, 0x66, 0x85, 0xAA,
+ 0xDD, 0x78, 0x96, 0xEB, 0x33, 0xA4, 0xCF, 0x63, 0x0E, 0xAF, 0xAD, 0x9B, 0x58, 0x24, 0xFE, 0xD2,
+ 0xBC, 0x8E, 0x50, 0x0E, 0x47, 0x53, 0xF0, 0xC7, 0xEC, 0xF1, 0xF0, 0x0F, 0xC4, 0x3F, 0x02, 0xFE,
+ 0x04, 0x4D, 0xE0, 0xFF, 0x00, 0xDA, 0xCB, 0xC1, 0xBF, 0x0F, 0x7F, 0x66, 0x4F, 0x83, 0x5E, 0x05,
+ 0xD1, 0xBE, 0x00, 0xEA, 0x5F, 0x08, 0xFC, 0x59, 0xF1, 0xC3, 0x5F, 0xF8, 0x6D, 0xAB, 0xD8, 0xE8,
+ 0xF7, 0x17, 0x36, 0x16, 0xBE, 0x1D, 0xD7, 0xEC, 0x7C, 0x2D, 0x34, 0xB6, 0x1A, 0xAC, 0x9A, 0x7D,
+ 0xBF, 0x86, 0x34, 0x33, 0x70, 0x35, 0xE5, 0xBA, 0xFB, 0x54, 0x1A, 0x9A, 0x24, 0x8B, 0x24, 0x6D,
+ 0x38, 0x70, 0x0F, 0x90, 0x7F, 0x6C, 0xCF, 0xF8, 0x5B, 0x7E, 0x2C, 0xFD, 0xB7, 0xBE, 0x08, 0x5A,
+ 0x78, 0x53, 0xE0, 0xCF, 0xED, 0x79, 0xE3, 0x1F, 0x03, 0xFC, 0x21, 0xFD, 0xA0, 0x53, 0xC5, 0xFE,
+ 0x33, 0xBF, 0xF8, 0x51, 0xF1, 0x2F, 0xC4, 0x9A, 0x1E, 0xA2, 0xBA, 0x75, 0xE7, 0xC0, 0xFF, 0x00,
+ 0x11, 0xE9, 0x73, 0x6B, 0xDE, 0x0D, 0xD3, 0x6F, 0x34, 0xDB, 0x3F, 0x08, 0x45, 0xA7, 0xDB, 0x5D,
+ 0x78, 0xAF, 0x4F, 0x8A, 0xE6, 0x41, 0xE2, 0x88, 0x75, 0x49, 0xA7, 0xB7, 0xD6, 0x2D, 0xED, 0xF4,
+ 0x9B, 0x99, 0x26, 0x81, 0x2F, 0x00, 0x3E, 0x93, 0xF8, 0xBB, 0xE2, 0xDF, 0x15, 0x6B, 0x3A, 0xFF,
+ 0x00, 0x82, 0x74, 0x78, 0xFE, 0x28, 0x7E, 0xD7, 0x7F, 0x00, 0xBE, 0x07, 0xE9, 0xFF, 0x00, 0x06,
+ 0x74, 0x0B, 0xEF, 0x02, 0x7C, 0x58, 0xF8, 0x5B, 0xFB, 0x33, 0xC5, 0xF1, 0x87, 0xE2, 0xFF, 0x00,
+ 0xC4, 0xEF, 0x11, 0x1D, 0x43, 0x56, 0xB4, 0xF1, 0x16, 0x87, 0xE3, 0x4B, 0x1F, 0x11, 0x78, 0x0F,
+ 0xC4, 0x97, 0x5A, 0x3B, 0x69, 0xD6, 0x7A, 0x67, 0x86, 0x6E, 0xA3, 0x6B, 0x8B, 0x0D, 0x3E, 0x5B,
+ 0xE9, 0x75, 0xAB, 0xF6, 0x59, 0x66, 0x16, 0x52, 0x24, 0x40, 0x1C, 0x17, 0xEC, 0xF5, 0xE1, 0xEF,
+ 0x8B, 0xDF, 0xB1, 0xDF, 0xC4, 0xBF, 0x86, 0x3A, 0x77, 0xC4, 0x6F, 0x05, 0xF8, 0x83, 0xE3, 0xD6,
+ 0x97, 0xF1, 0x6B, 0xF6, 0x5F, 0xF8, 0x55, 0xFB, 0x31, 0x78, 0x0F, 0xC7, 0x3F, 0xB3, 0x4F, 0xC1,
+ 0x7D, 0x6B, 0xC2, 0x9E, 0x13, 0xF0, 0x84, 0x7F, 0x0F, 0x7E, 0x23, 0x78, 0x9E, 0x1B, 0x19, 0x7C,
+ 0x5F, 0xA1, 0x6B, 0x7A, 0xBD, 0xE5, 0xD7, 0x87, 0x61, 0x8F, 0xC2, 0x9F, 0x16, 0x7C, 0x3D, 0xA8,
+ 0x3C, 0x93, 0xEA, 0x77, 0x9E, 0x62, 0xF8, 0x53, 0xC6, 0x9C, 0x43, 0x71, 0x1E, 0x97, 0x61, 0xAB,
+ 0x00, 0x7A, 0xF7, 0xED, 0x91, 0xFB, 0x3A, 0xEB, 0x7E, 0x24, 0xD3, 0xFE, 0x36, 0xAF, 0x85, 0x74,
+ 0x8B, 0x9D, 0x4B, 0xE1, 0xAF, 0xED, 0x77, 0xF0, 0xF3, 0xC3, 0x7F, 0xB3, 0x7F, 0xED, 0x13, 0xE0,
+ 0x2F, 0x0E, 0xCF, 0xAA, 0xDC, 0x5F, 0xF8, 0xB2, 0x6F, 0x11, 0xF8, 0xBF, 0x46, 0xF0, 0xCC, 0xFE,
+ 0x26, 0x1A, 0x6D, 0xB4, 0x4D, 0x0D, 0x9B, 0xC5, 0xE0, 0xFD, 0x7F, 0xC4, 0xD6, 0xBA, 0x9E, 0xB7,
+ 0x0B, 0xC5, 0x7A, 0xB6, 0x1A, 0x66, 0x85, 0xE6, 0x34, 0xB1, 0x68, 0x56, 0x7F, 0x61, 0x00, 0xEF,
+ 0xAF, 0x7C, 0x73, 0xF0, 0xEA, 0xF7, 0xF6, 0xAA, 0xD6, 0x87, 0xC4, 0x0F, 0x08, 0xFE, 0xD5, 0xFE,
+ 0x0C, 0xF1, 0xEF, 0x80, 0x3C, 0x67, 0xA3, 0xFC, 0x36, 0xF8, 0x57, 0x7F, 0xE1, 0xED, 0x67, 0xE3,
+ 0x1E, 0xAD, 0xFB, 0x3B, 0xFC, 0x5A, 0xD2, 0xF5, 0x6F, 0x0E, 0x58, 0x5C, 0xC5, 0xE2, 0x1B, 0x9D,
+ 0x13, 0x44, 0x66, 0xF0, 0x52, 0xC7, 0x16, 0xA5, 0xE2, 0x9D, 0x73, 0x4B, 0x9A, 0x5D, 0x5A, 0x16,
+ 0x96, 0x29, 0x74, 0x4F, 0xB4, 0xCB, 0x24, 0x71, 0x43, 0x6A, 0xF0, 0x80, 0x7E, 0x78, 0xF8, 0xE6,
+ 0xE7, 0xE2, 0x8F, 0x8D, 0xBF, 0x6D, 0x68, 0xF5, 0xFB, 0x8F, 0x83, 0x9F, 0xB7, 0xA5, 0x9F, 0xC2,
+ 0x7F, 0x87, 0x5A, 0xA7, 0xC4, 0xAF, 0x0F, 0x78, 0x83, 0x5F, 0xF0, 0x07, 0xC5, 0x2F, 0x14, 0x9F,
+ 0x1D, 0x78, 0x4E, 0xDE, 0xE3, 0x58, 0xD3, 0x6D, 0xD7, 0xC4, 0x90, 0x78, 0x7E, 0xEB, 0x4D, 0xB0,
+ 0xD1, 0xCF, 0x86, 0xEE, 0x3F, 0xB3, 0x6F, 0xAE, 0xAC, 0x2D, 0x3C, 0x2F, 0xAE, 0xF8, 0x9B, 0x59,
+ 0xB9, 0xB1, 0x97, 0x46, 0x3F, 0xD8, 0xB0, 0xCC, 0x6E, 0xED, 0x74, 0xC0, 0x0F, 0x6F, 0xFD, 0xA8,
+ 0x67, 0xF1, 0x3F, 0xC7, 0xFD, 0x43, 0xE3, 0x4F, 0xC3, 0xEF, 0x88, 0x5E, 0x35, 0xF8, 0xED, 0xF0,
+ 0x17, 0xE1, 0x07, 0x8A, 0xFC, 0x1D, 0x6F, 0xE0, 0xFF, 0x00, 0x85, 0x5E, 0x17, 0xF0, 0x5F, 0xEC,
+ 0x7F, 0x79, 0xFB, 0x40, 0x7C, 0x34, 0xFD, 0xA9, 0xFC, 0x27, 0xE2, 0x9F, 0x06, 0xD8, 0xC9, 0xAC,
+ 0xDF, 0xFC, 0x4E, 0x74, 0xF0, 0xA5, 0xD6, 0xB9, 0xA6, 0xD9, 0xC9, 0x7F, 0xA9, 0xEB, 0xFE, 0x1F,
+ 0xB8, 0xF0, 0xEE, 0x9F, 0xAC, 0xF8, 0x53, 0x5A, 0x86, 0xCF, 0x4C, 0xBB, 0xBB, 0xFB, 0x7D, 0xB3,
+ 0x6B, 0x1A, 0x75, 0xCE, 0x9E, 0x01, 0xEE, 0xFF, 0x00, 0x01, 0xEF, 0x3E, 0x2A, 0x7C, 0x11, 0xF8,
+ 0xDF, 0x75, 0xF0, 0xA3, 0xE3, 0x3F, 0x87, 0xFC, 0x7B, 0xF1, 0x5F, 0xC7, 0xBF, 0x1A, 0xBC, 0x3D,
+ 0xE0, 0x7D, 0x5B, 0x52, 0xFD, 0xA0, 0xFE, 0x1E, 0x7C, 0x35, 0x93, 0x4D, 0xF8, 0x23, 0xA8, 0xDF,
+ 0xE8, 0x3F, 0x0E, 0xE7, 0xB1, 0xF1, 0x46, 0xA5, 0xAB, 0xCE, 0xF7, 0x72, 0x1D, 0x16, 0x4F, 0xED,
+ 0x3F, 0x06, 0x2F, 0xFA, 0x13, 0xBD, 0xC1, 0xFF, 0x00, 0x8A, 0x9F, 0xC3, 0x6B, 0x6F, 0x2D, 0xD0,
+ 0x3A, 0x8B, 0x69, 0x40, 0x1C, 0xE7, 0xC6, 0xEF, 0x83, 0xBE, 0x3D, 0xD2, 0x7E, 0x2F, 0x8F, 0x0A,
+ 0x78, 0x7B, 0x42, 0xBD, 0xD7, 0xBE, 0x0A, 0x7E, 0xD3, 0x9F, 0xB4, 0x6F, 0xC1, 0xDF, 0x18, 0xE9,
+ 0x5A, 0x36, 0x95, 0x06, 0xA5, 0xE2, 0x6D, 0x2B, 0xE1, 0x47, 0x8C, 0x7C, 0x15, 0xA8, 0xEB, 0xBE,
+ 0x2C, 0xF8, 0x9F, 0xE2, 0x5F, 0x10, 0xEF, 0x89, 0xA0, 0xF0, 0xEE, 0x81, 0xAA, 0x68, 0x5F, 0x0E,
+ 0x7C, 0x0F, 0x65, 0x67, 0xF6, 0x26, 0x78, 0x6E, 0x7C, 0x49, 0x7F, 0x37, 0x9F, 0x6D, 0x6B, 0x2E,
+ 0xB9, 0x77, 0xA8, 0xDC, 0x80, 0x7A, 0x6F, 0xC2, 0xFF, 0x00, 0x17, 0xFC, 0x38, 0xF1, 0x07, 0xED,
+ 0x05, 0xE2, 0x2D, 0x67, 0xC4, 0x1E, 0x16, 0xFD, 0xAB, 0xBC, 0x01, 0xF1, 0xCA, 0xFF, 0x00, 0xC6,
+ 0xBE, 0x26, 0xF0, 0x27, 0xFC, 0x21, 0xFE, 0x26, 0xF1, 0x0F, 0xC6, 0x3F, 0x10, 0x7E, 0xCF, 0x97,
+ 0x5A, 0x6F, 0x87, 0xEE, 0xAE, 0xAC, 0x74, 0x7D, 0x7A, 0xCA, 0xCF, 0x7B, 0x7C, 0x3C, 0xB3, 0x87,
+ 0x54, 0xD1, 0x74, 0x3D, 0x37, 0x54, 0x85, 0xA1, 0x8E, 0x29, 0x15, 0xF5, 0x11, 0x1C, 0x8C, 0x6F,
+ 0xA4, 0x9B, 0xCC, 0x00, 0xFC, 0xD8, 0xF8, 0x77, 0xE2, 0x5F, 0x89, 0x5A, 0xCF, 0xED, 0x49, 0xE0,
+ 0x4F, 0x8D, 0x5E, 0x3F, 0xF8, 0x35, 0xFB, 0x7B, 0xF8, 0x57, 0xE1, 0x4F, 0x83, 0x7E, 0x1E, 0x78,
+ 0x97, 0x4A, 0xD7, 0x35, 0x4D, 0x1B, 0xC7, 0xDE, 0x39, 0xF8, 0x9D, 0xE2, 0xAF, 0x85, 0x72, 0x6A,
+ 0x7A, 0xFE, 0x85, 0x7D, 0xA4, 0x69, 0xBE, 0x3D, 0xF0, 0xB5, 0xCE, 0x89, 0xA7, 0x5D, 0x4C, 0xD3,
+ 0x9D, 0x01, 0xAC, 0xEE, 0x2C, 0xBC, 0x14, 0xDE, 0x3A, 0xB3, 0x8E, 0x73, 0x2C, 0x97, 0x17, 0xD0,
+ 0xE9, 0xD6, 0x89, 0xA9, 0xDC, 0x80, 0x7E, 0xAA, 0x7E, 0xDC, 0x9A, 0x4E, 0x93, 0xA8, 0x7E, 0xCF,
+ 0xF1, 0xEA, 0x5A, 0xED, 0xE7, 0x8B, 0xEC, 0xB4, 0x6F, 0x00, 0x7C, 0x7B, 0xF8, 0x3D, 0xF1, 0x8F,
+ 0x54, 0xFF, 0x00, 0x84, 0x03, 0xE1, 0x27, 0x89, 0xBE, 0x39, 0xF8, 0xC2, 0xFA, 0xDF, 0xC0, 0xBF,
+ 0x17, 0xBC, 0x31, 0xE2, 0x19, 0x6C, 0x2C, 0x3C, 0x2F, 0xE1, 0xEB, 0x3B, 0xBD, 0x5E, 0xE9, 0xEE,
+ 0x57, 0x41, 0x36, 0xFB, 0xED, 0xED, 0xA5, 0x16, 0xEB, 0x33, 0x5C, 0xCA, 0x04, 0x36, 0xF2, 0x15,
+ 0x00, 0xFA, 0xF3, 0x18, 0xE3, 0x8E, 0x38, 0xE3, 0xA7, 0x1E, 0x94, 0x00, 0x50, 0x01, 0x40, 0x16,
+ 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x0F, 0xF3, 0xF3, 0xFF, 0x00, 0x83,
+ 0x9F, 0x7F, 0xE5, 0x39, 0xFF, 0x00, 0xF0, 0x48, 0x7F, 0xFB, 0x05, 0x7C, 0x3D, 0xFF, 0x00, 0xD5,
+ 0xBD, 0x73, 0x5D, 0x99, 0x67, 0xFC, 0x8C, 0x30, 0xFF, 0x00, 0xE3, 0x87, 0xFE, 0x94, 0x8E, 0x7C,
+ 0x4F, 0xFB, 0xAD, 0x4F, 0xF0, 0xBF, 0xC8, 0xFB, 0x52, 0xBF, 0x53, 0x3E, 0x38, 0x28, 0x00, 0xA0,
+ 0x02, 0x80, 0x3F, 0x60, 0xBF, 0xE0, 0x88, 0x5F, 0xF2, 0x22, 0x7E, 0xDD, 0x7F, 0xF6, 0x7C, 0xF0,
+ 0x7F, 0xEA, 0x86, 0xF8, 0x65, 0x5F, 0x9D, 0x71, 0x07, 0xFC, 0x8D, 0x27, 0xE9, 0x1F, 0xFD, 0x25,
+ 0x1F, 0x51, 0x95, 0xFF, 0x00, 0xB9, 0x47, 0xE7, 0xF9, 0x9F, 0xB6, 0xD5, 0xE2, 0x9E, 0x88, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x87, 0xEE, 0x9F,
+ 0xF7, 0x7F, 0xA5, 0x00, 0x7C, 0xBD, 0xFB, 0x56, 0x7C, 0x67, 0xF1, 0xD7, 0xC0, 0x4F, 0x86, 0xB6,
+ 0xFF, 0x00, 0x10, 0xBC, 0x19, 0x61, 0xFB, 0x32, 0x49, 0x65, 0x65, 0xE2, 0x0B, 0x6D, 0x3B, 0xC5,
+ 0x9A, 0xC7, 0xED, 0x5B, 0xFB, 0x50, 0xDE, 0x7E, 0xC9, 0x9F, 0x0D, 0x3C, 0x3D, 0x65, 0x74, 0xAD,
+ 0x1D, 0xBC, 0xD1, 0xF8, 0x92, 0x0F, 0x0A, 0xF8, 0x85, 0x64, 0xBA, 0x92, 0xED, 0xAC, 0xA1, 0x4B,
+ 0x69, 0x6D, 0xED, 0x95, 0xC4, 0xAC, 0x44, 0xFB, 0x91, 0x62, 0x94, 0x03, 0xF3, 0x9B, 0xF6, 0x54,
+ 0xFD, 0xBC, 0xFE, 0x37, 0xF8, 0xDF, 0xC5, 0x1F, 0x07, 0xFC, 0x35, 0xE3, 0x9F, 0x89, 0x3F, 0xB2,
+ 0xBF, 0xC5, 0xD7, 0xF8, 0xA9, 0xFB, 0x7D, 0x78, 0xCB, 0xF6, 0x60, 0xF1, 0x6E, 0x9B, 0xF0, 0x0B,
+ 0x5E, 0xB8, 0xF8, 0xA3, 0xA5, 0x7C, 0x22, 0xD3, 0xDF, 0xE1, 0x5F, 0x8E, 0xBE, 0x28, 0x78, 0x59,
+ 0x74, 0xDF, 0x88, 0x96, 0xE3, 0x4D, 0xD3, 0xFC, 0x47, 0x0A, 0xE8, 0x1A, 0x3F, 0x80, 0x2C, 0x22,
+ 0x94, 0x78, 0x7B, 0x4F, 0x75, 0x8C, 0xDF, 0x0B, 0xA9, 0x2E, 0x2F, 0x52, 0x63, 0x08, 0x07, 0xEB,
+ 0x17, 0x8E, 0xFE, 0x27, 0x5B, 0x78, 0x1B, 0xC4, 0xFF, 0x00, 0x0E, 0x3C, 0x23, 0x3E, 0x85, 0x7F,
+ 0x75, 0x7D, 0xF1, 0x5A, 0xFF, 0x00, 0x55, 0xF0, 0xC7, 0x83, 0xF5, 0xB9, 0x6E, 0x20, 0xB2, 0xF0,
+ 0x84, 0x1A, 0xF6, 0x9F, 0xA3, 0xCF, 0xA9, 0xD9, 0x68, 0xFA, 0xA5, 0xC2, 0x99, 0x2E, 0xED, 0x8D,
+ 0xE5, 0xA6, 0x9B, 0xAB, 0xBC, 0x53, 0xC7, 0x69, 0x71, 0x1A, 0x9B, 0x19, 0x11, 0xCA, 0xC9, 0x2D,
+ 0xB4, 0x77, 0x00, 0x1F, 0x03, 0x7E, 0xC9, 0xFF, 0x00, 0xB4, 0xA7, 0xED, 0x75, 0xF1, 0x03, 0xE1,
+ 0x8E, 0xB1, 0xFB, 0x44, 0x7C, 0x4F, 0xF8, 0x61, 0xA7, 0x7C, 0x47, 0xF0, 0x1F, 0xC5, 0x2F, 0x88,
+ 0x5E, 0x23, 0xB5, 0xF8, 0x35, 0xF0, 0x7B, 0xF6, 0x68, 0x87, 0x4A, 0xF1, 0xB5, 0xEF, 0x84, 0x3C,
+ 0x3D, 0xA1, 0x6A, 0x72, 0x69, 0x5A, 0x67, 0x89, 0xAC, 0xFE, 0x25, 0xEB, 0xDA, 0x97, 0x86, 0x2C,
+ 0xFC, 0x51, 0xE1, 0x9D, 0x7D, 0x34, 0x59, 0xB5, 0xBD, 0x1E, 0xF2, 0x1D, 0x02, 0xD5, 0xE6, 0xD3,
+ 0xF5, 0xCD, 0x32, 0x51, 0x3D, 0xC4, 0x2C, 0x92, 0x30, 0x07, 0x96, 0xFF, 0x00, 0xC1, 0x4A, 0xBF,
+ 0x6B, 0x7F, 0xDA, 0x2B, 0xF6, 0x67, 0xD5, 0x74, 0x7D, 0x3F, 0xE1, 0xDF, 0xC5, 0x7B, 0xBF, 0x0B,
+ 0x58, 0x78, 0x83, 0xE2, 0xBF, 0xC2, 0x08, 0x74, 0x6B, 0x2F, 0x0B, 0xFF, 0x00, 0xC1, 0x2A, 0xFE,
+ 0x35, 0xFE, 0xD4, 0x1F, 0x60, 0xD0, 0xBC, 0x43, 0xF1, 0x33, 0x43, 0xD1, 0x7C, 0x45, 0x61, 0xA8,
+ 0xFC, 0x43, 0xD0, 0xB5, 0x09, 0xFC, 0x31, 0x35, 0xDD, 0xCC, 0x0D, 0xAF, 0x2A, 0xE9, 0x51, 0xDA,
+ 0x59, 0xEA, 0xD2, 0xC3, 0x75, 0x65, 0x69, 0x67, 0xE5, 0x5E, 0xDD, 0xD8, 0x5F, 0x48, 0x01, 0xF6,
+ 0x17, 0x80, 0x7F, 0x69, 0xFD, 0x4A, 0xC3, 0xE1, 0x47, 0x80, 0x7C, 0x4F, 0xE3, 0x8B, 0x3F, 0x1F,
+ 0x7C, 0x5F, 0xF1, 0x97, 0xC4, 0x09, 0x35, 0xDD, 0x6B, 0x4A, 0xF0, 0xFF, 0x00, 0xC3, 0x9F, 0xD9,
+ 0x07, 0xC6, 0xDF, 0xB3, 0x57, 0x8F, 0x6D, 0x3C, 0x3F, 0xE1, 0xFB, 0xA4, 0xB7, 0xD5, 0xF5, 0x5B,
+ 0xEF, 0x86, 0x9E, 0x2F, 0xD4, 0x65, 0xF1, 0x15, 0xAC, 0x56, 0x72, 0x4D, 0x68, 0x0E, 0xF6, 0x37,
+ 0x17, 0x9F, 0x6D, 0xD3, 0xBE, 0xC5, 0x67, 0x39, 0xBB, 0x80, 0x4C, 0x01, 0xDC, 0x68, 0x7F, 0xB6,
+ 0x9F, 0xEC, 0xB3, 0xE2, 0x1B, 0x0D, 0x0A, 0xFB, 0x4A, 0xF8, 0xD1, 0xE1, 0x27, 0x5D, 0x5F, 0x4B,
+ 0xD6, 0xF5, 0xBD, 0x53, 0x4E, 0xBB, 0xFB, 0x56, 0x95, 0xE2, 0x0F, 0x86, 0x76, 0x5E, 0x18, 0xB1,
+ 0x9E, 0xE7, 0xC5, 0x37, 0x7E, 0x3D, 0xD2, 0xE7, 0x85, 0x2F, 0x3C, 0x21, 0x0E, 0x94, 0x6C, 0xE4,
+ 0xB4, 0xD4, 0x5F, 0x5F, 0x87, 0x4D, 0x5B, 0x0B, 0xF9, 0x2D, 0x74, 0xCB, 0xA3, 0x05, 0xF5, 0xD5,
+ 0xBD, 0xAC, 0xC0, 0x19, 0x9A, 0x2F, 0xED, 0xAD, 0xF0, 0x27, 0xFB, 0x46, 0x4D, 0x0F, 0xE2, 0x76,
+ 0xA9, 0xAD, 0x7E, 0xCD, 0xDA, 0xF4, 0xBE, 0x1E, 0x1E, 0x33, 0xF0, 0xF6, 0x8D, 0xFB, 0x4D, 0x69,
+ 0x2B, 0xF0, 0x42, 0x5F, 0x1B, 0x68, 0x7B, 0x4B, 0x3E, 0xAB, 0xA1, 0xDC, 0xEA, 0x32, 0x25, 0xA5,
+ 0xE7, 0xD9, 0xD0, 0x40, 0xD7, 0xD6, 0x71, 0xCC, 0x6F, 0xF4, 0x91, 0x75, 0xA7, 0xAE, 0xA7, 0x69,
+ 0x60, 0xD7, 0xD6, 0xAB, 0x38, 0x04, 0xBA, 0xDF, 0xED, 0x91, 0xF0, 0xA7, 0x43, 0x7B, 0x6B, 0xD7,
+ 0xF0, 0xFF, 0x00, 0xC5, 0xDB, 0xBF, 0x07, 0x69, 0xDA, 0x16, 0x85, 0xE2, 0x0F, 0x89, 0xFE, 0x3F,
+ 0x8F, 0xE1, 0x26, 0xB5, 0xA5, 0x78, 0x73, 0xE0, 0x1D, 0xBF, 0x89, 0xAD, 0xE2, 0x9F, 0x44, 0x8B,
+ 0xC7, 0x36, 0x77, 0x90, 0xDB, 0xEA, 0xBA, 0x5D, 0xCF, 0xD9, 0xEE, 0xAD, 0xAE, 0x75, 0x0B, 0x53,
+ 0x63, 0x24, 0xFA, 0x0D, 0x94, 0xD6, 0xFA, 0x8E, 0xBB, 0x1E, 0x91, 0x61, 0x71, 0x05, 0xDC, 0xA0,
+ 0x1D, 0x25, 0xD7, 0xED, 0x55, 0xF0, 0x4E, 0xE3, 0x46, 0xD5, 0x75, 0x4F, 0x00, 0xF8, 0xA1, 0x7E,
+ 0x33, 0x5C, 0xD8, 0xA6, 0x85, 0x6F, 0xA4, 0x68, 0xDF, 0x05, 0xE1, 0x5F, 0x88, 0x57, 0x1E, 0x30,
+ 0xBE, 0xF1, 0x34, 0xB7, 0x11, 0xE8, 0x5A, 0x5E, 0x93, 0x7F, 0x6E, 0xDF, 0xD9, 0xB2, 0x4F, 0x28,
+ 0xB0, 0xB9, 0x9E, 0x76, 0x92, 0xEE, 0x28, 0x34, 0xEB, 0x25, 0xFE, 0xD2, 0xD4, 0x26, 0xB2, 0xD3,
+ 0xC1, 0xBC, 0x50, 0x0C, 0xAF, 0x0D, 0xFE, 0xD8, 0xDF, 0x00, 0xB5, 0xA8, 0x6F, 0xEC, 0x35, 0x8F,
+ 0x16, 0xCD, 0xF0, 0xF7, 0xE2, 0x06, 0x83, 0xAD, 0x5A, 0xF8, 0x5B, 0xC4, 0xFF, 0x00, 0x05, 0xBE,
+ 0x21, 0xE9, 0x33, 0xF8, 0x6F, 0xE3, 0x4E, 0x81, 0xAA, 0xDE, 0x5F, 0x9B, 0x1B, 0x3B, 0x24, 0xF0,
+ 0xDE, 0xD7, 0xB9, 0xD4, 0x62, 0xB9, 0xBC, 0x8E, 0x58, 0xAC, 0xEF, 0xF4, 0xC1, 0x7D, 0xA7, 0xEA,
+ 0x4A, 0x86, 0x7D, 0x3E, 0xEE, 0xF2, 0xDD, 0x92, 0x77, 0x00, 0xEC, 0xFE, 0x36, 0xFC, 0x42, 0xD7,
+ 0xFE, 0x1E, 0xC7, 0xF0, 0x98, 0xF8, 0x7E, 0x3D, 0x31, 0xFF, 0x00, 0xE1, 0x35, 0xF8, 0xDD, 0xE1,
+ 0xDF, 0x87, 0x9A, 0xC8, 0xD4, 0x6D, 0x5E, 0xE4, 0x26, 0x9F, 0xAA, 0x49, 0x2A, 0xDC, 0xB5, 0xB8,
+ 0x57, 0x4D, 0x93, 0x01, 0x12, 0x6D, 0x63, 0xB8, 0x0E, 0x72, 0xA7, 0xB0, 0x07, 0xB7, 0x60, 0x63,
+ 0x18, 0x18, 0xC6, 0x31, 0x81, 0x8C, 0x63, 0xA6, 0x28, 0x03, 0xE3, 0xEF, 0x19, 0x7C, 0x7B, 0xF8,
+ 0xA7, 0xF0, 0x02, 0x4F, 0x1D, 0x6B, 0xFF, 0x00, 0x1E, 0xBE, 0x15, 0xCF, 0xE2, 0x8F, 0x82, 0xBA,
+ 0x2E, 0xA3, 0x79, 0xAD, 0x78, 0x7F, 0xE3, 0x27, 0xEC, 0xEB, 0xA3, 0x6A, 0x9E, 0x3E, 0xD7, 0x74,
+ 0x5D, 0x11, 0xEE, 0x5E, 0x48, 0x2D, 0xFC, 0x57, 0xF0, 0xE5, 0x12, 0x7D, 0x75, 0x2E, 0xED, 0xA2,
+ 0xB8, 0xB1, 0xB3, 0x59, 0xB4, 0x13, 0xE2, 0x11, 0xA8, 0x3D, 0xB5, 0xD5, 0xF3, 0xDA, 0xE8, 0xEB,
+ 0x34, 0x76, 0x11, 0x00, 0x6C, 0xFC, 0x4C, 0xF8, 0xBB, 0x2F, 0x8A, 0x74, 0xFF, 0x00, 0xD9, 0xCB,
+ 0x4A, 0xF8, 0x1F, 0xF1, 0x0B, 0xC3, 0xED, 0xA1, 0xFE, 0xD3, 0x3E, 0x31, 0x6D, 0x2B, 0x45, 0xF8,
+ 0xCD, 0xE0, 0xD9, 0xB4, 0xBF, 0x1D, 0xE9, 0xF6, 0x5E, 0x1D, 0x8B, 0xC1, 0xFA, 0xB6, 0xBC, 0xDA,
+ 0xC7, 0x86, 0xA7, 0x6F, 0xB4, 0x69, 0x97, 0x77, 0x17, 0x11, 0xE8, 0xD6, 0xB1, 0x5B, 0x4D, 0x2C,
+ 0x77, 0x56, 0xAA, 0xB7, 0x2D, 0x3B, 0x45, 0x38, 0x8D, 0x62, 0x94, 0x03, 0xD1, 0xFC, 0x57, 0xA0,
+ 0x7C, 0x68, 0xBE, 0xF8, 0xC1, 0xF0, 0x8B, 0x5D, 0xF0, 0x77, 0x8F, 0xBC, 0x2F, 0xE1, 0xEF, 0x83,
+ 0x1E, 0x1F, 0xD3, 0x3C, 0x44, 0xBF, 0x19, 0x3C, 0x09, 0xAA, 0x78, 0x4C, 0x6B, 0xBE, 0x21, 0xF8,
+ 0x83, 0x3D, 0xD5, 0xA4, 0x11, 0xF8, 0x72, 0x3D, 0x2A, 0xF8, 0x34, 0x4D, 0xA7, 0x3D, 0xB5, 0xC8,
+ 0x9E, 0xE1, 0xEE, 0x4C, 0xB2, 0x21, 0x8A, 0x29, 0xAD, 0x5A, 0xCE, 0x76, 0xBE, 0x8A, 0xF3, 0x47,
+ 0x00, 0xFC, 0xFB, 0xD2, 0xFF, 0x00, 0x6E, 0x0F, 0xDA, 0x0F, 0x55, 0xFD, 0x9F, 0x3C, 0x3F, 0xE1,
+ 0x9B, 0x5F, 0xD9, 0xFB, 0xC5, 0xEB, 0xFB, 0x5C, 0xF8, 0x8F, 0x50, 0xBE, 0xFD, 0x96, 0x74, 0xFF,
+ 0x00, 0x1D, 0x4B, 0xA6, 0xF8, 0x5A, 0x3F, 0xD9, 0xA2, 0x2F, 0x8D, 0x3A, 0x4A, 0x5E, 0x69, 0x7A,
+ 0xBE, 0xAD, 0x3D, 0x8F, 0xFC, 0x25, 0x3F, 0xF0, 0x90, 0xC5, 0xE0, 0xEB, 0x6D, 0x4F, 0x44, 0xD5,
+ 0xF5, 0x72, 0x5A, 0xD4, 0x5F, 0x4D, 0xA2, 0x5A, 0x89, 0x6D, 0xE0, 0x9E, 0x7B, 0x8B, 0x68, 0x6E,
+ 0x00, 0x3F, 0x41, 0x3C, 0x0D, 0xE1, 0xFF, 0x00, 0x8D, 0x1A, 0x77, 0xC4, 0xDF, 0x8D, 0x5A, 0xCF,
+ 0x8F, 0x3C, 0x7F, 0xE1, 0x7F, 0x10, 0xFC, 0x28, 0xF1, 0x0E, 0xA3, 0xA1, 0x9F, 0x81, 0xDE, 0x04,
+ 0xD2, 0xFC, 0x26, 0x34, 0xEF, 0x12, 0xFC, 0x3E, 0x82, 0xD7, 0x49, 0x09, 0xAF, 0xBE, 0xA7, 0xAC,
+ 0xAB, 0xA0, 0xBB, 0x4B, 0xBB, 0xD6, 0x46, 0x86, 0xD8, 0xC3, 0x23, 0xDB, 0xFD, 0x9E, 0x79, 0x7E,
+ 0xD9, 0x2A, 0x5F, 0xC5, 0x65, 0xA4, 0x80, 0x79, 0xD7, 0xEC, 0xBB, 0xF1, 0x47, 0x5E, 0xF1, 0x84,
+ 0x1F, 0x1C, 0xFE, 0x15, 0x78, 0xDF, 0x59, 0xD4, 0x3C, 0x55, 0xF1, 0x03, 0xF6, 0x52, 0xF8, 0xDC,
+ 0xFF, 0x00, 0x00, 0xBC, 0x69, 0xE3, 0xFD, 0x47, 0x4E, 0xD3, 0xB4, 0xAF, 0xF8, 0x58, 0x8B, 0x3F,
+ 0x84, 0x34, 0x0F, 0x15, 0xF8, 0x77, 0x5C, 0x92, 0x3B, 0x28, 0xED, 0xED, 0x7E, 0xD9, 0x2F, 0x87,
+ 0x3C, 0x79, 0xE1, 0x95, 0xD4, 0x0C, 0x16, 0x5A, 0x7D, 0xB0, 0xD5, 0x22, 0xD5, 0xD6, 0xD6, 0xD2,
+ 0x2B, 0x45, 0xB6, 0xDE, 0x01, 0xD9, 0x7E, 0xCE, 0x7F, 0x13, 0x3C, 0x51, 0xF1, 0x9F, 0xE1, 0x7E,
+ 0x9D, 0xF1, 0x63, 0xC4, 0x1A, 0x26, 0x8D, 0xE1, 0xBD, 0x13, 0xE2, 0x06, 0xAD, 0x7F, 0xE2, 0x2F,
+ 0x85, 0xBA, 0x36, 0x95, 0x71, 0x36, 0xA1, 0x79, 0xFF, 0x00, 0x08, 0x63, 0xDC, 0xB4, 0x7E, 0x15,
+ 0xD5, 0x35, 0x3B, 0xA7, 0xD9, 0xBA, 0xF7, 0x53, 0xD3, 0xE1, 0xB5, 0xD5, 0x64, 0xB7, 0x58, 0x20,
+ 0xFB, 0x0F, 0xF6, 0x9A, 0x69, 0xCD, 0xF6, 0x87, 0xB0, 0x7B, 0xDB, 0xD0, 0x0A, 0x77, 0x3E, 0x34,
+ 0xF1, 0x3C, 0x7F, 0xB5, 0x36, 0x89, 0xF0, 0xE9, 0x35, 0x52, 0xBE, 0x0A, 0xBB, 0xFD, 0x9F, 0xB5,
+ 0x4F, 0x1A, 0x5C, 0x68, 0x5F, 0x61, 0xB5, 0x29, 0x26, 0xA9, 0x6F, 0xE2, 0x2D, 0x3E, 0xD6, 0x0B,
+ 0xBF, 0xB4, 0xF9, 0x5F, 0x68, 0x1B, 0x60, 0xB9, 0x9D, 0x3C, 0xB1, 0x20, 0x8C, 0xEF, 0xC9, 0x42,
+ 0xC0, 0x10, 0x01, 0xF4, 0x00, 0xE3, 0xA7, 0x1F, 0x4E, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x10, 0x28,
+ 0x1D, 0x00, 0x1F, 0x40, 0x07, 0x61, 0xFE, 0x03, 0xF2, 0x1E, 0x94, 0x01, 0xE1, 0x9A, 0xC7, 0xC4,
+ 0xAF, 0x13, 0x4B, 0xFB, 0x43, 0xF8, 0x2F, 0xE0, 0xC7, 0x86, 0x34, 0xDD, 0x0F, 0xFB, 0x0A, 0xD7,
+ 0xE1, 0xAE, 0xA7, 0xF1, 0x5F, 0xE2, 0xB7, 0x88, 0xF5, 0x33, 0x35, 0xD6, 0xA9, 0xA6, 0xDA, 0xB5,
+ 0xE4, 0x7A, 0x77, 0x85, 0xF4, 0x5D, 0x32, 0xCD, 0x1A, 0x34, 0x49, 0x6F, 0xAE, 0x9F, 0x5A, 0xBA,
+ 0x7B, 0xD9, 0x1E, 0x65, 0x82, 0x2F, 0x0F, 0xCB, 0x6A, 0x2D, 0x24, 0x7D, 0x4D, 0x2E, 0xB4, 0xD0,
+ 0x0E, 0xFF, 0x00, 0xE2, 0x1E, 0x81, 0xE2, 0xDF, 0x12, 0x78, 0x43, 0x53, 0xD2, 0x7C, 0x07, 0xE3,
+ 0xAB, 0x8F, 0x86, 0xDE, 0x2F, 0x32, 0x5A, 0xDF, 0xE8, 0x1E, 0x2E, 0x87, 0xC3, 0xB6, 0x5E, 0x2D,
+ 0xB3, 0xB3, 0x9E, 0xCA, 0xEE, 0x2B, 0x85, 0xB4, 0xD4, 0x34, 0xBB, 0x90, 0x12, 0xEB, 0x4F, 0xBA,
+ 0x16, 0xED, 0x6B, 0x77, 0x14, 0x32, 0xDA, 0x5C, 0xB5, 0xAD, 0xC5, 0xC8, 0xB5, 0xBD, 0xB1, 0xB9,
+ 0xF2, 0x2F, 0x2D, 0x80, 0x38, 0x6F, 0x83, 0xDF, 0x18, 0xBF, 0xE1, 0x61, 0xB6, 0xBD, 0xE0, 0xDF,
+ 0x18, 0xF8, 0x7A, 0x1F, 0x87, 0x3F, 0x1B, 0xFE, 0x1E, 0x43, 0x65, 0x17, 0xC5, 0x2F, 0x85, 0x6D,
+ 0xAC, 0xB6, 0xBD, 0x06, 0x8C, 0x6F, 0xA3, 0x63, 0x65, 0xAC, 0xF8, 0x7B, 0x54, 0x7B, 0x7B, 0x66,
+ 0xD6, 0x7C, 0x37, 0x7A, 0xD6, 0xF7, 0x82, 0xC7, 0x56, 0x5B, 0x5B, 0x61, 0x33, 0x5A, 0xDE, 0xDA,
+ 0xDC, 0x5B, 0xD8, 0xEA, 0x3A, 0x7E, 0xA3, 0xA6, 0xE9, 0xE0, 0x1E, 0xDD, 0x40, 0x05, 0x00, 0x14,
+ 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x58, 0xA0, 0x02, 0x80, 0x0A,
+ 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x3F, 0xCF, 0xCF, 0xFE, 0x0E, 0x7D, 0xFF, 0x00, 0x94, 0xE7,
+ 0xFF, 0x00, 0xC1, 0x21, 0xFF, 0x00, 0xEC, 0x15, 0xF0, 0xF7, 0xFF, 0x00, 0x56, 0xF5, 0xCD, 0x76,
+ 0x65, 0x9F, 0xF2, 0x30, 0xC3, 0xFF, 0x00, 0x8E, 0x1F, 0xFA, 0x52, 0x39, 0xF1, 0x3F, 0xEE, 0xB5,
+ 0x3F, 0xC2, 0xFF, 0x00, 0x23, 0xED, 0x4A, 0xFD, 0x4C, 0xF8, 0xE0, 0xA0, 0x02, 0x80, 0x0A, 0x00,
+ 0xFD, 0x82, 0xFF, 0x00, 0x82, 0x21, 0x7F, 0xC8, 0x89, 0xFB, 0x75, 0xFF, 0x00, 0xD9, 0xF3, 0xC1,
+ 0xFF, 0x00, 0xAA, 0x1B, 0xE1, 0x95, 0x7E, 0x75, 0xC4, 0x1F, 0xF2, 0x34, 0x9F, 0xA4, 0x7F, 0xF4,
+ 0x94, 0x7D, 0x46, 0x57, 0xFE, 0xE5, 0x1F, 0x9F, 0xE6, 0x7E, 0xDB, 0x57, 0x8A, 0x7A, 0x21, 0x40,
+ 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x02, 0x1F, 0xBA, 0x7F,
+ 0xDD, 0xFE, 0x94, 0x01, 0xE0, 0x3F, 0x1C, 0x7E, 0x0E, 0x6B, 0x3F, 0x14, 0x20, 0xF0, 0x66, 0xBF,
+ 0xE0, 0x8F, 0x88, 0x57, 0x7F, 0x0B, 0xFE, 0x29, 0xFC, 0x2A, 0xD6, 0xAF, 0x3C, 0x5D, 0xF0, 0xC3,
+ 0xC5, 0xB2, 0x78, 0x62, 0xCB, 0xC7, 0x3E, 0x12, 0x83, 0x53, 0xB9, 0xD2, 0x2E, 0xAC, 0x0D, 0xAF,
+ 0x88, 0xF4, 0x19, 0xCC, 0x52, 0x5F, 0xE9, 0x33, 0x45, 0x7F, 0x22, 0x5C, 0xC1, 0x67, 0x7B, 0xA5,
+ 0x5E, 0xB4, 0x46, 0x44, 0xB6, 0xD4, 0xAC, 0x64, 0x7F, 0x39, 0x40, 0x3C, 0x37, 0x5E, 0xFD, 0x93,
+ 0xBC, 0x71, 0xE3, 0x3F, 0x0A, 0xF8, 0x6B, 0xC7, 0x9E, 0x2B, 0xF1, 0x77, 0xEC, 0xED, 0x69, 0xFB,
+ 0x70, 0xF8, 0x17, 0xC5, 0xB6, 0x1E, 0x37, 0xF0, 0x67, 0xED, 0x47, 0xF0, 0xFF, 0x00, 0xF6, 0x5E,
+ 0xD4, 0x3C, 0x25, 0xE1, 0x2B, 0x7B, 0xCD, 0x1A, 0x0D, 0x7F, 0x4F, 0xD1, 0xEC, 0xF5, 0x7F, 0x07,
+ 0xDC, 0x78, 0xBA, 0xF7, 0x53, 0xD4, 0xF4, 0xD5, 0xD0, 0x7E, 0x20, 0x78, 0xEF, 0x4C, 0x92, 0xD6,
+ 0x6F, 0x11, 0x0D, 0xAB, 0xE2, 0x2D, 0x62, 0xEA, 0xCE, 0x4D, 0x3E, 0xE6, 0x68, 0xE6, 0x80, 0x03,
+ 0xE8, 0x7D, 0x4B, 0xE1, 0x12, 0xEA, 0xBF, 0x0F, 0x7C, 0x0B, 0xE1, 0x8D, 0x53, 0xC6, 0x3E, 0x20,
+ 0xF1, 0x2F, 0x8E, 0xFE, 0x19, 0x69, 0x11, 0xCB, 0xE0, 0x9F, 0x8C, 0x5E, 0x2E, 0xB5, 0xD3, 0xEF,
+ 0xBC, 0x65, 0x6F, 0xE2, 0x48, 0x7C, 0x3B, 0x75, 0xA4, 0x27, 0x8B, 0x75, 0x0B, 0x3B, 0x1B, 0x7B,
+ 0x2D, 0x2E, 0xE6, 0xF9, 0xE2, 0xD4, 0xEF, 0xE5, 0x96, 0x18, 0xED, 0x2D, 0xED, 0x19, 0xE7, 0x90,
+ 0x25, 0xBC, 0x4A, 0x11, 0x63, 0x00, 0xF0, 0x7D, 0x67, 0xF6, 0x6B, 0xF8, 0xD3, 0xE0, 0x0F, 0x06,
+ 0x7E, 0xCE, 0xDE, 0x12, 0xFD, 0x91, 0x3E, 0x38, 0xFC, 0x3D, 0xF8, 0x2D, 0x63, 0xF0, 0x07, 0xE1,
+ 0x07, 0xFC, 0x28, 0xC8, 0x7C, 0x2B, 0xF1, 0x6F, 0xE0, 0xD7, 0x88, 0xFE, 0x3C, 0x7C, 0x26, 0xF1,
+ 0x26, 0x85, 0x15, 0xA6, 0x8F, 0x0E, 0x9D, 0x3F, 0xFC, 0x23, 0xF6, 0x1E, 0x34, 0xF0, 0xF5, 0xC4,
+ 0x5A, 0xA5, 0x92, 0xF8, 0x66, 0x08, 0xAD, 0xAF, 0x27, 0xBF, 0xBC, 0x31, 0xDB, 0xDF, 0x6A, 0x71,
+ 0x18, 0xD9, 0xAE, 0x4C, 0xAA, 0x01, 0xE4, 0xDF, 0xB4, 0x7F, 0xEC, 0x15, 0xF1, 0x47, 0xF6, 0x9C,
+ 0xF8, 0x93, 0xF0, 0x17, 0xC6, 0x3E, 0x34, 0xFD, 0xAA, 0xFC, 0x4D, 0xE1, 0x4F, 0x0B, 0x7C, 0x34,
+ 0x1E, 0x08, 0xF1, 0x17, 0xC4, 0x3F, 0x01, 0xFC, 0x31, 0xB3, 0xF1, 0xBF, 0x81, 0x74, 0x4F, 0x14,
+ 0xF8, 0xAB, 0xC0, 0xBE, 0x27, 0x87, 0xC4, 0x56, 0x1A, 0xF7, 0x86, 0xF4, 0xCB, 0x7F, 0x1A, 0x8F,
+ 0x0F, 0x59, 0xC7, 0x73, 0xAB, 0x58, 0xE9, 0x82, 0x7B, 0x7F, 0x12, 0x68, 0xDE, 0x30, 0x78, 0xED,
+ 0x2C, 0xAD, 0xE2, 0xB4, 0xB8, 0xB3, 0xB8, 0x0D, 0x7A, 0xE0, 0x1F, 0x79, 0xFC, 0x36, 0xF0, 0xAF,
+ 0x8B, 0xFC, 0x19, 0xA0, 0x5C, 0x68, 0x1E, 0x2F, 0xF8, 0x97, 0xAC, 0xFC, 0x57, 0x92, 0xDB, 0x54,
+ 0x92, 0x5D, 0x0B, 0xC5, 0x9E, 0x29, 0xF0, 0xFE, 0x95, 0xA1, 0x78, 0xCD, 0xAC, 0x24, 0x8A, 0x36,
+ 0x5B, 0x5D, 0x61, 0xF4, 0xC8, 0x2D, 0x74, 0xEB, 0xB9, 0xA2, 0xB8, 0x37, 0x8B, 0x1C, 0xF6, 0xD6,
+ 0x16, 0x03, 0xEC, 0xC6, 0xCE, 0x29, 0x22, 0x96, 0x78, 0x66, 0xBC, 0xBC, 0x00, 0xEB, 0xED, 0xF4,
+ 0x7D, 0x22, 0xD3, 0x51, 0xBE, 0xD5, 0xED, 0x74, 0xBD, 0x3A, 0xDB, 0x56, 0xD5, 0x12, 0x18, 0xF5,
+ 0x3D, 0x52, 0xDE, 0xC6, 0x28, 0x75, 0x1D, 0x45, 0x6D, 0xD7, 0x6D, 0xBA, 0xCF, 0x38, 0x50, 0xF2,
+ 0x04, 0x52, 0x42, 0x86, 0x27, 0x68, 0x38, 0x18, 0x14, 0x00, 0x6A, 0x5A, 0x3E, 0x93, 0xAC, 0xDB,
+ 0xC7, 0x69, 0xAB, 0xE9, 0x7A, 0x76, 0xAB, 0x6B, 0x15, 0xC4, 0x77, 0x71, 0x5B, 0x6A, 0x56, 0x31,
+ 0x5F, 0x5B, 0xC5, 0x2C, 0x27, 0x31, 0x4A, 0xA8, 0xEA, 0x54, 0x3A, 0x9E, 0x55, 0x80, 0xC8, 0xED,
+ 0x8A, 0x00, 0xD1, 0xF4, 0xF6, 0xC6, 0x3D, 0xB1, 0xD3, 0x14, 0x01, 0x9F, 0xA6, 0xE9, 0x1A, 0x4E,
+ 0x8D, 0x1D, 0xCC, 0x5A, 0x3E, 0x97, 0xA7, 0x69, 0x51, 0x5E, 0xDE, 0xC9, 0xA9, 0x5E, 0x47, 0xA6,
+ 0xD9, 0x45, 0x63, 0x1D, 0xDD, 0xCC, 0xC4, 0x79, 0xD7, 0x12, 0xAA, 0x28, 0x0D, 0x23, 0xED, 0x5D,
+ 0xCE, 0x72, 0x4E, 0x06, 0x4F, 0x14, 0x00, 0xDB, 0x9D, 0x1B, 0x47, 0xBD, 0xD4, 0x34, 0xBD, 0x5A,
+ 0xF3, 0x4A, 0xD3, 0x6E, 0xF5, 0x5D, 0x0C, 0x4E, 0x34, 0x5D, 0x4E, 0xE6, 0xC6, 0x29, 0xF5, 0x0D,
+ 0x1C, 0x5C, 0xC6, 0x12, 0xE4, 0x5A, 0xCC, 0xCA, 0x5E, 0x2F, 0x31, 0x15, 0x55, 0xF6, 0x15, 0xDC,
+ 0x00, 0x07, 0x20, 0x50, 0x07, 0x9B, 0x7C, 0x61, 0xF8, 0x7B, 0xE2, 0x5F, 0x88, 0x9A, 0x3F, 0x82,
+ 0xAC, 0xFC, 0x27, 0xE2, 0xBF, 0x0E, 0x78, 0x33, 0x54, 0xF0, 0xA7, 0xC5, 0xBF, 0x0A, 0x7C, 0x41,
+ 0xB9, 0xD5, 0x7C, 0x47, 0xF0, 0xDA, 0xC3, 0xE2, 0x6C, 0x57, 0xBA, 0x66, 0x87, 0xAE, 0x5B, 0xDC,
+ 0xEB, 0x5A, 0x45, 0x95, 0xB5, 0xD4, 0xB1, 0x2D, 0x85, 0xDD, 0xFE, 0x9D, 0x15, 0xFD, 0x8C, 0x5A,
+ 0x9C, 0x45, 0xA6, 0xB1, 0x6B, 0xBF, 0xB4, 0xC6, 0x92, 0x34, 0x41, 0x18, 0x03, 0xD3, 0x35, 0x5D,
+ 0x57, 0x4A, 0xD0, 0x74, 0xAD, 0x4B, 0x5B, 0xD6, 0xF5, 0x2D, 0x3F, 0x45, 0xD1, 0x34, 0x5D, 0x3E,
+ 0x6D, 0x57, 0x57, 0xD5, 0xF5, 0x5B, 0xC8, 0xB4, 0xED, 0x2B, 0x49, 0xB4, 0xB6, 0x88, 0xC9, 0x71,
+ 0x73, 0x73, 0x71, 0x21, 0x58, 0xE2, 0x8A, 0x38, 0xD1, 0xDD, 0x9D, 0xCA, 0xAA, 0xAA, 0x92, 0x48,
+ 0x03, 0x80, 0x0F, 0x97, 0x34, 0xBF, 0xD9, 0xA7, 0xE1, 0x2F, 0xC4, 0xEF, 0x11, 0xF8, 0x7B, 0xE3,
+ 0x57, 0xC4, 0x8D, 0x6B, 0xC6, 0x5F, 0xB4, 0x4E, 0x6E, 0xEE, 0x3C, 0x7B, 0xF0, 0x8B, 0x49, 0xF8,
+ 0xD4, 0x6D, 0x2F, 0xFE, 0x1E, 0x7C, 0x2B, 0x4D, 0x64, 0xF9, 0xD6, 0x37, 0x3E, 0x1F, 0xF0, 0x64,
+ 0x56, 0x16, 0x5A, 0x5D, 0xBE, 0xA1, 0x6B, 0x63, 0x70, 0x2C, 0x6D, 0x75, 0x5B, 0xDB, 0x29, 0xF5,
+ 0x9B, 0x7B, 0x49, 0x6F, 0xAD, 0xCD, 0xF7, 0xFC, 0x4C, 0x75, 0x0F, 0xB6, 0x80, 0x6F, 0xFC, 0x4B,
+ 0xD0, 0xAD, 0xBE, 0x30, 0x6B, 0x1A, 0x1E, 0xA7, 0xF0, 0x9F, 0xC7, 0x1E, 0x17, 0x5F, 0x8A, 0xFF,
+ 0x00, 0xB2, 0xAF, 0xC6, 0x9B, 0x6D, 0x46, 0xF7, 0x4A, 0xD5, 0x92, 0x4D, 0x57, 0xC3, 0x69, 0xA8,
+ 0xDE, 0xF8, 0x45, 0x7F, 0xB5, 0x7C, 0x29, 0xE2, 0x18, 0xE0, 0x65, 0xB9, 0xB4, 0x7B, 0xCF, 0x0B,
+ 0xF8, 0xE6, 0x29, 0xED, 0xEE, 0xA2, 0x2E, 0xD6, 0x57, 0x17, 0x7A, 0x3D, 0xFB, 0xDB, 0x6A, 0x16,
+ 0xF0, 0x4D, 0xA6, 0x6A, 0x00, 0x1F, 0x49, 0xE0, 0x0E, 0x07, 0x41, 0xC0, 0xE0, 0x0E, 0x07, 0x4E,
+ 0x28, 0x03, 0xE6, 0x1B, 0x6F, 0xD9, 0x5F, 0xC0, 0x90, 0xFE, 0xD4, 0x1A, 0x87, 0xED, 0x36, 0xF2,
+ 0xB9, 0xD4, 0xA6, 0xF0, 0xC4, 0x31, 0xE9, 0xDE, 0x05, 0xB5, 0xB5, 0x36, 0x3E, 0x10, 0xB7, 0xF1,
+ 0x74, 0x96, 0x5F, 0xD9, 0x7A, 0x9F, 0xC4, 0x5B, 0xDB, 0x44, 0x93, 0xEC, 0xD7, 0xBE, 0x26, 0x97,
+ 0xC3, 0x76, 0x7A, 0x1F, 0x87, 0xE0, 0xD5, 0x25, 0xB7, 0xFB, 0x6D, 0xA6, 0x95, 0x6B, 0x77, 0xA7,
+ 0xC7, 0x72, 0x6D, 0x6F, 0xA4, 0xB7, 0x40, 0x0F, 0xA7, 0x86, 0x38, 0xF4, 0xE3, 0xA6, 0x3A, 0x7B,
+ 0x50, 0x07, 0xC0, 0x9E, 0x30, 0xF8, 0x3C, 0xDF, 0x0C, 0xFF, 0x00, 0x66, 0x6F, 0xDA, 0x3B, 0xC4,
+ 0x7E, 0x3D, 0xF8, 0xB3, 0xA3, 0xFC, 0x18, 0xD7, 0xBE, 0x30, 0x78, 0x92, 0xFB, 0xE3, 0xEF, 0xED,
+ 0x7F, 0xF1, 0xDF, 0xC3, 0x7E, 0x23, 0xD4, 0xBC, 0x27, 0x1F, 0x83, 0xF4, 0x2B, 0x6D, 0x3F, 0x4F,
+ 0xB4, 0xF1, 0x1B, 0x68, 0x5A, 0xDD, 0xBB, 0x5A, 0xDC, 0xE9, 0xF3, 0x69, 0x9E, 0x03, 0xF0, 0xA6,
+ 0x99, 0xA0, 0xD9, 0x6B, 0x30, 0x2D, 0x84, 0xF0, 0x8D, 0x32, 0xD7, 0x59, 0x68, 0xD6, 0xF1, 0x65,
+ 0x59, 0x40, 0x3E, 0xE7, 0xD0, 0xB4, 0x2D, 0x13, 0xC2, 0xFA, 0x26, 0x8F, 0xE1, 0x9F, 0x0C, 0xE8,
+ 0xDA, 0x57, 0x87, 0x7C, 0x37, 0xE1, 0xDD, 0x2A, 0xDB, 0x41, 0xF0, 0xFF, 0x00, 0x87, 0xB4, 0x2D,
+ 0x3A, 0x1D, 0x23, 0x43, 0xD0, 0x6C, 0x6C, 0xE1, 0x58, 0xAD, 0x2C, 0xAC, 0xAD, 0x22, 0x55, 0x8A,
+ 0x08, 0x22, 0x8A, 0x28, 0xE3, 0x48, 0xE3, 0x55, 0x54, 0x55, 0x55, 0x50, 0x00, 0x00, 0x00, 0x7C,
+ 0xFB, 0xE2, 0x8B, 0x2D, 0x3F, 0xC3, 0x1F, 0xB5, 0x27, 0xC2, 0xEF, 0x1D, 0xF8, 0x8B, 0xC5, 0x1E,
+ 0x14, 0xD0, 0xF4, 0xFF, 0x00, 0x88, 0x1F, 0x0F, 0x35, 0x7F, 0x80, 0x5E, 0x04, 0xD1, 0x35, 0x2D,
+ 0x51, 0xED, 0xBC, 0x4F, 0xE3, 0x0F, 0x13, 0xB9, 0x7F, 0x12, 0xB5, 0x86, 0x9D, 0x6A, 0x62, 0xF2,
+ 0xE5, 0xD9, 0xA2, 0xF8, 0x47, 0xC4, 0x57, 0x4D, 0x89, 0x43, 0x84, 0xB2, 0x98, 0x84, 0x2A, 0xA5,
+ 0x94, 0x03, 0xE9, 0x6A, 0x00, 0x28, 0x00, 0xA0, 0x0C, 0x0F, 0x15, 0xF8, 0xA7, 0xC3, 0x7E, 0x04,
+ 0xF0, 0xAF, 0x89, 0x7C, 0x6F, 0xE3, 0x0D, 0x67, 0x4F, 0xF0, 0xDF, 0x84, 0x3C, 0x1B, 0xE1, 0xFB,
+ 0xDF, 0x15, 0x78, 0xA7, 0xC4, 0x3A, 0xB4, 0xEB, 0x69, 0xA5, 0x68, 0x1A, 0x6E, 0x9D, 0x6C, 0xF7,
+ 0x17, 0xD7, 0xB7, 0x32, 0x9E, 0x12, 0x28, 0xA0, 0x86, 0x59, 0x19, 0x8F, 0x01, 0x50, 0x9E, 0xD4,
+ 0x01, 0xE5, 0x7F, 0x08, 0xFE, 0x0E, 0x7F, 0xC2, 0x03, 0xE2, 0x8F, 0x8C, 0x5F, 0x11, 0xFC, 0x49,
+ 0x7F, 0x0F, 0x89, 0x3E, 0x25, 0xFC, 0x64, 0xF1, 0xCB, 0xEA, 0x7A, 0xDF, 0x89, 0x4B, 0xCD, 0x72,
+ 0xDA, 0x4F, 0x86, 0xF4, 0x83, 0x25, 0xAF, 0x82, 0xFC, 0x2B, 0xA7, 0xB4, 0xC4, 0xB5, 0xAE, 0x9B,
+ 0x61, 0x62, 0xF3, 0x5C, 0x1B, 0x38, 0x7C, 0xBB, 0x6F, 0xED, 0x3D, 0x5B, 0xC4, 0x77, 0xEB, 0x18,
+ 0x9F, 0x55, 0xBA, 0x96, 0x70, 0x0F, 0x73, 0xA0, 0x0F, 0x15, 0xF8, 0xC3, 0xF0, 0x81, 0xBE, 0x22,
+ 0x47, 0xA0, 0x78, 0xA7, 0xC2, 0x3E, 0x21, 0x4F, 0x87, 0x9F, 0x1A, 0x7E, 0x1D, 0x0B, 0xDB, 0xBF,
+ 0x84, 0xFF, 0x00, 0x13, 0xD3, 0x4C, 0x9B, 0x5B, 0xB5, 0xD0, 0x65, 0xBE, 0x8E, 0x35, 0xBD, 0xD2,
+ 0x75, 0xFD, 0x26, 0x2B, 0xAB, 0x43, 0xAD, 0x78, 0x72, 0xF8, 0xDA, 0x58, 0x8B, 0xFD, 0x22, 0x4B,
+ 0x9B, 0x75, 0x9C, 0xDA, 0xD8, 0xDD, 0x5B, 0xCF, 0x65, 0xA8, 0xE9, 0xDA, 0x6E, 0xA5, 0xA7, 0x00,
+ 0x71, 0x97, 0xFE, 0x34, 0xFD, 0xAF, 0x6D, 0xEE, 0xA4, 0x87, 0x4E, 0xFD, 0x9D, 0xFE, 0x04, 0xEA,
+ 0x16, 0x71, 0x84, 0x58, 0xAF, 0x26, 0xFD, 0xAA, 0x35, 0x8B, 0x07, 0x9C, 0xEC, 0x1B, 0xC8, 0x8B,
+ 0xFE, 0x10, 0x66, 0xC2, 0x86, 0xDC, 0x01, 0x24, 0x12, 0x00, 0x24, 0x29, 0x3B, 0x54, 0x02, 0x9F,
+ 0xFC, 0x27, 0x5F, 0xB6, 0x5F, 0xFD, 0x1B, 0x57, 0xC0, 0x4F, 0xFC, 0x4B, 0x4D, 0x63, 0xFF, 0x00,
+ 0x98, 0x3A, 0x00, 0x3F, 0xE1, 0x3A, 0xFD, 0xB2, 0xFF, 0x00, 0xE8, 0xDA, 0xBE, 0x02, 0x7F, 0xE2,
+ 0x5A, 0x6B, 0x1F, 0xFC, 0xC1, 0xD0, 0x01, 0xFF, 0x00, 0x09, 0xD7, 0xED, 0x97, 0xFF, 0x00, 0x46,
+ 0xD5, 0xF0, 0x13, 0xFF, 0x00, 0x12, 0xD3, 0x58, 0xFF, 0x00, 0xE6, 0x0E, 0x80, 0x0F, 0xF8, 0x4E,
+ 0xBF, 0x6C, 0xBF, 0xFA, 0x36, 0xAF, 0x80, 0x9F, 0xF8, 0x96, 0x9A, 0xC7, 0xFF, 0x00, 0x30, 0x74,
+ 0x00, 0x7F, 0xC2, 0x75, 0xFB, 0x65, 0xFF, 0x00, 0xD1, 0xB5, 0x7C, 0x04, 0xFF, 0x00, 0xC4, 0xB4,
+ 0xD6, 0x3F, 0xF9, 0x83, 0xA0, 0x03, 0xFE, 0x13, 0xAF, 0xDB, 0x2F, 0xFE, 0x8D, 0xAB, 0xE0, 0x27,
+ 0xFE, 0x25, 0xA6, 0xB1, 0xFF, 0x00, 0xCC, 0x1D, 0x00, 0x1F, 0xF0, 0x9D, 0x7E, 0xD9, 0x7F, 0xF4,
+ 0x6D, 0x5F, 0x01, 0x3F, 0xF1, 0x2D, 0x35, 0x8F, 0xFE, 0x60, 0xE8, 0x00, 0xFF, 0x00, 0x84, 0xEB,
+ 0xF6, 0xCB, 0xFF, 0x00, 0xA3, 0x6A, 0xF8, 0x09, 0xFF, 0x00, 0x89, 0x69, 0xAC, 0x7F, 0xF3, 0x07,
+ 0x40, 0x07, 0xFC, 0x27, 0x5F, 0xB6, 0x5F, 0xFD, 0x1B, 0x57, 0xC0, 0x4F, 0xFC, 0x4B, 0x4D, 0x63,
+ 0xFF, 0x00, 0x98, 0x3A, 0x00, 0x3F, 0xE1, 0x3A, 0xFD, 0xB2, 0xFF, 0x00, 0xE8, 0xDA, 0xBE, 0x02,
+ 0x7F, 0xE2, 0x5A, 0x6B, 0x1F, 0xFC, 0xC1, 0xD0, 0x01, 0xFF, 0x00, 0x09, 0xD7, 0xED, 0x97, 0xFF,
+ 0x00, 0x46, 0xD5, 0xF0, 0x13, 0xFF, 0x00, 0x12, 0xD3, 0x58, 0xFF, 0x00, 0xE6, 0x0E, 0x80, 0x0F,
+ 0xF8, 0x4E, 0xBF, 0x6C, 0xBF, 0xFA, 0x36, 0xAF, 0x80, 0x9F, 0xF8, 0x96, 0x9A, 0xC7, 0xFF, 0x00,
+ 0x30, 0x74, 0x00, 0x7F, 0xC2, 0x75, 0xFB, 0x65, 0xFF, 0x00, 0xD1, 0xB5, 0x7C, 0x04, 0xFF, 0x00,
+ 0xC4, 0xB4, 0xD6, 0x3F, 0xF9, 0x83, 0xA0, 0x0F, 0xA3, 0x3C, 0x31, 0x75, 0xE2, 0x2B, 0xDF, 0x0F,
+ 0x68, 0xF7, 0x7E, 0x2E, 0xD1, 0x74, 0x9F, 0x0E, 0xF8, 0x9A, 0xE2, 0xC2, 0x39, 0x75, 0xCD, 0x0B,
+ 0x42, 0xD7, 0xA4, 0xF1, 0x4E, 0x8F, 0xA5, 0x5C, 0x95, 0xFD, 0xE4, 0x16, 0xDA, 0x8C, 0x96, 0xB6,
+ 0xAF, 0x71, 0x1A, 0x9E, 0x04, 0x8D, 0x6D, 0x09, 0x3F, 0xDC, 0x5E, 0x94, 0x01, 0xBB, 0x40, 0x05,
+ 0x00, 0x14, 0x01, 0x62, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0xFF, 0x00,
+ 0x3F, 0x3F, 0xF8, 0x39, 0xF7, 0xFE, 0x53, 0x9F, 0xFF, 0x00, 0x04, 0x87, 0xFF, 0x00, 0xB0, 0x57,
+ 0xC3, 0xDF, 0xFD, 0x5B, 0xD7, 0x35, 0xD9, 0x96, 0x7F, 0xC8, 0xC3, 0x0F, 0xFE, 0x38, 0x7F, 0xE9,
+ 0x48, 0xE7, 0xC4, 0xFF, 0x00, 0xBA, 0xD4, 0xFF, 0x00, 0x0B, 0xFC, 0x8F, 0xB5, 0x2B, 0xF5, 0x33,
+ 0xE3, 0x82, 0x80, 0x0A, 0x00, 0x28, 0x03, 0xF6, 0x0B, 0xFE, 0x08, 0x85, 0xFF, 0x00, 0x22, 0x27,
+ 0xED, 0xD7, 0xFF, 0x00, 0x67, 0xCF, 0x07, 0xFE, 0xA8, 0x6F, 0x86, 0x55, 0xF9, 0xD7, 0x10, 0x7F,
+ 0xC8, 0xD2, 0x7E, 0x91, 0xFF, 0x00, 0xD2, 0x51, 0xF5, 0x19, 0x5F, 0xFB, 0x94, 0x7E, 0x7F, 0x99,
+ 0xFB, 0x6D, 0x5E, 0x29, 0xE8, 0x85, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x08, 0x7E, 0xE9, 0xFF, 0x00, 0x77, 0xFA, 0x50, 0x04, 0x14, 0x00, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x15,
+ 0x6F, 0xAF, 0xAC, 0x74, 0xAB, 0x1B, 0xCD, 0x4F, 0x53, 0xBC, 0xB4, 0xD3, 0x74, 0xCD, 0x36, 0xD2,
+ 0x4B, 0xFD, 0x43, 0x50, 0xBE, 0xB8, 0x4B, 0x3B, 0x0B, 0x0B, 0x78, 0x50, 0xBC, 0xD3, 0x4D, 0x33,
+ 0x90, 0x91, 0xC6, 0x88, 0x8C, 0xCC, 0xCC, 0x40, 0x00, 0x12, 0x48, 0x02, 0x80, 0x3E, 0x52, 0xD2,
+ 0xB4, 0xEB, 0xFF, 0x00, 0xDA, 0x92, 0xF7, 0x4C, 0xF1, 0x67, 0x89, 0xAC, 0x6F, 0x74, 0xAF, 0xD9,
+ 0xBB, 0x4E, 0xB8, 0x83, 0x58, 0xF0, 0x17, 0x81, 0xF5, 0x3B, 0x49, 0xF4, 0xCD, 0x47, 0xE3, 0x9C,
+ 0x82, 0x24, 0x92, 0xD3, 0xC4, 0x3E, 0x21, 0xB6, 0x32, 0x2B, 0x26, 0x86, 0x3C, 0xD7, 0x36, 0xBA,
+ 0x4D, 0xD4, 0x01, 0xA7, 0x78, 0xE2, 0xBB, 0xB9, 0x50, 0xA2, 0x08, 0x10, 0x03, 0xEB, 0x7A, 0x00,
+ 0xF8, 0xA7, 0xF6, 0x56, 0xFF, 0x00, 0x92, 0xE7, 0xFF, 0x00, 0x05, 0x2A, 0xFF, 0x00, 0xB3, 0xD7,
+ 0xD0, 0x7F, 0xF5, 0x9C, 0x3E, 0x14, 0xD0, 0x07, 0xDA, 0xD4, 0x00, 0x50, 0x01, 0x40, 0x1F, 0x1E,
+ 0x7E, 0xD8, 0xF1, 0x5C, 0x1D, 0x23, 0xF6, 0x76, 0xB9, 0xD5, 0xE3, 0xD2, 0x24, 0xF8, 0x4D, 0xA6,
+ 0x7E, 0xD7, 0x3F, 0x0F, 0xB5, 0x3F, 0x8C, 0xC9, 0x7B, 0x0B, 0xCD, 0xAB, 0x47, 0x69, 0x0E, 0xA6,
+ 0xDF, 0xF0, 0x83, 0xCF, 0xA5, 0xAF, 0xFA, 0x91, 0x2C, 0x3F, 0x10, 0x0F, 0xC3, 0x49, 0xEE, 0x1E,
+ 0x70, 0x12, 0x3B, 0x08, 0x35, 0x49, 0x14, 0xAC, 0xD1, 0xC2, 0x40, 0x07, 0xD8, 0x60, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x1F, 0x80, 0xA0, 0x0F, 0x82, 0xBF, 0x6C,
+ 0x0F, 0xF9, 0x38, 0x4F, 0xF8, 0x25, 0x4F, 0xFD, 0x9F, 0xB7, 0x88, 0xBF, 0xF5, 0x97, 0x3E, 0x30,
+ 0xD0, 0x07, 0xDE, 0xB4, 0x00, 0x50, 0x01, 0x40, 0x1F, 0x24, 0x7E, 0xDF, 0xBF, 0xF2, 0x61, 0xDF,
+ 0xB6, 0xC7, 0xFD, 0x9A, 0x2F, 0xC4, 0x9F, 0xFD, 0x43, 0x35, 0x1A, 0x00, 0xFA, 0xE0, 0xF5, 0x34,
+ 0x00, 0x94, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14,
+ 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x58, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x3F,
+ 0xCF, 0xCF, 0xFE, 0x0E, 0x7D, 0xFF, 0x00, 0x94, 0xE7, 0xFF, 0x00, 0xC1, 0x21, 0xFF, 0x00, 0xEC,
+ 0x15, 0xF0, 0xF7, 0xFF, 0x00, 0x56, 0xF5, 0xCD, 0x76, 0x65, 0x9F, 0xF2, 0x30, 0xC3, 0xFF, 0x00,
+ 0x8E, 0x1F, 0xFA, 0x52, 0x39, 0xF1, 0x3F, 0xEE, 0xB5, 0x3F, 0xC2, 0xFF, 0x00, 0x23, 0xED, 0x4A,
+ 0xFD, 0x4C, 0xF8, 0xE0, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0xFD, 0x82, 0xFF, 0x00, 0x82, 0x21, 0x7F,
+ 0xC8, 0x89, 0xFB, 0x75, 0xFF, 0x00, 0xD9, 0xF3, 0xC1, 0xFF, 0x00, 0xAA, 0x1B, 0xE1, 0x95, 0x7E,
+ 0x75, 0xC4, 0x1F, 0xF2, 0x34, 0x9F, 0xA4, 0x7F, 0xF4, 0x94, 0x7D, 0x46, 0x57, 0xFE, 0xE5, 0x1F,
+ 0x9F, 0xE6, 0x7E, 0xDB, 0x57, 0x8A, 0x7A, 0x21, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40,
+ 0x05, 0x00, 0x14, 0x00, 0x50, 0x02, 0x1F, 0xBA, 0x7F, 0xDD, 0xFE, 0x94, 0x01, 0xE2, 0xBF, 0x1A,
+ 0x7E, 0x05, 0x78, 0x27, 0xE3, 0xE7, 0x87, 0xB4, 0xAF, 0x0C, 0x78, 0xE7, 0x5B, 0xF8, 0xC9, 0xA0,
+ 0xE9, 0xBA, 0x36, 0xB2, 0xBA, 0xED, 0x9D, 0xC7, 0xC1, 0x4F, 0xDA, 0x2F, 0xE2, 0x17, 0xEC, 0xD5,
+ 0xE2, 0x09, 0x67, 0x5B, 0x79, 0x21, 0x11, 0xDD, 0x6A, 0xDE, 0x10, 0xD6, 0xB4, 0xAB, 0xEB, 0xAB,
+ 0x6D, 0x97, 0x0E, 0x7E, 0xCD, 0x3C, 0xD2, 0x40, 0x5C, 0x47, 0x21, 0x8F, 0x7C, 0x48, 0xC8, 0x01,
+ 0xF3, 0x57, 0xFC, 0x3B, 0x6F, 0xF6, 0x78, 0xFF, 0x00, 0xA2, 0x89, 0xFB, 0x7C, 0xFF, 0x00, 0xE2,
+ 0xD6, 0xFF, 0x00, 0x6A, 0x4F, 0xFE, 0x78, 0x54, 0x00, 0x7F, 0xC3, 0xB6, 0xFF, 0x00, 0x67, 0x8F,
+ 0xFA, 0x28, 0x9F, 0xB7, 0xCF, 0xFE, 0x2D, 0x6F, 0xF6, 0xA4, 0xFF, 0x00, 0xE7, 0x85, 0x40, 0x07,
+ 0xFC, 0x3B, 0x6F, 0xF6, 0x78, 0xFF, 0x00, 0xA2, 0x89, 0xFB, 0x7C, 0xFF, 0x00, 0xE2, 0xD6, 0xFF,
+ 0x00, 0x6A, 0x4F, 0xFE, 0x78, 0x54, 0x00, 0x7F, 0xC3, 0xB6, 0xFF, 0x00, 0x67, 0x8F, 0xFA, 0x28,
+ 0x9F, 0xB7, 0xCF, 0xFE, 0x2D, 0x6F, 0xF6, 0xA4, 0xFF, 0x00, 0xE7, 0x85, 0x40, 0x07, 0xFC, 0x3B,
+ 0x6F, 0xF6, 0x78, 0xFF, 0x00, 0xA2, 0x89, 0xFB, 0x7C, 0xFF, 0x00, 0xE2, 0xD6, 0xFF, 0x00, 0x6A,
+ 0x4F, 0xFE, 0x78, 0x54, 0x00, 0x7F, 0xC3, 0xB6, 0xFF, 0x00, 0x67, 0x8F, 0xFA, 0x28, 0x9F, 0xB7,
+ 0xCF, 0xFE, 0x2D, 0x6F, 0xF6, 0xA4, 0xFF, 0x00, 0xE7, 0x85, 0x40, 0x07, 0xFC, 0x3B, 0x6F, 0xF6,
+ 0x78, 0xFF, 0x00, 0xA2, 0x89, 0xFB, 0x7C, 0xFF, 0x00, 0xE2, 0xD6, 0xFF, 0x00, 0x6A, 0x4F, 0xFE,
+ 0x78, 0x54, 0x00, 0x7F, 0xC3, 0xB6, 0xFF, 0x00, 0x67, 0x8F, 0xFA, 0x28, 0x9F, 0xB7, 0xCF, 0xFE,
+ 0x2D, 0x6F, 0xF6, 0xA4, 0xFF, 0x00, 0xE7, 0x85, 0x40, 0x07, 0xFC, 0x3B, 0x6F, 0xF6, 0x78, 0xFF,
+ 0x00, 0xA2, 0x89, 0xFB, 0x7C, 0xFF, 0x00, 0xE2, 0xD6, 0xFF, 0x00, 0x6A, 0x4F, 0xFE, 0x78, 0x54,
+ 0x00, 0x7F, 0xC3, 0xB6, 0xFF, 0x00, 0x67, 0x8F, 0xFA, 0x28, 0x9F, 0xB7, 0xCF, 0xFE, 0x2D, 0x6F,
+ 0xF6, 0xA4, 0xFF, 0x00, 0xE7, 0x85, 0x40, 0x1B, 0x5E, 0x1C, 0xFF, 0x00, 0x82, 0x79, 0xFE, 0xCE,
+ 0x3E, 0x1D, 0xD7, 0x74, 0x8D, 0x76, 0x7D, 0x57, 0xF6, 0xA8, 0xF1, 0xE2, 0x68, 0xD7, 0xB1, 0xEA,
+ 0x30, 0xF8, 0x53, 0xE3, 0x47, 0xED, 0xF7, 0xF1, 0xEB, 0xE3, 0xE7, 0xC3, 0x2D, 0x4A, 0x68, 0x4E,
+ 0xEB, 0x76, 0xD5, 0x3C, 0x21, 0xE2, 0x5F, 0x18, 0xEA, 0x1A, 0x1E, 0xA0, 0x22, 0x90, 0x47, 0x34,
+ 0x6B, 0x77, 0x67, 0x3A, 0xC7, 0x34, 0x50, 0x4C, 0x81, 0x64, 0x86, 0x37, 0x40, 0x0F, 0xB7, 0xA8,
+ 0x03, 0x9A, 0xF1, 0x9F, 0x8C, 0xBC, 0x25, 0xF0, 0xE7, 0xC1, 0xDE, 0x2B, 0xF8, 0x83, 0xE3, 0xDF,
+ 0x11, 0xE8, 0x9E, 0x0D, 0xF0, 0x27, 0x80, 0xFC, 0x33, 0x7F, 0xE3, 0x2F, 0x1A, 0x78, 0xBB, 0xC4,
+ 0x9A, 0x8C, 0x5A, 0x3F, 0x87, 0x3C, 0x29, 0xA4, 0x69, 0x56, 0x8F, 0x73, 0xA9, 0x6A, 0x57, 0xF7,
+ 0x72, 0x15, 0x8E, 0x0B, 0x68, 0x2D, 0xED, 0xE6, 0x96, 0x49, 0x1C, 0x85, 0x44, 0x46, 0x62, 0x40,
+ 0x1C, 0x00, 0x70, 0x3F, 0x05, 0x74, 0x3F, 0x0D, 0x1D, 0x03, 0x56, 0xF8, 0xAD, 0xA4, 0xFC, 0x3D,
+ 0xD7, 0xFE, 0x19, 0xF8, 0x9F, 0xF6, 0x89, 0xBC, 0xD2, 0x7E, 0x34, 0x7C, 0x4C, 0xF0, 0xC7, 0x8B,
+ 0x24, 0xB8, 0x4F, 0x16, 0x5A, 0xEB, 0x72, 0xF8, 0x4F, 0x47, 0xD2, 0x20, 0x8B, 0x55, 0xB3, 0x79,
+ 0x5E, 0x2B, 0x3B, 0xCB, 0x7D, 0x27, 0xC3, 0x7A, 0x0D, 0x94, 0xD6, 0xF0, 0x04, 0x8D, 0x5E, 0xC9,
+ 0xC9, 0x0D, 0x23, 0xC9, 0x24, 0xA0, 0x1E, 0xA1, 0xAD, 0x6B, 0x5A, 0x37, 0x86, 0xB4, 0x6D, 0x5B,
+ 0xC4, 0x5E, 0x22, 0xD5, 0xB4, 0xBD, 0x03, 0xC3, 0xDA, 0x06, 0x97, 0x3E, 0xB5, 0xAE, 0xEB, 0xBA,
+ 0xD5, 0xF4, 0x3A, 0x56, 0x8B, 0xA2, 0x59, 0x5A, 0x42, 0xD2, 0xDD, 0x5D, 0xDD, 0xDD, 0x4A, 0xCB,
+ 0x14, 0x30, 0x45, 0x14, 0x6E, 0xEF, 0x23, 0xB2, 0xAA, 0x2A, 0xB3, 0x12, 0x00, 0x24, 0x00, 0x7C,
+ 0xC1, 0x1F, 0xC5, 0x8F, 0x8E, 0xDE, 0x25, 0xD0, 0xF5, 0x0F, 0x8A, 0xDF, 0x0F, 0xFE, 0x18, 0xE9,
+ 0x9A, 0x9F, 0xC3, 0x0B, 0x1D, 0x52, 0xD2, 0xEB, 0xC3, 0x5F, 0x0F, 0xF5, 0x88, 0x26, 0xD2, 0x3E,
+ 0x36, 0xFC, 0x57, 0xF0, 0xFD, 0xBC, 0x1A, 0x8A, 0x6A, 0xBA, 0xA6, 0x92, 0x67, 0xB9, 0x83, 0x4F,
+ 0xD3, 0xEE, 0x2E, 0xA4, 0x93, 0xC3, 0xF7, 0x3A, 0x5D, 0xAD, 0xF0, 0x5F, 0x36, 0xDE, 0xDA, 0xE6,
+ 0x3B, 0xB9, 0x2C, 0x64, 0xD4, 0x91, 0xB4, 0x80, 0x0F, 0xA1, 0x7C, 0x09, 0xE3, 0xBF, 0x08, 0x7C,
+ 0x4C, 0xF0, 0x9E, 0x91, 0xE3, 0x7F, 0x02, 0x6B, 0xB6, 0x7E, 0x23, 0xF0, 0xBE, 0xB7, 0x1C, 0xBF,
+ 0x60, 0xD4, 0xEC, 0x83, 0xC5, 0xB6, 0x4B, 0x69, 0xDE, 0x0B, 0xCB, 0x4B, 0x88, 0x24, 0x54, 0x9A,
+ 0xDE, 0xEA, 0xDE, 0xE6, 0xDE, 0xE2, 0xDE, 0x7B, 0x69, 0x92, 0x39, 0xAD, 0xE7, 0x86, 0x68, 0x65,
+ 0x8E, 0x39, 0x22, 0x74, 0x50, 0x0E, 0x2B, 0xE3, 0xD7, 0x88, 0x3E, 0x19, 0xE8, 0x5F, 0x0C, 0x75,
+ 0x2D, 0x3F, 0xE3, 0x17, 0x85, 0x6C, 0x7C, 0x71, 0xF0, 0xDB, 0xE2, 0x47, 0x88, 0xFC, 0x39, 0xF0,
+ 0x1B, 0xC4, 0xDE, 0x0C, 0xD5, 0xBC, 0x39, 0x67, 0xE2, 0xDF, 0x0F, 0xF8, 0xAA, 0x3F, 0x88, 0xFE,
+ 0x23, 0xB0, 0xF0, 0xAD, 0xB6, 0x9D, 0xAA, 0xE9, 0x97, 0x5F, 0xE8, 0xD7, 0x3A, 0x74, 0xD7, 0x1E,
+ 0x25, 0xB6, 0x8E, 0xEA, 0x39, 0x55, 0xD4, 0xDB, 0x35, 0xC6, 0x63, 0x90, 0x7E, 0xED, 0xC0, 0x3D,
+ 0x88, 0x70, 0x00, 0xF4, 0x00, 0x7E, 0x43, 0xFF, 0x00, 0xAC, 0x28, 0x03, 0xE7, 0x3F, 0x89, 0x3F,
+ 0xF0, 0xAF, 0x7C, 0x53, 0xF1, 0xEB, 0xF6, 0x6F, 0xF0, 0x4E, 0xBD, 0xE0, 0xBB, 0xCF, 0x15, 0xF8,
+ 0xEB, 0xC0, 0x7A, 0x97, 0x89, 0x3F, 0x68, 0x9F, 0x03, 0xF8, 0x82, 0x2D, 0x5A, 0x7D, 0x2F, 0x49,
+ 0xF8, 0x52, 0xFA, 0x77, 0x86, 0xEE, 0xFC, 0x2B, 0x73, 0xAA, 0xDC, 0xA4, 0x52, 0x28, 0xB9, 0xB9,
+ 0xBB, 0xB4, 0xF8, 0x8F, 0xA8, 0x69, 0xF6, 0xF6, 0x93, 0xC6, 0xF1, 0x3C, 0x77, 0x1A, 0x9D, 0xD0,
+ 0xDB, 0x2E, 0x9B, 0x19, 0xA0, 0x0F, 0xA3, 0x28, 0x03, 0xC5, 0x3E, 0x30, 0xFC, 0x5E, 0x7F, 0x87,
+ 0x29, 0xE1, 0xBF, 0x0A, 0xF8, 0x47, 0xC3, 0x32, 0x7C, 0x45, 0xF8, 0xC9, 0xF1, 0x16, 0x6B, 0x9B,
+ 0x0F, 0x86, 0x1F, 0x0C, 0xAD, 0x75, 0x17, 0xD1, 0x60, 0xD5, 0x8D, 0x92, 0xC4, 0x75, 0x2D, 0x67,
+ 0x5D, 0xD5, 0x56, 0xDE, 0xE1, 0x74, 0x6F, 0x0F, 0xE9, 0xE9, 0x77, 0x68, 0xF7, 0xDA, 0x9C, 0xB0,
+ 0x4A, 0x23, 0x37, 0x16, 0x56, 0x76, 0xD0, 0x5E, 0xEA, 0x3A, 0x96, 0x9B, 0xA6, 0xEA, 0x20, 0x1C,
+ 0x9F, 0x80, 0xFE, 0x27, 0x7C, 0x41, 0xF0, 0x97, 0x8B, 0xB4, 0x7F, 0x83, 0xFF, 0x00, 0xB4, 0x6C,
+ 0x9E, 0x0C, 0x7F, 0x1A, 0x78, 0x96, 0xD5, 0xA7, 0xF8, 0x69, 0xF1, 0x63, 0xE1, 0xEF, 0x86, 0x75,
+ 0x3F, 0x06, 0x7C, 0x2C, 0xF8, 0xC7, 0x25, 0xBD, 0xA9, 0x9F, 0x54, 0xD2, 0xA2, 0xD2, 0xAF, 0x2F,
+ 0x35, 0x07, 0xD0, 0x75, 0xCB, 0x44, 0x49, 0x9D, 0x74, 0xBB, 0x8D, 0x56, 0xFD, 0xAF, 0xEC, 0xA0,
+ 0x93, 0x51, 0xB3, 0x9E, 0x51, 0x6B, 0xAA, 0xD9, 0xE8, 0x40, 0x1D, 0x5F, 0xED, 0x2B, 0x7F, 0xF0,
+ 0xD3, 0x4A, 0xFD, 0x9C, 0x7E, 0x3F, 0xEA, 0x7F, 0x19, 0xF4, 0x6D, 0x43, 0xC4, 0x3F, 0x07, 0x74,
+ 0xDF, 0x82, 0x5E, 0x2B, 0xBF, 0xF8, 0xB1, 0xE1, 0xED, 0x21, 0xE5, 0x8B, 0x55, 0xD7, 0x7C, 0x33,
+ 0x06, 0x83, 0x74, 0xFA, 0xF5, 0x95, 0xAB, 0x45, 0x34, 0x12, 0x89, 0x65, 0xB1, 0x4B, 0xA8, 0xD0,
+ 0xA4, 0xF0, 0xB0, 0x66, 0x5D, 0xB2, 0x21, 0xC3, 0x28, 0x07, 0xB6, 0x63, 0x1C, 0x71, 0xC7, 0x1C,
+ 0x63, 0x1C, 0x7A, 0x7E, 0x54, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40,
+ 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x01, 0x62, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0,
+ 0x02, 0x80, 0x0A, 0x00, 0xFF, 0x00, 0x3F, 0x3F, 0xF8, 0x39, 0xF7, 0xFE, 0x53, 0x9F, 0xFF, 0x00,
+ 0x04, 0x87, 0xFF, 0x00, 0xB0, 0x57, 0xC3, 0xDF, 0xFD, 0x5B, 0xD7, 0x35, 0xD9, 0x96, 0x7F, 0xC8,
+ 0xC3, 0x0F, 0xFE, 0x38, 0x7F, 0xE9, 0x48, 0xE7, 0xC4, 0xFF, 0x00, 0xBA, 0xD4, 0xFF, 0x00, 0x0B,
+ 0xFC, 0x8F, 0xB5, 0x2B, 0xF5, 0x33, 0xE3, 0x82, 0x80, 0x0A, 0x00, 0x28, 0x03, 0xF6, 0x0B, 0xFE,
+ 0x08, 0x85, 0xFF, 0x00, 0x22, 0x27, 0xED, 0xD7, 0xFF, 0x00, 0x67, 0xCF, 0x07, 0xFE, 0xA8, 0x6F,
+ 0x86, 0x55, 0xF9, 0xD7, 0x10, 0x7F, 0xC8, 0xD2, 0x7E, 0x91, 0xFF, 0x00, 0xD2, 0x51, 0xF5, 0x19,
+ 0x5F, 0xFB, 0x94, 0x7E, 0x7F, 0x99, 0xFB, 0x6D, 0x5E, 0x29, 0xE8, 0x85, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x08, 0x7E, 0xE9, 0xFF, 0x00, 0x77, 0xFA,
+ 0x50, 0x04, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x01, 0xF3, 0x07, 0xED, 0x2F, 0xE0, 0x7F, 0x12,
+ 0x7C, 0x5D, 0xB3, 0xF8, 0x7B, 0xF0, 0x61, 0x7C, 0x3F, 0xA4, 0x5E, 0x7C, 0x20, 0xF1, 0xCF, 0x8B,
+ 0xA3, 0xD4, 0x7F, 0x68, 0xBD, 0x5F, 0xC4, 0x9A, 0xBD, 0xB5, 0xBF, 0x87, 0xEF, 0xBC, 0x1D, 0xA2,
+ 0xEC, 0xB9, 0xB8, 0xF0, 0x73, 0x69, 0x44, 0xBC, 0xBA, 0xB1, 0xD7, 0xAF, 0x06, 0x9B, 0xA7, 0xDD,
+ 0x58, 0xCD, 0x0A, 0xE9, 0xF2, 0xE8, 0xCD, 0xE2, 0x65, 0xBA, 0x9F, 0x79, 0xB4, 0xB0, 0xD5, 0x80,
+ 0x3E, 0x92, 0x5D, 0x43, 0x4E, 0xF9, 0x55, 0x6F, 0xAC, 0xCF, 0x45, 0x50, 0x2E, 0x90, 0x93, 0xE8,
+ 0x3A, 0xFD, 0x28, 0x03, 0xC0, 0xB5, 0x8F, 0x87, 0xBE, 0x2D, 0xF8, 0xB3, 0xF1, 0x06, 0x49, 0xBE,
+ 0x26, 0x5A, 0xC5, 0xA3, 0xFC, 0x1B, 0xF8, 0x7F, 0xAE, 0x5B, 0xDE, 0xF8, 0x1F, 0xE1, 0xED, 0xA6,
+ 0xAB, 0xF6, 0x99, 0xBE, 0x27, 0xEA, 0xB6, 0x6D, 0x6B, 0x73, 0x69, 0xE2, 0x6F, 0x12, 0x3C, 0x0E,
+ 0xAA, 0xB6, 0x96, 0x97, 0x31, 0x4E, 0x96, 0x7A, 0x4B, 0x19, 0x63, 0x77, 0x44, 0xBE, 0xB9, 0xDD,
+ 0x2A, 0xDA, 0xC1, 0xA7, 0x80, 0x7D, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xE0, 0x01, 0xF8, 0x0A, 0x00, 0xF9, 0xD3, 0xC5, 0x3F, 0x0F, 0x3C, 0x5D, 0xE0, 0x9F, 0x1E,
+ 0xCD, 0xF1, 0x6F, 0xE0, 0xC5, 0xAC, 0x17, 0xF3, 0xF8, 0xAF, 0x51, 0xB5, 0x4F, 0x8D, 0x5F, 0x0A,
+ 0xAF, 0x75, 0x6F, 0xEC, 0xBD, 0x1B, 0xE2, 0x44, 0x29, 0x1D, 0xA5, 0xA4, 0x5E, 0x21, 0xD3, 0x26,
+ 0x94, 0x98, 0x2C, 0x7C, 0x41, 0x61, 0x63, 0x66, 0x12, 0x32, 0x04, 0x30, 0x6A, 0x50, 0xA4, 0x76,
+ 0x77, 0x8E, 0x86, 0x2B, 0x1B, 0xDD, 0x2C, 0x03, 0xE7, 0x1F, 0xDA, 0x0B, 0xC7, 0xFF, 0x00, 0x11,
+ 0xBE, 0x3D, 0x78, 0x4F, 0xE1, 0x47, 0x82, 0x7E, 0x16, 0x7E, 0xCB, 0x7F, 0xB4, 0x5E, 0xB3, 0xA7,
+ 0x6A, 0x1F, 0xB5, 0x07, 0xC2, 0x8F, 0x16, 0xF8, 0xB3, 0xC7, 0x5E, 0x25, 0xD2, 0x7C, 0x29, 0xF0,
+ 0xA3, 0xC3, 0x9F, 0x0C, 0x34, 0xCF, 0x03, 0x7C, 0x54, 0xF0, 0xA7, 0x88, 0xF5, 0x8B, 0xED, 0x5F,
+ 0x4D, 0xF1, 0x0E, 0xBD, 0xA7, 0x6B, 0xB7, 0x30, 0xB6, 0x9B, 0xA6, 0xDF, 0x98, 0x4E, 0x95, 0xA6,
+ 0xEA, 0x45, 0xE4, 0xB7, 0x92, 0x2C, 0x2B, 0x80, 0xA4, 0x03, 0xF4, 0x66, 0x80, 0x3E, 0x70, 0xF8,
+ 0x43, 0xF0, 0xDF, 0xC4, 0xD0, 0xFC, 0x4D, 0xF8, 0xD5, 0xF1, 0xB7, 0xE2, 0x54, 0x17, 0x49, 0xE3,
+ 0x0F, 0x1A, 0x78, 0x94, 0xF8, 0x07, 0xE1, 0xC6, 0x91, 0x77, 0xAA, 0xAD, 0xFD, 0xAF, 0xC3, 0xEF,
+ 0x87, 0xDE, 0x1C, 0x73, 0x0E, 0x91, 0x63, 0x65, 0x04, 0x13, 0x3D, 0x92, 0x3E, 0xA7, 0xA8, 0xB6,
+ 0xB5, 0xAE, 0xCF, 0x70, 0xB1, 0xAD, 0xEC, 0xA9, 0xAA, 0xE9, 0x96, 0x37, 0x92, 0x32, 0x68, 0x96,
+ 0x56, 0xF6, 0x00, 0x1E, 0xAD, 0xF1, 0x23, 0x5E, 0xF1, 0x8F, 0x86, 0xBC, 0x19, 0xAB, 0x6A, 0x7F,
+ 0x0F, 0x3C, 0x0E, 0x3E, 0x22, 0xF8, 0xDF, 0x36, 0xDA, 0x77, 0x86, 0x3C, 0x25, 0x2F, 0x88, 0xAD,
+ 0x3C, 0x21, 0xA5, 0xDD, 0xDD, 0xDE, 0x5D, 0x47, 0x6F, 0x1D, 0xD6, 0xA7, 0xA9, 0xCF, 0xBB, 0xEC,
+ 0xDA, 0x6D, 0xA8, 0x9D, 0xAE, 0xEF, 0x24, 0x82, 0x1B, 0xCB, 0xA5, 0xB4, 0xB6, 0xBA, 0x36, 0x96,
+ 0x57, 0xD7, 0x22, 0x0B, 0x2B, 0x90, 0x0E, 0x2F, 0xE0, 0xEF, 0xC1, 0xA8, 0xFE, 0x1C, 0x37, 0x88,
+ 0x7C, 0x61, 0xE2, 0xBD, 0x76, 0x3F, 0x88, 0x9F, 0x1B, 0xBE, 0x22, 0x45, 0x69, 0xFF, 0x00, 0x0B,
+ 0x4F, 0xE2, 0xCD, 0xC6, 0x89, 0x1E, 0x85, 0x73, 0xAF, 0xC5, 0x61, 0x2D, 0xD4, 0xBA, 0x47, 0x87,
+ 0xF4, 0x8B, 0x11, 0x24, 0xC7, 0x4C, 0xF0, 0xDE, 0x96, 0x75, 0x5D, 0x4E, 0x3D, 0x37, 0x4B, 0x13,
+ 0xDC, 0x18, 0x05, 0xDD, 0xED, 0xCD, 0xC5, 0xC5, 0xF6, 0xA3, 0xA8, 0xEA, 0x5A, 0x96, 0xA2, 0x01,
+ 0xDE, 0x78, 0xF7, 0xC0, 0x1E, 0x10, 0xF8, 0x9F, 0xE1, 0x3D, 0x4B, 0xC1, 0x3E, 0x39, 0xD1, 0x62,
+ 0xD7, 0x3C, 0x39, 0xAA, 0x49, 0x6B, 0x77, 0x25, 0xB7, 0xDA, 0xAE, 0x34, 0xCB, 0xED, 0x3E, 0xF3,
+ 0x4F, 0xBB, 0x8A, 0xEF, 0x4B, 0xD4, 0xF4, 0xEB, 0xEB, 0x77, 0x8E, 0xEA, 0xC7, 0x50, 0xB3, 0xBD,
+ 0xB4, 0xB2, 0xBB, 0xB4, 0xBD, 0xB5, 0x96, 0x1B, 0x9B, 0x4B, 0x9B, 0x6B, 0x6B, 0x98, 0x25, 0x8A,
+ 0x68, 0x23, 0x91, 0x00, 0x3F, 0x3D, 0xFF, 0x00, 0x69, 0xFB, 0x6F, 0xDA, 0xAA, 0x3F, 0xD9, 0x2B,
+ 0xF6, 0x91, 0xFD, 0x9C, 0x2D, 0x7E, 0x05, 0xFC, 0x4E, 0xFD, 0xAA, 0xFC, 0x61, 0xE3, 0x7F, 0x83,
+ 0xDA, 0xFF, 0x00, 0xC1, 0xFF, 0x00, 0x86, 0x3F, 0x15, 0xBE, 0x1B, 0xEB, 0xDF, 0x0D, 0x7C, 0x14,
+ 0xFE, 0x2A, 0xB2, 0xF1, 0x47, 0x85, 0xF5, 0x5B, 0x1D, 0x3B, 0x51, 0xF1, 0x8D, 0xA7, 0x88, 0x3C,
+ 0x4D, 0xA2, 0xC7, 0x6D, 0xAA, 0xD8, 0x4F, 0x05, 0xB4, 0x7A, 0xA4, 0x9A, 0x7C, 0x0D, 0x6B, 0x75,
+ 0xF6, 0xEB, 0x0B, 0xDB, 0x0B, 0x68, 0x85, 0xC5, 0xE6, 0x97, 0xA0, 0x80, 0x7E, 0x9D, 0x71, 0xDB,
+ 0xA7, 0x6E, 0x31, 0xC7, 0x6E, 0x3F, 0x2A, 0x00, 0x4A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A,
+ 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28,
+ 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x2C, 0x50, 0x01, 0x40, 0x05,
+ 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x1F, 0xE7, 0xE7, 0xFF, 0x00, 0x07, 0x3E, 0xFF, 0x00, 0xCA,
+ 0x73, 0xFF, 0x00, 0xE0, 0x90, 0xFF, 0x00, 0xF6, 0x0A, 0xF8, 0x7B, 0xFF, 0x00, 0xAB, 0x7A, 0xE6,
+ 0xBB, 0x32, 0xCF, 0xF9, 0x18, 0x61, 0xFF, 0x00, 0xC7, 0x0F, 0xFD, 0x29, 0x1C, 0xF8, 0x9F, 0xF7,
+ 0x5A, 0x9F, 0xE1, 0x7F, 0x91, 0xF6, 0xA5, 0x7E, 0xA6, 0x7C, 0x70, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x7E, 0xC1, 0x7F, 0xC1, 0x10, 0xBF, 0xE4, 0x44, 0xFD, 0xBA, 0xFF, 0x00, 0xEC, 0xF9, 0xE0, 0xFF,
+ 0x00, 0xD5, 0x0D, 0xF0, 0xCA, 0xBF, 0x3A, 0xE2, 0x0F, 0xF9, 0x1A, 0x4F, 0xD2, 0x3F, 0xFA, 0x4A,
+ 0x3E, 0xA3, 0x2B, 0xFF, 0x00, 0x72, 0x8F, 0xCF, 0xF3, 0x3F, 0x6D, 0xAB, 0xC5, 0x3D, 0x10, 0xA0,
+ 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x01, 0x0F, 0xDD, 0x3F,
+ 0xEE, 0xFF, 0x00, 0x4A, 0x00, 0x82, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00,
+ 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x3C, 0xDF, 0xE2, 0x2F,
+ 0xC1, 0xAF, 0x84, 0x1F, 0x18, 0x2D, 0xB4, 0xAB, 0x3F, 0x8B, 0x7F, 0x0A, 0x7E, 0x1A, 0xFC, 0x52,
+ 0xB4, 0xD0, 0xA6, 0x96, 0xE3, 0x44, 0xB5, 0xF8, 0x8D, 0xE0, 0x5D, 0x2F, 0xC6, 0xF6, 0xDA, 0x34,
+ 0x93, 0xAA, 0xAC, 0xD2, 0x5A, 0x47, 0x7B, 0x04, 0xAB, 0x0B, 0x3A, 0xC5, 0x18, 0x62, 0x81, 0x49,
+ 0x08, 0xA0, 0xF4, 0x18, 0x00, 0xF3, 0x2B, 0x4F, 0xD8, 0xBF, 0xF6, 0x3B, 0xB0, 0xBA, 0xB5, 0xBE,
+ 0xB0, 0xFD, 0x93, 0xBF, 0x66, 0x7B, 0x2B, 0xDB, 0x29, 0xE3, 0xBA, 0xB3, 0xBB, 0xB4, 0xF8, 0x0F,
+ 0xE1, 0x5B, 0x6B, 0xAB, 0x49, 0x62, 0x60, 0xD1, 0xCB, 0x14, 0x8B, 0x62, 0x19, 0x19, 0x59, 0x54,
+ 0x86, 0x04, 0x10, 0x40, 0x23, 0xA5, 0x00, 0x7D, 0x2B, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x07,
+ 0xC9, 0x1F, 0x16, 0xFC, 0x47, 0x77, 0xE3, 0x8F, 0xDA, 0x1F, 0xE0, 0x5F, 0xEC, 0xFF, 0x00, 0xE1,
+ 0x8F, 0x15, 0xF8, 0x87, 0x4D, 0x8F, 0xC3, 0xAB, 0x2F, 0xED, 0x23, 0xF1, 0xCB, 0x4F, 0xF0, 0x46,
+ 0xB7, 0x2E, 0x8B, 0x7B, 0x6F, 0xE1, 0xED, 0x1E, 0x47, 0xB5, 0xF0, 0x5E, 0x93, 0xAF, 0xEA, 0x16,
+ 0x8C, 0x2F, 0x2C, 0x2D, 0x75, 0x6F, 0x12, 0x7F, 0xA4, 0xC1, 0x6D, 0xBE, 0xD9, 0x35, 0x9B, 0x7F,
+ 0x08, 0xF8, 0x96, 0xCA, 0x46, 0xBA, 0xB1, 0xB7, 0xD5, 0x6C, 0x6E, 0x80, 0x3D, 0xC7, 0xE2, 0x7F,
+ 0xC4, 0xFF, 0x00, 0x0D, 0xFC, 0x28, 0xF0, 0xE5, 0xBE, 0xB9, 0xAE, 0xC7, 0x7F, 0xA9, 0xEA, 0x1A,
+ 0xC6, 0xAF, 0x6F, 0xE1, 0x4F, 0x04, 0xF8, 0x37, 0x40, 0x5B, 0x79, 0xFC, 0x5D, 0xF1, 0x0F, 0x5D,
+ 0xBD, 0x0D, 0xFD, 0x9F, 0xA1, 0x68, 0xB6, 0xF3, 0x4B, 0x0C, 0x2F, 0x75, 0x37, 0x95, 0x2B, 0x6E,
+ 0x9A, 0x58, 0x2D, 0xE0, 0x86, 0x2B, 0x8B, 0xAB, 0x99, 0xAD, 0xED, 0xAD, 0xA7, 0x9E, 0x10, 0x0E,
+ 0x03, 0xE1, 0x8F, 0xC2, 0xCD, 0x7A, 0x7F, 0x11, 0xFF, 0x00, 0xC2, 0xE8, 0xF8, 0xD3, 0xFD, 0x8F,
+ 0xAC, 0x7C, 0x60, 0xD4, 0x34, 0xF7, 0xD3, 0xFC, 0x3D, 0xA3, 0xE9, 0xEA, 0x2F, 0xFC, 0x27, 0xF0,
+ 0x2F, 0x48, 0x99, 0xDD, 0x8E, 0x83, 0xE1, 0xB7, 0x90, 0x16, 0x37, 0x32, 0x24, 0x90, 0xA6, 0xA5,
+ 0xAA, 0x28, 0x8A, 0x4D, 0x4E, 0x5B, 0x78, 0x18, 0xC7, 0x05, 0xAD, 0xB5, 0x95, 0x8D, 0x88, 0x07,
+ 0xD0, 0xB4, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14,
+ 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x58, 0xA0, 0x02, 0x80, 0x0A,
+ 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x3F, 0xCF, 0xCF, 0xFE, 0x0E, 0x7D, 0xFF, 0x00, 0x94, 0xE7,
+ 0xFF, 0x00, 0xC1, 0x21, 0xFF, 0x00, 0xEC, 0x15, 0xF0, 0xF7, 0xFF, 0x00, 0x56, 0xF5, 0xCD, 0x76,
+ 0x65, 0x9F, 0xF2, 0x30, 0xC3, 0xFF, 0x00, 0x8E, 0x1F, 0xFA, 0x52, 0x39, 0xF1, 0x3F, 0xEE, 0xB5,
+ 0x3F, 0xC2, 0xFF, 0x00, 0x23, 0xED, 0x4A, 0xFD, 0x4C, 0xF8, 0xE0, 0xA0, 0x02, 0x80, 0x0A, 0x00,
+ 0xFD, 0x82, 0xFF, 0x00, 0x82, 0x21, 0x7F, 0xC8, 0x89, 0xFB, 0x75, 0xFF, 0x00, 0xD9, 0xF3, 0xC1,
+ 0xFF, 0x00, 0xAA, 0x1B, 0xE1, 0x95, 0x7E, 0x75, 0xC4, 0x1F, 0xF2, 0x34, 0x9F, 0xA4, 0x7F, 0xF4,
+ 0x94, 0x7D, 0x46, 0x57, 0xFE, 0xE5, 0x1F, 0x9F, 0xE6, 0x7E, 0xDB, 0x57, 0x8A, 0x7A, 0x21, 0x40,
+ 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x02, 0x1F, 0xBA, 0x7F,
+ 0xDD, 0xFE, 0x94, 0x01, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40,
+ 0x05, 0x00, 0x14, 0x01, 0x8F, 0xE2, 0x19, 0xB5, 0xFB, 0x5F, 0x0F, 0xEB, 0x97, 0x1E, 0x13, 0xD3,
+ 0x34, 0x6D, 0x6B, 0xC5, 0x36, 0xFA, 0x3D, 0xCC, 0xDE, 0x1A, 0xD1, 0xBC, 0x43, 0xAE, 0x4F, 0xE1,
+ 0x7F, 0x0F, 0xEA, 0xDA, 0x82, 0x40, 0xC6, 0xCA, 0xD6, 0xFB, 0x53, 0x86, 0xD2, 0xF2, 0x6B, 0x4B,
+ 0x79, 0x25, 0x11, 0x24, 0x93, 0xC7, 0x69, 0x74, 0xF1, 0x23, 0x33, 0xAC, 0x12, 0x95, 0x11, 0xB0,
+ 0x07, 0xC5, 0xFE, 0x1E, 0xB4, 0xFD, 0xB2, 0x7C, 0x31, 0xE2, 0x5F, 0x1E, 0xF8, 0xBF, 0x49, 0xFD,
+ 0x99, 0x3F, 0x64, 0xE8, 0xF5, 0xFF, 0x00, 0x89, 0x5A, 0xB5, 0x8E, 0xB1, 0xE2, 0xAB, 0xD9, 0xFF,
+ 0x00, 0x6E, 0x6F, 0x1B, 0xDD, 0x0B, 0x99, 0x34, 0xDD, 0x2A, 0xDF, 0x4F, 0xB3, 0x8A, 0x08, 0xDB,
+ 0xE1, 0x59, 0x58, 0x61, 0x48, 0x2C, 0x90, 0x88, 0xE3, 0x0A, 0xBE, 0x64, 0x93, 0xC8, 0x46, 0xE9,
+ 0x58, 0x90, 0x0F, 0x7E, 0xF0, 0x0F, 0x82, 0xB5, 0xBD, 0x5F, 0x5E, 0xD2, 0xBE, 0x30, 0x7C, 0x5C,
+ 0xF0, 0x5F, 0x84, 0xBC, 0x31, 0xF1, 0x9E, 0xD3, 0xC2, 0x37, 0x5F, 0x0F, 0xED, 0xF4, 0xCF, 0x05,
+ 0x7C, 0x4A, 0xD4, 0xFE, 0x2A, 0x78, 0x2B, 0xC2, 0x5A, 0x4C, 0xDA, 0xA1, 0xB9, 0x9C, 0x68, 0xF7,
+ 0xF7, 0xBA, 0x46, 0x92, 0xE9, 0x35, 0xFF, 0x00, 0xD9, 0xF4, 0x87, 0xBC, 0x65, 0xD3, 0xE1, 0x2E,
+ 0x74, 0xFD, 0x3E, 0x26, 0x79, 0x56, 0xCE, 0x27, 0x20, 0x1E, 0xD5, 0x40, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05,
+ 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x16, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00,
+ 0xA0, 0x0F, 0xF3, 0xF3, 0xFF, 0x00, 0x83, 0x9F, 0x7F, 0xE5, 0x39, 0xFF, 0x00, 0xF0, 0x48, 0x7F,
+ 0xFB, 0x05, 0x7C, 0x3D, 0xFF, 0x00, 0xD5, 0xBD, 0x73, 0x5D, 0x99, 0x67, 0xFC, 0x8C, 0x30, 0xFF,
+ 0x00, 0xE3, 0x87, 0xFE, 0x94, 0x8E, 0x7C, 0x4F, 0xFB, 0xAD, 0x4F, 0xF0, 0xBF, 0xC8, 0xFB, 0x52,
+ 0xBF, 0x53, 0x3E, 0x38, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x3F, 0x60, 0xBF, 0xE0, 0x88, 0x5F, 0xF2,
+ 0x22, 0x7E, 0xDD, 0x7F, 0xF6, 0x7C, 0xF0, 0x7F, 0xEA, 0x86, 0xF8, 0x65, 0x5F, 0x9D, 0x71, 0x07,
+ 0xFC, 0x8D, 0x27, 0xE9, 0x1F, 0xFD, 0x25, 0x1F, 0x51, 0x95, 0xFF, 0x00, 0xB9, 0x47, 0xE7, 0xF9,
+ 0x9F, 0xB6, 0xD5, 0xE2, 0x9E, 0x88, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40,
+ 0x05, 0x00, 0x14, 0x00, 0x87, 0xEE, 0x9F, 0xF7, 0x7F, 0xA5, 0x00, 0x41, 0x40, 0x05, 0x00, 0x14,
+ 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40,
+ 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x58, 0xA0, 0x02, 0x80,
+ 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x3F, 0xCF, 0xCF, 0xFE, 0x0E, 0x7D, 0xFF, 0x00, 0x94,
+ 0xE7, 0xFF, 0x00, 0xC1, 0x21, 0xFF, 0x00, 0xEC, 0x15, 0xF0, 0xF7, 0xFF, 0x00, 0x56, 0xF5, 0xCD,
+ 0x76, 0x65, 0x9F, 0xF2, 0x30, 0xC3, 0xFF, 0x00, 0x8E, 0x1F, 0xFA, 0x52, 0x39, 0xF1, 0x3F, 0xEE,
+ 0xB5, 0x3F, 0xC2, 0xFF, 0x00, 0x23, 0xED, 0x4A, 0xFD, 0x4C, 0xF8, 0xE0, 0xA0, 0x02, 0x80, 0x0A,
+ 0x00, 0xFD, 0x82, 0xFF, 0x00, 0x82, 0x21, 0x7F, 0xC8, 0x89, 0xFB, 0x75, 0xFF, 0x00, 0xD9, 0xF3,
+ 0xC1, 0xFF, 0x00, 0xAA, 0x1B, 0xE1, 0x95, 0x7E, 0x75, 0xC4, 0x1F, 0xF2, 0x34, 0x9F, 0xA4, 0x7F,
+ 0xF4, 0x94, 0x7D, 0x46, 0x57, 0xFE, 0xE5, 0x1F, 0x9F, 0xE6, 0x7E, 0xDB, 0x57, 0x8A, 0x7A, 0x21,
+ 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x81, 0x8C,
+ 0x63, 0x8C, 0x63, 0x1D, 0x38, 0xC7, 0x4A, 0x00, 0x6E, 0xC5, 0xF4, 0xA0, 0x03, 0x62, 0xFA, 0x50,
+ 0x01, 0xB1, 0x7D, 0x28, 0x00, 0xD8, 0xBE, 0x94, 0x00, 0x6C, 0x5F, 0x4A, 0x00, 0x36, 0x2F, 0xA5,
+ 0x00, 0x1B, 0x17, 0xD2, 0x80, 0x0D, 0x8B, 0xE9, 0x40, 0x06, 0xC5, 0xF4, 0xA0, 0x03, 0x62, 0xFA,
+ 0x50, 0x01, 0xB1, 0x7D, 0x28, 0x00, 0xD8, 0xBE, 0x94, 0x00, 0x6C, 0x5F, 0x4A, 0x00, 0x36, 0x2F,
+ 0xA5, 0x00, 0x1B, 0x17, 0xD2, 0x80, 0x0D, 0x8B, 0xE9, 0x40, 0x06, 0xC5, 0xF4, 0xA0, 0x03, 0x62,
+ 0xFA, 0x50, 0x01, 0xB1, 0x7D, 0x28, 0x00, 0xD8, 0xBE, 0x94, 0x00, 0x6C, 0x5F, 0x4A, 0x00, 0x36,
+ 0x2F, 0xA5, 0x00, 0x1B, 0x17, 0xD2, 0x80, 0x0D, 0x8B, 0xE9, 0x40, 0x06, 0xC5, 0xF4, 0xA0, 0x03,
+ 0x62, 0xFA, 0x50, 0x01, 0xB1, 0x7D, 0x28, 0x00, 0xD8, 0xBE, 0x94, 0x00, 0x6C, 0x5F, 0x4A, 0x00,
+ 0x36, 0x2F, 0xA5, 0x00, 0x1B, 0x17, 0xD2, 0x80, 0x0D, 0x8B, 0xE9, 0x40, 0x06, 0xC5, 0xF4, 0xA0,
+ 0x03, 0x62, 0xFA, 0x50, 0x01, 0xB1, 0x7D, 0x28, 0x00, 0xD8, 0xBE, 0x94, 0x00, 0x6C, 0x5F, 0x4A,
+ 0x00, 0x36, 0x2F, 0xA5, 0x00, 0x1B, 0x17, 0xD2, 0x80, 0x0D, 0x8B, 0xE9, 0x40, 0x06, 0xC5, 0xF4,
+ 0xA0, 0x03, 0x62, 0xFA, 0x50, 0x01, 0xB1, 0x7D, 0x28, 0x00, 0xD8, 0xBE, 0x94, 0x00, 0x6C, 0x5F,
+ 0x4A, 0x00, 0x36, 0x2F, 0xA5, 0x00, 0x3A, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A,
+ 0x00, 0xFF, 0x00, 0x3F, 0x3F, 0xF8, 0x39, 0xF7, 0xFE, 0x53, 0x9F, 0xFF, 0x00, 0x04, 0x87, 0xFF,
+ 0x00, 0xB0, 0x57, 0xC3, 0xDF, 0xFD, 0x5B, 0xD7, 0x35, 0xD9, 0x96, 0x7F, 0xC8, 0xC3, 0x0F, 0xFE,
+ 0x38, 0x7F, 0xE9, 0x48, 0xE7, 0xC4, 0xFF, 0x00, 0xBA, 0xD4, 0xFF, 0x00, 0x0B, 0xFC, 0x8F, 0xB5,
+ 0x2B, 0xF5, 0x33, 0xE3, 0x82, 0x80, 0x0A, 0x00, 0x28, 0x03, 0xF6, 0x0B, 0xFE, 0x08, 0x85, 0xFF,
+ 0x00, 0x22, 0x27, 0xED, 0xD7, 0xFF, 0x00, 0x67, 0xCF, 0x07, 0xFE, 0xA8, 0x6F, 0x86, 0x55, 0xF9,
+ 0xD7, 0x10, 0x7F, 0xC8, 0xD2, 0x7E, 0x91, 0xFF, 0x00, 0xD2, 0x51, 0xF5, 0x19, 0x5F, 0xFB, 0x94,
+ 0x7E, 0x7F, 0x99, 0xFB, 0x6D, 0x5E, 0x29, 0xE8, 0x85, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05,
+ 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14,
+ 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40,
+ 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x7F, 0x9F, 0x9F, 0xFC, 0x1C, 0xFB, 0xFF, 0x00, 0x29, 0xCF, 0xFF, 0x00, 0x82,
+ 0x43, 0xFF, 0x00, 0xD8, 0x2B, 0xE1, 0xEF, 0xFE, 0xAD, 0xEB, 0x9A, 0xEC, 0xCB, 0x3F, 0xE4, 0x61,
+ 0x87, 0xFF, 0x00, 0x1C, 0x3F, 0xF4, 0xA4, 0x73, 0xE2, 0x7F, 0xDD, 0x6A, 0x7F, 0x85, 0xFE, 0x47,
+ 0xDA, 0x95, 0xFA, 0x99, 0xF1, 0xC1, 0x40, 0x05, 0x00, 0x14, 0x01, 0xFB, 0x05, 0xFF, 0x00, 0x04,
+ 0x42, 0xFF, 0x00, 0x91, 0x13, 0xF6, 0xEB, 0xFF, 0x00, 0xB3, 0xE7, 0x83, 0xFF, 0x00, 0x54, 0x37,
+ 0xC3, 0x2A, 0xFC, 0xEB, 0x88, 0x3F, 0xE4, 0x69, 0x3F, 0x48, 0xFF, 0x00, 0xE9, 0x28, 0xFA, 0x8C,
+ 0xAF, 0xFD, 0xCA, 0x3F, 0x3F, 0xCC, 0xFD, 0xB6, 0xAF, 0x14, 0xF4, 0x42, 0x80, 0x0A, 0x00, 0x28,
+ 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0,
+ 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80,
+ 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00,
+ 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00,
+ 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02,
+ 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A,
+ 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x3F, 0xCF, 0xCF, 0xFE, 0x0E, 0x7D, 0xFF, 0x00, 0x94, 0xE7,
+ 0xFF, 0x00, 0xC1, 0x21, 0xFF, 0x00, 0xEC, 0x15, 0xF0, 0xF7, 0xFF, 0x00, 0x56, 0xF5, 0xCD, 0x76,
+ 0x65, 0x9F, 0xF2, 0x30, 0xC3, 0xFF, 0x00, 0x8E, 0x1F, 0xFA, 0x52, 0x39, 0xF1, 0x3F, 0xEE, 0xB5,
+ 0x3F, 0xC2, 0xFF, 0x00, 0x23, 0xED, 0x4A, 0xFD, 0x4C, 0xF8, 0xE0, 0xA0, 0x02, 0x80, 0x0A, 0x00,
+ 0xFD, 0x82, 0xFF, 0x00, 0x82, 0x21, 0x7F, 0xC8, 0x89, 0xFB, 0x75, 0xFF, 0x00, 0xD9, 0xF3, 0xC1,
+ 0xFF, 0x00, 0xAA, 0x1B, 0xE1, 0x95, 0x7E, 0x75, 0xC4, 0x1F, 0xF2, 0x34, 0x9F, 0xA4, 0x7F, 0xF4,
+ 0x94, 0x7D, 0x46, 0x57, 0xFE, 0xE5, 0x1F, 0x9F, 0xE6, 0x7E, 0xDB, 0x57, 0x8A, 0x7A, 0x21, 0x40,
+ 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05,
+ 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14,
+ 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x1F, 0xE7, 0xE7, 0xFF, 0x00, 0x07, 0x3E,
+ 0xFF, 0x00, 0xCA, 0x73, 0xFF, 0x00, 0xE0, 0x90, 0xFF, 0x00, 0xF6, 0x0A, 0xF8, 0x7B, 0xFF, 0x00,
+ 0xAB, 0x7A, 0xE6, 0xBB, 0x32, 0xCF, 0xF9, 0x18, 0x61, 0xFF, 0x00, 0xC7, 0x0F, 0xFD, 0x29, 0x1C,
+ 0xF8, 0x9F, 0xF7, 0x5A, 0x9F, 0xE1, 0x7F, 0x91, 0xF6, 0xA5, 0x7E, 0xA6, 0x7C, 0x70, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x7E, 0xC1, 0x7F, 0xC1, 0x10, 0xBF, 0xE4, 0x44, 0xFD, 0xBA, 0xFF, 0x00, 0xEC,
+ 0xF9, 0xE0, 0xFF, 0x00, 0xD5, 0x0D, 0xF0, 0xCA, 0xBF, 0x3A, 0xE2, 0x0F, 0xF9, 0x1A, 0x4F, 0xD2,
+ 0x3F, 0xFA, 0x4A, 0x3E, 0xA3, 0x2B, 0xFF, 0x00, 0x72, 0x8F, 0xCF, 0xF3, 0x3F, 0x6D, 0xAB, 0xC5,
+ 0x3D, 0x10, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00,
+ 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02,
+ 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A,
+ 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28,
+ 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0,
+ 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80,
+ 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x0F, 0xF3, 0xF3, 0xFF,
+ 0x00, 0x83, 0x9F, 0x7F, 0xE5, 0x39, 0xFF, 0x00, 0xF0, 0x48, 0x7F, 0xFB, 0x05, 0x7C, 0x3D, 0xFF,
+ 0x00, 0xD5, 0xBD, 0x73, 0x5D, 0x99, 0x67, 0xFC, 0x8C, 0x30, 0xFF, 0x00, 0xE3, 0x87, 0xFE, 0x94,
+ 0x8E, 0x7C, 0x4F, 0xFB, 0xAD, 0x4F, 0xF0, 0xBF, 0xC8, 0xFB, 0x52, 0xBF, 0x53, 0x3E, 0x38, 0x28,
+ 0x00, 0xA0, 0x02, 0x80, 0x3F, 0x60, 0xBF, 0xE0, 0x88, 0x5F, 0xF2, 0x22, 0x7E, 0xDD, 0x7F, 0xF6,
+ 0x7C, 0xF0, 0x7F, 0xEA, 0x86, 0xF8, 0x65, 0x5F, 0x9D, 0x71, 0x07, 0xFC, 0x8D, 0x27, 0xE9, 0x1F,
+ 0xFD, 0x25, 0x1F, 0x51, 0x95, 0xFF, 0x00, 0xB9, 0x47, 0xE7, 0xF9, 0x9F, 0xB6, 0xD5, 0xE2, 0x9E,
+ 0x88, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40,
+ 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05,
+ 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x07, 0xF9, 0xF9, 0xFF, 0x00,
+ 0xC1, 0xCF, 0xBF, 0xF2, 0x9C, 0xFF, 0x00, 0xF8, 0x24, 0x3F, 0xFD, 0x82, 0xBE, 0x1E, 0xFF, 0x00,
+ 0xEA, 0xDE, 0xB9, 0xAE, 0xCC, 0xB3, 0xFE, 0x46, 0x18, 0x7F, 0xF1, 0xC3, 0xFF, 0x00, 0x4A, 0x47,
+ 0x3E, 0x27, 0xFD, 0xD6, 0xA7, 0xF8, 0x5F, 0xE4, 0x7D, 0xA9, 0x5F, 0xA9, 0x9F, 0x1C, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x1F, 0xB0, 0x5F, 0xF0, 0x44, 0x2F, 0xF9, 0x11, 0x3F, 0x6E, 0xBF, 0xFB, 0x3E,
+ 0x78, 0x3F, 0xF5, 0x43, 0x7C, 0x32, 0xAF, 0xCE, 0xB8, 0x83, 0xFE, 0x46, 0x93, 0xF4, 0x8F, 0xFE,
+ 0x92, 0x8F, 0xA8, 0xCA, 0xFF, 0x00, 0xDC, 0xA3, 0xF3, 0xFC, 0xCF, 0xDB, 0x6A, 0xF1, 0x4F, 0x44,
+ 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00,
+ 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02,
+ 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A,
+ 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28,
+ 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0,
+ 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80,
+ 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x03, 0xFC, 0xFC, 0xFF, 0x00, 0xE0,
+ 0xE7, 0xDF, 0xF9, 0x4E, 0x7F, 0xFC, 0x12, 0x1F, 0xFE, 0xC1, 0x5F, 0x0F, 0x7F, 0xF5, 0x6F, 0x5C,
+ 0xD7, 0x66, 0x59, 0xFF, 0x00, 0x23, 0x0C, 0x3F, 0xF8, 0xE1, 0xFF, 0x00, 0xA5, 0x23, 0x9F, 0x13,
+ 0xFE, 0xEB, 0x53, 0xFC, 0x2F, 0xF2, 0x3E, 0xD4, 0xAF, 0xD4, 0xCF, 0x8E, 0x0A, 0x00, 0x28, 0x00,
+ 0xA0, 0x0F, 0xD8, 0x2F, 0xF8, 0x22, 0x17, 0xFC, 0x88, 0x9F, 0xB7, 0x5F, 0xFD, 0x9F, 0x3C, 0x1F,
+ 0xFA, 0xA1, 0xBE, 0x19, 0x57, 0xE7, 0x5C, 0x41, 0xFF, 0x00, 0x23, 0x49, 0xFA, 0x47, 0xFF, 0x00,
+ 0x49, 0x47, 0xD4, 0x65, 0x7F, 0xEE, 0x51, 0xF9, 0xFE, 0x67, 0xED, 0xB5, 0x78, 0xA7, 0xA2, 0x14,
+ 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40,
+ 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05,
+ 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x01, 0xFE, 0x7E, 0x7F, 0xF0, 0x73, 0xEF,
+ 0xFC, 0xA7, 0x3F, 0xFE, 0x09, 0x0F, 0xFF, 0x00, 0x60, 0xAF, 0x87, 0xBF, 0xFA, 0xB7, 0xAE, 0x6B,
+ 0xB3, 0x2C, 0xFF, 0x00, 0x91, 0x86, 0x1F, 0xFC, 0x70, 0xFF, 0x00, 0xD2, 0x91, 0xCF, 0x89, 0xFF,
+ 0x00, 0x75, 0xA9, 0xFE, 0x17, 0xF9, 0x1F, 0x6A, 0x57, 0xEA, 0x67, 0xC7, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x07, 0xEC, 0x0F, 0xFC, 0x11, 0x0F, 0x8F, 0x01, 0xFE, 0xDD, 0x98, 0x03, 0x8F, 0xDB, 0x9E,
+ 0x1C, 0x0C, 0x71, 0xC7, 0xC0, 0x6F, 0x86, 0x58, 0x18, 0xFC, 0x05, 0x7E, 0x75, 0xC4, 0x1F, 0xF2,
+ 0x34, 0x9F, 0xA4, 0x7F, 0xF4, 0x94, 0x7D, 0x46, 0x57, 0xFE, 0xE5, 0x1F, 0x9F, 0xE6, 0x7E, 0xD2,
+ 0xEA, 0x1A, 0xA5, 0x86, 0x91, 0x65, 0x3E, 0xA3, 0xA9, 0xDD, 0xDA, 0xE9, 0xF6, 0x16, 0x91, 0x99,
+ 0x6E, 0x2E, 0xEE, 0xE5, 0x58, 0x2D, 0xE1, 0x50, 0x3A, 0x96, 0x38, 0x1D, 0xBA, 0x0F, 0xC2, 0xBC,
+ 0x68, 0xC5, 0xC9, 0xA8, 0xC5, 0x6B, 0xD1, 0x23, 0xBD, 0xB8, 0xC2, 0x37, 0x6E, 0xC8, 0xF3, 0xBD,
+ 0x3F, 0xE3, 0x1F, 0x82, 0xF5, 0x52, 0x4E, 0x9B, 0x79, 0x2C, 0xD6, 0xA8, 0x8C, 0xEF, 0xA8, 0x4D,
+ 0x6A, 0xF6, 0x9A, 0x64, 0x4A, 0xA3, 0xAB, 0xCC, 0xD8, 0x0A, 0x0E, 0x30, 0x33, 0x8C, 0xF1, 0x5B,
+ 0xAC, 0x25, 0x7D, 0x23, 0x18, 0xDD, 0xBD, 0x12, 0x5A, 0xBF, 0x44, 0x96, 0xBF, 0x77, 0xF9, 0x1C,
+ 0xEB, 0x15, 0x41, 0x26, 0xEF, 0x68, 0xA5, 0xBB, 0xD1, 0x76, 0xFE, 0xBA, 0x1A, 0xDF, 0xF0, 0xB2,
+ 0x7C, 0x2E, 0x93, 0xC3, 0x6C, 0xD7, 0xF0, 0xBB, 0x39, 0x09, 0x24, 0x96, 0xA4, 0x5C, 0xDA, 0xD9,
+ 0x64, 0x70, 0x67, 0x90, 0x7C, 0xB1, 0x83, 0x85, 0x00, 0x1E, 0x49, 0x2A, 0x00, 0xE6, 0xB3, 0x95,
+ 0x1A, 0x94, 0xE0, 0xE5, 0x52, 0x2E, 0x29, 0x2E, 0xAA, 0xDF, 0x72, 0x7F, 0xA6, 0x9A, 0x1A, 0xD2,
+ 0xAB, 0x4E, 0xB4, 0xE3, 0x4E, 0x8B, 0xBB, 0x6D, 0x24, 0x97, 0x77, 0xA2, 0x5F, 0x96, 0x9E, 0x87,
+ 0x87, 0xFC, 0x10, 0xFD, 0xAD, 0x3C, 0x27, 0xF1, 0xFB, 0xE2, 0xD7, 0xC6, 0x6F, 0x86, 0xBE, 0x03,
+ 0xF0, 0xBF, 0x89, 0x1B, 0x44, 0xF8, 0x29, 0x06, 0x95, 0x69, 0xAD, 0xFC, 0x42, 0xD4, 0x52, 0x1B,
+ 0x6F, 0x0F, 0xEB, 0x5A, 0x9E, 0xA4, 0xF7, 0x3B, 0xB4, 0xEB, 0x18, 0x55, 0x9A, 0x43, 0xE5, 0x43,
+ 0x69, 0x1C, 0x85, 0xDF, 0x69, 0x22, 0x55, 0x1B, 0x14, 0x05, 0x2F, 0xF3, 0xF9, 0x4E, 0x77, 0x4B,
+ 0x37, 0xC5, 0x62, 0xA8, 0xE1, 0x69, 0xB5, 0x4A, 0x83, 0x8C, 0x1C, 0xDD, 0x92, 0x94, 0xDA, 0x72,
+ 0x6A, 0x29, 0x74, 0x84, 0x79, 0x5B, 0x6E, 0xD7, 0xE6, 0x49, 0x2B, 0x2B, 0x9F, 0xA0, 0x71, 0x7F,
+ 0x01, 0xE2, 0xF8, 0x27, 0x2A, 0xCA, 0x31, 0x39, 0xAE, 0x22, 0x0F, 0x17, 0x8E, 0xA7, 0x52, 0xB2,
+ 0xA1, 0x04, 0xDB, 0xA3, 0x46, 0x32, 0x8C, 0x29, 0xCE, 0xAC, 0x9D, 0x92, 0x95, 0x69, 0xAA, 0xAA,
+ 0x10, 0x8A, 0x92, 0x51, 0xA5, 0x26, 0xE7, 0x76, 0xA2, 0xBE, 0xAC, 0x0C, 0x78, 0x18, 0x00, 0x70,
+ 0x38, 0x18, 0xC0, 0xF6, 0xAF, 0x70, 0xF8, 0x42, 0x4A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A,
+ 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28,
+ 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0,
+ 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80,
+ 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00,
+ 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00,
+ 0xA0, 0x02, 0x80, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x02, 0x80, 0x0A, 0x00, 0xFF, 0x00, 0x3F, 0x3F,
+ 0xF8, 0x39, 0xF7, 0xFE, 0x53, 0x9F, 0xFF, 0x00, 0x04, 0x87, 0xFF, 0x00, 0xB0, 0x57, 0xC3, 0xDF,
+ 0xFD, 0x5B, 0xD7, 0x35, 0xD9, 0x96, 0x7F, 0xC8, 0xC3, 0x0F, 0xFE, 0x38, 0x7F, 0xE9, 0x48, 0xE7,
+ 0xC4, 0xFF, 0x00, 0xBA, 0xD4, 0xFF, 0x00, 0x0B, 0xFC, 0x8F, 0xB5, 0x2B, 0xF5, 0x33, 0xE3, 0x82,
+ 0x80, 0x0A, 0x00, 0x28, 0x03, 0xF6, 0x07, 0xFE, 0x08, 0x88, 0x3F, 0xE2, 0x83, 0xFD, 0xBB, 0x00,
+ 0x1F, 0xF3, 0x7C, 0xD0, 0x80, 0x00, 0xFF, 0x00, 0xAA, 0x0D, 0xF0, 0xCB, 0x00, 0x0F, 0xCA, 0xBF,
+ 0x3A, 0xE2, 0x0F, 0xF9, 0x1A, 0x4F, 0xD2, 0x3F, 0xFA, 0x4A, 0x3E, 0xA3, 0x2B, 0xFF, 0x00, 0x72,
+ 0x8F, 0xCF, 0xF3, 0x3E, 0x97, 0xFD, 0xA5, 0x7E, 0x2D, 0x34, 0xDE, 0x21, 0xB9, 0xD1, 0x61, 0x96,
+ 0x39, 0x74, 0xAD, 0x06, 0xFB, 0xFB, 0x1B, 0x4A, 0xD3, 0x64, 0x6C, 0xD9, 0x6A, 0x5A, 0x8A, 0x45,
+ 0xBA, 0xEA, 0xE6, 0xE2, 0x3E, 0x03, 0xA4, 0x0A, 0xCA, 0x02, 0x9E, 0x09, 0x64, 0x07, 0x86, 0x61,
+ 0x5E, 0xE7, 0x09, 0x64, 0x51, 0xCC, 0x6B, 0x27, 0x51, 0xDA, 0x9A, 0x4A, 0x52, 0xB6, 0x8E, 0xD7,
+ 0xB2, 0x8A, 0x7D, 0x39, 0xAC, 0xEE, 0xD5, 0xAC, 0x93, 0xD9, 0xD9, 0x9F, 0x39, 0xC5, 0x19, 0xC5,
+ 0x5C, 0xBF, 0x0C, 0xFD, 0x84, 0x53, 0x9B, 0xD2, 0x2B, 0xA5, 0xEC, 0xAF, 0x26, 0xBA, 0xF2, 0xDD,
+ 0x24, 0xB6, 0x6D, 0xAD, 0x2D, 0x73, 0xE7, 0x18, 0xFE, 0x21, 0xF8, 0x9F, 0xC1, 0xDA, 0x2D, 0xFE,
+ 0xBB, 0x67, 0xE2, 0x6D, 0x59, 0xAD, 0xAC, 0xE5, 0x8E, 0xEF, 0x56, 0x94, 0xA2, 0x6A, 0x16, 0x2A,
+ 0xF2, 0x0D, 0x89, 0xE7, 0x40, 0x57, 0x6E, 0xCF, 0x9B, 0x6A, 0xA7, 0xCA, 0xA0, 0xE0, 0x28, 0x1C,
+ 0x63, 0xF4, 0x4C, 0x5E, 0x55, 0x93, 0x4E, 0x2A, 0x18, 0xBA, 0x10, 0x8C, 0x23, 0x16, 0xA3, 0xBC,
+ 0x5A, 0x4A, 0xCF, 0xDD, 0x6B, 0x54, 0xF4, 0x57, 0x69, 0x37, 0x6F, 0x2D, 0x0F, 0x81, 0xCA, 0xF1,
+ 0x79, 0xCA, 0xA9, 0x7A, 0x35, 0xE6, 0xE5, 0x27, 0x79, 0x27, 0x66, 0x9B, 0xDB, 0x54, 0xD3, 0xBD,
+ 0x96, 0xC9, 0xB4, 0x96, 0xCA, 0xC7, 0xCD, 0xFA, 0x67, 0xED, 0xE7, 0xF0, 0xC7, 0xE2, 0x47, 0xC5,
+ 0x2F, 0x89, 0x9A, 0x3E, 0x89, 0xAF, 0x6A, 0xDA, 0xEF, 0x8A, 0x7E, 0x0B, 0xFC, 0x38, 0xD7, 0xFC,
+ 0x49, 0xE2, 0x6F, 0x12, 0xE8, 0x36, 0x57, 0x1E, 0x13, 0xF0, 0x5E, 0x9D, 0x69, 0xA6, 0xBC, 0x56,
+ 0xD1, 0x59, 0xEA, 0x71, 0xDB, 0xDA, 0x8D, 0x3E, 0x49, 0x52, 0xFA, 0xEA, 0x03, 0xE4, 0xBD, 0xE4,
+ 0xB2, 0xAB, 0xBC, 0x8A, 0xE9, 0xFE, 0x8F, 0xB6, 0x2F, 0xC5, 0xF8, 0xBB, 0x38, 0xC3, 0x65, 0x99,
+ 0x06, 0x2A, 0x8E, 0x12, 0x2A, 0x34, 0xED, 0x6E, 0x4B, 0xBA, 0x8E, 0x32, 0xB3, 0x4E, 0xD3, 0x92,
+ 0xD1, 0xDB, 0x44, 0xA2, 0x96, 0xC9, 0xA4, 0x9B, 0x77, 0xFE, 0x82, 0xF0, 0xB7, 0x86, 0x71, 0x1C,
+ 0x49, 0xC6, 0xD9, 0x6E, 0x12, 0xB3, 0xE6, 0x6E, 0x71, 0x6E, 0x56, 0x50, 0x4E, 0x11, 0x69, 0xEB,
+ 0x05, 0xA5, 0xAF, 0x67, 0x77, 0xD3, 0x76, 0xD2, 0x56, 0xFD, 0x28, 0xFF, 0x00, 0x82, 0x64, 0xFC,
+ 0x31, 0x87, 0xC0, 0x5F, 0xB2, 0xE6, 0x81, 0xE3, 0x8B, 0xFB, 0xA4, 0xB9, 0xF1, 0x3F, 0xC7, 0xAB,
+ 0xF9, 0x7E, 0x36, 0xF8, 0xA6, 0xE4, 0x4F, 0x14, 0xF6, 0xD1, 0x2E, 0xB0, 0x8A, 0xDA, 0x54, 0x31,
+ 0x4A, 0xA0, 0x65, 0x23, 0xD3, 0x23, 0xD3, 0x81, 0x25, 0x98, 0x6E, 0xF3, 0x08, 0xC0, 0x38, 0x1F,
+ 0x27, 0xC3, 0xD9, 0x5A, 0xCA, 0x32, 0x8A, 0x38, 0x49, 0x2F, 0xDE, 0xB5, 0xCF, 0x51, 0xF7, 0x9C,
+ 0xFD, 0xE9, 0x7F, 0xE0, 0x37, 0x50, 0x5F, 0xDD, 0x8A, 0x3E, 0xAB, 0xC4, 0xAE, 0x2C, 0x5C, 0x67,
+ 0xC6, 0xB8, 0xEC, 0xDF, 0x0F, 0x2F, 0xF6, 0x48, 0x38, 0xD0, 0xC3, 0xAE, 0x91, 0xC3, 0xD0, 0x8A,
+ 0xA7, 0x4A, 0xCB, 0xA7, 0x3A, 0x8B, 0xAB, 0x2F, 0xEF, 0xD4, 0x91, 0xFA, 0x15, 0x14, 0xF6, 0xEE,
+ 0x91, 0xC9, 0x1C, 0xF6, 0xEF, 0x13, 0xAA, 0xBC, 0x6F, 0x1C, 0xC8, 0xC8, 0xCA, 0x47, 0xCA, 0x54,
+ 0x83, 0x82, 0x08, 0xC7, 0x4A, 0xF6, 0x8F, 0x85, 0x27, 0xF3, 0xA0, 0xFF, 0x00, 0x9E, 0xB1, 0x7F,
+ 0xDF, 0x6B, 0x40, 0x07, 0x9D, 0x07, 0xFC, 0xF5, 0x8B, 0xFE, 0xFB, 0x5A, 0x00, 0x3C, 0xE8, 0x3F,
+ 0xE7, 0xAC, 0x5F, 0xF7, 0xDA, 0xD0, 0x01, 0xE7, 0x41, 0xFF, 0x00, 0x3D, 0x62, 0xFF, 0x00, 0xBE,
+ 0xD6, 0x80, 0x0F, 0x3A, 0x0F, 0xF9, 0xEB, 0x17, 0xFD, 0xF6, 0xB4, 0x00, 0x79, 0xD0, 0x7F, 0xCF,
+ 0x58, 0xBF, 0xEF, 0xB5, 0xA0, 0x03, 0xCE, 0x83, 0xFE, 0x7A, 0xC5, 0xFF, 0x00, 0x7D, 0xAD, 0x00,
+ 0x1E, 0x74, 0x1F, 0xF3, 0xD6, 0x2F, 0xFB, 0xED, 0x68, 0x00, 0xF3, 0xA0, 0xFF, 0x00, 0x9E, 0xB1,
+ 0x7F, 0xDF, 0x6B, 0x40, 0x07, 0x9D, 0x07, 0xFC, 0xF5, 0x8B, 0xFE, 0xFB, 0x5A, 0x00, 0x3C, 0xE8,
+ 0x3F, 0xE7, 0xAC, 0x5F, 0xF7, 0xDA, 0xD0, 0x01, 0xE7, 0x41, 0xFF, 0x00, 0x3D, 0x62, 0xFF, 0x00,
+ 0xBE, 0xD6, 0x80, 0x0F, 0x3A, 0x0F, 0xF9, 0xEB, 0x17, 0xFD, 0xF6, 0xB4, 0x00, 0x79, 0xD0, 0x7F,
+ 0xCF, 0x58, 0xBF, 0xEF, 0xB5, 0xA0, 0x03, 0xCE, 0x83, 0xFE, 0x7A, 0xC5, 0xFF, 0x00, 0x7D, 0xAD,
+ 0x00, 0x1E, 0x74, 0x1F, 0xF3, 0xD6, 0x2F, 0xFB, 0xED, 0x68, 0x00, 0xF3, 0xA0, 0xFF, 0x00, 0x9E,
+ 0xB1, 0x7F, 0xDF, 0x6B, 0x40, 0x07, 0x9D, 0x07, 0xFC, 0xF5, 0x8B, 0xFE, 0xFB, 0x5A, 0x00, 0x3C,
+ 0xE8, 0x3F, 0xE7, 0xAC, 0x5F, 0xF7, 0xDA, 0xD0, 0x01, 0xE7, 0x41, 0xFF, 0x00, 0x3D, 0x62, 0xFF,
+ 0x00, 0xBE, 0xD6, 0x80, 0x0F, 0x3A, 0x0F, 0xF9, 0xEB, 0x17, 0xFD, 0xF6, 0xB4, 0x00, 0x79, 0xD0,
+ 0x7F, 0xCF, 0x58, 0xBF, 0xEF, 0xB5, 0xA0, 0x03, 0xCE, 0x83, 0xFE, 0x7A, 0xC5, 0xFF, 0x00, 0x7D,
+ 0xAD, 0x00, 0x1E, 0x74, 0x1F, 0xF3, 0xD6, 0x2F, 0xFB, 0xED, 0x68, 0x00, 0xF3, 0xA0, 0xFF, 0x00,
+ 0x9E, 0xB1, 0x7F, 0xDF, 0x6B, 0x40, 0x07, 0x9D, 0x07, 0xFC, 0xF5, 0x8B, 0xFE, 0xFB, 0x5A, 0x00,
+ 0x3C, 0xE8, 0x3F, 0xE7, 0xAC, 0x5F, 0xF7, 0xDA, 0xD0, 0x01, 0xE7, 0x41, 0xFF, 0x00, 0x3D, 0x62,
+ 0xFF, 0x00, 0xBE, 0xD6, 0x80, 0x0F, 0x3A, 0x0F, 0xF9, 0xEB, 0x17, 0xFD, 0xF6, 0xB4, 0x00, 0x79,
+ 0xD0, 0x7F, 0xCF, 0x58, 0xBF, 0xEF, 0xB5, 0xA0, 0x03, 0xCE, 0x83, 0xFE, 0x7A, 0xC5, 0xFF, 0x00,
+ 0x7D, 0xAD, 0x00, 0x1E, 0x74, 0x1F, 0xF3, 0xD6, 0x2F, 0xFB, 0xED, 0x68, 0x00, 0xF3, 0xA0, 0xFF,
+ 0x00, 0x9E, 0xB1, 0x7F, 0xDF, 0x6B, 0x40, 0x07, 0x9D, 0x07, 0xFC, 0xF5, 0x8B, 0xFE, 0xFB, 0x5A,
+ 0x00, 0x3C, 0xE8, 0x3F, 0xE7, 0xAC, 0x5F, 0xF7, 0xDA, 0xD0, 0x01, 0xE7, 0x41, 0xFF, 0x00, 0x3D,
+ 0x62, 0xFF, 0x00, 0xBE, 0xD6, 0x80, 0x0F, 0x3A, 0x0F, 0xF9, 0xEB, 0x17, 0xFD, 0xF6, 0xB4, 0x00,
+ 0x79, 0xD0, 0x7F, 0xCF, 0x58, 0xBF, 0xEF, 0xB5, 0xA0, 0x03, 0xCE, 0x83, 0xFE, 0x7A, 0xC5, 0xFF,
+ 0x00, 0x7D, 0xAD, 0x00, 0x1E, 0x74, 0x1F, 0xF3, 0xD6, 0x2F, 0xFB, 0xED, 0x68, 0x00, 0xF3, 0xA0,
+ 0xFF, 0x00, 0x9E, 0xB1, 0x7F, 0xDF, 0x6B, 0x40, 0x07, 0x9D, 0x07, 0xFC, 0xF5, 0x8B, 0xFE, 0xFB,
+ 0x5A, 0x00, 0x3C, 0xE8, 0x3F, 0xE7, 0xAC, 0x5F, 0xF7, 0xDA, 0xD0, 0x01, 0xE7, 0x41, 0xFF, 0x00,
+ 0x3D, 0x62, 0xFF, 0x00, 0xBE, 0xD6, 0x80, 0x0F, 0x3A, 0x0F, 0xF9, 0xEB, 0x17, 0xFD, 0xF6, 0xB4,
+ 0x00, 0x79, 0xD0, 0x7F, 0xCF, 0x58, 0xBF, 0xEF, 0xB5, 0xA0, 0x03, 0xCE, 0x83, 0xFE, 0x7A, 0xC5,
+ 0xFF, 0x00, 0x7D, 0xAD, 0x00, 0x1E, 0x74, 0x1F, 0xF3, 0xD6, 0x2F, 0xFB, 0xED, 0x68, 0x00, 0xF3,
+ 0xA0, 0xFF, 0x00, 0x9E, 0xB1, 0x7F, 0xDF, 0x6B, 0x40, 0x07, 0x9D, 0x07, 0xFC, 0xF5, 0x8B, 0xFE,
+ 0xFB, 0x5A, 0x00, 0x3C, 0xE8, 0x3F, 0xE7, 0xAC, 0x5F, 0xF7, 0xDA, 0xD0, 0x01, 0xE7, 0x41, 0xFF,
+ 0x00, 0x3D, 0x62, 0xFF, 0x00, 0xBE, 0xD6, 0x80, 0x0F, 0x3A, 0x0F, 0xF9, 0xEB, 0x17, 0xFD, 0xF6,
+ 0xB4, 0x00, 0x79, 0xD0, 0x7F, 0xCF, 0x58, 0xBF, 0xEF, 0xB5, 0xA0, 0x03, 0xCE, 0x83, 0xFE, 0x7A,
+ 0xC5, 0xFF, 0x00, 0x7D, 0xAD, 0x00, 0x3D, 0x1E, 0x37, 0xFF, 0x00, 0x56, 0xC8, 0xDB, 0x71, 0xF7,
+ 0x08, 0x38, 0xF4, 0xE9, 0xF4, 0xA0, 0x07, 0x0C, 0x76, 0xC7, 0x1C, 0x71, 0x8E, 0x31, 0xDB, 0xF9,
+ 0x50, 0x07, 0xF9, 0xF9, 0xFF, 0x00, 0xC1, 0xCF, 0xBF, 0xF2, 0x9C, 0xFF, 0x00, 0xF8, 0x24, 0x3F,
+ 0xFD, 0x82, 0xBE, 0x1E, 0xFF, 0x00, 0xEA, 0xDE, 0xB9, 0xAE, 0xCC, 0xB3, 0xFE, 0x46, 0x18, 0x7F,
+ 0xF1, 0xC3, 0xFF, 0x00, 0x4A, 0x47, 0x3E, 0x27, 0xFD, 0xD6, 0xA7, 0xF8, 0x5F, 0xE4, 0x7D, 0xA9,
+ 0x5F, 0xA9, 0x9F, 0x1C, 0x14, 0x00, 0x50, 0x01, 0x40, 0x1F, 0xB0, 0x5F, 0xF0, 0x44, 0x3C, 0x0F,
+ 0x01, 0xFE, 0xDD, 0x7C, 0x70, 0x3F, 0x6E, 0x78, 0x78, 0x00, 0x74, 0x1F, 0x01, 0xBE, 0x19, 0x70,
+ 0x07, 0xE1, 0x5F, 0x9D, 0x71, 0x07, 0xFC, 0x8D, 0x27, 0xE9, 0x1F, 0xFD, 0x25, 0x1F, 0x51, 0x95,
+ 0xFF, 0x00, 0xB9, 0x47, 0xE7, 0xF9, 0x9E, 0x5F, 0xFF, 0x00, 0x05, 0x05, 0xF8, 0x53, 0xFB, 0x61,
+ 0x6A, 0x7A, 0xCF, 0xC2, 0x9D, 0x67, 0xF6, 0x45, 0xF0, 0x55, 0xAF, 0x8B, 0xBC, 0x6B, 0xE0, 0x6F,
+ 0x8C, 0xFE, 0x36, 0x87, 0xE2, 0x5F, 0x87, 0x6F, 0xEC, 0x34, 0xF9, 0xB4, 0x6D, 0x73, 0x48, 0xD7,
+ 0xBC, 0x25, 0x72, 0xDE, 0x15, 0xBC, 0xBE, 0x8A, 0xEA, 0x78, 0x16, 0x68, 0x63, 0xD6, 0xA1, 0xD2,
+ 0xB7, 0x6D, 0x95, 0x02, 0x70, 0xD2, 0x1F, 0x25, 0x1C, 0x1D, 0xF0, 0x39, 0xC6, 0x2F, 0x2F, 0xA2,
+ 0xFE, 0xA7, 0x51, 0xC1, 0xB4, 0xAC, 0xD5, 0xB4, 0xB4, 0x5A, 0x6B, 0xE6, 0xDA, 0xB5, 0xBF, 0x03,
+ 0x8F, 0x15, 0x97, 0x61, 0xB1, 0x53, 0x51, 0xC4, 0xD3, 0x52, 0x49, 0xED, 0xF3, 0x56, 0x7F, 0x72,
+ 0xF4, 0xD9, 0x1E, 0x85, 0xFB, 0x2A, 0x78, 0x1B, 0xE2, 0x27, 0x84, 0xFE, 0x23, 0xF8, 0xEF, 0xE1,
+ 0x4F, 0xC5, 0x0F, 0x0C, 0xBF, 0x88, 0xBE, 0x0C, 0x7C, 0x40, 0xF8, 0x2F, 0xA8, 0x6B, 0x9A, 0xBF,
+ 0xC6, 0x4F, 0x16, 0xAD, 0xEE, 0x8D, 0xE2, 0xBF, 0x01, 0x6B, 0x3A, 0x9E, 0xA5, 0x2D, 0xD4, 0xFE,
+ 0x12, 0xBD, 0xB5, 0x2F, 0xFD, 0x9F, 0x25, 0xAE, 0x9D, 0x0D, 0xDD, 0x9C, 0x11, 0xDC, 0xDB, 0xB2,
+ 0x4B, 0x14, 0x96, 0x8A, 0x92, 0x83, 0xB5, 0x2E, 0x6E, 0x3A, 0x33, 0x6C, 0xF7, 0x33, 0xCC, 0x79,
+ 0x53, 0xA8, 0xB9, 0x23, 0x2E, 0x68, 0x28, 0xDA, 0xEA, 0x4E, 0xE9, 0xEC, 0x93, 0xB5, 0x9D, 0xA2,
+ 0x9E, 0xD1, 0x56, 0x77, 0x32, 0xCB, 0x72, 0x9C, 0x06, 0x0E, 0xEE, 0x30, 0xF7, 0x9C, 0x79, 0x64,
+ 0xF5, 0x4A, 0xDA, 0x59, 0x5A, 0xF6, 0xBE, 0x8A, 0xF6, 0xEB, 0xB5, 0x96, 0x87, 0xE0, 0xDF, 0xC3,
+ 0x2D, 0x53, 0x4B, 0xFD, 0x89, 0x7C, 0x03, 0xE2, 0xBF, 0xD9, 0xCF, 0xE2, 0xD7, 0xC0, 0xFF, 0x00,
+ 0x1E, 0x6A, 0x7F, 0x16, 0x9F, 0xC5, 0x7E, 0x1D, 0x87, 0xC4, 0xA9, 0xE0, 0xFF, 0x00, 0x09, 0xEB,
+ 0x9E, 0x35, 0xF0, 0xFF, 0x00, 0xED, 0x37, 0xA0, 0xE9, 0x12, 0xC2, 0x91, 0xE9, 0xFE, 0x18, 0xD7,
+ 0xEC, 0xEC, 0xA6, 0xD3, 0x17, 0x4E, 0xD4, 0xE1, 0xB6, 0x37, 0x22, 0x69, 0xE7, 0x52, 0x3E, 0xDD,
+ 0x2F, 0x9E, 0x91, 0xBC, 0x6C, 0xAD, 0xF1, 0x39, 0xBE, 0x0E, 0xB6, 0x61, 0x84, 0xC2, 0xE1, 0xE2,
+ 0xD2, 0x54, 0xAA, 0xC6, 0x72, 0x8C, 0xA2, 0xF9, 0x66, 0x94, 0x93, 0x6B, 0x99, 0x3B, 0xDD, 0x24,
+ 0xD2, 0x4E, 0x2E, 0x29, 0xA5, 0x7B, 0xA6, 0xED, 0xFA, 0x4F, 0x05, 0xF1, 0x0E, 0x0B, 0x86, 0xB1,
+ 0x39, 0x8D, 0x7A, 0xF4, 0xE6, 0xE7, 0x88, 0xC2, 0xD5, 0xA1, 0x4E, 0xA5, 0x29, 0xC5, 0x4E, 0x8C,
+ 0xAA, 0x53, 0x71, 0x8C, 0xB9, 0x64, 0xAC, 0xE3, 0x76, 0xB9, 0xB9, 0x65, 0x19, 0x72, 0xDD, 0xC1,
+ 0xA9, 0x28, 0x9F, 0xD3, 0xF7, 0xFC, 0x12, 0x93, 0xC0, 0xDF, 0x13, 0x7C, 0x09, 0xFB, 0x17, 0x7C,
+ 0x3F, 0xD0, 0xBE, 0x2C, 0x68, 0x51, 0x78, 0x63, 0x56, 0xB8, 0xBF, 0xD5, 0x75, 0x2D, 0x1F, 0xC1,
+ 0x28, 0x64, 0x96, 0xD3, 0xC1, 0x1A, 0x45, 0xEE, 0xA1, 0x34, 0xF6, 0x1A, 0x0C, 0x0B, 0x20, 0x04,
+ 0x5B, 0x59, 0xC5, 0x70, 0x2D, 0x22, 0x4C, 0x00, 0xB1, 0x5B, 0xC4, 0x80, 0x2A, 0xA8, 0x55, 0xEE,
+ 0x6F, 0x44, 0xBB, 0x1F, 0x25, 0x45, 0x24, 0x9D, 0x92, 0x4B, 0x45, 0xA6, 0xDA, 0x2B, 0x69, 0xF9,
+ 0x7C, 0x8F, 0x34, 0xF1, 0xF7, 0xFC, 0x10, 0x9B, 0xFE, 0x09, 0x35, 0xF1, 0x2B, 0xC5, 0xBA, 0xDF,
+ 0x8D, 0xBC, 0x49, 0xFB, 0x11, 0x7C, 0x0E, 0x4F, 0x10, 0x78, 0x97, 0x53, 0x9F, 0x59, 0xD6, 0xE7,
+ 0xD1, 0x7C, 0x13, 0x61, 0xA1, 0xDA, 0xDF, 0xDD, 0xDD, 0x4A, 0xD2, 0x5C, 0x5C, 0x35, 0xBC, 0x30,
+ 0xAC, 0x61, 0xDE, 0x49, 0x1D, 0x8E, 0xD5, 0x03, 0x24, 0xD2, 0x36, 0x39, 0x0F, 0xF8, 0x87, 0xA7,
+ 0xFE, 0x08, 0xFF, 0x00, 0xFF, 0x00, 0x46, 0x51, 0xF0, 0x97, 0xFF, 0x00, 0x09, 0xFB, 0x6F, 0xFE,
+ 0x37, 0x40, 0x07, 0xFC, 0x43, 0xD3, 0xFF, 0x00, 0x04, 0x7F, 0xFF, 0x00, 0xA3, 0x28, 0xF8, 0x4B,
+ 0xFF, 0x00, 0x84, 0xFD, 0xB7, 0xFF, 0x00, 0x1B, 0xA0, 0x03, 0xFE, 0x21, 0xE9, 0xFF, 0x00, 0x82,
+ 0x3F, 0xFF, 0x00, 0xD1, 0x94, 0x7C, 0x25, 0xFF, 0x00, 0xC2, 0x7E, 0xDB, 0xFF, 0x00, 0x8D, 0xD0,
+ 0x01, 0xFF, 0x00, 0x10, 0xF4, 0xFF, 0x00, 0xC1, 0x1F, 0xFF, 0x00, 0xE8, 0xCA, 0x3E, 0x12, 0xFF,
+ 0x00, 0xE1, 0x3F, 0x6D, 0xFF, 0x00, 0xC6, 0xE8, 0x00, 0xFF, 0x00, 0x88, 0x7A, 0x7F, 0xE0, 0x8F,
+ 0xFF, 0x00, 0xF4, 0x65, 0x1F, 0x09, 0x7F, 0xF0, 0x9F, 0xB6, 0xFF, 0x00, 0xE3, 0x74, 0x00, 0x7F,
+ 0xC4, 0x3D, 0x3F, 0xF0, 0x47, 0xFF, 0x00, 0xFA, 0x32, 0x8F, 0x84, 0xBF, 0xF8, 0x4F, 0xDB, 0x7F,
+ 0xF1, 0xBA, 0x00, 0x3F, 0xE2, 0x1E, 0x9F, 0xF8, 0x23, 0xFF, 0x00, 0xFD, 0x19, 0x47, 0xC2, 0x5F,
+ 0xFC, 0x27, 0xED, 0xBF, 0xF8, 0xDD, 0x00, 0x1F, 0xF1, 0x0F, 0x4F, 0xFC, 0x11, 0xFF, 0x00, 0xFE,
+ 0x8C, 0xA3, 0xE1, 0x2F, 0xFE, 0x13, 0xF6, 0xDF, 0xFC, 0x6E, 0x80, 0x0F, 0xF8, 0x87, 0xA7, 0xFE,
+ 0x08, 0xFF, 0x00, 0xFF, 0x00, 0x46, 0x51, 0xF0, 0x97, 0xFF, 0x00, 0x09, 0xFB, 0x6F, 0xFE, 0x37,
+ 0x40, 0x07, 0xFC, 0x43, 0xD3, 0xFF, 0x00, 0x04, 0x7F, 0xFF, 0x00, 0xA3, 0x28, 0xF8, 0x4B, 0xFF,
+ 0x00, 0x84, 0xFD, 0xB7, 0xFF, 0x00, 0x1B, 0xA0, 0x03, 0xFE, 0x21, 0xE9, 0xFF, 0x00, 0x82, 0x3F,
+ 0xFF, 0x00, 0xD1, 0x94, 0x7C, 0x25, 0xFF, 0x00, 0xC2, 0x7E, 0xDB, 0xFF, 0x00, 0x8D, 0xD0, 0x01,
+ 0xFF, 0x00, 0x10, 0xF4, 0xFF, 0x00, 0xC1, 0x1F, 0xFF, 0x00, 0xE8, 0xCA, 0x3E, 0x12, 0xFF, 0x00,
+ 0xE1, 0x3F, 0x6D, 0xFF, 0x00, 0xC6, 0xE8, 0x00, 0xFF, 0x00, 0x88, 0x7A, 0x7F, 0xE0, 0x8F, 0xFF,
+ 0x00, 0xF4, 0x65, 0x1F, 0x09, 0x7F, 0xF0, 0x9F, 0xB6, 0xFF, 0x00, 0xE3, 0x74, 0x00, 0x7F, 0xC4,
+ 0x3D, 0x3F, 0xF0, 0x47, 0xFF, 0x00, 0xFA, 0x32, 0x8F, 0x84, 0xBF, 0xF8, 0x4F, 0xDB, 0x7F, 0xF1,
+ 0xBA, 0x00, 0x3F, 0xE2, 0x1E, 0x9F, 0xF8, 0x23, 0xFF, 0x00, 0xFD, 0x19, 0x47, 0xC2, 0x5F, 0xFC,
+ 0x27, 0xED, 0xBF, 0xF8, 0xDD, 0x00, 0x1F, 0xF1, 0x0F, 0x4F, 0xFC, 0x11, 0xFF, 0x00, 0xFE, 0x8C,
+ 0xA3, 0xE1, 0x2F, 0xFE, 0x13, 0xF6, 0xDF, 0xFC, 0x6E, 0x80, 0x0F, 0xF8, 0x87, 0xA7, 0xFE, 0x08,
+ 0xFF, 0x00, 0xFF, 0x00, 0x46, 0x51, 0xF0, 0x97, 0xFF, 0x00, 0x09, 0xFB, 0x6F, 0xFE, 0x37, 0x40,
+ 0x07, 0xFC, 0x43, 0xD3, 0xFF, 0x00, 0x04, 0x7F, 0xFF, 0x00, 0xA3, 0x28, 0xF8, 0x4B, 0xFF, 0x00,
+ 0x84, 0xFD, 0xB7, 0xFF, 0x00, 0x1B, 0xA0, 0x03, 0xFE, 0x21, 0xE9, 0xFF, 0x00, 0x82, 0x3F, 0xFF,
+ 0x00, 0xD1, 0x94, 0x7C, 0x25, 0xFF, 0x00, 0xC2, 0x7E, 0xDB, 0xFF, 0x00, 0x8D, 0xD0, 0x01, 0xFF,
+ 0x00, 0x10, 0xF4, 0xFF, 0x00, 0xC1, 0x1F, 0xFF, 0x00, 0xE8, 0xCA, 0x3E, 0x12, 0xFF, 0x00, 0xE1,
+ 0x3F, 0x6D, 0xFF, 0x00, 0xC6, 0xE8, 0x00, 0xFF, 0x00, 0x88, 0x7A, 0x7F, 0xE0, 0x8F, 0xFF, 0x00,
+ 0xF4, 0x65, 0x1F, 0x09, 0x7F, 0xF0, 0x9F, 0xB6, 0xFF, 0x00, 0xE3, 0x74, 0x00, 0x7F, 0xC4, 0x3D,
+ 0x3F, 0xF0, 0x47, 0xFF, 0x00, 0xFA, 0x32, 0x8F, 0x84, 0xBF, 0xF8, 0x4F, 0xDB, 0x7F, 0xF1, 0xBA,
+ 0x00, 0x3F, 0xE2, 0x1E, 0x9F, 0xF8, 0x23, 0xFF, 0x00, 0xFD, 0x19, 0x47, 0xC2, 0x5F, 0xFC, 0x27,
+ 0xED, 0xBF, 0xF8, 0xDD, 0x00, 0x1F, 0xF1, 0x0F, 0x4F, 0xFC, 0x11, 0xFF, 0x00, 0xFE, 0x8C, 0xA3,
+ 0xE1, 0x2F, 0xFE, 0x13, 0xF6, 0xDF, 0xFC, 0x6E, 0x80, 0x0F, 0xF8, 0x87, 0xA7, 0xFE, 0x08, 0xFF,
+ 0x00, 0xFF, 0x00, 0x46, 0x51, 0xF0, 0x97, 0xFF, 0x00, 0x09, 0xFB, 0x6F, 0xFE, 0x37, 0x40, 0x1C,
+ 0x7F, 0x8F, 0xFF, 0x00, 0xE0, 0x85, 0x9F, 0xF0, 0x44, 0x0F, 0x84, 0xFE, 0x0C, 0xF1, 0x0F, 0xC4,
+ 0x5F, 0x8A, 0x5F, 0xB3, 0x0F, 0xEC, 0xEB, 0xF0, 0xD3, 0xE1, 0xEF, 0x84, 0x74, 0xF3, 0xAA, 0xF8,
+ 0xAF, 0xC7, 0x7E, 0x3F, 0x9B, 0x49, 0xF0, 0x6F, 0x83, 0x3C, 0x31, 0x68, 0xAC, 0x15, 0xAE, 0x75,
+ 0x1D, 0x52, 0xEC, 0xC5, 0x6D, 0x6D, 0x10, 0x67, 0x41, 0xBE, 0x47, 0x45, 0x04, 0x81, 0x9E, 0x45,
+ 0x00, 0x76, 0x03, 0xFE, 0x0D, 0xEA, 0xFF, 0x00, 0x82, 0x3F, 0xE0, 0x63, 0xF6, 0x28, 0xF8, 0x4A,
+ 0x06, 0x06, 0x07, 0xFC, 0x23, 0xD6, 0xE3, 0x03, 0x1C, 0x0C, 0x79, 0x7F, 0x4A, 0x00, 0x3F, 0xE2,
+ 0x1E, 0x9F, 0xF8, 0x23, 0xFF, 0x00, 0xFD, 0x19, 0x47, 0xC2, 0x5F, 0xFC, 0x27, 0xED, 0xBF, 0xF8,
+ 0xDD, 0x00, 0x1F, 0xF1, 0x0F, 0x4F, 0xFC, 0x11, 0xFF, 0x00, 0xFE, 0x8C, 0xA3, 0xE1, 0x2F, 0xFE,
+ 0x13, 0xF6, 0xDF, 0xFC, 0x6E, 0x80, 0x0F, 0xF8, 0x87, 0xA7, 0xFE, 0x08, 0xFF, 0x00, 0xFF, 0x00,
+ 0x46, 0x51, 0xF0, 0x97, 0xFF, 0x00, 0x09, 0xFB, 0x6F, 0xFE, 0x37, 0x40, 0x07, 0xFC, 0x43, 0xD3,
+ 0xFF, 0x00, 0x04, 0x7F, 0xFF, 0x00, 0xA3, 0x28, 0xF8, 0x4B, 0xFF, 0x00, 0x84, 0xFD, 0xB7, 0xFF,
+ 0x00, 0x1B, 0xA0, 0x03, 0xFE, 0x21, 0xE9, 0xFF, 0x00, 0x82, 0x3F, 0xFF, 0x00, 0xD1, 0x94, 0x7C,
+ 0x25, 0xFF, 0x00, 0xC2, 0x7E, 0xDB, 0xFF, 0x00, 0x8D, 0xD0, 0x01, 0xFF, 0x00, 0x10, 0xF4, 0xFF,
+ 0x00, 0xC1, 0x1F, 0xFF, 0x00, 0xE8, 0xCA, 0x3E, 0x12, 0xFF, 0x00, 0xE1, 0x3F, 0x6D, 0xFF, 0x00,
+ 0xC6, 0xE8, 0x00, 0xFF, 0x00, 0x88, 0x7A, 0x7F, 0xE0, 0x8F, 0xFF, 0x00, 0xF4, 0x65, 0x1F, 0x09,
+ 0x7F, 0xF0, 0x9F, 0xB6, 0xFF, 0x00, 0xE3, 0x74, 0x00, 0x7F, 0xC4, 0x3D, 0x3F, 0xF0, 0x47, 0xFF,
+ 0x00, 0xFA, 0x32, 0x8F, 0x84, 0xBF, 0xF8, 0x4F, 0xDB, 0x7F, 0xF1, 0xBA, 0x00, 0x3F, 0xE2, 0x1E,
+ 0x9F, 0xF8, 0x23, 0xFF, 0x00, 0xFD, 0x19, 0x47, 0xC2, 0x5F, 0xFC, 0x27, 0xED, 0xBF, 0xF8, 0xDD,
+ 0x00, 0x1F, 0xF1, 0x0F, 0x4F, 0xFC, 0x11, 0xFF, 0x00, 0xFE, 0x8C, 0xA3, 0xE1, 0x2F, 0xFE, 0x13,
+ 0xF6, 0xDF, 0xFC, 0x6E, 0x80, 0x0F, 0xF8, 0x87, 0xA7, 0xFE, 0x08, 0xFF, 0x00, 0xFF, 0x00, 0x46,
+ 0x51, 0xF0, 0x97, 0xFF, 0x00, 0x09, 0xFB, 0x6F, 0xFE, 0x37, 0x40, 0x07, 0xFC, 0x43, 0xD3, 0xFF,
+ 0x00, 0x04, 0x7F, 0xFF, 0x00, 0xA3, 0x28, 0xF8, 0x4B, 0xFF, 0x00, 0x84, 0xFD, 0xB7, 0xFF, 0x00,
+ 0x1B, 0xA0, 0x03, 0xFE, 0x21, 0xE9, 0xFF, 0x00, 0x82, 0x3F, 0xFF, 0x00, 0xD1, 0x94, 0x7C, 0x25,
+ 0xFF, 0x00, 0xC2, 0x7E, 0xDB, 0xFF, 0x00, 0x8D, 0xD0, 0x01, 0xFF, 0x00, 0x10, 0xF4, 0xFF, 0x00,
+ 0xC1, 0x1F, 0xFF, 0x00, 0xE8, 0xCA, 0x3E, 0x12, 0xFF, 0x00, 0xE1, 0x3F, 0x6D, 0xFF, 0x00, 0xC6,
+ 0xE8, 0x00, 0xFF, 0x00, 0x88, 0x7A, 0x7F, 0xE0, 0x8F, 0xFF, 0x00, 0xF4, 0x65, 0x1F, 0x09, 0x7F,
+ 0xF0, 0x9F, 0xB6, 0xFF, 0x00, 0xE3, 0x74, 0x00, 0x7F, 0xC4, 0x3D, 0x3F, 0xF0, 0x47, 0xFF, 0x00,
+ 0xFA, 0x32, 0x8F, 0x84, 0xBF, 0xF8, 0x4F, 0xDB, 0x7F, 0xF1, 0xBA, 0x00, 0x3F, 0xE2, 0x1E, 0x9F,
+ 0xF8, 0x23, 0xFF, 0x00, 0xFD, 0x19, 0x47, 0xC2, 0x5F, 0xFC, 0x27, 0xED, 0xBF, 0xF8, 0xDD, 0x00,
+ 0x1F, 0xF1, 0x0F, 0x4F, 0xFC, 0x11, 0xFF, 0x00, 0xFE, 0x8C, 0xA3, 0xE1, 0x2F, 0xFE, 0x13, 0xF6,
+ 0xDF, 0xFC, 0x6E, 0x80, 0x0F, 0xF8, 0x87, 0xA7, 0xFE, 0x08, 0xFF, 0x00, 0xFF, 0x00, 0x46, 0x51,
+ 0xF0, 0x97, 0xFF, 0x00, 0x09, 0xFB, 0x6F, 0xFE, 0x37, 0x40, 0x07, 0xFC, 0x43, 0xD3, 0xFF, 0x00,
+ 0x04, 0x7F, 0xFF, 0x00, 0xA3, 0x28, 0xF8, 0x4B, 0xFF, 0x00, 0x84, 0xFD, 0xB7, 0xFF, 0x00, 0x1B,
+ 0xA0, 0x03, 0xFE, 0x21, 0xE9, 0xFF, 0x00, 0x82, 0x3F, 0xFF, 0x00, 0xD1, 0x94, 0x7C, 0x25, 0xFF,
+ 0x00, 0xC2, 0x7E, 0xDB, 0xFF, 0x00, 0x8D, 0xD0, 0x01, 0xFF, 0x00, 0x10, 0xF4, 0xFF, 0x00, 0xC1,
+ 0x1F, 0xFF, 0x00, 0xE8, 0xCA, 0x3E, 0x12, 0xFF, 0x00, 0xE1, 0x3F, 0x6D, 0xFF, 0x00, 0xC6, 0xE8,
+ 0x00, 0xFF, 0x00, 0x88, 0x7A, 0x7F, 0xE0, 0x8F, 0xFF, 0x00, 0xF4, 0x65, 0x1F, 0x09, 0x7F, 0xF0,
+ 0x9F, 0xB6, 0xFF, 0x00, 0xE3, 0x74, 0x00, 0x7F, 0xC4, 0x3D, 0x3F, 0xF0, 0x47, 0xFF, 0x00, 0xFA,
+ 0x32, 0x8F, 0x84, 0xBF, 0xF8, 0x4F, 0xDB, 0x7F, 0xF1, 0xBA, 0x00, 0x3F, 0xE2, 0x1E, 0x9F, 0xF8,
+ 0x23, 0xFF, 0x00, 0xFD, 0x19, 0x47, 0xC2, 0x5F, 0xFC, 0x27, 0xED, 0xBF, 0xF8, 0xDD, 0x00, 0x1F,
+ 0xF1, 0x0F, 0x4F, 0xFC, 0x11, 0xFF, 0x00, 0xFE, 0x8C, 0xA3, 0xE1, 0x2F, 0xFE, 0x13, 0xF6, 0xDF,
+ 0xFC, 0x6E, 0x80, 0x0F, 0xF8, 0x87, 0xA7, 0xFE, 0x08, 0xFF, 0x00, 0xFF, 0x00, 0x46, 0x51, 0xF0,
+ 0x97, 0xFF, 0x00, 0x09, 0xFB, 0x6F, 0xFE, 0x37, 0x40, 0x07, 0xFC, 0x43, 0xD3, 0xFF, 0x00, 0x04,
+ 0x7F, 0xFF, 0x00, 0xA3, 0x28, 0xF8, 0x4B, 0xFF, 0x00, 0x84, 0xFD, 0xB7, 0xFF, 0x00, 0x1B, 0xA0,
+ 0x0F, 0x5A, 0xF8, 0x21, 0xFF, 0x00, 0x04, 0x5F, 0xFF, 0x00, 0x82, 0x70, 0x7E, 0xCD, 0xBF, 0x11,
+ 0xF4, 0x1F, 0x8B, 0xBF, 0x02, 0x3F, 0x66, 0xFF, 0x00, 0x0A, 0x7C, 0x2A, 0xF8, 0x91, 0xE1, 0xAF,
+ 0x35, 0x74, 0x7F, 0x17, 0x78, 0x21, 0x4F, 0x87, 0xB5, 0x9B, 0x58, 0xE7, 0x88, 0xC7, 0x3C, 0x26,
+ 0x58, 0x42, 0x97, 0x89, 0xD1, 0x8A, 0xB4, 0x6D, 0x95, 0x6E, 0x32, 0x38, 0x18, 0x00, 0xFD, 0x47,
+ 0x8A, 0x31, 0x14, 0x69, 0x18, 0x2C, 0xC1, 0x14, 0x28, 0x2C, 0x72, 0xC4, 0x00, 0x00, 0x24, 0xFA,
+ 0xF0, 0x28, 0x03, 0xFC, 0xFD, 0xBF, 0xE0, 0xE7, 0xDF, 0xF9, 0x4E, 0x7F, 0xFC, 0x12, 0x1F, 0xFE,
+ 0xC1, 0x5F, 0x0F, 0x7F, 0xF5, 0x6F, 0x5C, 0xD7, 0x66, 0x59, 0xFF, 0x00, 0x23, 0x0C, 0x3F, 0xF8,
+ 0xE1, 0xFF, 0x00, 0xA5, 0x23, 0x9F, 0x13, 0xFE, 0xEB, 0x53, 0xFC, 0x2F, 0xF2, 0x3E, 0xD4, 0xAF,
+ 0xD4, 0xCF, 0x8E, 0x0A, 0x00, 0x28, 0x00, 0xA0, 0x0F, 0xD8, 0x1F, 0xF8, 0x22, 0x1E, 0x3F, 0xE1,
+ 0x03, 0xFD, 0xBB, 0x00, 0xC7, 0x1F, 0xB7, 0x3C, 0x23, 0x03, 0x1C, 0x7F, 0xC5, 0x86, 0xF8, 0x63,
+ 0x81, 0x8F, 0xCA, 0xBF, 0x3A, 0xE2, 0x0F, 0xF9, 0x1A, 0x4F, 0xD2, 0x3F, 0xFA, 0x4A, 0x3E, 0xA3,
+ 0x2B, 0xFF, 0x00, 0x72, 0x8F, 0xCF, 0xF3, 0x3E, 0xAE, 0xFD, 0xBA, 0x3F, 0x62, 0x9D, 0x43, 0xF6,
+ 0xC5, 0xD5, 0xBF, 0x66, 0x25, 0xFF, 0x00, 0x84, 0xEB, 0x53, 0xF0, 0x67, 0x85, 0x3E, 0x0C, 0x7C,
+ 0x65, 0x7F, 0x88, 0x7E, 0x3C, 0xD3, 0x34, 0x0B, 0xEB, 0xDD, 0x07, 0xC4, 0x3E, 0x35, 0xD3, 0x9F,
+ 0x49, 0x9A, 0xDA, 0x3D, 0x3E, 0xD3, 0x54, 0xB5, 0x9E, 0x29, 0x6D, 0x0A, 0x5D, 0x49, 0x67, 0x70,
+ 0x59, 0x49, 0x66, 0x16, 0xE1, 0x14, 0xA1, 0x6D, 0xE9, 0xE2, 0xAF, 0x76, 0xDC, 0xA7, 0x74, 0xA3,
+ 0x74, 0x92, 0x5A, 0x1F, 0x8E, 0xDF, 0xB5, 0x97, 0xEC, 0x5F, 0xFF, 0x00, 0x05, 0x1E, 0xD7, 0xF4,
+ 0x2B, 0x5F, 0x83, 0x76, 0xBF, 0xB6, 0x07, 0xC5, 0x5F, 0x16, 0x78, 0x02, 0x4D, 0x17, 0xC3, 0x3F,
+ 0xF0, 0x9C, 0x8D, 0x47, 0xC0, 0x3A, 0x80, 0xD1, 0xBC, 0x51, 0xAC, 0xF8, 0x7F, 0xC5, 0x76, 0x3A,
+ 0xBD, 0xD6, 0xA1, 0x6D, 0x7D, 0x01, 0x90, 0xC9, 0x6F, 0x7D, 0x06, 0x9E, 0xD0, 0x35, 0x9B, 0x01,
+ 0x0C, 0x5E, 0x63, 0x46, 0xC9, 0x34, 0x43, 0x63, 0xFA, 0x98, 0x4A, 0x74, 0x6A, 0xC2, 0xF5, 0x5D,
+ 0xDE, 0x8B, 0xA3, 0x69, 0x26, 0x9E, 0xDA, 0x5B, 0x45, 0x65, 0x6E, 0xF6, 0xD8, 0xF3, 0x6B, 0x3A,
+ 0x94, 0x9A, 0x8C, 0x34, 0x56, 0xEB, 0x74, 0xB6, 0x6B, 0xA7, 0x9D, 0xBE, 0xEF, 0x43, 0xD5, 0xFE,
+ 0x01, 0xFE, 0xC5, 0xBF, 0xF0, 0x54, 0xAD, 0x73, 0xC0, 0x9F, 0x0F, 0x2C, 0xBC, 0x6B, 0xFB, 0x71,
+ 0x5E, 0x5D, 0xDB, 0x78, 0x25, 0xF4, 0x8B, 0x7F, 0x10, 0x68, 0x7E, 0x25, 0xF8, 0x5F, 0x2E, 0x9D,
+ 0x6F, 0xE2, 0xE5, 0xB3, 0xB9, 0xBC, 0x6D, 0x5D, 0x60, 0xBA, 0x9D, 0x22, 0x9C, 0xD9, 0x6A, 0x56,
+ 0xFA, 0x92, 0x2B, 0xA1, 0x2D, 0x24, 0x12, 0x59, 0x58, 0x6D, 0x90, 0xC5, 0x04, 0x90, 0x5E, 0xF2,
+ 0xE2, 0x62, 0xA1, 0x34, 0xA2, 0xD6, 0xCB, 0xAA, 0x7A, 0xAE, 0xE9, 0x6D, 0xE9, 0xF9, 0x9B, 0xE1,
+ 0xD3, 0x9C, 0x36, 0xD1, 0x6D, 0xA5, 0xB4, 0xB6, 0x89, 0x6D, 0x7F, 0x5B, 0x6D, 0xDB, 0x65, 0xF4,
+ 0x07, 0x87, 0xFF, 0x00, 0x62, 0xBF, 0xF8, 0x29, 0xEF, 0x86, 0xBC, 0x2F, 0xE1, 0x1D, 0x02, 0xC7,
+ 0xF6, 0xF2, 0xD3, 0x5D, 0xFC, 0x17, 0xE2, 0xD8, 0x75, 0x5D, 0x33, 0xCA, 0xF0, 0x3A, 0x69, 0x1A,
+ 0x4D, 0xE6, 0x93, 0x06, 0xBF, 0x0D, 0xD4, 0x1A, 0x2C, 0xF6, 0x56, 0xEE, 0x91, 0x9B, 0x64, 0xD2,
+ 0x20, 0xFE, 0xC8, 0xF2, 0xFE, 0xE7, 0x97, 0x1C, 0x77, 0x40, 0x0B, 0x89, 0xA7, 0x2D, 0xC9, 0x6D,
+ 0x2C, 0x75, 0x59, 0xE9, 0x65, 0xE8, 0x7B, 0xCF, 0xEC, 0x89, 0xFB, 0x32, 0xFE, 0xD9, 0x1F, 0x07,
+ 0xFE, 0x3B, 0xF8, 0xBF, 0xE2, 0xBF, 0xC7, 0xBF, 0x8D, 0xFE, 0x10, 0xF8, 0xC1, 0xA5, 0x7C, 0x40,
+ 0xF8, 0x5B, 0xA7, 0x7C, 0x35, 0xD7, 0xAC, 0x6D, 0xF4, 0xBB, 0xED, 0x3B, 0x5A, 0xD2, 0xE4, 0xF0,
+ 0xEF, 0x8B, 0x7C, 0x49, 0xA9, 0xF8, 0x7B, 0x50, 0xB5, 0x94, 0xDC, 0x1B, 0x77, 0x55, 0xD3, 0xFC,
+ 0x68, 0xD6, 0x13, 0x09, 0x20, 0xF3, 0x59, 0x74, 0xDB, 0x47, 0xF3, 0x4E, 0xE6, 0x54, 0x12, 0xB2,
+ 0x48, 0x22, 0x9A, 0xE9, 0xA7, 0xF5, 0xFD, 0x7F, 0x56, 0x3F, 0x50, 0xA9, 0x9A, 0x05, 0x00, 0x14,
+ 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40,
+ 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x1E, 0x3D, 0xF1, 0xF3, 0xE1, 0xBF, 0x88, 0x3E, 0x2D,
+ 0xFC, 0x22, 0xF1, 0x9F, 0xC3, 0xBF, 0x09, 0xF8, 0x9F, 0x47, 0xF0, 0x4F, 0x88, 0x7C, 0x4B, 0xA7,
+ 0x47, 0x65, 0xA5, 0x78, 0xB3, 0x5B, 0xD0, 0xF5, 0x8D, 0x76, 0xD3, 0xC3, 0xCE, 0xB3, 0xA3, 0x35,
+ 0xD4, 0x29, 0xA4, 0x6B, 0x3A, 0x2E, 0xAF, 0x6F, 0x72, 0xA8, 0x8E, 0x60, 0xBB, 0xD3, 0xB5, 0x6D,
+ 0x3A, 0xF2, 0xD2, 0x6F, 0x26, 0xE6, 0xDE, 0xE6, 0x29, 0x60, 0x46, 0x00, 0x1D, 0x1F, 0xC2, 0x8F,
+ 0x87, 0xDA, 0x6F, 0xC2, 0x5F, 0x85, 0xBF, 0x0D, 0x7E, 0x15, 0x68, 0xD3, 0xC5, 0x75, 0xA3, 0xFC,
+ 0x33, 0xF0, 0x06, 0x8D, 0xF0, 0xFB, 0x49, 0xB9, 0x83, 0xC3, 0x9A, 0x2F, 0x83, 0xA0, 0xB8, 0xB6,
+ 0xD1, 0x74, 0xE8, 0x6C, 0xED, 0xE4, 0x4D, 0x23, 0x47, 0xB2, 0xB2, 0xD2, 0x2C, 0x55, 0x92, 0xD9,
+ 0x08, 0xB6, 0xB0, 0xB3, 0xB4, 0xB5, 0x84, 0x11, 0x1C, 0x16, 0xF0, 0xC4, 0x89, 0x1A, 0x00, 0x77,
+ 0xD4, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05,
+ 0x00, 0x14, 0x00, 0x50, 0x07, 0xF9, 0xFA, 0x7F, 0xC1, 0xCF, 0xAB, 0x8F, 0xF8, 0x2E, 0x77, 0xFC,
+ 0x12, 0x1C, 0xE3, 0x0B, 0xFD, 0x97, 0xF0, 0xF5, 0x41, 0xC6, 0x07, 0x1F, 0x17, 0xAE, 0x72, 0x07,
+ 0xD3, 0x23, 0xF4, 0xAE, 0xCC, 0xB3, 0xFE, 0x46, 0x18, 0x7F, 0xF1, 0xC3, 0xFF, 0x00, 0x4A, 0x47,
+ 0x3E, 0x27, 0xFD, 0xD6, 0xA7, 0xF8, 0x5F, 0xE4, 0x7D, 0xA7, 0x5F, 0xA9, 0x9F, 0x1C, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x1F, 0x09, 0xFE, 0xDA, 0xBF, 0xB0, 0x7F, 0x81, 0x3F, 0x6C, 0x1F, 0x05, 0xDA,
+ 0xE8, 0xB6, 0x3A, 0xBE, 0x83, 0xF0, 0x57, 0xE2, 0x08, 0xF1, 0xC6, 0x9D, 0xE2, 0xCD, 0x5F, 0xE3,
+ 0x47, 0x85, 0xFE, 0x18, 0x69, 0xDA, 0xE7, 0xC4, 0x8F, 0x10, 0xD9, 0xE9, 0xDA, 0x55, 0xDD, 0x8A,
+ 0xE8, 0x77, 0x9A, 0x8A, 0xCF, 0x67, 0x79, 0x25, 0xA3, 0x0B, 0xCB, 0x27, 0xDA, 0xF7, 0x4E, 0x8B,
+ 0xFD, 0x9F, 0x6A, 0xBE, 0x51, 0xD8, 0x86, 0x2F, 0x2B, 0x32, 0xCA, 0x68, 0x66, 0x14, 0xD4, 0x52,
+ 0x50, 0x9D, 0xD3, 0x72, 0x51, 0x4D, 0xB4, 0x93, 0x56, 0xBE, 0x8E, 0xDB, 0x75, 0xB6, 0x8B, 0x4E,
+ 0xDD, 0x98, 0x4C, 0x65, 0x4C, 0x2B, 0xD3, 0x58, 0xDA, 0xD6, 0xBD, 0x92, 0xDB, 0x5B, 0x6D, 0xD3,
+ 0xB1, 0xF9, 0xA1, 0xFF, 0x00, 0x0E, 0x0B, 0x3F, 0xF4, 0x7C, 0x5F, 0x11, 0x3F, 0xF0, 0xD2, 0xFF,
+ 0x00, 0xF8, 0x47, 0x5E, 0x2F, 0xFA, 0xA7, 0x1F, 0xF9, 0xFF, 0x00, 0xFF, 0x00, 0x92, 0x7F, 0xF6,
+ 0xC7, 0x77, 0xF6, 0xC4, 0xBF, 0xE7, 0xDA, 0xFB, 0xFF, 0x00, 0xE0, 0x08, 0x7F, 0xE0, 0x81, 0x20,
+ 0x80, 0x0F, 0xED, 0xC1, 0xF1, 0x0C, 0x81, 0x8C, 0x03, 0xF0, 0x8C, 0x10, 0x30, 0x38, 0xC0, 0xFF,
+ 0x00, 0x84, 0x8E, 0x8F, 0xF5, 0x4E, 0x3F, 0xF3, 0xFF, 0x00, 0xFF, 0x00, 0x24, 0xFF, 0x00, 0xED,
+ 0x83, 0xFB, 0x62, 0x56, 0x4B, 0xD9, 0xAB, 0x7A, 0xFF, 0x00, 0xC0, 0x14, 0x7F, 0xC1, 0x02, 0xB6,
+ 0x80, 0x17, 0xF6, 0xE1, 0xF8, 0x88, 0xA0, 0x74, 0x03, 0xE1, 0x26, 0x00, 0xE3, 0xB0, 0xFF, 0x00,
+ 0x84, 0x8F, 0xD8, 0x51, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F,
+ 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4,
+ 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F,
+ 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD,
+ 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF,
+ 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3,
+ 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7,
+ 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE,
+ 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1,
+ 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D,
+ 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF,
+ 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C,
+ 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F,
+ 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD,
+ 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F,
+ 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00,
+ 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82,
+ 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE,
+ 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00,
+ 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE,
+ 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF,
+ 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE,
+ 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B,
+ 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC,
+ 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0,
+ 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17,
+ 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4,
+ 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF,
+ 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F,
+ 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F,
+ 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9,
+ 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF,
+ 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11,
+ 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE,
+ 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34,
+ 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F,
+ 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4,
+ 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F,
+ 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD,
+ 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF,
+ 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3,
+ 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7,
+ 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE,
+ 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1,
+ 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D,
+ 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF,
+ 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C,
+ 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F,
+ 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD,
+ 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F,
+ 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00,
+ 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82,
+ 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE,
+ 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00,
+ 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE,
+ 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF,
+ 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE,
+ 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B,
+ 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC,
+ 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0,
+ 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17,
+ 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4,
+ 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF,
+ 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F,
+ 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F,
+ 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9,
+ 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF,
+ 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11,
+ 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE,
+ 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34,
+ 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F,
+ 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4,
+ 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F,
+ 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD,
+ 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF,
+ 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3,
+ 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7,
+ 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE,
+ 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1,
+ 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D,
+ 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF,
+ 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C,
+ 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F,
+ 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD,
+ 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F,
+ 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00,
+ 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82,
+ 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE,
+ 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00,
+ 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE,
+ 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF,
+ 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE,
+ 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B,
+ 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC,
+ 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0,
+ 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17,
+ 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4,
+ 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF,
+ 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F,
+ 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F,
+ 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9,
+ 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF,
+ 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11,
+ 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE,
+ 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34,
+ 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F,
+ 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4,
+ 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F,
+ 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD,
+ 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF,
+ 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3,
+ 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7,
+ 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE,
+ 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1,
+ 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D,
+ 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF,
+ 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C,
+ 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F,
+ 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD,
+ 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F,
+ 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00,
+ 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82,
+ 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE,
+ 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00,
+ 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE,
+ 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF,
+ 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC, 0x34, 0xBF, 0xFE,
+ 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0, 0x7F, 0x6C, 0x4B,
+ 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x00, 0x7F, 0xC3, 0x82, 0xCF, 0xFD, 0x1F, 0x17, 0xC4, 0x4F, 0xFC,
+ 0x34, 0xBF, 0xFE, 0x11, 0xD1, 0xFE, 0xA9, 0xC7, 0xFE, 0x7F, 0xFF, 0x00, 0xE4, 0x9F, 0xFD, 0xB0,
+ 0x7F, 0x6C, 0x4B, 0xFE, 0x7D, 0xAF, 0xBF, 0xFE, 0x01, 0xDE, 0x7C, 0x1E, 0xFF, 0x00, 0x82, 0x1D,
+ 0xE9, 0x7F, 0x0A, 0x7E, 0x36, 0x7C, 0x1E, 0xF8, 0xD3, 0x77, 0xFB, 0x58, 0x78, 0xAF, 0xC6, 0xB7,
+ 0xBF, 0x08, 0x7E, 0x25, 0x68, 0x1F, 0x11, 0xAC, 0xF4, 0x2D, 0x57, 0xE1, 0x2C, 0x76, 0x6B, 0xAD,
+ 0x1D, 0x07, 0x56, 0x82, 0xF9, 0x2C, 0x0D, 0xE1, 0xD7, 0x66, 0x68, 0x12, 0x56, 0xB5, 0xD8, 0x5C,
+ 0x47, 0x26, 0xCD, 0xE5, 0x82, 0x36, 0x30, 0x77, 0xC3, 0x70, 0xCA, 0xC3, 0x62, 0x29, 0xD7, 0x55,
+ 0xAF, 0xCB, 0x24, 0xED, 0xCB, 0x6B, 0xD9, 0xA7, 0x6F, 0x8B, 0x4D, 0xBB, 0x11, 0x53, 0x35, 0x95,
+ 0x4A, 0x52, 0xA5, 0xEC, 0xD2, 0x4D, 0x35, 0xBE, 0xD7, 0x56, 0xEC, 0x7E, 0xEF, 0xD7, 0xD4, 0x1E,
+ 0x40, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40,
+ 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05,
+ 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14,
+ 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40,
+ 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00,
+ 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00,
+ 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01,
+ 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05,
+ 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14,
+ 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50, 0x01, 0x40, 0x05, 0x00, 0x14, 0x00, 0x50,
+ 0x07, 0xFF, 0xD9,
+};
+
+UINT SizeOfWaterMark()
+{
+ return sizeof(WaterMark);
+}
+
+UINT SizeOfSaitama()
+{
+ return sizeof(Saitama);
+}
+
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/WaterMark.h b/src/Cedar/WaterMark.h
new file mode 100644
index 00000000..cfd10767
--- /dev/null
+++ b/src/Cedar/WaterMark.h
@@ -0,0 +1,110 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// WaterMark.h
+// Header of WaterMark.c
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+
+#ifndef WATERMARK_H
+#define WATERMARK_H
+
+// Digital watermark
+extern BYTE WaterMark[];
+extern BYTE Saitama[];
+
+UINT SizeOfWaterMark();
+UINT SizeOfSaitama();
+
+#define MAX_WATERMARK_SIZE (SizeOfWaterMark() + HTTP_PACK_RAND_SIZE_MAX * 2)
+
+#endif // WATERMARK_H
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/WebUI.c b/src/Cedar/WebUI.c
new file mode 100644
index 00000000..86541f49
--- /dev/null
+++ b/src/Cedar/WebUI.c
@@ -0,0 +1,1961 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Tetsuo Sugiyama
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// WebUI.c
+// Web User Interface module
+
+#include "CedarPch.h"
+
+static WU_CONTEXT *WuNewContext(WEBUI *wu, char *hubname);
+static void WuFreeContext(WU_CONTEXT *context);
+static WU_WEBPAGE *WuNewUniWebPage(wchar_t *content);
+static WU_WEBPAGE *WuNewWebPage(char *content, UINT size, char *filename);
+static wchar_t *WuErrorPage(UINT errorcode);
+static wchar_t *WuRedirectPage(char *url);
+static wchar_t *WuUniReadFile(char *filename);
+static void WuUniReplace(wchar_t **buf, wchar_t *from, wchar_t *to);
+static void WuUniInsertBefore(wchar_t **buf, wchar_t *insert, wchar_t *before);
+static LIST *WuAnalyzeTarget(char *target,char *filename, UINT size);
+static void WuFreeStrStrMap(LIST *params);
+static void WuEnableTag(wchar_t **buf, wchar_t *keyword);
+static char *WuNewSessionKey();
+static void WuUniStrReplace(wchar_t **buf, wchar_t *from, char *to);
+static wchar_t *WuUniGetTemplate(wchar_t **str, wchar_t *start, wchar_t *end, bool erase);
+static void WuUniUintReplace(wchar_t **buf, wchar_t *key, UINT num);
+static void WuUniUint64Replace(wchar_t **buf, wchar_t *key, UINT64 num);
+static wchar_t *WuUniGetTemplate(wchar_t **str, wchar_t *start, wchar_t *end, bool erase);
+static LIST *WuUniMakeTable(wchar_t *def);
+static LIST *WuUniMakeTableFromTemplate(wchar_t **str, wchar_t *start, wchar_t *end);
+static void WuExpireSessionKey(WEBUI *wu);
+static WU_CONTEXT *WuGetContext(LIST *contexts, char *sessionkey);
+
+#define WP_DEFAULT "/webui/"
+#define WP_LOGIN "/webui/login.cgi"
+#define WP_REDIRECT "/webui/redirect.cgi"
+#define WP_ERROR "/webui/error.cgi"
+#define WP_SERVER "/webui/server.cgi"
+#define WP_LISTENER "/webui/listener.cgi"
+#define WP_HUB "/webui/hub.cgi"
+#define WP_USER "/webui/user.cgi"
+#define WP_EDITUSER "/webui/edituser.cgi"
+#define WP_NEWHUB "/webui/newhub.cgi"
+#define WP_LICENSE "/webui/license.cgi"
+#define WP_LOCALBRIDGE "/webui/localbridge.cgi"
+#define WP_SECURENAT "/webui/securenat.cgi"
+#define WP_SESSION "/webui/session.cgi"
+
+static wchar_t *WpDefault(WEBUI *wu, LIST *params);
+static wchar_t *WpLogin(WEBUI *wu, LIST *params);
+static wchar_t *WpServer(WEBUI *wu, LIST *params);
+static wchar_t *WpListener(WEBUI *wu, LIST *params);
+static wchar_t *WpHub(WEBUI *wu, LIST *params);
+static wchar_t *WpUser(WEBUI *wu, LIST *params);
+static wchar_t *WpEditUser(WEBUI *wu, LIST *params);
+static wchar_t *WpNewHub(WEBUI *wu, LIST *params);
+static wchar_t *WpLicense(WEBUI *wu, LIST *params);
+static wchar_t *WpLocalBridge(WEBUI *wu, LIST *params);
+static wchar_t *WpSecureNAT(WEBUI *wu, LIST *params);
+static wchar_t *WpSession(WEBUI *wu, LIST *params);
+
+// WebUI page handler table
+static STRMAP_ENTRY wu_pages[] = {
+ {WP_DEFAULT, WpDefault},
+ {WP_LOGIN, WpLogin},
+ {WP_SERVER, WpServer},
+ {WP_LISTENER, WpListener},
+ {WP_HUB, WpHub},
+ {WP_USER, WpUser},
+ {WP_EDITUSER, WpEditUser},
+ {WP_NEWHUB, WpNewHub},
+ {WP_LICENSE, WpLicense},
+ {WP_LOCALBRIDGE, WpLocalBridge},
+ {WP_SECURENAT, WpSecureNAT},
+ {WP_SESSION, WpSession},
+};
+
+// **** Page handlers
+
+// Redirect the directory access to the login screen
+static wchar_t *WpDefault(WEBUI *wu, LIST *params)
+{
+ return WuRedirectPage(WP_LOGIN);
+}
+
+// Login page
+static wchar_t *WpLogin(WEBUI *wu, LIST *params)
+{
+ UINT result;
+ char random[20], securepass[SHA1_SIZE];
+ char *password = (char*)StrMapSearch(params, "PASS");
+ char *hubname = (char*)StrMapSearch(params, "HUB");
+
+ if(password == NULL)
+ {
+ wchar_t *buf = WuUniReadFile("|"WP_LOGIN);
+ WuUniStrReplace(&buf, L"ACTION", WP_LOGIN);
+ WuUniStrReplace(&buf, L"HUBNAME", hubname == NULL ? "" : hubname);
+ return buf;
+ }
+
+ // Administrator authentication
+ Rand(random,sizeof(random));
+ Hash(securepass, password, StrLen(password), true);
+ SecurePassword(securepass, securepass, random);
+ result = AdminCheckPassword(wu->Cedar, random, securepass, hubname, false, NULL);
+
+ if(result == ERR_NO_ERROR)
+ {
+ // Successful login
+ char tmp[MAX_SIZE];
+ STRMAP_ENTRY *context;
+
+ // Create a new context
+ context = Malloc(sizeof(STRMAP_ENTRY));
+ context->Name = WuNewSessionKey();
+ context->Value = WuNewContext(wu, hubname);
+ Add(wu->Contexts, context);
+
+ // Transfer to the server management screen
+ Format(tmp, sizeof(tmp), "%s?KEY=%s", WP_SERVER, context->Name);
+ return WuRedirectPage(tmp);
+ }else{
+ // Login failure
+ wchar_t *buf = WuUniReadFile("|"WP_LOGIN);
+ WuUniStrReplace(&buf, L"ACTION", WP_LOGIN);
+ WuUniStrReplace(&buf, L"HUBNAME",hubname == NULL ? "" : hubname);
+ WuUniReplace(&buf, L"<!--ERR1-->", GetUniErrorStr(result));
+ return buf;
+ }
+}
+
+// Server management
+static wchar_t *WpServer(WEBUI *wu, LIST *params)
+{
+ char *sessionkey = (char*)StrMapSearch(params, "KEY");
+ WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
+ UINT i;
+ wchar_t *buf;
+ LIST *strmap;
+
+ if(context == NULL)
+ {
+ return WuRedirectPage(WP_LOGIN);
+ }
+
+ buf = WuUniReadFile("|"WP_SERVER);
+ strmap = WuUniMakeTableFromTemplate(&buf, L"<!--STRMAP:", L":STRMAP-->");
+
+ // Show the Virtual HUB list
+ {
+ wchar_t *tmpl = WuUniGetTemplate(&buf, L"<!--HUBS_TMPL:", L":HUBS_TMPL-->", true);
+ RPC_ENUM_HUB t;
+
+ t.Hubs = NULL;
+ StEnumHub(context->Admin, &t);
+ for(i=0; i<t.NumHub; i++)
+ {
+ wchar_t *tmp = UniCopyStr(tmpl);
+ wchar_t lastlogin[MAX_SIZE], lastcomm[MAX_SIZE];
+ RPC_ENUM_HUB_ITEM *item = &t.Hubs[i];
+
+ GetDateTimeStr64Uni(lastlogin,sizeof(lastlogin), SystemToLocal64(item->LastLoginTime));
+ GetDateTimeStr64Uni(lastcomm, sizeof(lastcomm), SystemToLocal64(item->LastCommTime));
+ WuUniStrReplace(&tmp, L"{HUBNAME}", item->HubName);
+ WuUniReplace(&tmp, L"{HUBSTATE}", item->Online ? StrMapSearch(strmap, "HUB_ONLINE") : StrMapSearch(strmap, "HUB_OFFLINE"));
+ WuUniReplace(&tmp, L"{HUBTYPE}", item->HubType == HUB_TYPE_STANDALONE ? StrMapSearch(strmap, "HUB_STANDALONE")
+ : item->HubType == HUB_TYPE_FARM_DYNAMIC ? StrMapSearch(strmap,"HUB_DYNAMIC") : StrMapSearch(strmap, "HUB_STATIC"));
+ WuUniUintReplace(&tmp, L"{HUBUSERS}", item->NumUsers);
+ WuUniUintReplace(&tmp, L"{HUBGROUPS}", item->NumGroups);
+ WuUniUintReplace(&tmp, L"{HUBSESSIONS}", item->NumSessions);
+ WuUniUintReplace(&tmp, L"{HUBMACS}", item->NumMacTables);
+ WuUniUintReplace(&tmp, L"{HUBIPS}", item->NumIpTables);
+ WuUniUintReplace(&tmp, L"{HUBLOGINS}", item->NumLogin);
+ WuUniReplace(&tmp, L"{HUBLASTLOGINDATE}", lastlogin);
+ WuUniReplace(&tmp, L"{HUBLASTCOMMDATE}", lastcomm);
+
+ WuUniInsertBefore(&buf, tmp, L"<!--HUBS-->");
+ Free(tmp);
+ }
+ FreeRpcEnumHub(&t);
+ Free(tmpl);
+ }
+
+ // Show the listener list
+ {
+ RPC_LISTENER_LIST t;
+ wchar_t *tmpl = WuUniGetTemplate(&buf, L"<!--LISTENER_TMPL:", L":LISTENER_TMPL-->", true);
+ Zero(&t, sizeof(t));
+ StEnumListener(context->Admin, &t);
+ for(i=0; i<t.NumPort; i++)
+ {
+ wchar_t *tmp = UniCopyStr(tmpl);
+ WuUniReplace(&tmp, L"{PORT_STATE}", t.Enables[i] == false ? StrMapSearch(strmap,"LISTENER_OFFLINE")
+ : t.Errors[i] == true ? StrMapSearch(strmap,"LISTENER_ERROR") : StrMapSearch(strmap, "LISTENER_ONLINE"));
+ WuUniUintReplace(&tmp, L"{PORTNUM}", t.Ports[i]);
+ WuEnableTag(&tmp, t.Enables[i] ? L"STOPA" : L"STARTA");
+ WuUniInsertBefore(&buf, tmp, L"<!--LISTENERS-->");
+ Free(tmp);
+ }
+ FreeRpcListenerList(&t);
+ Free(tmpl);
+ }
+ WuUniStrReplace(&buf, L"{LINK_HUB}", WP_HUB);
+ WuUniStrReplace(&buf, L"{SESSIONKEY}", sessionkey);
+ WuUniStrReplace(&buf, L"{LISTENER_LINK}", WP_LISTENER);
+ WuUniStrReplace(&buf, L"{LINK_NEWHUB}", WP_NEWHUB);
+ WuUniStrReplace(&buf, L"{LINK_SERVER}", WP_SERVER);
+ WuUniStrReplace(&buf, L"{LINK_LICENSE}", WP_LICENSE);
+ WuUniStrReplace(&buf, L"{LINK_LOCALBRIDGE}", WP_LOCALBRIDGE);
+
+ WuFreeStrStrMap(strmap);
+
+ return buf;
+}
+
+// Listener management
+static wchar_t *WpListener(WEBUI *wu, LIST *params)
+{
+ char *sessionkey = (char*)StrMapSearch(params, "KEY");
+ WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
+ char *cmd = (char*)StrMapSearch(params, "CMD");
+ RPC_LISTENER t;
+ UINT retcode;
+
+ if(context == NULL)
+ {
+ return WuRedirectPage(WP_LOGIN);
+ }
+
+ t.Port = ToInt((char*)StrMapSearch(params, "PORT"));
+
+ if( StrCmp(cmd, "CREATE") == 0 )
+ {
+ // Create a new listener
+ if(t.Port == 0)
+ {
+ wchar_t *buf = WuUniReadFile("|"WP_LISTENER);
+ WuUniStrReplace(&buf, L"ACTION", WP_LISTENER);
+ WuUniStrReplace(&buf, L"SESSIONKEY", sessionkey);
+ return buf;
+ }
+ else
+ {
+ t.Enable = true;
+ retcode = StCreateListener(context->Admin, &t);
+ }
+ }
+ else if( StrCmp(cmd, "DEL")==0 )
+ {
+ retcode = StDeleteListener(context->Admin, &t);
+ }
+ else if(StrCmp(cmd, "START")==0 )
+ {
+ t.Enable = true;
+ retcode = StEnableListener(context->Admin, &t);
+ }
+ else if(StrCmp(cmd, "STOP")==0 )
+ {
+ t.Enable = false;
+ retcode = StEnableListener(context->Admin, &t);
+ }
+
+ if(retcode == ERR_NO_ERROR)
+ {
+ char tmp[MAX_SIZE];
+ Format(tmp, sizeof(tmp), "%s?KEY=%s", WP_SERVER, sessionkey);
+ return WuRedirectPage(tmp);
+ }
+ return WuErrorPage(retcode);
+}
+
+// Virtual HUB management
+static wchar_t *WpHub(WEBUI *wu, LIST *params)
+{
+ char *hubname = (char*)StrMapSearch(params, "HUB");
+ char *sessionkey = (char*)StrMapSearch(params, "KEY");
+ char *cmd = (char*)StrMapSearch(params, "CMD");
+ WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
+
+ // Confirm the session
+ if(context == NULL)
+ {
+ return WuRedirectPage(WP_LOGIN);
+ }
+
+ if(StrCmp(cmd, "ONLINE") == 0 || StrCmp(cmd, "OFFLINE") == 0)
+ {
+ // Online / offline switching
+ UINT retcode;
+ RPC_SET_HUB_ONLINE t;
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+ t.Online = (StrCmp(cmd, "ONLINE") == 0) ? true : false;
+ retcode = StSetHubOnline(context->Admin, &t);
+ if(retcode == ERR_NO_ERROR){
+ char tmp[MAX_SIZE];
+ Format(tmp, sizeof(tmp), "%s?HUB=%s&KEY=%s", WP_HUB, hubname, sessionkey);
+ return WuRedirectPage(tmp);
+ }else{
+ return WuErrorPage(retcode);
+ }
+ }
+ else if(StrCmp(cmd, "DELETE") == 0)
+ {
+ // Delete the Virtual HUB
+ RPC_DELETE_HUB t;
+ UINT retcode;
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+ retcode = StDeleteHub(context->Admin, &t);
+ if(retcode == ERR_NO_ERROR)
+ {
+ char tmp[MAX_SIZE];
+ Format(tmp, sizeof(tmp), "%s?KEY=%s", WP_SERVER, sessionkey);
+ return WuRedirectPage(tmp);
+ }
+ return WuErrorPage(retcode);
+ }
+ else
+ {
+ // Show the status and commands of the virtual HUB
+ RPC_HUB_STATUS t;
+ UINT retcode;
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+ retcode = StGetHubStatus(context->Admin, &t);
+ if(retcode == ERR_NO_ERROR)
+ {
+ wchar_t tmp[MAX_SIZE];
+ wchar_t *buf = WuUniReadFile("|"WP_HUB);
+ LIST *strmap = WuUniMakeTableFromTemplate(&buf, L"<!--STRMAP:", L":STRMAP-->");
+
+ WuUniStrReplace(&buf, L"{HUBNAME}", t.HubName);
+ WuUniReplace(&buf, L"{HUBSTATE}", StrMapSearch(strmap, t.Online == false ? "HUB_OFFLINE" : "HUB_ONLINE"));
+ WuUniReplace(&buf, L"{HUBTYPE}", GetHubTypeStr(t.HubType));
+ WuUniReplace(&buf, L"{HUBSNAT}", StrMapSearch(strmap, t.SecureNATEnabled == false ? "SECNAT_OFF" : "SECNAT_ON"));
+ WuUniUintReplace(&buf, L"{HUBSESSIONS}", t.NumSessions);
+ WuUniUintReplace(&buf, L"{HUBACLS}", t.NumAccessLists);
+ WuUniUintReplace(&buf, L"{HUBUSERS}", t.NumUsers);
+ WuUniUintReplace(&buf, L"{HUBGROUPS}", t.NumGroups);
+ WuUniUintReplace(&buf, L"{HUBMACTBLS}", t.NumMacTables);
+ WuUniUintReplace(&buf, L"{HUBIPTBLS}", t.NumIpTables);
+ WuUniUintReplace(&buf, L"{HUBLOGINS}", t.NumLogin);
+ GetDateTimeStr64Uni(tmp, sizeof(tmp), SystemToLocal64(t.LastLoginTime));
+ WuUniReplace(&buf, L"{HUBLASTLOGIN}", tmp);
+ GetDateTimeStr64Uni(tmp, sizeof(tmp), SystemToLocal64(t.LastCommTime));
+ WuUniReplace(&buf, L"{HUBLASTCOMM}", tmp);
+ WuUniUint64Replace(&buf, L"{HUBTXUNIPKTS}", t.Traffic.Send.UnicastCount);
+ WuUniUint64Replace(&buf, L"{HUBTXUNISIZE}", t.Traffic.Send.UnicastBytes);
+ WuUniUint64Replace(&buf, L"{HUBTXBRPKTS}", t.Traffic.Send.BroadcastCount);
+ WuUniUint64Replace(&buf, L"{HUBTXBRSIZE}", t.Traffic.Send.BroadcastBytes);
+ WuUniUint64Replace(&buf, L"{HUBRXUNIPKTS}", t.Traffic.Recv.UnicastCount);
+ WuUniUint64Replace(&buf, L"{HUBRXUNISIZE}", t.Traffic.Recv.UnicastBytes);
+ WuUniUint64Replace(&buf, L"{HUBRXBRPKTS}", t.Traffic.Recv.BroadcastCount);
+ WuUniUint64Replace(&buf, L"{HUBRXBRSIZE}", t.Traffic.Recv.BroadcastBytes);
+
+ WuEnableTag(&buf, t.Online ? L"ENABLE_OFFLINE" : L"ENABLE_ONLINE");
+
+ WuUniStrReplace(&buf, L"{LINK_HUB}", WP_HUB);
+ WuUniStrReplace(&buf, L"{LINK_USER}", WP_USER);
+ WuUniStrReplace(&buf, L"{LINK_SERVER}", WP_SERVER);
+ WuUniStrReplace(&buf, L"{LINK_SESSION}", WP_SESSION);
+ WuUniStrReplace(&buf, L"{HUBNAME}", hubname);
+ WuUniStrReplace(&buf, L"{SESSIONKEY}", sessionkey);
+ WuUniStrReplace(&buf, L"{LINK_SECURENAT}", WP_SECURENAT);
+
+ WuFreeStrStrMap(strmap);
+
+ return buf;
+ }else{
+ return WuErrorPage(retcode);
+ }
+ }
+}
+
+// User list
+static wchar_t *WpUser(WEBUI *wu, LIST *params)
+{
+ char *sessionkey = (char*)StrMapSearch(params, "KEY");
+ WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
+ char *hubname = (char*)StrMapSearch(params, "HUB");
+ char *cmd = (char*)StrMapSearch(params, "CMD");
+ UINT retcode;
+ RPC_ENUM_USER t;
+
+ // Check the context
+ if(context == NULL)
+ {
+ return WuRedirectPage(WP_LOGIN);
+ }
+
+ if(cmd != NULL && StrCmp(cmd, "DEL") == 0)
+ {
+ char *username = (char*)StrMapSearch(params, "USER");
+ RPC_DELETE_USER t;
+ UINT retcode;
+
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+ StrCpy(t.Name, sizeof(t.Name), username);
+ retcode = StDeleteUser(context->Admin, &t);
+ if(retcode == ERR_NO_ERROR)
+ {
+ char tmp[MAX_SIZE];
+ Format(tmp, sizeof(tmp), "%s?HUB=%s&KEY=%s", WP_USER, hubname, sessionkey);
+ return WuRedirectPage(tmp);
+ }else
+ {
+ return WuErrorPage(retcode);
+ }
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+ retcode = StEnumUser(context->Admin, &t);
+ if(retcode == ERR_NO_ERROR)
+ {
+ UINT i;
+ wchar_t *buf = WuUniReadFile("|"WP_USER);
+ wchar_t *tmpl = WuUniGetTemplate(&buf, L"<!--USER_TMPL:", L"-->", true);
+ wchar_t tmp[MAX_SIZE];
+ wchar_t datestr[MAX_SIZE];
+
+ for(i=0; i<t.NumUser; i++)
+ {
+ RPC_ENUM_USER_ITEM *item = &t.Users[i];
+ GetDateTimeStr64Uni(datestr, sizeof(datestr), SystemToLocal64(item->LastLoginTime));
+ UniFormat(tmp, sizeof(tmp), tmpl, item->Name, item->Name, item->Name, item->Realname, item->GroupName,
+ item->Note, GetAuthTypeStr(item->AuthType), item->NumLogin, datestr);
+ WuUniInsertBefore(&buf, tmp, L"<!--USERS-->");
+ }
+ WuUniStrReplace(&buf, L"{SESSIONKEY}", sessionkey);
+ WuUniStrReplace(&buf, L"{HUBNAME}", hubname);
+ WuUniStrReplace(&buf, L"{LINK_USER}", WP_USER);
+ WuUniStrReplace(&buf, L"{LINK_EDITUSER}", WP_EDITUSER);
+ WuUniStrReplace(&buf, L"{LINK_HUB}", WP_HUB);
+
+ FreeRpcEnumUser(&t);
+ Free(tmpl);
+ return buf;
+ }else{
+ return WuErrorPage(retcode);
+ }
+}
+
+// User edit page
+static wchar_t *WpEditUser(WEBUI *wu, LIST *params)
+{
+ char *sessionkey = (char*)StrMapSearch(params, "KEY");
+ WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
+ char *hubname = (char*)StrMapSearch(params, "HUB");
+ char *username = (char*)StrMapSearch(params, "USER");
+ char *cmd = (char*)StrMapSearch(params, "CMD");
+ char tmp[MAX_SIZE];
+ wchar_t utmp[MAX_SIZE];
+ UINT retcode;
+ RPC_SET_USER t;
+ wchar_t *buf;
+
+ // Check the context
+ if(context == NULL)
+ {
+ return WuRedirectPage(WP_LOGIN);
+ }
+
+ if(cmd != NULL && (StrCmp(cmd, "SET") == 0 || StrCmp(cmd, "CREATE") == 0))
+ {
+ char *authtype = (char*)StrMapSearch(params, "AUTHTYPE");
+ char *password = (char*)StrMapSearch(params, "PASSWORD");
+ char *password2 = (char*)StrMapSearch(params, "PASSWORD2");
+ bool create = (StrCmp(cmd, "CREATE") == 0);
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.Name, sizeof(t.Name), username);
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+ // Read the original user data in the case of edit mode.
+ if(!create)
+ {
+ retcode = StGetUser(context->Admin, &t);
+ if(retcode != ERR_NO_ERROR)
+ {
+ return WuErrorPage(retcode);
+ }
+ }
+
+ // Set the authentication method
+ if(StrCmp(authtype, "ANONYMOUS") == 0)
+ {
+ FreeAuthData(t.AuthType, t.AuthData);
+ t.AuthType = AUTHTYPE_ANONYMOUS;
+ t.AuthData = NULL;
+ }
+ else if(StrCmp(authtype, "PASSWORD") == 0)
+ {
+ if(StrCmp(password,password2) != 0)
+ {
+ // Password for confirmation is mismatched
+ return WuErrorPage(ERR_INVALID_PARAMETER);
+ }
+
+ // If the password field has not changed, leave as is
+ if(t.AuthType != AUTHTYPE_PASSWORD || StrCmp(password, WU_PASSWORD_NOCHANGE) != 0)
+ {
+ FreeAuthData(t.AuthType, t.AuthData);
+ t.AuthType = AUTHTYPE_PASSWORD;
+ t.AuthData = NewPasswordAuthData(username, password);
+ }
+ }
+ else
+ {
+ // Parameters of the authentication method is invalid
+ return WuErrorPage(ERR_INVALID_PARAMETER);
+ }
+
+ // Set the user information
+ if(create)
+ {
+ retcode = StCreateUser(context->Admin, &t);
+ }
+ else
+ {
+ retcode = StSetUser(context->Admin, &t);
+ }
+ if(retcode != ERR_NO_ERROR)
+ {
+ return WuErrorPage(retcode);
+ }
+
+ Format(tmp, sizeof(tmp), "%s?KEY=%s&HUB=%s", WP_USER, sessionkey, hubname);
+ return WuRedirectPage(tmp);
+ }
+
+ // Generate the user edit page
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+ if( username == NULL )
+ {
+ t.AuthType = AUTHTYPE_PASSWORD;
+ }else{
+ UINT retcode;
+ StrCpy(t.Name, sizeof(t.Name), username);
+ retcode = StGetUser(context->Admin, &t);
+ if(retcode != ERR_NO_ERROR)
+ {
+ return WuErrorPage(retcode);
+ }
+ }
+
+ buf = WuUniReadFile("|"WP_EDITUSER);
+
+ if( username == NULL)
+ {
+ WuEnableTag(&buf, L"{USERNAMEINPUT}");
+ WuUniReplace(&buf, L"{USERNAME}", L"");
+ WuUniReplace(&buf, L"{CMDNAME}", L"CREATE");
+ WuUniReplace(&buf, L"{PASSWORD}", L"");
+ }
+ else
+ {
+ WuEnableTag(&buf, L"{USERNAMEHIDDEN}");
+ WuUniStrReplace(&buf, L"{USERNAME}", username);
+ WuUniReplace(&buf, L"{CMDNAME}", L"SET");
+ WuUniStrReplace(&buf, L"{PASSWORD}", WU_PASSWORD_NOCHANGE);
+ }
+
+ // Select the authentication method
+ if(t.AuthType == AUTHTYPE_ANONYMOUS)
+ {
+ WuUniReplace(&buf, L"{SELANONYM}", L"checked");
+ }
+ else
+ {
+ WuUniReplace(&buf, L"{SELANONYM}", L"");
+ if(t.AuthType == AUTHTYPE_PASSWORD)
+ {
+ WuUniReplace(&buf, L"{SELPASSWD}", L"checked");
+ }
+ else
+ {
+ WuUniReplace(&buf, L"{SELPASSWD}", L"");
+ }
+ }
+
+ WuUniReplace(&buf, L"{REALNAME}", t.Realname);
+ WuUniReplace(&buf, L"{NOTETEXT}", t.Note);
+ WuUniStrReplace(&buf, L"{GROUPNAME}", t.GroupName);
+ GetDateTimeStr64Uni(utmp, sizeof(utmp), SystemToLocal64(t.ExpireTime));
+ WuUniReplace(&buf, L"{EXPIREDATE}", utmp);
+
+ WuUniStrReplace(&buf, L"{SESSIONKEY}", sessionkey);
+ WuUniStrReplace(&buf, L"{HUBNAME}", hubname);
+ WuUniStrReplace(&buf, L"{LINK_EDITUSER}", WP_EDITUSER);
+ WuUniStrReplace(&buf, L"{LINK_USER}", WP_USER);
+
+ return buf;
+}
+
+// Create a new Virtual HUB
+static wchar_t *WpNewHub(WEBUI *wu, LIST *params)
+{
+ char *sessionkey = (char*)StrMapSearch(params, "KEY");
+ WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
+ char *cmd = (char*)StrMapSearch(params, "CMD");
+ wchar_t *buf;
+
+ if(context == NULL)
+ {
+ return WuRedirectPage(WP_LOGIN);
+ }
+
+ if(StrCmp(cmd, "CREATE") == 0)
+ {
+ UINT retcode;
+ char tmp[MAX_SIZE];
+ RPC_CREATE_HUB t;
+ RPC_SERVER_INFO t2;
+ char *hubname = (char*)StrMapSearch(params, "NAME");
+ char *passwd = (char*)StrMapSearch(params, "PASSWD");
+ char *passwd2 = (char*)StrMapSearch(params, "PASSWD2");
+
+ if(strcmp(passwd,passwd2) != 0)
+ {
+ return WuErrorPage(ERR_INVALID_PARAMETER);
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+ Hash(t.HashedPassword, passwd, StrLen(passwd), true);
+ HashPassword(t.SecurePassword, ADMINISTRATOR_USERNAME, passwd);
+ t.Online = true;
+ t.HubType = HUB_TYPE_STANDALONE;
+
+ // Set to dynamic HUB in the case of cluster controller
+ Zero(&t2, sizeof(t2));
+ if (StGetServerInfo(context->Admin, &t2) == ERR_NO_ERROR)
+ {
+ if (t2.ServerType == SERVER_TYPE_FARM_CONTROLLER)
+ {
+ t.HubType = HUB_TYPE_FARM_DYNAMIC;
+ }
+ FreeRpcServerInfo(&t2);
+ }
+
+ retcode = StCreateHub(context->Admin, &t);
+ if(retcode != ERR_NO_ERROR)
+ {
+ return WuErrorPage(retcode);
+ }
+
+ Format(tmp, sizeof(tmp), "%s?KEY=%s", WP_SERVER, sessionkey);
+ return WuRedirectPage(tmp);
+ }
+
+ buf = WuUniReadFile("|"WP_NEWHUB);
+ WuUniStrReplace(&buf, L"{SESSIONKEY}", sessionkey);
+ WuUniStrReplace(&buf, L"{LINK_NEWHUB}", WP_NEWHUB);
+ WuUniStrReplace(&buf, L"{LINK_SERVER}", WP_SERVER);
+ return buf;
+}
+
+// License management page
+static wchar_t *WpLicense(WEBUI *wu, LIST *params)
+{
+ char *sessionkey = (char*)StrMapSearch(params, "KEY");
+ WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
+ char *cmd = (char*)StrMapSearch(params, "CMD");
+ UINT retcode;
+ wchar_t *buf;
+ LIST *strmap;
+
+ if(context == NULL)
+ {
+ return WuRedirectPage(WP_LOGIN);
+ }
+
+ // Add a license
+ if(StrCmp(cmd, "ADD") == 0)
+ {
+ RPC_TEST t;
+ char tmp[MAX_SIZE];
+ char *licensekey = (char*)StrMapSearch(params, "KEYSTRINGS");
+
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.StrValue, sizeof(t.StrValue), licensekey);
+
+ retcode = StAddLicenseKey(context->Admin, &t);
+ if(retcode != ERR_NO_ERROR)
+ {
+ return WuErrorPage(retcode);
+ }
+
+ Format(tmp, sizeof(tmp), "%s?KEY=%s", WP_LICENSE, sessionkey);
+ return WuRedirectPage(tmp);
+
+ }
+ // Remove the license
+ else if(StrCmp(cmd, "DEL") == 0)
+ {
+ RPC_TEST t;
+ char tmp[MAX_SIZE];
+ char *id = (char*)StrMapSearch(params, "ID");
+
+ Zero(&t, sizeof(t));
+ t.IntValue = ToInt(id);
+
+ retcode = StDelLicenseKey(context->Admin, &t);
+ if(retcode != ERR_NO_ERROR)
+ {
+ return WuErrorPage(retcode);
+ }
+
+ Format(tmp, sizeof(tmp), "%s?KEY=%s", WP_LICENSE, sessionkey);
+ return WuRedirectPage(tmp);
+ }
+
+ buf = WuUniReadFile("|"WP_LICENSE);
+ strmap = WuUniMakeTableFromTemplate(&buf, L"<!--STRMAP:", L"-->");
+
+ // Enumerate the license keys
+ {
+ UINT i;
+ RPC_ENUM_LICENSE_KEY t;
+ wchar_t *tmpl;
+ Zero(&t, sizeof(t));
+
+ retcode = StEnumLicenseKey(context->Admin, &t);
+
+ if(retcode != ERR_NO_ERROR)
+ {
+ WuFreeStrStrMap(strmap);
+ Free(buf);
+ return WuErrorPage(retcode);
+ }
+
+ tmpl = WuUniGetTemplate(&buf, L"<!--LICENSES_TMPL:", L":LICENSES_TMPL-->", true);
+
+ for(i = 0; i < t.NumItem; i++)
+ {
+ wchar_t *status, expires[128];
+ wchar_t *tmp = UniCopyStr(tmpl);
+ RPC_ENUM_LICENSE_KEY_ITEM *item = &t.Items[i];
+
+ status = LiGetLicenseStatusStr(item->Status);
+
+ if(item->Expires == 0)
+ {
+ UniStrCpy(expires, sizeof(expires), StrMapSearch(strmap, "EXPIRE_INFINITE"));
+ }
+ else
+ {
+ GetDateStrEx64(expires, sizeof(expires), item->Expires, NULL);
+ }
+
+ WuUniUintReplace(&tmp, L"{ID}", i);
+ WuUniStrReplace(&tmp, L"{LICENSEKEY}", item->LicenseKey);
+ WuUniStrReplace(&tmp, L"{LICENSENAME}", item->LicenseName);
+ WuUniReplace(&tmp, L"{STATUS}", status);
+ WuUniReplace(&tmp, L"{EXPIRES}", expires);
+ WuUniStrReplace(&tmp, L"{LICENSEID}", item->LicenseId);
+ WuUniUintReplace(&tmp, L"{PRODUCTID}", item->ProductId);
+ WuUniUint64Replace(&tmp, L"{SYSTEMID}", item->SystemId);
+ WuUniUintReplace(&tmp, L"{SERIALID}", item->SerialId);
+
+ WuUniInsertBefore(&buf, tmp, L"<!--LICENSES-->");
+ Free(tmp);
+ }
+ FreeRpcEnumLicenseKey(&t);
+ Free(tmpl);
+ }
+
+ // Show the license status
+ {
+ RPC_LICENSE_STATUS t;
+
+ Zero(&t, sizeof(t));
+
+ retcode = StGetLicenseStatus(context->Admin, &t);
+
+ if(retcode != ERR_NO_ERROR)
+ {
+ WuFreeStrStrMap(strmap);
+ Free(buf);
+ return WuErrorPage(retcode);
+ }
+
+ WuUniStrReplace(&buf, L"{LSEDITIONNAME}", t.EditionStr);
+ WuUniUint64Replace(&buf, L"{LSSERVERID}", t.SystemId);
+ if(t.SystemExpires == 0)
+ {
+ WuUniReplace(&buf, L"{LSEXPIRES}", StrMapSearch(strmap, "NOEXPIRE"));
+ }
+ else
+ {
+ wchar_t expires[128];
+ GetDateStrEx64(expires, sizeof(expires), t.SystemExpires, NULL);
+ WuUniReplace(&buf, L"{LSEXPIRES}", expires);
+ }
+
+ if(t.NumBridgeConnectLicense == INFINITE)
+ {
+ WuUniReplace(&buf, L"{LSNUMBRIDGES}", StrMapSearch(strmap, "LICENSE_INFINITE"));
+ }
+ else
+ {
+ WuUniUintReplace(&buf, L"{LSNUMBRIDGES}", t.NumBridgeConnectLicense);
+ }
+
+ if(t.NumClientConnectLicense == INFINITE)
+ {
+ WuUniReplace(&buf, L"{LSNUMCLIENTS}", StrMapSearch(strmap, "LICENSE_INFINITE"));
+ }
+ else
+ {
+ WuUniUintReplace(&buf, L"{LSNUMCLIENTS}", t.NumClientConnectLicense);
+ }
+
+ }
+
+ WuUniStrReplace(&buf, L"{LINK_LICENSE}", WP_LICENSE);
+ WuUniStrReplace(&buf, L"{LINK_SERVER}", WP_SERVER);
+ WuUniStrReplace(&buf, L"{SESSIONKEY}", sessionkey);
+ WuFreeStrStrMap(strmap);
+
+ return buf;
+
+}
+
+// Local bridge setup page
+static wchar_t *WpLocalBridge(WEBUI *wu, LIST *params)
+{
+ char *sessionkey = (char*)StrMapSearch(params, "KEY");
+ WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
+ char *cmd = (char*)StrMapSearch(params, "CMD");
+ UINT retcode;
+ wchar_t *buf;
+ LIST *strmap;
+
+ if(context == NULL)
+ {
+ return WuRedirectPage(WP_LOGIN);
+ }
+
+ // Create a local bridge
+ if(StrCmp(cmd, "CREATE") == 0)
+ {
+ RPC_LOCALBRIDGE t;
+ RPC_ENUM_ETH eth;
+ char tmp[MAX_SIZE];
+ char *tapmode = (char*)StrMapSearch(params, "TAPMODE");
+ char *tapname = (char*)StrMapSearch(params, "TAPNAME");
+ char *devid = (char*)StrMapSearch(params, "DEVID");
+ char *hubname = (char*)StrMapSearch(params, "LBHUBNAME");
+ UINT id = ToInt(devid);
+
+ Zero(&eth, sizeof(eth));
+ retcode = StEnumEthernet(context->Admin, &eth);
+
+ if(retcode != ERR_NO_ERROR)
+ {
+ FreeRpcEnumEth(&eth);
+ return WuErrorPage(retcode);
+ }
+
+ Zero(&t, sizeof(t));
+ t.Active = true;
+ if(StrCmp(tapmode, "YES") == 0)
+ {
+ t.TapMode = true;
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), tapname);
+ }
+ else
+ {
+ t.TapMode = false;
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), eth.Items[id].DeviceName);
+ }
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+ t.Online = true;
+ FreeRpcEnumEth(&eth);
+
+ retcode = StAddLocalBridge(context->Admin, &t);
+
+ if(retcode != ERR_NO_ERROR)
+ {
+ return WuErrorPage(retcode);
+ }
+
+ Format(tmp, sizeof(tmp), "%s?KEY=%s", WP_LOCALBRIDGE, sessionkey);
+ return WuRedirectPage(tmp);
+ }
+
+ // Delete the local bridge
+ if(StrCmp(cmd, "DEL") == 0)
+ {
+ RPC_LOCALBRIDGE t;
+ RPC_ENUM_LOCALBRIDGE et;
+ char tmp[MAX_SIZE];
+ char *listid = (char*)StrMapSearch(params, "LISTID");
+ UINT id = ToInt(listid);
+
+ Zero(&et, sizeof(et));
+ retcode = StEnumLocalBridge(context->Admin, &et);
+ if(retcode != ERR_NO_ERROR)
+ {
+ return WuErrorPage(retcode);
+ }
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.DeviceName, sizeof(t.DeviceName), et.Items[id].DeviceName);
+ StrCpy(t.HubName, sizeof(t.HubName), et.Items[id].HubName);
+ FreeRpcEnumLocalBridge(&et);
+
+ retcode = StDeleteLocalBridge(context->Admin, &t);
+
+ if(retcode != ERR_NO_ERROR)
+ {
+ return WuErrorPage(retcode);
+ }
+
+ Format(tmp, sizeof(tmp), "%s?KEY=%s", WP_LOCALBRIDGE, sessionkey);
+ return WuRedirectPage(tmp);
+ }
+
+ // Show the current local bridge list and the Virtual HUB list and the device list to be bridged
+ buf = WuUniReadFile("|"WP_LOCALBRIDGE);
+ strmap = WuUniMakeTableFromTemplate(&buf, L"<!--STRMAP:", L"-->");
+
+ // Show the current local bridge list
+ {
+ UINT i;
+ RPC_ENUM_LOCALBRIDGE t;
+ wchar_t *tmpl;
+
+ Zero(&t, sizeof(t));
+ retcode = StEnumLocalBridge(context->Admin, &t);
+
+ if(retcode != ERR_NO_ERROR)
+ {
+ FreeRpcEnumLocalBridge(&t);
+ Free(buf);
+ WuFreeStrStrMap(strmap);
+ return WuErrorPage(retcode);
+ }
+
+ tmpl = WuUniGetTemplate(&buf, L"<!--LBLIST_TMPL", L"LBLIST_TMPL-->", true);
+
+ for(i = 0; i < t.NumItem; i++)
+ {
+ RPC_LOCALBRIDGE *item = &t.Items[i];
+ wchar_t *tmp = UniCopyStr(tmpl);
+ WuUniUintReplace(&tmp, L"{LISTID}", i);
+ WuUniStrReplace(&tmp, L"{HUBNAME}", item->HubName);
+ WuUniStrReplace(&tmp, L"{DEVICENAME}", item->DeviceName);
+ WuUniReplace(&tmp, L"{STATUS}", item->Online ? item->Active ? StrMapSearch(strmap, "BRIDGE_ONLINE")
+ : StrMapSearch(strmap, "BRIDGE_ERROR") : StrMapSearch(strmap, "BRIDGE_OFFLINE"));
+ WuUniInsertBefore(&buf, tmp, L"<!--LBLIST-->");
+ Free(tmp);
+ }
+ Free(tmpl);
+ FreeRpcEnumLocalBridge(&t);
+ }
+
+ // Show the Virtual HUB list
+ {
+ wchar_t *tmpl;
+ RPC_ENUM_HUB t;
+ UINT i;
+
+ Zero(&t, sizeof(t));
+ retcode = StEnumHub(context->Admin, &t);
+
+ if(retcode != ERR_NO_ERROR)
+ {
+ FreeRpcEnumHub(&t);
+ Free(buf);
+ WuFreeStrStrMap(strmap);
+ return WuErrorPage(retcode);
+ }
+
+ tmpl = WuUniGetTemplate(&buf, L"<!--HUBS_TMPL", L"HUBS_TMPL-->", true);
+ for(i=0; i<t.NumHub; i++)
+ {
+ wchar_t *tmp = UniCopyStr(tmpl);
+ WuUniStrReplace(&tmp, L"{LBHUBNAME}", t.Hubs[i].HubName);
+ WuUniInsertBefore(&buf, tmp, L"<!--HUBS-->");
+ Free(tmp);
+ }
+ FreeRpcEnumHub(&t);
+ Free(tmpl);
+ }
+
+ // Get the device list to be bridge
+ {
+ UINT i;
+ RPC_ENUM_ETH t;
+ wchar_t *tmpl;
+
+ Zero(&t, sizeof(t));
+ retcode = StEnumEthernet(context->Admin, &t);
+
+ if(retcode != ERR_NO_ERROR)
+ {
+ FreeRpcEnumEth(&t);
+ Free(buf);
+ WuFreeStrStrMap(strmap);
+ return WuErrorPage(retcode);
+ }
+
+ tmpl = WuUniGetTemplate(&buf, L"<!--LBDEVLIST_TMPL", L"LBDEVLIST_TMPL-->", true);
+
+ for(i = 0; i < t.NumItem; i++)
+ {
+ wchar_t *tmp = UniCopyStr(tmpl);
+ WuUniUintReplace(&tmp, L"{DEVID}", i);
+ WuUniStrReplace(&tmp, L"{ABLEDEVICE}", t.Items[i].DeviceName);
+ WuUniInsertBefore(&buf, tmp, L"<!--LBDEVLIST-->");
+ Free(tmp);
+ }
+ FreeRpcEnumEth(&t);
+ Free(tmpl);
+ }
+
+ WuUniStrReplace(&buf, L"{LINK_LOCALBRIDGE}", WP_LOCALBRIDGE);
+ WuUniStrReplace(&buf, L"{LINK_SERVER}", WP_SERVER);
+ WuUniStrReplace(&buf, L"{SESSIONKEY}", sessionkey);
+ WuFreeStrStrMap(strmap);
+
+ return buf;
+
+}
+
+// Configure the virtual DHCP function and virtual NAT (SecureNAT)
+static wchar_t *WpSecureNAT(WEBUI *wu, LIST *params)
+{
+ char *sessionkey = (char*)StrMapSearch(params, "KEY");
+
+ WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
+ char *cmd = (char*)StrMapSearch(params, "CMD");
+ char *hubname = (char*)StrMapSearch(params, "HUB");
+
+ UINT retcode;
+ wchar_t *buf;
+
+ if(context == NULL)
+ {
+ return WuRedirectPage(WP_LOGIN);
+ }
+
+ // Enable / disable the SecureNAT function
+ if(StrCmp(cmd, "ENABLE") == 0 || StrCmp(cmd, "DISABLE") == 0)
+ {
+ RPC_HUB t;
+ char tmp[MAX_SIZE];
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+ if(StrCmp(cmd, "ENABLE") == 0)
+ {
+ retcode = StEnableSecureNAT(context->Admin, &t);
+ }
+ else
+ {
+ retcode = StDisableSecureNAT(context->Admin, &t);
+ }
+
+ if(retcode != ERR_NO_ERROR)
+ {
+ return WuErrorPage(retcode);
+ }
+
+ Format(tmp, sizeof(tmp), "%s?HUB=%s&KEY=%s", WP_SECURENAT, hubname, sessionkey);
+ return WuRedirectPage(tmp);
+ }
+ // Set the SecureNAT options
+ else if(StrCmp(cmd, "SAVE") == 0)
+ {
+ char tmp[MAX_SIZE];
+ VH_OPTION t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+ // Configure the a virtual host
+ StrToMac(t.MacAddress, (char*)StrMapSearch(params, "HOSTMAC"));
+ StrToIP(&t.Ip, (char*)StrMapSearch(params, "HOSTIP"));
+ StrToIP(&t.Mask, (char*)StrMapSearch(params, "HOSTMASK"));
+
+ // Configure the virtual NAT function
+ t.UseNat = (StrCmp((char*)StrMapSearch(params, "NATCHECK"), "on") == 0);
+ t.Mtu = ToInt((char*)StrMapSearch(params, "NATMTU"));
+ t.NatTcpTimeout = ToInt((char*)StrMapSearch(params, "NATTCPTIMEOUT"));
+ t.NatUdpTimeout = ToInt((char*)StrMapSearch(params, "NATUDPTIMEOUT"));
+ t.SaveLog = (StrCmp((char*)StrMapSearch(params, "NATSAVELOG"), "on") == 0);
+
+ // Configure the virtual DHCP server function
+ t.UseDhcp = (StrCmp((char*)StrMapSearch(params, "DHCPCHECK"), "on") == 0);
+ StrToIP(&t.DhcpLeaseIPStart, (char*)StrMapSearch(params, "DHCPIPS"));
+ StrToIP(&t.DhcpLeaseIPEnd, (char*)StrMapSearch(params, "DHCPIPE"));
+ StrToIP(&t.DhcpSubnetMask, (char*)StrMapSearch(params, "DHCPMASK"));
+ t.DhcpExpireTimeSpan = ToInt((char*)StrMapSearch(params, "DHCPEXPIRE"));
+ StrToIP(&t.DhcpGatewayAddress, (char*)StrMapSearch(params, "DHCPGW"));
+ StrToIP(&t.DhcpDnsServerAddress, (char*)StrMapSearch(params, "DHCPDNS"));
+ StrCpy(t.DhcpDomainName, sizeof(t.DhcpDomainName), (char*)StrMapSearch(params, "DHCPDOMAIN"));
+
+ retcode = StSetSecureNATOption(context->Admin, &t);
+ if(retcode == ERR_NO_ERROR)
+ {
+ Format(tmp, sizeof(tmp), "%s?HUB=%s&KEY=%s", WP_SECURENAT, hubname, sessionkey);
+ return WuRedirectPage(tmp);
+ }
+ return WuErrorPage(retcode);
+ }
+
+ buf = WuUniReadFile("|"WP_SECURENAT);
+
+ // Get the enable / disable state of the current SecureNAT
+ {
+ RPC_HUB_STATUS t;
+ Zero(&t, sizeof(&t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+ retcode = StGetHubStatus(context->Admin, &t);
+
+ if(retcode != ERR_NO_ERROR)
+ {
+ Free(buf);
+ return WuErrorPage(retcode);
+ }
+
+ WuEnableTag(&buf, t.SecureNATEnabled ? L"DISABLESNAT" : L"ENABLESNAT");
+ }
+
+ // Show the advanced settings of the current SecureNAT
+ {
+ char mac[MAX_SIZE], ip[MAX_SIZE], mask[MAX_SIZE];
+ char dhcpips[MAX_SIZE], dhcpipe[MAX_SIZE], dhcpmask[MAX_SIZE];
+ char optgw[MAX_SIZE], optdns[MAX_SIZE];
+ VH_OPTION t;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hubname);
+
+ retcode = StGetSecureNATOption(context->Admin, &t);
+
+
+ // Configure the virtual interfaces
+ MacToStr(mac, sizeof(mac), t.MacAddress);
+ IPToStr(ip, sizeof(ip), &t.Ip);
+ IPToStr(mask, sizeof(mask), &t.Mask);
+ WuUniStrReplace(&buf, L"{HOSTMAC}", mac);
+ WuUniStrReplace(&buf, L"{HOSTIP}", ip);
+ WuUniStrReplace(&buf, L"{HOSTMASK}", mask);
+
+ // Configure the Virtual NAT
+ WuUniStrReplace(&buf, L"{NATCHECK}", t.UseNat ? "CHECKED" : "");
+ WuUniUintReplace(&buf, L"{NATMTU}", t.Mtu);
+ WuUniUintReplace(&buf, L"{NATTCPTIMEOUT}", t.NatTcpTimeout);
+ WuUniUintReplace(&buf, L"{NATUDPTIMEOUT}", t.NatUdpTimeout);
+
+ WuUniStrReplace(&buf, L"{NATSAVELOG}", t.SaveLog ? "CHECKED" : "");
+
+ // Configure the Virtual DHCP server
+ WuUniStrReplace(&buf, L"{DHCPCHECK}", t.UseDhcp ? "CHECKED" : "");
+
+ IPToStr(dhcpips, sizeof(dhcpips), &t.DhcpLeaseIPStart);
+ IPToStr(dhcpipe, sizeof(dhcpipe), &t.DhcpLeaseIPEnd);
+ IPToStr(dhcpmask, sizeof(dhcpmask), &t.DhcpSubnetMask);
+ WuUniStrReplace(&buf, L"{DHCPIPS}", dhcpips);
+ WuUniStrReplace(&buf, L"{DHCPIPE}", dhcpipe);
+ WuUniStrReplace(&buf, L"{DHCPMASK}", dhcpmask);
+ WuUniUintReplace(&buf, L"{DHCPEXPIRE}", t.DhcpExpireTimeSpan);
+
+ IPToStr(optgw, sizeof(optgw), &t.DhcpGatewayAddress);
+ IPToStr(optdns, sizeof(optdns), &t.DhcpDnsServerAddress);
+ WuUniStrReplace(&buf, L"{DHCPGW}", optgw);
+ WuUniStrReplace(&buf, L"{DHCPDNS}", optdns);
+ WuUniStrReplace(&buf, L"{DHCPDOMAIN}", t.DhcpDomainName);
+ }
+
+ WuUniStrReplace(&buf, L"{LINK_HUB}", WP_HUB);
+ WuUniStrReplace(&buf, L"{LINK_SECURENAT}", WP_SECURENAT);
+ WuUniStrReplace(&buf, L"{HUBNAME}", hubname);
+ WuUniStrReplace(&buf, L"{SESSIONKEY}", sessionkey);
+
+ return buf;
+}
+
+static wchar_t *WpSession(WEBUI *wu, LIST *params)
+{
+ char *sessionkey = (char*)StrMapSearch(params, "KEY");
+ WU_CONTEXT *context = WuGetContext(wu->Contexts, sessionkey);
+ char *hub = (char*)StrMapSearch(params, "HUB");
+ char *cmd = (char*)StrMapSearch(params, "CMD");
+
+ if(context == NULL)
+ {
+ return WuRedirectPage(WP_LOGIN);
+ }
+
+ if(StrCmp(cmd, "DEL") == 0)
+ {
+ char *session = (char*)StrMapSearch(params, "SESSION");
+ RPC_DELETE_SESSION t;
+ UINT retcode;
+ char tmp[MAX_SIZE];
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hub);
+ StrCpy(t.Name, sizeof(t.Name), session);
+
+ retcode = StDeleteSession(context->Admin, &t);
+ if(retcode != ERR_NO_ERROR)
+ {
+ return WuErrorPage(retcode);
+ }
+
+ Format(tmp, sizeof(tmp), "%s?HUB=%s&KEY=%s", WP_SESSION, hub, session);
+ return WuRedirectPage(tmp);
+ }
+
+ // Show the session list
+ {
+ RPC_ENUM_SESSION t;
+ UINT retcode;
+
+ Zero(&t, sizeof(t));
+ StrCpy(t.HubName, sizeof(t.HubName), hub);
+
+ retcode = StEnumSession(context->Admin, &t);
+ if(retcode != ERR_NO_ERROR)
+ {
+ return WuErrorPage(retcode);
+ }else{
+ wchar_t *buf = WuUniReadFile("|"WP_SESSION);
+ wchar_t *tmpl = WuUniGetTemplate(&buf, L"<!--SESSION_TMPL:", L":SESSION_TMPL-->", true);
+ UINT i;
+ for(i=0; i<t.NumSession; i++){
+ RPC_ENUM_SESSION_ITEM *item = &(t.Sessions[i]);
+ wchar_t *tmp = CopyUniStr(tmpl);
+
+ WuUniStrReplace(&tmp, L"{SESSION_NAME}", item->Name);
+ WuUniStrReplace(&tmp, L"{SESSION_SERVER}", item->RemoteHostname);
+ WuUniStrReplace(&tmp, L"{SESSION_USER}", item->Username);
+ WuUniStrReplace(&tmp, L"{SESSION_HOST}", item->Hostname);
+ WuUniUintReplace(&tmp, L"{SESSION_TCP}", item->CurrentNumTcp);
+ WuUniUint64Replace(&tmp, L"{SESSION_BYTES}", item->PacketSize);
+ WuUniUint64Replace(&tmp, L"{SESSION_PKTS}", item->PacketNum);
+ WuUniStrReplace(&tmp, L"{SESSION}", item->Name);
+
+ WuUniInsertBefore(&buf, tmp, L"<!--SESSIONS-->");
+ Free(tmp);
+ }
+
+ WuUniStrReplace(&buf, L"{HUBNAME}", hub);
+ WuUniStrReplace(&buf, L"{SESSIONKEY}", sessionkey);
+ WuUniStrReplace(&buf, L"{LINK_HUB}", WP_HUB);
+ WuUniStrReplace(&buf, L"{LINK_SESSION}", WP_SESSION);
+
+ FreeRpcEnumSession(&t);
+ Free(tmpl);
+ return buf;
+ }
+ }
+}
+
+
+// **** Public interface of the WebUI module
+
+// Get the page
+WU_WEBPAGE *WuGetPage(char *target, WEBUI *wu)
+{
+ char filename[MAX_SIZE];
+ LIST *params;
+ wchar_t *(*handler)(WEBUI *wu, LIST *params);
+
+ // Delete the expired session keys
+ WuExpireSessionKey(wu);
+
+ params = WuAnalyzeTarget(target, filename, sizeof(filename));
+
+ // Search for the handler corresponding to the URL
+ handler = StrMapSearch(wu->PageList, filename);
+
+ // Call the handler
+ if(handler != NULL)
+ {
+ wchar_t *unitmp;
+ WU_WEBPAGE *page;
+ unitmp = handler(wu, params);
+ WuFreeStrStrMap(params);
+ page = WuNewUniWebPage(unitmp);
+ Free(unitmp);
+ return page;
+ }
+
+ WuFreeStrStrMap(params);
+
+ // If it missed, try to read the file directly
+ if(StartWith(filename, WP_DEFAULT))
+ {
+ char tmp[MAX_SIZE] = "|";
+ BUF *buf;
+ WU_WEBPAGE *page;
+
+ StrCat(tmp, sizeof(tmp), filename);
+ buf = ReadDump(tmp);
+ if(buf == NULL)
+ {
+ return NULL;
+ }
+
+ page = WuNewWebPage(buf->Buf, buf->Size, filename);
+ FreeBuf(buf);
+ return page;
+ }
+
+ return NULL;
+}
+
+// Start the WebUI
+WEBUI *WuNewWebUI(CEDAR *cedar)
+{
+ WEBUI *wu = (WEBUI*)Malloc(sizeof(WEBUI));
+ int i;
+
+ wu->Cedar = cedar;
+
+ wu->PageList = NewStrMap();
+ for(i=0;i<sizeof(wu_pages)/sizeof(STRMAP_ENTRY);i++)
+ {
+ Add(wu->PageList, &wu_pages[i]);
+ }
+
+ wu->Contexts = NewStrMap();
+
+ return wu;
+}
+
+// Release the WebUI
+bool WuFreeWebUI(WEBUI *wu)
+{
+ UINT i;
+
+ if(wu == NULL)
+ {
+ return false;
+ }
+
+ for(i=0; i<LIST_NUM(wu->Contexts); i++)
+ {
+ STRMAP_ENTRY *se = LIST_DATA(wu->Contexts, i);
+ Free(se->Name);
+ WuFreeContext((WU_CONTEXT*)se->Value);
+ Free(se);
+ }
+ ReleaseList(wu->Contexts);
+
+ ReleaseList(wu->PageList);
+ Free(wu);
+ return true;
+}
+
+void WuFreeWebPage(WU_WEBPAGE *page)
+{
+ if(page == NULL)
+ {
+ return;
+ }
+
+ FreeHttpHeader(page->header);
+ Free(page->data);
+ Free(page);
+}
+
+// **** Module local utility functions
+
+// Initialize the context
+static WU_CONTEXT *WuNewContext(WEBUI *wu, char *hubname)
+{
+ WU_CONTEXT *context = (WU_CONTEXT*)Malloc(sizeof(WU_CONTEXT));
+
+ if(StrLen(hubname) == 0)
+ {
+ hubname=NULL;
+ }
+ context->Admin = (ADMIN*)ZeroMalloc(sizeof(ADMIN));
+ context->Admin->HubName = hubname != NULL ? CopyStr(hubname) : NULL;
+ context->Admin->Server = wu->Cedar->Server;
+ context->Admin->ServerAdmin = hubname == NULL ? true: false;
+ context->Admin->Rpc = (RPC*)ZeroMalloc(sizeof(RPC));
+ StrCpy(context->Admin->Rpc->Name, sizeof(context->Admin->Rpc->Name), "WEBUI");
+ context->Admin->Rpc->Param = context->Admin;
+ context->Admin->Rpc->ServerAdminMode = context->Admin->ServerAdmin;
+ context->Admin->Rpc->ServerMode = true;
+ context->Admin->Rpc->IsVpnServer = true;
+ context->Admin->Rpc->Lock = NewLock();
+ context->Admin->LogFileList = NULL;
+
+ context->ExpireDate = Tick64() + WU_CONTEXT_EXPIRE;
+
+ return context;
+}
+
+// Release the context
+static void WuFreeContext(WU_CONTEXT *context)
+{
+ DeleteLock(context->Admin->Rpc->Lock);
+ Free(context->Admin->Rpc);
+ Free(context->Admin->HubName);
+ Free(context->Admin);
+ Free(context);
+}
+
+// Create a WebPage structure from the Unicode string
+static WU_WEBPAGE *WuNewUniWebPage(wchar_t *content)
+{
+ WU_WEBPAGE *ret;
+
+ if(content == NULL)
+ {
+ return NULL;
+ }
+
+ ret = (WU_WEBPAGE*)Malloc(sizeof(WU_WEBPAGE));
+ ret->size = CalcUniToUtf8(content);
+ ret->data = (char*)Malloc(ret->size);
+ UniToUtf8(ret->data, ret->size, content);
+
+ ret->header = NewHttpHeader("HTTP/1.1", "202", "OK");
+ AddHttpValue(ret->header, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE4));
+ AddHttpValue(ret->header, NewHttpValue("Connection", "Keep-Alive"));
+ AddHttpValue(ret->header, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));
+
+ return ret;
+}
+
+// Generate the WebPage structure from the raw data
+static WU_WEBPAGE *WuNewWebPage(char *content, UINT size, char *filename)
+{
+ WU_WEBPAGE *ret;
+
+ if(content == NULL)
+ {
+ return NULL;
+ }
+
+ ret = (WU_WEBPAGE*)Malloc(sizeof(WU_WEBPAGE));
+ ret->size = size;
+ ret->data = (char*)Malloc(size);
+ Copy(ret->data, content, size);
+
+ ret->header = NewHttpHeader("HTTP/1.1", "202", "OK");
+ AddHttpValue(ret->header, NewHttpValue("Connection", "Keep-Alive"));
+ AddHttpValue(ret->header, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));
+
+ if(EndWith(filename, "jpg"))
+ {
+ AddHttpValue(ret->header, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE3));
+ }
+ AddHttpValue(ret->header, NewHttpValue("Content-Type", HTTP_CONTENT_TYPE4));
+
+ return ret;
+}
+
+// Return an error page
+static wchar_t *WuErrorPage(UINT errorcode)
+{
+ wchar_t *buf = WuUniReadFile("|"WP_ERROR);
+ wchar_t tmp[MAX_SIZE];
+ UniFormat(tmp, sizeof(tmp), L"%d\n<H2>%s</H2>", errorcode, GetUniErrorStr(errorcode));
+ WuUniReplace(&buf, L"ERRMSG", tmp);
+ return buf;
+}
+
+// Redirect
+static wchar_t *WuRedirectPage(char *url)
+{
+ wchar_t *buf = WuUniReadFile("|"WP_REDIRECT);
+ wchar_t tmp[MAX_SIZE];
+ StrToUni(tmp, sizeof(tmp), url);
+ WuUniReplace(&buf, L"REDIRECT_TO", tmp);
+ return buf;
+}
+
+// Analyse the URL
+static LIST *WuAnalyzeTarget(char *target,char *filename, UINT size)
+{
+ char *start, tmp;
+
+ if(target == NULL || filename == NULL)
+ {
+ return NULL;
+ }
+
+ // Process the absolute path specification
+ if(StartWith(target,"http://"))
+ {
+ // Skip http://
+ target += 7;
+
+ // Skip the host name portion
+ while(*target != '/' && *target != '\0')
+ {
+ target ++;
+ }
+
+ // Error if the "/" isn't included after "http://"
+ if(*target == '\0')
+ {
+ return NULL;
+ }
+
+ target++;
+ }
+
+ // Unescape
+ // (not implemented)
+
+ // Extract the file name portion
+ start = target;
+ while(*target != '?' && *target != '\0')
+ {
+ target ++;
+ }
+ tmp = *target;
+ *target = '\0';
+ StrCpy(filename, size, start);
+ *target = tmp;
+
+ // Interpret if there are parameters
+ if(*target == '?')
+ {
+ LIST *params = NewStrMap();
+ UINT i;
+ TOKEN_LIST *tl;
+ target++;
+ tl =ParseToken(target,"&");
+ for(i=0;i<tl->NumTokens;i++)
+ {
+ char *token = tl->Token[i];
+ char *body = token;
+ STRMAP_ENTRY *newentry = (STRMAP_ENTRY*)Malloc(sizeof(STRMAP_ENTRY));
+
+ while(*body != '=' && *body != '\0')
+ {
+ *body ++;
+ }
+ if(*body == '=')
+ {
+ *body = '\0';
+ body++;
+ }
+ newentry->Name = CopyStr(token);
+ newentry->Value = CopyStr(body);
+ Add(params, newentry);
+// Debug("PARAMS: %s : %s\n",token,body);
+ }
+ FreeToken(tl);
+ return params;
+ }
+ return NULL;
+}
+
+// Release the parameter list
+static void WuFreeStrStrMap(LIST *params)
+{
+ UINT i;
+
+ if(params == NULL)
+ {
+ return;
+ }
+
+ for(i=0; i<LIST_NUM(params); i++)
+ {
+ STRMAP_ENTRY *e = (STRMAP_ENTRY*)LIST_DATA(params, i);
+ Free(e->Name);
+ Free(e->Value);
+ Free(e);
+ }
+ ReleaseList(params);
+}
+
+// Read the UTF-8 file and convert as an Unicode string
+static wchar_t *WuUniReadFile(char *filename)
+{
+ IO *io;
+ UINT size, usize;
+ BYTE *utf8;
+ wchar_t *wchars;
+
+ // Validate arguments
+ if (filename == NULL)
+ {
+ return NULL;
+ }
+
+ io = FileOpen(filename, false);
+ if (io == NULL)
+ {
+ return NULL;
+ }
+
+ // Load the file
+ size = FileSize(io);
+ utf8 = (BYTE*)Malloc(size);
+ FileRead(io, (void*)utf8, size);
+ FileClose(io);
+
+ usize = CalcUtf8ToUni(utf8, size);
+ wchars = (wchar_t*)ZeroMalloc(usize+sizeof(wchar_t));
+ Utf8ToUni(wchars, usize, utf8, size);
+ Free(utf8);
+
+ return wchars;
+}
+
+// Replace string (with memory reallocation)
+static void WuUniReplace(wchar_t **buf, wchar_t *from, wchar_t *to)
+{
+ UINT dstsize;
+ wchar_t *oldbuf = *buf;
+
+ if(buf == NULL || from == NULL || to == NULL)
+ {
+ return;
+ }
+
+ dstsize = (UniCalcReplaceStrEx(*buf, from, to, true) + 1) * sizeof(wchar_t);
+ *buf = (wchar_t*)Malloc(dstsize);
+ UniReplaceStr(*buf, dstsize, oldbuf, from, to);
+ Free(oldbuf);
+}
+
+// Insert the string in front of a specified pattern
+static void WuUniInsertBefore(wchar_t **buf, wchar_t *insert, wchar_t *before)
+{
+ UINT tmpsize;
+ wchar_t *tmp;
+
+ if(buf == NULL || insert == NULL || before == NULL)
+ {
+ return;
+ }
+
+ tmpsize = (UniStrLen(insert)+UniStrLen(before)+1)*sizeof(wchar_t);
+ tmp = (wchar_t*)Malloc(tmpsize);
+ UniStrCpy(tmp, tmpsize, insert);
+ UniStrCat(tmp, tmpsize, before);
+ WuUniReplace(buf, before, tmp);
+ Free(tmp);
+}
+
+// Uncomment the tag specified by the keyword
+static void WuEnableTag(wchar_t **buf, wchar_t *keyword)
+{
+ wchar_t tmp[MAX_SIZE];
+ if(buf == NULL || keyword == NULL)
+ {
+ return;
+ }
+
+ UniFormat(tmp, sizeof(tmp), L"!--%s", keyword);
+ WuUniReplace(buf, tmp, L"");
+
+ UniFormat(tmp, sizeof(tmp), L"%s--", keyword);
+ WuUniReplace(buf, tmp, L"");
+ return;
+}
+
+// Generate a session key
+static char *WuNewSessionKey()
+{
+ char tmp[MD5_SIZE], *ret;
+ UINT size;
+ Rand(tmp, sizeof(tmp));
+ size = sizeof(tmp)*2+1;
+ ret = Malloc(size);
+ BinToStr(ret, size, tmp, sizeof(tmp));
+ return ret;
+}
+
+// Replace the Unicode pattern in Unicode string with ASCII string
+static void WuUniStrReplace(wchar_t **buf, wchar_t *from, char *to)
+{
+ UINT unisize;
+ wchar_t *tmp;
+
+ if(buf == NULL || *buf == NULL || from == NULL || to == NULL)
+ {
+ return;
+ }
+
+ unisize = CalcStrToUni(to);
+ tmp = (wchar_t*)Malloc(unisize);
+ StrToUni(tmp, unisize, to);
+ WuUniReplace(buf, from, tmp);
+ Free(tmp);
+}
+
+// Extract the template surrounded by specified Unicode string from Unicode string
+static wchar_t *WuUniGetTemplate(wchar_t **str, wchar_t *start, wchar_t *end, bool erase)
+{
+ UINT startidx, endidx, len, size, i;
+ wchar_t *ret;
+
+ if(str == NULL || *str == NULL || start == NULL || end == NULL)
+ {
+ return NULL;
+ }
+
+ startidx = UniSearchStr(*str, start, 0);
+ if(startidx == INFINITE)
+ {
+ return NULL;
+ }
+ startidx += UniStrLen(start);
+
+ endidx = UniSearchStr(*str, end, startidx);
+ if(endidx == INFINITE)
+ {
+ return NULL;
+ }
+
+ len = endidx - startidx;
+ size = (len + 1) * sizeof(wchar_t);
+ ret = (wchar_t*)Malloc(size);
+ for(i=0; i<len; i++)
+ {
+ ret[i] = (*str)[startidx + i];
+ }
+ ret[i] = 0;
+
+ if(erase)
+ {
+ wchar_t tmp[MAX_SIZE*10];
+ UniFormat(tmp, sizeof(tmp), L"%s%s%s", start, ret, end);
+ WuUniReplace(str, tmp, L"");
+ }
+ return ret;
+}
+
+// Replace the Unicode pattern in the Unicode string with the UINT number
+static void WuUniUintReplace(wchar_t **buf, wchar_t *key, UINT num)
+{
+ wchar_t tmp[MAX_SIZE];
+ UniFormat(tmp, sizeof(tmp), L"%d", num);
+ WuUniReplace(buf, key, tmp);
+}
+
+// Replace the Unicode pattern in the Unicode string with the UINT64 number
+static void WuUniUint64Replace(wchar_t **buf, wchar_t *key, UINT64 num)
+{
+ wchar_t tmp[MAX_SIZE];
+ UniFormat(tmp, sizeof(tmp), L"%I64d", num);
+ WuUniReplace(buf, key, tmp);
+}
+
+// Copy the Unicode string until the appearance of the specified character (escapable with '\')
+static wchar_t *WuUniCopyStrTill(wchar_t *str, wchar_t delimiter, wchar_t **ret){
+ UINT num = 0, i;
+ wchar_t *next = str;
+ wchar_t *ptr = str;
+
+ // Count the number of characters to copy
+ while(*next)
+ {
+ if(*next==L'\\')
+ {
+ next++;
+ if(*next == 0)
+ {
+ break;
+ }
+ }
+ else
+ {
+ if(*next == delimiter)
+ {
+ break;
+ }
+ }
+ next++;
+ num++;
+ }
+
+ // Allocate the memory and copy the string
+ *ret = (wchar_t*)Malloc((num+1)*sizeof(wchar_t));
+ for(i=0;i<num;i++)
+ {
+ if(*ptr == L'\\')
+ {
+ ptr++;
+ }
+ (*ret)[i] = *ptr;
+ ptr++;
+ }
+ (*ret)[num]=0;
+
+ // Return a pointer to the next to the delimiter or the end of the string
+ return *next ? next+1 : next;
+}
+
+// Create a string table from Unicode string
+static LIST *WuUniMakeTable(wchar_t *def)
+{
+ LIST *table;
+ STRMAP_ENTRY *entry;
+
+ if(def==NULL)
+ {
+ return NULL;
+ }
+
+ table = NewStrMap();
+ while(*def)
+ {
+ wchar_t *keytmp;
+ UINT keylen;
+ entry = (STRMAP_ENTRY*)Malloc(sizeof(STRMAP_ENTRY));
+ def = WuUniCopyStrTill(def, L':', &keytmp);
+ keylen = CalcUniToStr(keytmp);
+ entry->Name = (char*)Malloc(keylen);
+ UniToStr(entry->Name, keylen, keytmp);
+ def = WuUniCopyStrTill(def, L',', (wchar_t**)&(entry->Value));
+ Add(table, entry);
+ Free(keytmp);
+ }
+ return table;
+}
+
+// Extract the template from Unicode string, and create a string table from it
+static LIST *WuUniMakeTableFromTemplate(wchar_t **str, wchar_t *start, wchar_t *end)
+{
+ wchar_t *tmpl = WuUniGetTemplate(str, start, end, true);
+ LIST *ret = WuUniMakeTable(tmpl);
+ Free(tmpl);
+ return ret;
+}
+
+// Delete the expired session key
+static void WuExpireSessionKey(WEBUI *wu)
+{
+ LIST *Expired = NewList(NULL);
+ UINT i;
+
+ LockList(wu->Contexts);
+
+ for(i=0; i<LIST_NUM(wu->Contexts); i++)
+ {
+ STRMAP_ENTRY *entry = (STRMAP_ENTRY*)LIST_DATA(wu->Contexts, i);
+ WU_CONTEXT *context = (WU_CONTEXT*)entry->Value;
+ if(context->ExpireDate < Tick64())
+ {
+ Add(Expired, entry);
+ }
+ }
+
+ for(i=0; i<LIST_NUM(Expired); i++)
+ {
+ STRMAP_ENTRY *entry = LIST_DATA(Expired, i);
+ Delete(wu->Contexts, entry);
+ Free(entry->Name);
+ WuFreeContext(entry->Value);
+ Free(entry);
+ }
+ ReleaseList(Expired);
+
+ UnlockList(wu->Contexts);
+}
+
+// Get the context, and extend its expiration date
+static WU_CONTEXT *WuGetContext(LIST *contexts, char *sessionkey)
+{
+ WU_CONTEXT *ret = StrMapSearch(contexts, sessionkey);
+ if(ret != NULL)
+ {
+ ret->ExpireDate = Tick64() + WU_CONTEXT_EXPIRE;
+ }
+ return ret;
+}
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/WebUI.h b/src/Cedar/WebUI.h
new file mode 100644
index 00000000..944db614
--- /dev/null
+++ b/src/Cedar/WebUI.h
@@ -0,0 +1,119 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Tetsuo Sugiyama
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// WebUI.h
+// Header of WebUI.c
+
+#define WU_PASSWORD_NOCHANGE "********"
+#define WU_CONTEXT_EXPIRE 600000
+
+// Prototype declaration
+
+typedef struct WEBUI
+{
+ CEDAR *Cedar;
+ LIST *PageList;
+ LIST *Contexts;
+} WEBUI;
+
+// WebUI context
+typedef struct WU_CONTEXT
+{
+ ADMIN *Admin;
+ UINT64 ExpireDate;
+} WU_CONTEXT;
+
+typedef struct WU_WEBPAGE
+{
+ char *data;
+ UINT size;
+ HTTP_HEADER *header;
+} WU_WEBPAGE;
+
+// Prototype declaration
+bool WuFreeWebUI(WEBUI *wu);
+WEBUI *WuNewWebUI(CEDAR *cedar);
+WU_WEBPAGE *WuGetPage(char *target, WEBUI *wu);
+void WuFreeWebPage(WU_WEBPAGE *page);
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Win32Com.cpp b/src/Cedar/Win32Com.cpp
new file mode 100644
index 00000000..0500fd00
--- /dev/null
+++ b/src/Cedar/Win32Com.cpp
@@ -0,0 +1,979 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Win32Com.c
+// Win32 COM module call
+
+#include <GlobalConst.h>
+
+#ifdef WIN32
+
+#define WIN32COM_CPP
+
+#define _WIN32_DCOM
+
+//#define _WIN32_WINNT 0x0502
+//#define WINVER 0x0502
+#include <winsock2.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <wininet.h>
+#include <Wbemidl.h>
+#include <comdef.h>
+#include <Mshtmhst.h>
+#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#include <iphlpapi.h>
+#include <Natupnp.h>
+#include <devguid.h>
+#include <regstr.h>
+#include <cfgmgr32.h>
+#include <tchar.h>
+#include <objbase.h>
+#include <Setupapi.h>
+#include "netcfgn.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+extern "C"
+{
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+}
+#include "../PenCore/resource.h"
+
+// Add a UPnP port
+bool Win32UPnPAddPort(UINT outside_port, UINT inside_port, bool udp, char *local_ip, wchar_t *description, bool remove_before_add)
+{
+ bool ret = false;
+ HRESULT hr;
+ IUPnPNAT *nat = NULL;
+ wchar_t ip_str[MAX_SIZE];
+ BSTR bstr_ip, bstr_description, bstr_protocol;
+ wchar_t *protocol_str = (udp ? L"UDP" : L"TCP");
+ // Validate arguments
+ if (outside_port == 0 || outside_port >= 65536 || inside_port == 0 || inside_port >= 65536 ||
+ IsEmptyStr(local_ip) || UniIsEmptyStr(description))
+ {
+ return false;
+ }
+
+ StrToUni(ip_str, sizeof(ip_str), local_ip);
+ bstr_ip = SysAllocString(ip_str);
+ bstr_description = SysAllocString(description);
+ bstr_protocol = SysAllocString(protocol_str);
+
+ hr = CoCreateInstance(CLSID_UPnPNAT, NULL, CLSCTX_INPROC_SERVER, IID_IUPnPNAT, (void **)&nat);
+
+ if (SUCCEEDED(hr))
+ {
+ if (nat != NULL)
+ {
+ IStaticPortMappingCollection *collection = NULL;
+ hr = nat->get_StaticPortMappingCollection(&collection);
+
+ if (SUCCEEDED(hr))
+ {
+ if (collection != NULL)
+ {
+ IStaticPortMapping *mapping = NULL;
+
+ if (remove_before_add)
+ {
+ hr = collection->Remove((long)outside_port, bstr_protocol);
+ }
+
+ hr = collection->Add((long)outside_port, bstr_protocol, (long)inside_port,
+ bstr_ip, VARIANT_TRUE, bstr_description, &mapping);
+
+ if (SUCCEEDED(hr))
+ {
+ ret = true;
+
+ if (mapping != NULL)
+ {
+ mapping->Release();
+ }
+ }
+
+ collection->Release();
+ }
+ else
+ {
+ WHERE;
+ }
+ }
+ else
+ {
+ WHERE;
+ }
+
+ nat->Release();
+ }
+ else
+ {
+ WHERE;
+ }
+ }
+ else
+ {
+ WHERE;
+ }
+
+ SysFreeString(bstr_ip);
+ SysFreeString(bstr_description);
+ SysFreeString(bstr_protocol);
+
+ return ret;
+}
+
+// Install the NDIS protocol driver
+bool InstallNdisProtocolDriver(wchar_t *inf_path, wchar_t *id, UINT lock_timeout)
+{
+ bool ret = false;
+ HRESULT hr;
+ INetCfg *pNetCfg;
+ HINSTANCE hSetupApiDll = NULL;
+ BOOL (WINAPI *_SetupCopyOEMInfW)(PCWSTR, PCWSTR, DWORD, DWORD, PWSTR, DWORD, PDWORD, PWSTR *) = NULL;
+ BOOL (WINAPI *_SetupUninstallOEMInfW)(PCWSTR, DWORD, PVOID) = NULL;
+ // Validate arguments
+ if (inf_path == NULL || id == NULL)
+ {
+ return false;
+ }
+
+ hSetupApiDll = LoadLibraryA("setupapi.dll");
+ if (hSetupApiDll == NULL)
+ {
+ WHERE;
+ goto LABEL_CLEANUP;
+ }
+
+ _SetupCopyOEMInfW =
+ (UINT (__stdcall *)(PCWSTR,PCWSTR,DWORD,DWORD,PWSTR,DWORD,PDWORD,PWSTR *))
+ GetProcAddress(hSetupApiDll, "SetupCopyOEMInfW");
+
+ _SetupUninstallOEMInfW =
+ (UINT (__stdcall *)(PCWSTR,DWORD,PVOID))
+ GetProcAddress(hSetupApiDll, "SetupUninstallOEMInfW");
+
+ if (_SetupCopyOEMInfW == NULL || _SetupUninstallOEMInfW == NULL)
+ {
+ WHERE;
+ goto LABEL_CLEANUP;
+ }
+
+ hr = CoCreateInstance(CLSID_CNetCfg, NULL, CLSCTX_INPROC_SERVER, IID_INetCfg, (void **)&pNetCfg);
+
+ if (SUCCEEDED(hr))
+ {
+ INetCfgLock *pLock;
+
+ hr = pNetCfg->QueryInterface(IID_INetCfgLock, (PVOID*)&pLock);
+
+ if (SUCCEEDED(hr))
+ {
+ LPWSTR locked_by;
+
+ hr = pLock->AcquireWriteLock(lock_timeout, L"SoftEther VPN", &locked_by);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pNetCfg->Initialize(NULL);
+
+ if (SUCCEEDED(hr))
+ {
+ wchar_t inf_dir[MAX_PATH];
+
+ GetDirNameFromFilePathW(inf_dir, sizeof(inf_dir), inf_path);
+
+ if (_SetupCopyOEMInfW(inf_path, inf_dir, SPOST_PATH, 0, NULL, 0, NULL, 0))
+ {
+ INetCfgClassSetup *pSetup;
+
+ hr = pNetCfg->QueryNetCfgClass(&GUID_DEVCLASS_NETTRANS, IID_INetCfgClassSetup, (void **)&pSetup);
+
+ if (SUCCEEDED(hr))
+ {
+ OBO_TOKEN token;
+ INetCfgComponent *pComponent;
+
+ Zero(&token, sizeof(token));
+
+ token.Type = OBO_USER;
+
+ hr = pSetup->Install(id, &token, 0, 0, NULL, NULL, &pComponent);
+
+ if (SUCCEEDED(hr))
+ {
+ pNetCfg->Apply();
+
+ ret = true;
+ }
+ else
+ {
+ WHERE;
+ Debug("0x%x\n", hr);
+ }
+
+ pSetup->Release();
+ }
+ else
+ {
+ WHERE;
+ }
+
+ if (ret == false)
+ {
+ wchar_t dst_inf_name[MAX_PATH];
+ DWORD dst_inf_name_size = MAX_PATH;
+
+ if (_SetupCopyOEMInfW(inf_path, inf_dir, SPOST_PATH, SP_COPY_REPLACEONLY,
+ dst_inf_name, dst_inf_name_size, &dst_inf_name_size, NULL) == false &&
+ GetLastError() == ERROR_FILE_EXISTS)
+ {
+ _SetupUninstallOEMInfW(dst_inf_name, 0, NULL);
+ }
+ }
+ }
+ else
+ {
+ WHERE;
+ }
+ }
+ else
+ {
+ WHERE;
+ }
+
+ pLock->ReleaseWriteLock();
+ }
+ else
+ {
+ WHERE;
+ }
+
+ pLock->Release();
+ }
+
+ pNetCfg->Release();
+ }
+ else
+ {
+ WHERE;
+ }
+
+LABEL_CLEANUP:
+
+ if (hSetupApiDll != NULL)
+ {
+ FreeLibrary(hSetupApiDll);
+ }
+
+ return ret;
+}
+
+typedef struct FOLDER_DLG_INNER_DATA
+{
+ wchar_t *default_dir;
+} FOLDER_DLG_INNER_DATA;
+
+int CALLBACK FolderDlgInnerCallbackA(HWND hWnd, UINT msg, LPARAM lParam, LPARAM lData)
+{
+ FOLDER_DLG_INNER_DATA *data = (FOLDER_DLG_INNER_DATA *)lData;
+ LPITEMIDLIST pidl;
+
+ switch (msg)
+ {
+ case BFFM_INITIALIZED:
+ if (data->default_dir != NULL)
+ {
+ char *default_dir_a = CopyUniToStr(data->default_dir);
+
+ SendMessage(hWnd, BFFM_SETSELECTIONA, true, (LPARAM)default_dir_a);
+
+ Free(default_dir_a);
+ }
+ break;
+
+ case BFFM_SELCHANGED:
+ pidl = (LPITEMIDLIST)lParam;
+
+ if (pidl)
+ {
+ char tmp[MAX_PATH];
+
+ Zero(tmp, sizeof(tmp));
+ if (SHGetPathFromIDListA(pidl, tmp))
+ {
+ SendMessage(hWnd, BFFM_ENABLEOK, 0, 1);
+ }
+ else
+ {
+ SendMessage(hWnd, BFFM_ENABLEOK, 0, 0);
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
+
+char *FolderDlgInnerA(HWND hWnd, wchar_t *title, char *default_dir)
+{
+ BROWSEINFOA info;
+ char display_name[MAX_PATH];
+ FOLDER_DLG_INNER_DATA data;
+ LPMALLOC pMalloc;
+ char *ret = NULL;
+ char *title_a;
+ if (UniIsEmptyStr(title))
+ {
+ title = NULL;
+ }
+ if (IsEmptyStr(default_dir))
+ {
+ default_dir = NULL;
+ }
+
+ Zero(&data, sizeof(data));
+ data.default_dir = CopyStrToUni(default_dir);
+
+ Zero(display_name, sizeof(display_name));
+ Zero(&info, sizeof(info));
+ info.hwndOwner = hWnd;
+ info.pidlRoot = NULL;
+ info.pszDisplayName = display_name;
+ title_a = CopyUniToStr(title);
+ info.lpszTitle = title_a;
+ info.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS | BIF_VALIDATE | BIF_SHAREABLE;
+ info.lpfn = FolderDlgInnerCallbackA;
+ info.lParam = (LPARAM)&data;
+
+ if (SUCCEEDED(SHGetMalloc(&pMalloc)))
+ {
+ LPITEMIDLIST pidl;
+
+ pidl = SHBrowseForFolderA(&info);
+
+ if (pidl)
+ {
+ char tmp[MAX_PATH];
+
+ if (SHGetPathFromIDListA(pidl, tmp))
+ {
+ ret = CopyStr(tmp);
+ }
+
+ pMalloc->Free(pidl);
+ }
+
+ pMalloc->Release();
+ }
+
+ Free(data.default_dir);
+ Free(title_a);
+
+ return ret;
+}
+
+int CALLBACK FolderDlgInnerCallbackW(HWND hWnd, UINT msg, LPARAM lParam, LPARAM lData)
+{
+ FOLDER_DLG_INNER_DATA *data = (FOLDER_DLG_INNER_DATA *)lData;
+ LPITEMIDLIST pidl;
+
+ switch (msg)
+ {
+ case BFFM_INITIALIZED:
+ if (data->default_dir != NULL)
+ {
+ SendMessage(hWnd, BFFM_SETSELECTIONW, true, (LPARAM)data->default_dir);
+ }
+ break;
+
+ case BFFM_SELCHANGED:
+ pidl = (LPITEMIDLIST)lParam;
+
+ if (pidl)
+ {
+ wchar_t tmp[MAX_PATH];
+
+ Zero(tmp, sizeof(tmp));
+ if (SHGetPathFromIDListW(pidl, tmp))
+ {
+ SendMessage(hWnd, BFFM_ENABLEOK, 0, 1);
+ }
+ else
+ {
+ SendMessage(hWnd, BFFM_ENABLEOK, 0, 0);
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
+
+wchar_t *FolderDlgInnerW(HWND hWnd, wchar_t *title, wchar_t *default_dir)
+{
+ BROWSEINFOW info;
+ wchar_t display_name[MAX_PATH];
+ FOLDER_DLG_INNER_DATA data;
+ LPMALLOC pMalloc;
+ wchar_t *ret = NULL;
+ if (UniIsEmptyStr(title))
+ {
+ title = NULL;
+ }
+ if (UniIsEmptyStr(default_dir))
+ {
+ default_dir = NULL;
+ }
+
+ Zero(&data, sizeof(data));
+ data.default_dir = default_dir;
+
+ Zero(display_name, sizeof(display_name));
+ Zero(&info, sizeof(info));
+ info.hwndOwner = hWnd;
+ info.pidlRoot = NULL;
+ info.pszDisplayName = display_name;
+ info.lpszTitle = title;
+ info.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS | BIF_VALIDATE | BIF_SHAREABLE;
+ info.lpfn = FolderDlgInnerCallbackW;
+ info.lParam = (LPARAM)&data;
+
+ if (SUCCEEDED(SHGetMalloc(&pMalloc)))
+ {
+ LPITEMIDLIST pidl;
+
+ pidl = SHBrowseForFolderW(&info);
+
+ if (pidl)
+ {
+ wchar_t tmp[MAX_PATH];
+
+ if (SHGetPathFromIDListW(pidl, tmp))
+ {
+ ret = CopyUniStr(tmp);
+ }
+
+ pMalloc->Free(pidl);
+ }
+
+ pMalloc->Release();
+ }
+
+ return ret;
+}
+
+
+class CModule
+{
+public:
+ CModule()
+ {
+ m_hInstLib = NULL;
+ }
+ CModule( HINSTANCE hInstLib )
+ {
+ m_hInstLib = NULL;
+ this->Attach( hInstLib );
+ }
+ CModule( LPCTSTR pszModuleName )
+ {
+ m_hInstLib = NULL;
+ this->LoadLibrary( pszModuleName );
+ }
+ virtual ~CModule()
+ {
+ this->FreeLibrary();
+ }
+
+public:
+ BOOL Attach( HINSTANCE hInstLib )
+ {
+ this->FreeLibrary();
+ m_hInstLib = hInstLib;
+
+ return TRUE;
+ }
+ BOOL Detach()
+ {
+ m_hInstLib = NULL;
+
+ return TRUE;
+ }
+
+public:
+ HMODULE GetHandle()
+ {
+ return m_hInstLib;
+ }
+ // Load the DLL
+ HINSTANCE LoadLibrary( LPCTSTR pszModuleName )
+ {
+ this->FreeLibrary();
+ m_hInstLib = ::LoadLibrary( pszModuleName );
+
+ return m_hInstLib;
+ }
+ // Release the DLL
+ BOOL FreeLibrary()
+ {
+ if (m_hInstLib == NULL)
+ {
+ return FALSE;
+ }
+
+ BOOL bResult = ::FreeLibrary( m_hInstLib );
+ m_hInstLib = NULL;
+
+ return bResult;
+ }
+ // Get the address of the function
+ FARPROC GetProcAddress( LPCTSTR pszProcName )
+ {
+ if (m_hInstLib == NULL)
+ {
+ return NULL;
+ }
+
+ return ::GetProcAddress(m_hInstLib, pszProcName);
+ }
+ // Get a handle to the information block of resource with the specified name and the type
+ HRSRC FindResource(LPCTSTR lpName, LPCTSTR lpType)
+ {
+ if (m_hInstLib == NULL)
+ {
+ return NULL;
+ }
+
+ return ::FindResource(m_hInstLib, lpName, lpType);
+ }
+ // Load the specified resource
+ HGLOBAL LoadResource(HRSRC hResInfo)
+ {
+ if (m_hInstLib == NULL)
+ {
+ return NULL;
+ }
+
+ return ::LoadResource(m_hInstLib, hResInfo);
+ }
+
+protected:
+ HINSTANCE m_hInstLib;
+};
+
+
+
+static HRESULT _ShowHTMLDialog(
+ HWND hwndParent,
+ IMoniker* pMk,
+ VARIANT* pvarArgIn = NULL,
+ WCHAR* pchOptions = NULL,
+ VARIANT* pvarArgOut = NULL)
+{
+ HRESULT hr = S_OK;
+
+ try
+ {
+ CModule Module("MSHTML.DLL");
+ if (Module.GetHandle() == NULL)
+ {
+ return E_FAIL;
+ }
+
+ SHOWHTMLDIALOGFN* fnShowHTMLDialog =
+ (SHOWHTMLDIALOGFN*)Module.GetProcAddress("ShowHTMLDialog");
+ if (fnShowHTMLDialog == NULL)
+ {
+ return E_FAIL;
+ }
+
+ hr = (*fnShowHTMLDialog)(hwndParent, pMk, pvarArgIn, pchOptions, pvarArgOut);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+ catch (...)
+ {
+ return E_FAIL;
+ }
+
+ return hr;
+}
+
+HRESULT ShowHTMLDialogFromURL(HWND hwndParent,wchar_t *szURL,VARIANT* pvarArgIn,WCHAR* pchOptions,VARIANT* pvarArgOut)
+{
+ HRESULT hr = S_OK;
+
+ try
+ {
+ IMonikerPtr spMoniker;
+ hr = ::CreateURLMoniker(NULL, szURL, &spMoniker);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ hr = ::_ShowHTMLDialog(hwndParent, spMoniker, pvarArgIn, pchOptions, pvarArgOut);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+ catch (...)
+ {
+ return E_FAIL;
+ }
+
+ return hr;
+}
+
+// Create a shortcut
+bool CreateLinkInnerA(char *filename, char *target, char *workdir, char *args,
+ char *comment, char *icon, UINT icon_index)
+{
+ HRESULT r;
+ wchar_t tmp[MAX_SIZE];
+ IShellLinkA* pShellLink;
+ IPersistFile* pPersistFile;
+
+ r = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkA, (void **)&pShellLink);
+ if (FAILED(r))
+ {
+ return false;
+ }
+
+ r = pShellLink->QueryInterface(IID_IPersistFile,(void **)&pPersistFile);
+ if (FAILED(r))
+ {
+ pShellLink->Release();
+ return false;
+ }
+
+ r = pShellLink->SetPath(target);
+ if (FAILED(r))
+ {
+ pShellLink->Release();
+ pPersistFile->Release();
+ return false;
+ }
+
+ if (workdir != NULL)
+ {
+ r = pShellLink->SetWorkingDirectory(workdir);
+ if (FAILED(r))
+ {
+ pShellLink->Release();
+ pPersistFile->Release();
+ return false;
+ }
+ }
+
+ if (args != NULL)
+ {
+ r = pShellLink->SetArguments(args);
+ if (FAILED(r))
+ {
+ pShellLink->Release();
+ pPersistFile->Release();
+ return false;
+ }
+ }
+
+ if (comment != NULL)
+ {
+ r = pShellLink->SetDescription(comment);
+ if (FAILED(r))
+ {
+ pShellLink->Release();
+ pPersistFile->Release();
+ return false;
+ }
+ }
+
+ if (icon != NULL)
+ {
+ r = pShellLink->SetIconLocation(icon, icon_index);
+ if (FAILED(r))
+ {
+ pShellLink->Release();
+ pPersistFile->Release();
+ return false;
+ }
+ }
+
+ StrToUni(tmp, sizeof(tmp), filename);
+ r = pPersistFile->Save(tmp, true);
+ if (FAILED(r))
+ {
+ pShellLink->Release();
+ pPersistFile->Release();
+ return false;
+ }
+
+ pShellLink->Release();
+ pPersistFile->Release();
+ return true;
+}
+bool CreateLinkInner(wchar_t *filename, wchar_t *target, wchar_t *workdir, wchar_t *args,
+ wchar_t *comment, wchar_t *icon, UINT icon_index)
+{
+ HRESULT r;
+ bool ret;
+ IShellLinkW* pShellLink;
+ IPersistFile* pPersistFile;
+
+ if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType))
+ {
+ char *a1, *a2, *a3, *a4, *a5, *a6;
+ a1 = CopyUniToStr(filename);
+ a2 = CopyUniToStr(target);
+ a3 = CopyUniToStr(workdir);
+ a4 = CopyUniToStr(args);
+ a5 = CopyUniToStr(icon);
+ a6 = CopyUniToStr(comment);
+
+ ret = CreateLinkInnerA(a1, a2, a3, a4, a6, a5, icon_index);
+
+ Free(a1);
+ Free(a2);
+ Free(a3);
+ Free(a4);
+ Free(a5);
+ Free(a6);
+
+ return ret;
+ }
+
+ r = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (void **)&pShellLink);
+ if (FAILED(r))
+ {
+ return false;
+ }
+
+ r = pShellLink->QueryInterface(IID_IPersistFile,(void **)&pPersistFile);
+ if (FAILED(r))
+ {
+ pShellLink->Release();
+ return false;
+ }
+
+ r = pShellLink->SetPath(target);
+ if (FAILED(r))
+ {
+ pShellLink->Release();
+ pPersistFile->Release();
+ return false;
+ }
+
+ if (workdir != NULL)
+ {
+ r = pShellLink->SetWorkingDirectory(workdir);
+ if (FAILED(r))
+ {
+ pShellLink->Release();
+ pPersistFile->Release();
+ return false;
+ }
+ }
+
+ if (comment != NULL)
+ {
+ r = pShellLink->SetDescription(comment);
+ if (FAILED(r))
+ {
+ pShellLink->Release();
+ pPersistFile->Release();
+ return false;
+ }
+ }
+
+ if (args != NULL)
+ {
+ r = pShellLink->SetArguments(args);
+ if (FAILED(r))
+ {
+ pShellLink->Release();
+ pPersistFile->Release();
+ return false;
+ }
+ }
+
+ if (icon != NULL)
+ {
+ r = pShellLink->SetIconLocation(icon, icon_index);
+ if (FAILED(r))
+ {
+ pShellLink->Release();
+ pPersistFile->Release();
+ return false;
+ }
+ }
+
+ r = pPersistFile->Save(filename, true);
+ if (FAILED(r))
+ {
+ pShellLink->Release();
+ pPersistFile->Release();
+ return false;
+ }
+
+ pShellLink->Release();
+ pPersistFile->Release();
+ return true;
+}
+
+extern "C"
+{
+
+// Show the folder selection dialog
+wchar_t *FolderDlgW(HWND hWnd, wchar_t *title, wchar_t *default_dir)
+{
+ wchar_t *ret;
+
+ if (MsIsNt() == false)
+ {
+ char *default_dir_a = CopyUniToStr(default_dir);
+ char *ret_a = FolderDlgA(hWnd, title, default_dir_a);
+
+ ret = CopyStrToUni(ret_a);
+ Free(ret_a);
+ Free(default_dir_a);
+
+ return ret;
+ }
+
+ ret = FolderDlgInnerW(hWnd, title, default_dir);
+
+ return ret;
+}
+char *FolderDlgA(HWND hWnd, wchar_t *title, char *default_dir)
+{
+ char *ret;
+
+ ret = FolderDlgInnerA(hWnd, title, default_dir);
+
+ return ret;
+}
+
+// Create a shortcut
+bool CreateLink(wchar_t *filename, wchar_t *target, wchar_t *workdir, wchar_t *args,
+ wchar_t *comment, wchar_t *icon, UINT icon_index)
+{
+ if (filename == NULL || target == NULL)
+ {
+ return false;
+ }
+
+ return CreateLinkInner(filename, target, workdir, args, comment, icon, icon_index);
+}
+
+// Show the HTML
+void ShowHtml(HWND hWnd, char *url, wchar_t *option)
+{
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (url == NULL || option == NULL)
+ {
+ return;
+ }
+
+ StrToUni(tmp, sizeof(tmp), url);
+
+ ShowHTMLDialogFromURL(hWnd, tmp, NULL, option, NULL);
+}
+
+}
+
+#endif
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Win32Com.h b/src/Cedar/Win32Com.h
new file mode 100644
index 00000000..abf3048d
--- /dev/null
+++ b/src/Cedar/Win32Com.h
@@ -0,0 +1,400 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Win32Com.h
+// Header of Win32Com.c
+
+#ifndef WIN32COM_H
+#define WIN32COM_H
+
+#ifdef WIN32COM_CPP
+
+// Internal function
+
+#endif // WIN32COM_CPP
+
+// For external function
+
+#pragma comment(lib,"htmlhelp.lib")
+#pragma comment(lib,"Urlmon.lib")
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+ void ShowHtml(HWND hWnd, char *url, wchar_t *option);
+ bool CreateLink(wchar_t *filename, wchar_t *target, wchar_t *workdir, wchar_t *args,
+ wchar_t *comment, wchar_t *icon, UINT icon_index);
+ wchar_t *FolderDlgW(HWND hWnd, wchar_t *title, wchar_t *default_dir);
+ char *FolderDlgA(HWND hWnd, wchar_t *title, char *default_dir);
+
+ bool InstallNdisProtocolDriver(wchar_t *inf_path, wchar_t *id, UINT lock_timeout);
+ bool Win32UPnPAddPort(UINT outside_port, UINT inside_port, bool udp, char *local_ip, wchar_t *description, bool remove_before_add);
+
+ //////////////////////////////////////////////////////////////////////////
+ //JumpList
+
+ //Application ID for VPN Client Manager
+ #define APPID_CM GC_UI_APPID_CM
+
+ typedef void* JL_PCustomDestinationList;
+ typedef void* JL_PObjectArray;
+ typedef void* JL_PShellLink;
+ typedef void* JL_PObjectCollection;
+ typedef long JL_HRESULT;
+
+ JL_HRESULT JL_CreateCustomDestinationList(JL_PCustomDestinationList* poc, wchar_t* appID);
+ JL_HRESULT JL_ReleaseCustomDestinationList(JL_PCustomDestinationList poc);
+
+ JL_HRESULT JL_BeginList(JL_PCustomDestinationList poc, JL_PObjectArray* oaRemoved);
+ JL_HRESULT JL_CommitList(JL_PCustomDestinationList cdl);
+
+
+ JL_HRESULT JL_CreateObjectCollection(JL_PObjectCollection* poc);
+ JL_HRESULT JL_ReleaseObjectCollection(JL_PObjectCollection poc);
+ JL_HRESULT JL_ObjectCollectionAddShellLink(JL_PObjectCollection poc, JL_PShellLink ppsl);
+
+ JL_HRESULT JL_AddCategoryToList(JL_PCustomDestinationList pcdl,
+ JL_PObjectCollection poc,
+ wchar_t* categoryName,
+ JL_PObjectArray poaRemoved);
+ JL_HRESULT JL_DeleteJumpList(JL_PCustomDestinationList jpcdl,wchar_t* appID);
+
+
+ JL_HRESULT JL_CreateShellLink(
+ wchar_t* pszPath,
+ wchar_t* pszArguments,
+ wchar_t* pszTitle,
+ wchar_t* iconLocation,
+ int iconIndex,
+ wchar_t* description, JL_PShellLink *ppsl);
+ JL_HRESULT JL_ReleaseShellLink(JL_PShellLink ppsl);
+
+
+ //SetApplicationID for Windows 7
+ JL_HRESULT JL_SetCurrentProcessExplicitAppUserModelID(wchar_t* appID);
+
+
+ //JL_HRESULT JL_AddTasksToList(JL_PCustomDestinationList pcdl, JL_PObjectCollection poc);
+
+ //////////////////////////////////////////////////////////////////////////
+ //DrawImage
+ //
+
+ #if defined(__cplusplus)
+
+typedef UCHAR ct_uchar;
+typedef char ct_char;
+
+#define ct_max(a,b) (((a) > (b)) ? (a): (b))
+#define ct_min(a,b) (((a) < (b)) ? (a): (b))
+#define ct_clamp(n,mi,ma) (ct_max(ct_min((n),(ma)),(mi)))
+#define ct_clamp01(n) ct_clamp(n,0,1)
+
+/**
+* Union representing 32-bit color with alpha channel.
+* CT_Color32, CT_AHSV32, CT_AYCbCr32 are also the same.
+*
+*/
+typedef union CT_ARGB32
+{
+public:
+
+ /** 32-bit integer intensity */
+ UINT ARGB;
+
+ /** RGB Color System */
+ struct
+ {
+ ct_uchar B;
+ ct_uchar G;
+ ct_uchar R;
+ ct_uchar A;
+ };
+
+ /** HSV Color System */
+ struct HSVA
+ {
+ ct_uchar V;
+ ct_uchar S;
+ ct_uchar H;
+ ct_uchar A;
+ }HSVA;
+
+ /** YCbCr Color System */
+ struct YCbCrA
+ {
+ ct_uchar Y;
+ ct_char Cb;
+ ct_char Cr;
+ ct_uchar A;
+ }YCbCrA;
+
+
+ /** Default constructor */
+ CT_ARGB32(){}
+
+ /** Constructor to initialize by specified color.
+ * @param a Alpha channel
+ * @param r Red, Hue, Cr
+ * @param g Green, Saturation, Cb
+ * @param b Blue, Value, Y
+ */
+ CT_ARGB32(ct_uchar a,ct_uchar r,ct_uchar g,ct_uchar b)
+ {
+ A = a;
+ R = r;
+ G = g;
+ B = b;
+ }
+
+
+
+}CT_ARGB32;
+
+
+class CT_Size
+{
+public:
+ int Width;
+ int Height;
+
+ CT_Size(int w, int h)
+ {
+ Width = w;
+ Height = h;
+ }
+};
+
+class CT_Rect
+{
+public:
+ int X;
+ int Y;
+ int Width;
+ int Height;
+
+ CT_Rect()
+ {
+ X = 0;
+ Y = 0;
+ Width = 0;
+ Height = 0;
+ }
+
+ CT_Rect(int x, int y,int w, int h)
+ {
+ X = x;
+ Y = y;
+ Width = w;
+ Height = h;
+ }
+
+ int Right(){return X + Width;}
+ int Bottom(){return Y + Height;}
+
+ void Right(int r){ Width = r - X;}
+ void Bottom(int b){ Height = b - Y;}
+
+};
+
+
+
+#endif //__cplusplus
+
+typedef struct CT_RectF_c
+{
+ float X;
+ float Y;
+ float Width;
+ float Height;
+} CT_RectF_c;
+
+void CT_DrawImage(UCHAR* dest, CT_RectF_c destRect, int destWidth, int destHeight,
+ UCHAR* src, CT_RectF_c srcRect, int srcWidth, int srcHeight);
+
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+
+//EXTERN_C const IID IID_IObjectCollection;
+//EXTERN_C const IID IID_ICustomDestinationList;
+
+#if defined(__cplusplus)
+
+
+#ifndef __IObjectArray_INTERFACE_DEFINED__
+#define __IObjectArray_INTERFACE_DEFINED__
+
+MIDL_INTERFACE("92CA9DCD-5622-4bba-A805-5E9F541BD8C9")
+IObjectArray : public IUnknown
+{
+public:
+ virtual HRESULT STDMETHODCALLTYPE GetCount(
+ /* [out] */ __RPC__out UINT *pcObjects) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAt(
+ /* [in] */ UINT uiIndex,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0;
+
+};
+
+MIDL_INTERFACE("5632b1a4-e38a-400a-928a-d4cd63230295")
+IObjectCollection : public IObjectArray
+{
+public:
+ virtual HRESULT STDMETHODCALLTYPE AddObject(
+ /* [in] */ __RPC__in_opt IUnknown *punk) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AddFromArray(
+ /* [in] */ __RPC__in_opt IObjectArray *poaSource) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RemoveObjectAt(
+ /* [in] */ UINT uiIndex) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clear( void) = 0;
+
+};
+
+#endif // __IObjectArray_INTERFACE_DEFINED__
+
+#ifndef __ICustomDestinationList_INTERFACE_DEFINED__
+#define __ICustomDestinationList_INTERFACE_DEFINED__
+
+typedef /* [v1_enum] */
+enum KNOWNDESTCATEGORY
+{
+ KDC_FREQUENT = 1,
+ KDC_RECENT = ( KDC_FREQUENT + 1 )
+} KNOWNDESTCATEGORY;
+
+MIDL_INTERFACE("6332debf-87b5-4670-90c0-5e57b408a49e")
+ICustomDestinationList : public IUnknown
+{
+public:
+ virtual HRESULT STDMETHODCALLTYPE SetAppID(
+ /* [string][in] */ __RPC__in_string LPCWSTR pszAppID) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE BeginList(
+ /* [out] */ __RPC__out UINT *pcMinSlots,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AppendCategory(
+ /* [string][in] */ __RPC__in_string LPCWSTR pszCategory,
+ /* [in] */ __RPC__in_opt IObjectArray *poa) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AppendKnownCategory(
+ /* [in] */ KNOWNDESTCATEGORY category) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AddUserTasks(
+ /* [in] */ __RPC__in_opt IObjectArray *poa) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CommitList( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRemovedDestinations(
+ /* [in] */ __RPC__in REFIID riid,
+ /* [iid_is][out] */ __RPC__deref_out_opt void **ppv) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DeleteList(
+ /* [string][unique][in] */ __RPC__in_opt_string LPCWSTR pszAppID) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AbortList( void) = 0;
+
+};
+
+
+#endif // __ICustomDestinationList_INTERFACE_DEFINED__
+
+
+#endif //defined(__cplusplus)
+
+
+
+#endif // WIN32COM_H
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/WinJumpList.cpp b/src/Cedar/WinJumpList.cpp
new file mode 100644
index 00000000..9ba6eeac
--- /dev/null
+++ b/src/Cedar/WinJumpList.cpp
@@ -0,0 +1,759 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// WinJumpList.cpp
+// HTML display module source code for Win32
+
+#include <GlobalConst.h>
+
+#ifdef WIN32
+
+//#define NTDDI_WIN7 0x06010000
+//#define _WIN32_WINNT _WIN32_WINNT_VISTA
+//#define NTDDI_VERSION NTDDI_VISTA // Specifies that the minimum required platform is Windows 7.
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+#define STRICT_TYPED_ITEMIDS // Utilize strictly typed IDLists
+
+//#include <objectarray.h>
+#include <shobjidl.h>
+#include <propkey.h>
+#include <propvarutil.h>
+//#include <knownfolders.h>
+//#include <shlobj.h>
+
+
+#ifdef StrCpy
+#undef StrCpy
+#endif
+
+#ifdef StrCat
+#undef StrCat
+#endif
+
+#ifdef StrCmp
+#undef StrCmp
+#endif
+
+
+#define WIN32COM_CPP
+
+//#define _WIN32_WINNT 0x0502
+//#define WINVER 0x0502
+#include <winsock2.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <wininet.h>
+#include <comdef.h>
+#include <Mshtmhst.h>
+//#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+
+extern "C"
+{
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+}
+#include "../PenCore/resource.h"
+
+extern "C"
+{
+
+ //////////////////////////////////////////////////////////////////////////
+ //JumpList
+ //#define NTDDI_WIN7 0x06010000
+ //#define NTDDI_VERSION NTDDI_WIN7 // Specifies that the minimum required platform is Windows 7.
+ //#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+ //#define STRICT_TYPED_ITEMIDS // Utilize strictly typed IDLists
+ //
+ //
+ //#include <shobjidl.h>
+ //#include <propkey.h>
+ //#include <propvarutil.h>
+ //#include <knownfolders.h>
+ //#include <shlobj.h>
+ //
+ //#pragma comment(lib, "propsys.lib")
+ //#pragma comment(lib, "shlwapi.lib")
+
+ #define CREATE_PROPERTYKEY(l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid }
+
+
+ // Determines if the provided IShellItem is listed in the array of items that the user has removed
+ bool _IsItemInArray(IShellItem *psi, IObjectArray *poaRemoved)
+ {
+ bool fRet = false;
+ UINT cItems;
+ if (SUCCEEDED(poaRemoved->GetCount(&cItems)))
+ {
+ IShellItem *psiCompare;
+ for (UINT i = 0; !fRet && i < cItems; i++)
+ {
+ if (SUCCEEDED(poaRemoved->GetAt(i, IID_PPV_ARGS(&psiCompare))))
+ {
+ int iOrder;
+ fRet = SUCCEEDED(psiCompare->Compare(psi, SICHINT_CANONICAL, &iOrder)) && (0 == iOrder);
+ psiCompare->Release();
+ }
+ }
+ }
+ return fRet;
+ }
+
+
+ JL_HRESULT JL_CreateCustomDestinationList(JL_PCustomDestinationList* poc, wchar_t* appID)
+ {
+ ICustomDestinationList *pcdl;
+
+ //CLSID_DestinationList = 6332DEBF-87B5-4670-90C0-5E57-B408-A49E
+
+ GUID destList;
+
+ destList.Data1 = 2012286192;
+ destList.Data2 = 15797;
+ destList.Data3 = 18790;
+
+ destList.Data4[0] = 181;
+ destList.Data4[1] = 32;
+ destList.Data4[2] = 183;
+ destList.Data4[3] = 197;
+ destList.Data4[4] = 79;
+ destList.Data4[5] = 211;
+ destList.Data4[6] = 94;
+ destList.Data4[7] = 214;
+
+ //destList = CLSID_DestinationList;
+
+ //HRESULT hr = CoCreateInstance(CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pcdl));
+ HRESULT hr = CoCreateInstance(destList,
+ NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pcdl));
+
+ if (SUCCEEDED(hr))
+ {
+ pcdl->SetAppID(appID);
+ (*poc) = (void*)pcdl;
+ }
+ else
+ {
+ (*poc) = NULL;
+ }
+
+ return hr;
+ }
+
+ JL_HRESULT JL_ReleaseCustomDestinationList(JL_PCustomDestinationList poc)
+ {
+ ICustomDestinationList *pcdl = (ICustomDestinationList*)poc;
+ if(pcdl != NULL)
+ {
+ pcdl->Release();
+ }
+
+ return 0;
+ }
+
+ JL_HRESULT JL_BeginList(JL_PCustomDestinationList poc, JL_PObjectArray* oaRemoved)
+ {
+ UINT cMinSlots;
+ IObjectArray *poaRemoved;
+
+ ICustomDestinationList *pcdl = (ICustomDestinationList*)poc;
+
+ HRESULT hr = pcdl->BeginList(&cMinSlots, IID_PPV_ARGS(&poaRemoved));
+
+ (*oaRemoved) = poaRemoved;
+
+ return hr;
+ }
+
+ JL_HRESULT JL_CommitList(JL_PCustomDestinationList cdl)
+ {
+ ICustomDestinationList *pcdl = (ICustomDestinationList*)cdl;
+
+ return pcdl->CommitList();
+ }
+
+
+ //JL_HRESULT JL_AddTasksToList(JL_PCustomDestinationList pcdl, JL_PObjectCollection poc)
+ //{
+ // return 0;
+ //}
+
+ JL_HRESULT JL_CreateObjectCollection(JL_PObjectCollection* jpoc)
+ {
+
+ //CLSID_EnumerableObjectCollection = 2D3468C1-36A7-43B6-AC24-D3F0-2FD9-607A
+
+
+ GUID enumObjCol;
+
+ enumObjCol.Data1 = 758409409;
+ enumObjCol.Data2 = 13991;
+ enumObjCol.Data3 = 17334;
+
+ enumObjCol.Data4[0] = 172;
+ enumObjCol.Data4[1] = 36;
+ enumObjCol.Data4[2] = 211;
+ enumObjCol.Data4[3] = 240;
+ enumObjCol.Data4[4] = 47;
+ enumObjCol.Data4[5] = 217;
+ enumObjCol.Data4[6] = 96;
+ enumObjCol.Data4[7] = 122;
+
+ //enumObjCol = CLSID_EnumerableObjectCollection;
+
+ IObjectCollection *poc;
+ //HRESULT hr = CoCreateInstance(CLSID_EnumerableObjectCollection, NULL, CLSCTX_INPROC, IID_PPV_ARGS(&poc));
+ HRESULT hr = CoCreateInstance(enumObjCol,
+ NULL, CLSCTX_INPROC, IID_PPV_ARGS(&poc));
+
+ if (SUCCEEDED(hr))
+ {
+ (*jpoc) = poc;
+ }
+ else{
+ (*jpoc) = NULL;
+ }
+ return hr;
+ }
+
+ JL_HRESULT JL_ReleaseObjectCollection(JL_PObjectCollection jpoc)
+ {
+ IObjectCollection *poc = (IObjectCollection *)jpoc;
+ if(poc != NULL)
+ {
+ return poc->Release();
+ }
+
+ return 0;
+ }
+
+ JL_HRESULT JL_ObjectCollectionAddShellLink(JL_PObjectCollection jpoc, JL_PShellLink jpsl)
+ {
+ IObjectCollection *poc = (IObjectCollection *)jpoc;
+ IShellLink *psl = (IShellLink *) jpsl;
+
+ return poc->AddObject(psl);
+
+ }
+
+
+ JL_HRESULT JL_AddCategoryToList(JL_PCustomDestinationList jpcdl,
+ JL_PObjectCollection jpoc,
+ wchar_t* categoryName,
+ JL_PObjectArray jpoaRemoved)
+ {
+ ICustomDestinationList *pcdl = (ICustomDestinationList*)jpcdl;
+ IObjectCollection *poc = (IObjectCollection *)jpoc;
+ IObjectArray *poaRemoved = (IObjectArray*)jpoaRemoved;
+
+ //for (UINT i = 0; i < ARRAYSIZE(c_rgpszFiles); i++)
+ //{
+ // IShellItem *psi;
+ // if (SUCCEEDED(SHCreateItemInKnownFolder(FOLDERID_Documents, KF_FLAG_DEFAULT, c_rgpszFiles[i], IID_PPV_ARGS(&psi))))
+ // {
+ // // Items listed in the removed list may not be re-added to the Jump List during this
+ // // list-building transaction. They should not be re-added to the Jump List until
+ // // the user has used the item again. The AppendCategory call below will fail if
+ // // an attempt to add an item in the removed list is made.
+ // if (!_IsItemInArray(psi, poaRemoved))
+ // {
+ // poc->AddObject(psi);
+ // }
+ // psi->Release();
+ // }
+ //}
+
+ IObjectArray *poa;
+ HRESULT hr = poc->QueryInterface(IID_PPV_ARGS(&poa));
+ if (SUCCEEDED(hr))
+ {
+
+ // Add the category to the Jump List. If there were more categories, they would appear
+ // from top to bottom in the order they were appended.
+ hr = pcdl->AppendCategory(categoryName, poa);
+ //hr = pcdl->AddUserTasks(poa);
+ poa->Release();
+
+ if (SUCCEEDED(hr))
+ {
+ }
+ else
+ {
+ Print("Failed AppendCategory\n");
+ }
+ }
+ else
+ {
+ Print("Failed QueryInterface\n");
+ }
+
+
+ return hr;
+ }
+
+
+
+ JL_HRESULT JL_CreateShellLink(
+ wchar_t* pszPath,
+ wchar_t* pszArguments,
+ wchar_t* pszTitle,
+ wchar_t* iconLocation,
+ int iconIndex,
+ wchar_t* description, JL_PShellLink *ppsl)
+ {
+ IShellLinkW *psl;
+ HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&psl));
+ if (SUCCEEDED(hr))
+ {
+ // Determine our executable's file path so the task will execute this application
+ //WCHAR szAppPath[MAX_PATH];
+ //if (GetModuleFileName(NULL, szAppPath, ARRAYSIZE(szAppPath)))
+ //{
+ //hr = psl->SetPath(L"C:\\Program Files\\PacketiX VPN Client\\vpncmgr.exe");
+ //hr = psl->SetArguments(L"50792311B00B9E01E7534AAA881087AB2BB83A1F");
+
+
+ psl->SetPath(pszPath);
+ psl->SetArguments(pszArguments);
+ if(iconLocation != NULL)
+ {
+ psl->SetIconLocation(iconLocation,iconIndex);
+ }
+
+ if(description != NULL)
+ {
+ psl->SetDescription(description);
+ }
+ if (SUCCEEDED(hr))
+ {
+ // The title property is required on Jump List items provided as an IShellLink
+ // instance. This value is used as the display name in the Jump List.
+ IPropertyStore *pps;
+ hr = psl->QueryInterface(IID_PPV_ARGS(&pps));
+ if (SUCCEEDED(hr))
+ {
+ PROPVARIANT propvar;
+ hr = InitPropVariantFromString(pszTitle, &propvar);
+ if (SUCCEEDED(hr))
+ {
+
+ ////PKEY_Title
+ //#define DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid)
+ //EXTERN_C const PROPERTYKEY DECLSPEC_SELECTANY name
+ // = { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid }
+ //DEFINE_PROPERTYKEY(PKEY_Title, 0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 2);
+
+ PROPERTYKEY pkey_title =
+ CREATE_PROPERTYKEY(0xF29F85E0, 0x4FF9, 0x1068, 0xAB, 0x91, 0x08, 0x00, 0x2B, 0x27, 0xB3, 0xD9, 2);
+
+
+ //hr = pps->SetValue(PKEY_Title, propvar);
+ hr = pps->SetValue(pkey_title, propvar);
+
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pps->Commit();
+ if (SUCCEEDED(hr))
+ {
+ IShellLink *tpsl;
+ hr = psl->QueryInterface(IID_PPV_ARGS(&tpsl));
+ (*ppsl) = tpsl;
+ }
+ }
+ PropVariantClear(&propvar);
+ }
+ pps->Release();
+ }
+ }
+
+ /*
+ hr = psl->SetPath(szAppPath);
+ if (SUCCEEDED(hr))
+ {
+ hr = psl->SetArguments(pszArguments);
+ if (SUCCEEDED(hr))
+ {
+ // The title property is required on Jump List items provided as an IShellLink
+ // instance. This value is used as the display name in the Jump List.
+ IPropertyStore *pps;
+ hr = psl->QueryInterface(IID_PPV_ARGS(&pps));
+ if (SUCCEEDED(hr))
+ {
+ PROPVARIANT propvar;
+ hr = InitPropVariantFromString(pszTitle, &propvar);
+ if (SUCCEEDED(hr))
+ {
+ hr = pps->SetValue(PKEY_Title, propvar);
+ if (SUCCEEDED(hr))
+ {
+ hr = pps->Commit();
+ if (SUCCEEDED(hr))
+ {
+ hr = psl->QueryInterface(IID_PPV_ARGS(ppsl));
+ }
+ }
+ PropVariantClear(&propvar);
+ }
+ pps->Release();
+ }
+ }
+ }
+ */
+ //}
+ //else
+ //{
+ // hr = HRESULT_FROM_WIN32(GetLastError());
+ //}
+ psl->Release();
+ }
+ return hr;
+ }
+
+ JL_HRESULT JL_ReleaseShellLink(JL_PShellLink jpsl)
+ {
+ IShellLink *psl = (IShellLink *) jpsl;
+
+ if(psl != NULL)
+ {
+ return psl->Release();
+ }
+
+ return 0;
+ }
+
+ // Removes that existing custom Jump List for this application.
+ JL_HRESULT JL_DeleteJumpList(JL_PCustomDestinationList jpcdl,wchar_t* appID)
+ {
+ ICustomDestinationList *pcdl = (ICustomDestinationList *)jpcdl;
+ //HRESULT hr = CoCreateInstance(CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pcdl));
+
+ HRESULT hr = pcdl->DeleteList(appID);
+
+
+ return hr;
+ }
+
+
+
+ //////////////////////////////////////////////////////////////////////////
+ //SetApplicationID for Windows 7
+ JL_HRESULT JL_SetCurrentProcessExplicitAppUserModelID(wchar_t* appID)
+ {
+#ifdef UNICODE
+ HMODULE hModule = LoadLibraryW( L"shell32.dll");
+#else
+ HMODULE hModule = LoadLibraryA( "shell32.dll");
+#endif
+ HRESULT (__stdcall *SetAppID) (PCWSTR);
+
+ if( hModule == NULL )
+ {
+ //// Load failure (there is no DLL)
+ // MessageBoxW( NULL, L"shell32.dll not found", L"Error", MB_OK );
+ Print("Not Found shell32.dll");
+ }
+ else
+ {
+ // Get the address of the function in the DLL
+ SetAppID = (HRESULT (__stdcall *)(PCWSTR))
+ GetProcAddress( hModule, "SetCurrentProcessExplicitAppUserModelID" );
+ if( SetAppID != NULL )
+ {
+ FreeLibrary( hModule );
+ return SetAppID(appID);
+ }
+ else
+ {
+ //MessageBoxW( NULL, L"There may not be a function", L"Error", MB_OK );
+ Print("Not Found SetCurrentProcessExplicitAppUserModelID");
+
+ }
+
+ // Release the loaded DLL
+ FreeLibrary( hModule );
+ }
+ return 0;
+
+
+ }
+
+
+
+}
+
+#endif
+
+//////////////////////////////////////////////////////////////////////////
+// Size Rect
+//
+
+CT_Rect GetBoundingRect(CT_RectF_c* rect)
+{
+ CT_Rect r = CT_Rect((int)rect->X,(int)rect->Y,(int)rect->Width,(int)rect->Height);
+ if(r.Right() < (rect->X + rect->Width))
+ r.Width+=1;
+ if(r.Bottom() < (rect->Y + rect->Height))
+ r.Height+=1;
+
+ return r;
+}
+
+
+CT_ARGB32 CT_GetAAPix32(UCHAR* srcPtr, int width, int height, int xFix, int yFix);
+
+//////////////////////////////////////////////////////////////////////////
+// DrawImage method
+void CT_DrawImage(UCHAR* dest, CT_RectF_c destRect, int destWidth, int destHeight,
+ UCHAR* src, CT_RectF_c srcRect, int srcWidth, int srcHeight)
+{
+
+ double scaleW = destRect.Width / srcRect.Width;
+ double scaleH = destRect.Height / srcRect.Height;
+
+
+ CT_ARGB32* dest32 = (CT_ARGB32*)(dest);
+ CT_ARGB32* src32 = (CT_ARGB32*)(src);
+
+ float dfx = (float)(1 / scaleW);
+ float dfy = (float)(1 / scaleH);
+
+ float srcSX = srcRect.X;
+ float srcSY = srcRect.Y;
+
+ int srcSXFix = (int)(srcSX*65536);
+ int srcSYFix = (int)(srcSY*65536);
+ int dfxFix = (int)(dfx*65536);
+ int dfyFix = (int)(dfy*65536);
+
+ //CT_Rect dRect = destRect.GetBoundingRect();
+
+ CT_Rect dRect = GetBoundingRect(&destRect);
+
+ // Clipping not supported: ToDo
+ dRect.X = ct_max(0,dRect.X);
+ dRect.Y = ct_max(0,dRect.Y);
+ dRect.Right((int)ct_min(destRect.X + destRect.Width,dRect.Right()));
+ dRect.Bottom((int)ct_min(destRect.Y + destRect.Height,dRect.Bottom()));
+
+ //CT_ARGB32* dPix = dest32->GetPixelAddressNC(dRect.X, dRect.Y);
+ CT_ARGB32* dPix = &(dest32[destWidth*dRect.Y + dRect.X]);
+
+ //int dpW = dest32->GetWidth() - dRect.Width;
+ int dpW = destWidth - dRect.Width;
+ for (int dy = dRect.Y; dy < dRect.Bottom(); dy++)
+ {
+
+ int syFix = srcSYFix;
+ int sxFix = srcSXFix;
+
+ // Anti-aliasing
+ for (int dx = dRect.X; dx < dRect.Right(); dx++)
+ {
+ int rPixX = ( ((sxFix >> 15) & 0x00000001) == 1) ? (sxFix >> 16)+1 : (sxFix >> 16);
+ int rPixY = ( ((syFix >> 15) & 0x00000001) == 1) ? (syFix >> 16)+1 : (syFix >> 16);
+
+ //CT_ARGB32* sPix = &(src32[rPixY * srcWidth + rPixX]);
+
+ //*dPix = *sPix;
+ //if(sPix != NULL)
+ {
+ //*dPix = src32->GetAAPix32(sxFix,syFix);
+ *dPix = CT_GetAAPix32((UCHAR*)src32, srcWidth, srcHeight,sxFix, syFix);
+ }
+
+ sxFix += dfxFix;
+ dPix++;
+ }
+
+
+ srcSYFix += dfyFix;
+ dPix += dpW;
+ }
+
+}
+
+bool isWhiteColor(CT_ARGB32 col)
+{
+ return
+ (col.R == 255 &&
+ col.G == 255 &&
+ col.B == 255);
+}
+
+
+CT_ARGB32 CT_GetAAPix32(UCHAR* srcPtr, int width, int height, int xFix, int yFix)
+{
+
+ //return CT_ARGB32(255,255,255,255);
+
+ //CT_Bitmap32* src = this;
+ CT_ARGB32* src = (CT_ARGB32*)(srcPtr);
+
+ int fixx = xFix;
+ int fixy = yFix;
+
+ int fx = (fixx >> 8) & 0xFF;
+ int fy = (fixy >> 8) & 0xFF;
+
+ int f[4];
+ f[0] = ((255 - fx) * (255 - fy)) >> 8;
+ f[1] = (fx * (255 - fy)) >> 8;
+ f[2] = ((255 - fx) * fy) >> 8;
+ f[3] = (fx * fy) >> 8;
+
+ int px = fixx >> 16;
+ int py = fixy >> 16;
+
+ int a, r, g, b;
+ a = r = g = b = 0;
+ CT_Size size = CT_Size(width, height);
+ CT_ARGB32 col = CT_ARGB32(0,255,255,255);
+
+ CT_ARGB32 pixs[4];
+ for(int j = 0; j < 2; j++)
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ int sx = px + i;
+ int sy = py + j;
+
+ CT_ARGB32* c;
+
+ if(sx < 0 || sx >= width || sy < 0 || sy >= height)
+ {
+ c = &col;
+ }
+ else
+ {
+ //c = src->GetPixelAddressNC(sx, sy);
+ c = &(src[sy * width + sx]);
+ }
+ pixs[j*2+i] = *c;
+
+ a += c->A * f[j*2 + i];
+ r += c->R * f[j*2 + i];
+ g += c->G * f[j*2 + i];
+ b += c->B * f[j*2 + i];
+
+ }
+ }
+
+ bool isAllWhite = true;
+ for(int k = 0; k < 4; k++)
+ {
+ if(!isWhiteColor(pixs[k]))
+ {
+ isAllWhite = false;
+ break;
+ }
+ }
+
+ if(isAllWhite)
+ {
+ //
+ return CT_ARGB32(0, 255, 255, 255);
+ }
+ else
+ {
+ a = a >> 8;
+ r = r >> 8;
+ g = g >> 8;
+ b = b >> 8;
+
+ return CT_ARGB32(a, r, g, b);
+ }
+
+}
+
+//
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/WinUi.c b/src/Cedar/WinUi.c
new file mode 100644
index 00000000..0cdf6ff8
--- /dev/null
+++ b/src/Cedar/WinUi.c
@@ -0,0 +1,11339 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// WinUi.c
+// User interface code for Win32
+
+#include <GlobalConst.h>
+
+#ifdef WIN32
+
+#define WINUI_C
+
+#define _WIN32_WINNT 0x0502
+#define WINVER 0x0502
+#include <winsock2.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <wininet.h>
+#include <Iphlpapi.h>
+#include <shlobj.h>
+#include <commctrl.h>
+#include <Dbghelp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <Mayaqua/Mayaqua.h>
+#include <Cedar/Cedar.h>
+#include "../PenCore/resource.h"
+
+char cached_pin_code[MAX_SIZE] = {0};
+UINT64 cached_pin_code_expires = 0;
+
+static HINSTANCE hDll = NULL;
+static wchar_t *title_bar = NULL;
+static char *font_name = NULL;
+static UINT font_size = 9;
+static HIMAGELIST large_image_list = NULL, small_image_list = NULL;
+static LIST *icon_list = NULL;
+static HINSTANCE hMsHtml = NULL;
+static UINT init_winui_counter = 0;
+static HDC hCommonDC = NULL;
+static LOCK *lock_common_dc = NULL;
+
+bool UseAlpha = false;
+UINT AlphaValue = 100;
+
+static THREAD *led_thread = NULL;
+static bool thread_stop = false;
+static bool g_led_special = false;
+static bool g_tcpip_topmost = false;
+static DWORD tls_current_wizard = 0xFFFFFFFF;
+
+#define WINUI_PSM_SHOWWIZBUTTONS (WM_USER + 138)
+#define WINUI_PropSheet_ShowWizButtons(hDlg, dwFlag, dwButton) \
+ PSTMSG(hDlg, WINUI_PSM_SHOWWIZBUTTONS, (WPARAM)(dwFlag), (LPARAM)(dwButton))
+
+typedef struct _WINUI_SHSTOCKICONINFO
+{
+ DWORD cbSize;
+ HICON hIcon;
+ int iSysImageIndex;
+ int iIcon;
+ WCHAR szPath[MAX_PATH];
+} WINUI_SHSTOCKICONINFO;
+
+// Get whether the current process is foreground
+bool IsThisProcessForeground()
+{
+ HWND hWnd = GetForegroundWindow();
+ DWORD proc_id, thread_id;
+
+ if (hWnd == NULL)
+ {
+ return false;
+ }
+
+ proc_id = 0;
+ thread_id = GetWindowThreadProcessId(hWnd, &proc_id);
+
+ if (proc_id == MsGetCurrentProcessId())
+ {
+ return true;
+ }
+
+ return false;
+}
+bool IsThisProcessForegroundForUpdateUi(UPDATE_CLIENT *c, void *p)
+{
+ return IsThisProcessForeground();
+}
+
+// Update notification screen dialog procedure
+UINT UpdateConfigDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ WINUI_UPDATE *u = (WINUI_UPDATE *)param;
+ UPDATE_CLIENT_SETTING s;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetTimer(hWnd, 1, 100, NULL);
+
+ LoadUpdateUiSetting(u, &s);
+
+ Check(hWnd, S_ENABLE, s.DisableCheck == false);
+ Check(hWnd, S_DISBLE, s.DisableCheck);
+
+ DlgFont(hWnd, S_TITLE, 10, true);
+ FormatText(hWnd, S_TITLE, u->SoftwareTitle);
+ FormatText(hWnd, S_INFO, u->SoftwareTitle);
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ if (u->UpdateClient->HaltFlag)
+ {
+ goto LABEL_CLOSE;
+ }
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+LABEL_CLOSE:
+ LoadUpdateUiSetting(u, &s);
+
+ s.DisableCheck = IsChecked(hWnd, S_DISBLE);
+
+ if (s.DisableCheck)
+ {
+ s.LatestIgnoreBuild = 0;
+ }
+
+ SaveUpdateUiSetting(u, &s);
+
+ SetUpdateClientSetting(u->UpdateClient, &s);
+
+ EndDialog(hWnd, !s.DisableCheck);
+
+ break;
+ }
+
+ return 0;
+}
+
+// Show the update notification setting screen
+bool ConfigUpdateUi(WINUI_UPDATE *u, HWND hWnd)
+{
+ // Validate arguments
+ if (u == NULL)
+ {
+ return false;
+ }
+
+ return Dialog(hWnd, D_UPDATE_CONFIG, UpdateConfigDlgProc, u);
+}
+
+// Update notification dialog procedure
+UINT UpdateNoticeDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ WINUI_UPDATE_DLG_PARAM *p = (WINUI_UPDATE_DLG_PARAM *)param;
+ WINUI_UPDATE *u = NULL;
+ UPDATE_CLIENT_SETTING s;
+ char date_current[64];
+ char date_latest[64];
+ wchar_t date_current_str[128];
+ wchar_t date_latest_str[128];
+ char *font_name = NULL;
+
+ if (p != NULL)
+ {
+ u = p->Update;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ Zero(date_current_str, sizeof(date_current_str));
+ Zero(date_latest_str, sizeof(date_latest_str));
+
+ GetDateStr64(date_current, sizeof(date_current), u->CurrentDate);
+ if (u->CurrentDate != 0)
+ {
+ UniFormat(date_current_str, sizeof(date_current_str), _UU("DLG_UPDATE_DATE"), date_current);
+ }
+
+ GetDateStr64(date_latest, sizeof(date_latest), p->LatestDate);
+ if (p->LatestDate != 0)
+ {
+ UniFormat(date_latest_str, sizeof(date_latest_str), _UU("DLG_UPDATE_DATE"), date_latest);
+ }
+
+ FormatText(hWnd, 0, u->UpdateClient->SoftwareTitle);
+ FormatText(hWnd, S_INFO, u->UpdateClient->SoftwareTitle);
+ SetText(hWnd, S_PRODUCT_STR, u->UpdateClient->SoftwareTitle);
+
+ FormatText(hWnd, S_CURRENT_STR, u->CurrentVer / 100, u->CurrentVer % 100, u->CurrentBuild, date_current_str);
+ FormatText(hWnd, S_LATEST_STR, p->LatestVer, date_latest_str);
+
+ if (MsIsWindows7())
+ {
+ if (_GETLANG() == 0)
+ {
+ font_name = GetMeiryoFontName();
+ }
+ else if (_GETLANG() == 2)
+ {
+ font_name = "Microsoft YaHei";
+ }
+ }
+
+ SetFont(hWnd, S_INFO, GetFont(font_name, 11, false, false, false, false));
+ SetFont(hWnd, IDOK, GetFont(font_name, 0, true, false, false, false));
+ SetFont(hWnd, IDCANCEL, GetFont(font_name, 0, false, false, false, false));
+ SetFont(hWnd, S_PRODUCT_STR, GetFont(font_name, 10, true, false, false, false));
+ SetFont(hWnd, S_CURRENT_STR, GetFont(font_name, 10, true, false, false, false));
+ SetFont(hWnd, S_LATEST_STR, GetFont(font_name, 10, true, false, false, false));
+
+ SetFont(hWnd, S_PRODUCT, GetFont(font_name, 0, false, false, false, false));
+ SetFont(hWnd, S_CURRENT, GetFont(font_name, 0, false, false, false, false));
+ SetFont(hWnd, S_LATEST, GetFont(font_name, 0, false, false, false, false));
+ SetFont(hWnd, B_CONFIG, GetFont(font_name, 0, false, false, false, false));
+
+ SetTimer(hWnd, 1, 100, NULL);
+
+ //MessageBeep(MB_ICONASTERISK);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK: // Web View
+ OnceMsgEx(hWnd, NULL, _UU("DLG_UPDATE_HINT"), true, ICO_INTERNET, (bool *)p->halt_flag);
+
+ ShellExecuteA(hWnd, "open", p->Url, NULL, NULL, SW_SHOWNORMAL);
+ SleepThread(250);
+
+ // Ignore the update notification of this version for future
+ LoadUpdateUiSetting(u, &s);
+ s.LatestIgnoreBuild = p->LatestBuild;
+ SaveUpdateUiSetting(u, &s);
+
+ EndDialog(hWnd, 1);
+ break;
+
+ case IDCANCEL: // Ignore this version
+ LoadUpdateUiSetting(u, &s);
+ s.LatestIgnoreBuild = p->LatestBuild;
+ SaveUpdateUiSetting(u, &s);
+ Close(hWnd);
+ break;
+
+ case B_CONFIG: // Show the notification settings screen
+ p->IsInConfigDialog = true;
+
+ if (ConfigUpdateUi(u, hWnd) == false)
+ {
+ // Decided not to notify any more as a result of setting
+ Close(hWnd);
+ }
+
+ p->IsInConfigDialog = false;
+ break;
+ }
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ if (p->IsInConfigDialog == false)
+ {
+ if (*(p->halt_flag))
+ {
+ // Close the screen forcibly
+ EndDialog(hWnd, 0);
+ }
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE: // Close
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Update notification dialog
+void UpdateNotifyProcUi(UPDATE_CLIENT *c, UINT latest_build, UINT64 latest_date, char *latest_ver, char *url, volatile bool *halt_flag, void *param)
+{
+ WINUI_UPDATE *u = (WINUI_UPDATE *)param;
+ WINUI_UPDATE_DLG_PARAM p;
+ // Validate arguments
+ if (c == NULL || latest_build == 0 || latest_date == 0 || latest_ver == NULL || url == NULL || halt_flag == NULL || param == NULL)
+ {
+ return;
+ }
+
+ // Show the update screen
+ Zero(&p, sizeof(p));
+
+ p.Update = u;
+ p.LatestBuild = latest_build;
+ p.LatestDate = latest_date;
+ p.LatestVer = latest_ver;
+ p.Url = url;
+ p.halt_flag = halt_flag;
+
+ Dialog(NULL, D_UPDATE_NOTICE, UpdateNoticeDlgProc, &p);
+}
+
+// Initialize the update notification
+WINUI_UPDATE *InitUpdateUi(wchar_t *title, char *name, char *family_name, UINT64 current_date, UINT current_build, UINT current_ver, char *client_id)
+{
+ WINUI_UPDATE *u;
+ UPDATE_CLIENT_SETTING s;
+ LANGLIST t;
+ // Validate arguments
+ if (title == NULL || name == NULL || current_build == 0 || current_ver == 0)
+ {
+ return NULL;
+ }
+ if (IsEmptyStr(family_name))
+ {
+ family_name = UPDATE_FAMILY_NAME;
+ }
+
+ u = ZeroMalloc(sizeof(WINUI_UPDATE));
+
+ StrCpy(u->ClientId, sizeof(u->ClientId), client_id);
+ UniStrCpy(u->SoftwareTitle, sizeof(u->SoftwareTitle), title);
+ StrCpy(u->SoftwareName, sizeof(u->SoftwareName), name);
+ u->CurrentDate = current_date;
+ u->CurrentBuild = current_build;
+ u->CurrentVer = current_ver;
+
+ Format(u->RegKey, sizeof(u->RegKey), WINUI_UPDATE_REGKEY, u->SoftwareName);
+
+ Zero(&s, sizeof(s));
+ LoadUpdateUiSetting(u, &s);
+
+ Zero(&t, sizeof(t));
+ GetCurrentLang(&t);
+
+ u->UpdateClient = NewUpdateClient(UpdateNotifyProcUi, IsThisProcessForegroundForUpdateUi, u, family_name, u->SoftwareName, u->SoftwareTitle,
+ u->CurrentBuild, u->CurrentDate, t.Name, &s, client_id);
+
+ if (u->UpdateClient == NULL)
+ {
+ Free(u);
+ return NULL;
+ }
+
+ return u;
+}
+
+// Release the update notification
+void FreeUpdateUi(WINUI_UPDATE *u)
+{
+ // Validate arguments
+ if (u == NULL)
+ {
+ return;
+ }
+
+ if (u->UpdateClient != NULL)
+ {
+ FreeUpdateClient(u->UpdateClient);
+ }
+
+ Free(u);
+}
+
+// Read the current settings from the registry
+void LoadUpdateUiSetting(WINUI_UPDATE *u, UPDATE_CLIENT_SETTING *s)
+{
+ Zero(s, sizeof(UPDATE_CLIENT_SETTING));
+ // Validate arguments
+ if (u == NULL || s == NULL)
+ {
+ return;
+ }
+
+ s->DisableCheck = MsRegReadInt(REG_CURRENT_USER, u->RegKey, "DisableCheck");
+ s->LatestIgnoreBuild = MsRegReadInt(REG_CURRENT_USER, u->RegKey, "LatestIgnoreBuild");
+}
+
+// Write the current settings to the registry
+void SaveUpdateUiSetting(WINUI_UPDATE *u, UPDATE_CLIENT_SETTING *s)
+{
+ // Validate arguments
+ if (u == NULL || s == NULL)
+ {
+ return;
+ }
+
+ MsRegWriteInt(REG_CURRENT_USER, u->RegKey, "DisableCheck", s->DisableCheck);
+ MsRegWriteInt(REG_CURRENT_USER, u->RegKey, "LatestIgnoreBuild", s->LatestIgnoreBuild);
+}
+
+// Set the UAC icon to the control in the dialog
+void SetUacIcon(HWND hWnd, UINT id)
+{
+ static HINSTANCE hShell32 = NULL;
+ static HRESULT (__stdcall *_SHGetStockIconInfo)(UINT siid, UINT uFlags, void *psii) = NULL;
+ bool ok = false;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (MsIsVista() == false)
+ {
+ goto LABEL_FAILED;
+ }
+
+ if (hShell32 == NULL)
+ {
+ hShell32 = LoadLibraryA("shell32.dll");
+ }
+
+ if (hShell32 != NULL)
+ {
+ if (_SHGetStockIconInfo == NULL)
+ {
+ _SHGetStockIconInfo = (HRESULT (__stdcall *)(UINT,UINT,void *))GetProcAddress(hShell32, "SHGetStockIconInfo");
+ }
+ }
+
+ if (_SHGetStockIconInfo != NULL)
+ {
+ WINUI_SHSTOCKICONINFO sii;
+
+ Zero(&sii, sizeof(sii));
+
+ sii.cbSize = sizeof(sii);
+ if (_SHGetStockIconInfo(77, 0x000000100 | 0x000000001, &sii) == S_OK)
+ {
+ SendMessage(DlgItem(hWnd, id), STM_SETICON, (WPARAM)sii.hIcon, 0);
+
+ ok = true;
+ }
+ }
+
+ if (ok)
+ {
+ return;
+ }
+
+LABEL_FAILED:
+
+ Hide(hWnd, id);
+}
+
+// Procedure of the wizard page
+UINT CALLBACK WizardPageDefDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ DIALOG_PARAM *dp = (DIALOG_PARAM *)GetParam(hWnd);
+ WIZARD_PAGE *wizard_page = NULL;
+ WIZARD *wizard = NULL;
+ UINT ret_value = 0;
+ bool do_not_send_msg = false;
+
+ if (dp != NULL)
+ {
+ wizard_page = dp->wizard_page;
+ wizard = wizard_page->Wizard;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ PROPSHEETPAGEW_V3 *t = (PROPSHEETPAGEW_V3 *)lParam;
+ dp = (DIALOG_PARAM *)t->lParam;
+ wizard_page = dp->wizard_page;
+ wizard = wizard_page->Wizard;
+
+ wizard->hWndWizard = GetParent(hWnd);
+ wizard_page->hWndPage = hWnd;
+
+ SetParam(hWnd, dp);
+
+ InitDialogInternational(hWnd, dp);
+ }
+ break;
+
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORDLG:
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORLISTBOX:
+ case WM_CTLCOLORMSGBOX:
+ case WM_CTLCOLORSCROLLBAR:
+ case WM_CTLCOLORSTATIC:
+ return (UINT)GetStockObject(WHITE_BRUSH);
+ break;
+
+ case WM_NOTIFY:
+ {
+ NMHDR *pnmh = (NMHDR *)lParam;
+ UINT ret = 0;
+ UINT next_page = INFINITE;
+
+ switch (pnmh->code)
+ {
+ case PSN_SETACTIVE: // Activate
+ SetWizardButton(wizard_page, true, true, true, false);
+ dp->wizard_proc(hWnd, WM_WIZ_SHOW, 0, 0, wizard, wizard_page, wizard->Param);
+ break;
+
+ case PSN_KILLACTIVE: // Deactivate
+ dp->wizard_proc(hWnd, WM_WIZ_HIDE, 0, 0, wizard, wizard_page, wizard->Param);
+ break;
+
+ case PSN_WIZNEXT: // Determine the destination of [Next] button
+ ret = dp->wizard_proc(hWnd, WM_WIZ_NEXT, 0, 0, wizard, wizard_page, wizard->Param);
+ do_not_send_msg = true;
+
+ if (ret == 0)
+ {
+ SetWindowLong(hWnd, DWLP_MSGRESULT, -1);
+ }
+ else
+ {
+ SetWindowLong(hWnd, DWLP_MSGRESULT, ret);
+ }
+
+ ret_value = 1;
+ break;
+
+ case PSN_WIZBACK: // Determine the destination of [back] button
+ ret = dp->wizard_proc(hWnd, WM_WIZ_BACK, 0, 0, wizard, wizard_page, wizard->Param);
+ do_not_send_msg = true;
+
+ if (ret == 0)
+ {
+ SetWindowLong(hWnd, DWLP_MSGRESULT, -1);
+ }
+ else
+ {
+ SetWindowLong(hWnd, DWLP_MSGRESULT, ret);
+ }
+
+ ret_value = 1;
+ break;
+
+ case PSN_QUERYCANCEL: // Determine the process of the [Cancel] button
+ if (dp->wizard_page->EnableClose == false)
+ {
+ SetWindowLong(hWnd, DWLP_MSGRESULT, 1);
+ }
+ else
+ {
+
+ ret = dp->wizard_proc(hWnd, WM_WIZ_CLOSE, 0, 0, wizard, wizard_page, wizard->Param);
+
+ if (ret == 0)
+ {
+ if (IsEmptyUniStr(wizard->CloseConfirmMsg) == false &&
+ MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2, wizard->CloseConfirmMsg) == IDNO)
+ {
+ ret = 1;
+ }
+ }
+
+ if (ret == 0)
+ {
+ SetWindowLong(hWnd, DWLP_MSGRESULT, 0);
+ }
+ else
+ {
+ SetWindowLong(hWnd, DWLP_MSGRESULT, 1);
+ }
+ }
+ ret_value = 1;
+ do_not_send_msg = true;
+ break;
+ }
+ break;
+ }
+ }
+
+ if (do_not_send_msg == false)
+ {
+ if (dp != NULL)
+ {
+ UINT ret = dp->wizard_proc(hWnd, msg, wParam, lParam, wizard, wizard_page, wizard->Param);
+
+ if (ret != 0)
+ {
+ ret_value = ret;
+ }
+ }
+ }
+
+ if (msg == WM_INITDIALOG)
+ {
+ if (wizard->SetCenterFlag == false)
+ {
+ wizard->SetCenterFlag = true;
+
+ Center(wizard->hWndWizard);
+ }
+
+ SetForegroundWindow(wizard->hWndWizard);
+ SetActiveWindow(wizard->hWndWizard);
+ }
+
+ return ret_value;
+}
+
+// Button setting of the wizard
+void SetWizardButton(WIZARD_PAGE *p, bool enable_next, bool enable_back, bool enable_close, bool is_finish)
+{
+ SetWizardButtonEx(p, enable_next, enable_back, enable_close, is_finish, false);
+}
+void SetWizardButtonEx(WIZARD_PAGE *p, bool enable_next, bool enable_back, bool enable_close, bool is_finish, bool shield_icon)
+{
+ DWORD flags = 0;
+ DWORD flags2 = 0;
+ DWORD flags3 = 0;
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ p->EnableNext = enable_next;
+ p->EnableBack = enable_back;
+ p->EnableClose = enable_close;
+ p->IsFinish = is_finish;
+
+ if (is_finish == false)
+ {
+ if (p->EnableNext)
+ {
+ flags |= PSWIZB_NEXT;
+ flags2 |= PSWIZB_NEXT;
+
+ if (shield_icon)
+ {
+ if (p->Wizard->IsAreoStyle)
+ {
+ if (MsIsAdmin() == false)
+ {
+ flags3 |= PSWIZBF_ELEVATIONREQUIRED;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (p->EnableNext)
+ {
+ flags |= PSWIZB_FINISH;
+ flags2 |= PSWIZB_FINISH;
+ }
+ else
+ {
+ flags |= PSWIZB_DISABLEDFINISH;
+ flags2 |= PSWIZB_FINISH;
+ }
+ }
+
+ if (p->EnableBack)
+ {
+ flags |= PSWIZB_BACK;
+ flags2 |= PSWIZB_BACK;
+ }
+
+ if (p->EnableClose)
+ {
+ flags2 |= 0x00000010;
+ }
+
+ PostMessage(p->Wizard->hWndWizard, PSM_SETWIZBUTTONS, flags3, flags);
+
+ SetEnable(p->Wizard->hWndWizard, IDCANCEL, p->EnableClose);
+
+ WINUI_PropSheet_ShowWizButtons(p->Wizard->hWndWizard,
+ flags2, PSWIZB_BACK | PSWIZB_NEXT | PSWIZB_FINISH | 0x00000010);
+
+ if (p->EnableClose)
+ {
+ EnableClose(p->Wizard->hWndWizard);
+ }
+ else
+ {
+ DisableClose(p->Wizard->hWndWizard);
+ }
+}
+
+LRESULT CALLBACK WizardCustomizedWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WIZARD *wizard = (WIZARD *)TlsGetValue(tls_current_wizard);
+
+ if (wizard != NULL)
+ {
+ switch (msg)
+ {
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORDLG:
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORLISTBOX:
+ case WM_CTLCOLORMSGBOX:
+ case WM_CTLCOLORSCROLLBAR:
+ case WM_CTLCOLORSTATIC:
+ return (UINT)GetStockObject(WHITE_BRUSH);
+ break;
+ }
+
+ if (MsIsNt())
+ {
+ return CallWindowProcW(wizard->OriginalWindowProc, hWnd, msg, wParam, lParam);
+ }
+ else
+ {
+ return CallWindowProcA(wizard->OriginalWindowProc, hWnd, msg, wParam, lParam);
+ }
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// Procedure of the wizard
+UINT CALLBACK WizardDlgProc(HWND hWnd, UINT msg, LPARAM lParam)
+{
+ WIZARD *wizard = (WIZARD *)TlsGetValue(tls_current_wizard);
+ switch (msg)
+ {
+ case PSCB_INITIALIZED:
+ if (wizard != NULL)
+ {
+ if (wizard->hWndWizard != NULL)
+ {
+ wizard->hWndWizard = hWnd;
+ }
+
+ if (wizard->ReplaceWindowProcFlag == false)
+ {
+ wizard->ReplaceWindowProcFlag = true;
+
+ if (MsIsNt())
+ {
+ wizard->OriginalWindowProc = (void *)GetWindowLongPtrW(hWnd, GWLP_WNDPROC);
+ }
+ else
+ {
+ wizard->OriginalWindowProc = (void *)GetWindowLongPtrA(hWnd, GWLP_WNDPROC);
+ }
+
+ if (wizard->OriginalWindowProc != NULL)
+ {
+ if (MsIsNt())
+ {
+ SetWindowLongPtrW(hWnd, GWLP_WNDPROC, (LONG_PTR)WizardCustomizedWindowProc);
+ }
+ else
+ {
+ SetWindowLongPtrA(hWnd, GWLP_WNDPROC, (LONG_PTR)WizardCustomizedWindowProc);
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Jump to another wizard page
+void JumpWizard(WIZARD_PAGE *p, UINT next_id)
+{
+ // Validate arguments
+ if (p == NULL || next_id == 0)
+ {
+ return;
+ }
+
+ PropSheet_SetCurSelByID(p->Wizard->hWndWizard, next_id);
+}
+
+// Close the wizard
+void CloseWizard(WIZARD_PAGE *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ p->Wizard->CloseConfirmMsg = NULL;
+ SetWizardButton(p, false, false, true, false);
+
+ if (p->Wizard->IsAreoStyle)
+ {
+ PropSheet_PressButton(p->hWndPage, PSBTN_CANCEL);
+ }
+ else
+ {
+ Close(p->Wizard->hWndWizard);
+ }
+}
+
+// Show the wizard
+void ShowWizard(HWND hWndParent, WIZARD *w, UINT start_id)
+{
+ void **pages_array;
+ UINT num_pages;
+ UINT i;
+ PROPSHEETHEADERW_V2 h;
+ WIZARD_PAGE *start_page;
+ // Validate arguments
+ if (w == NULL)
+ {
+ return;
+ }
+
+ num_pages = LIST_NUM(w->Pages);
+ pages_array = ZeroMalloc(sizeof(void *) * num_pages);
+
+ for (i = 0;i < num_pages;i++)
+ {
+ WIZARD_PAGE *p = LIST_DATA(w->Pages, i);
+
+ pages_array[i] = CreateWizardPageInstance(w, p);
+
+ p->Index = i;
+ }
+
+ Zero(&h, sizeof(h));
+ h.dwSize = sizeof(PROPSHEETHEADERW_V2);
+ h.dwFlags = PSH_WIZARD97 | PSH_HEADER | PSH_USEICONID | PSH_USECALLBACK;
+
+ if (MsIsVista() == false)
+ {
+ // Aero Wizard is unavailable in pre-Vista
+ w->IsAreoStyle = false;
+ }
+
+ if (MsIsAeroColor() == false)
+ {
+ // Aero Wizard can not be used If the color of Aero is disabled
+ // even in Vista or later (if the background color is not white)
+ w->IsAreoStyle = false;
+ }
+
+ if (w->IsAreoStyle)
+ {
+ // Aero Wizard
+ h.dwFlags = PSH_WIZARD | 0x00004000 | PSH_HEADER | PSH_USEICONID | PSH_USECALLBACK;
+ }
+
+ h.hInstance = hDll;
+ h.pszIcon = MAKEINTRESOURCEW(w->Icon);
+ h.hwndParent = hWndParent;
+ h.nPages = num_pages;
+ h.phpage = (HPROPSHEETPAGE *)pages_array;
+ h.pszbmHeader = MAKEINTRESOURCEW(w->Bitmap);
+ h.pszCaption = w->Caption;
+ h.pfnCallback = WizardDlgProc;
+
+ start_page = GetWizardPage(w, start_id);
+ if (start_page != NULL)
+ {
+ h.nStartPage = start_page->Index;
+ }
+
+ w->hWndParent = hWndParent;
+ w->hWndWizard = NULL;
+ w->SetCenterFlag = false;
+
+ TlsSetValue(tls_current_wizard, w);
+
+ PropertySheetW(&h);
+
+ TlsSetValue(tls_current_wizard, NULL);
+
+ Free(pages_array);
+}
+
+// Create an instance of the wizard page
+void *CreateWizardPageInstance(WIZARD *w, WIZARD_PAGE *p)
+{
+ PROPSHEETPAGEW_V3 t;
+ // Validate arguments
+ if (w == NULL || p == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&t, sizeof(t));
+ t.dwSize = sizeof(PROPSHEETPAGEW_V3);
+ t.dwFlags = PSP_USETITLE | PSP_USEHEADERTITLE;// | PSP_USEHEADERSUBTITLE;
+ t.hInstance = hDll;
+ t.pszTemplate = MAKEINTRESOURCEW(p->Id);
+ t.pfnDlgProc = (DLGPROC)WizardPageDefDlgProc;
+ t.pszHeaderTitle = p->Title;
+ t.pszTitle = w->Caption;
+
+ if (p->DialogParam != NULL)
+ {
+ FreeBitmapList(p->DialogParam->BitmapList);
+ Free(p->DialogParam);
+ }
+
+ p->DialogParam = ZeroMalloc(sizeof(DIALOG_PARAM));
+
+ p->DialogParam->BitmapList = NewBitmapList();
+ p->DialogParam->wizard = w;
+ p->DialogParam->wizard_page = p;
+ p->DialogParam->wizard_proc = p->Proc;
+ p->DialogParam->param = w->Param;
+ p->DialogParam->white = false;
+ p->DialogParam->meiryo = false;
+
+ t.lParam = (LPARAM)p->DialogParam;
+
+ return CreatePropertySheetPageW(&t);
+}
+
+// Create a new wizard
+WIZARD *NewWizard(UINT icon, UINT bitmap, wchar_t *caption, void *param)
+{
+ WIZARD *w = ZeroMalloc(sizeof(WIZARD));
+
+ w->Icon = icon;
+ w->Pages = NewList(NULL);
+ w->Param = param;
+ w->Bitmap = bitmap;
+ w->Caption = CopyUniStr(caption);
+
+ return w;
+}
+
+// Release the wizard
+void FreeWizard(WIZARD *w)
+{
+ UINT i;
+ // Validate arguments
+ if (w == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(w->Pages);i++)
+ {
+ WIZARD_PAGE *p = LIST_DATA(w->Pages, i);
+
+ FreeWizardPage(p);
+ }
+
+ ReleaseList(w->Pages);
+
+ Free(w->Caption);
+
+ Free(w);
+}
+
+// Get the index page of the wizard
+UINT GetWizardPageIndex(WIZARD *w, UINT id)
+{
+ WIZARD_PAGE *p;
+ // Validate arguments
+ if (w == NULL || id == 0)
+ {
+ return INFINITE;
+ }
+
+ p = GetWizardPage(w, id);
+ if (p == NULL)
+ {
+ return INFINITE;
+ }
+
+ return p->Index;
+}
+
+// Get the wizard page
+WIZARD_PAGE *GetWizardPage(WIZARD *w, UINT id)
+{
+ UINT i;
+ // Validate arguments
+ if (w == NULL || id == 0)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < LIST_NUM(w->Pages);i++)
+ {
+ WIZARD_PAGE *p = LIST_DATA(w->Pages, i);
+
+ if (p->Id == id)
+ {
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+// Add a wizard page
+void AddWizardPage(WIZARD *w, WIZARD_PAGE *p)
+{
+ // Validate arguments
+ if (w == NULL || p == NULL)
+ {
+ return;
+ }
+
+ Add(w->Pages, p);
+
+ p->Wizard = w;
+}
+
+// Create a new wizard page
+WIZARD_PAGE *NewWizardPage(UINT id, WINUI_WIZARD_PROC *proc, wchar_t *title)
+{
+ WIZARD_PAGE *p;
+ // Validate arguments
+ if (id == 0 || proc == NULL)
+ {
+ return NULL;
+ }
+
+ p = ZeroMalloc(sizeof(WIZARD_PAGE));
+ p->Id = id;
+ p->Proc = proc;
+ p->Title = CopyUniStr(title);
+
+ return p;
+}
+
+// Release the wizard page
+void FreeWizardPage(WIZARD_PAGE *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ if (p->DialogParam != NULL)
+ {
+ FreeBitmapList(p->DialogParam->BitmapList);
+ Free(p->DialogParam);
+ }
+
+ Free(p->Title);
+
+ Free(p);
+}
+
+// NIC information dialog procedure
+UINT NicInfoProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ UI_NICINFO *info = (UI_NICINFO *)param;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ NicInfoInit(hWnd, info);
+
+ SetTimer(hWnd, 1, 50, NULL);
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+
+ NicInfoOnTimer(hWnd, info);
+
+ SetTimer(hWnd, 1, 50, NULL);
+ break;
+
+ case 2:
+ KillTimer(hWnd, 2);
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ KillTimer(hWnd, 1);
+ KillTimer(hWnd, 2);
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+void NicInfoCloseAfterTime(HWND hWnd, UI_NICINFO *info, UINT tick)
+{
+ UINT64 now;
+ UINT64 closetime;
+ // Validate arguments
+ if (hWnd == NULL || info == NULL)
+ {
+ return;
+ }
+
+ now = Tick64();
+ closetime = now + (UINT64)tick;
+
+ if (info->CloseAfterTime == 0 || info->CloseAfterTime >= closetime)
+ {
+ info->CloseAfterTime = closetime;
+ KillTimer(hWnd, 2);
+ SetTimer(hWnd, 2, tick, NULL);
+ }
+}
+void NicInfoShowStatus(HWND hWnd, UI_NICINFO *info, wchar_t *msg1, wchar_t *msg2, UINT icon, bool animate)
+{
+ // Validate arguments
+ if (hWnd == NULL || info == NULL)
+ {
+ return;
+ }
+ if (icon == 0)
+ {
+ icon = ICO_TEST;
+ }
+ if (msg1 == NULL)
+ {
+ msg1 = L"";
+ }
+ if (msg2 == NULL)
+ {
+ msg2 = L"";
+ }
+
+ if (info->CurrentIcon != icon)
+ {
+ SetIcon(hWnd, S_ICON, icon);
+ info->CurrentIcon = icon;
+ }
+
+ SetText(hWnd, S_STATUS1, msg1);
+ SetText(hWnd, S_STATUS2, msg2);
+
+ SetShow(hWnd, P_BAR, animate && MsIsWinXPOrWinVista());
+}
+void NicInfoRefresh(HWND hWnd, UI_NICINFO *info)
+{
+ MS_ADAPTER *a;
+ IP ip;
+ char ip_str[MAX_SIZE];
+ char title[MAX_SIZE];
+ UINT i;
+ wchar_t tmp[MAX_SIZE];
+ bool has_ip = false;
+ // Validate arguments
+ if (hWnd == NULL || info == NULL)
+ {
+ return;
+ }
+
+ Format(title, sizeof(title), VLAN_ADAPTER_NAME_TAG, info->NicName);
+
+ a = MsGetAdapter(title);
+ if (a == NULL)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ // Check whether an IP address is assigned
+ Zero(&ip, sizeof(ip));
+ for (i = 0;i < MAX_MS_ADAPTER_IP_ADDRESS;i++)
+ {
+ if (IsZeroIP(&a->IpAddresses[i]) == false)
+ {
+ Copy(&ip, &a->IpAddresses[i], sizeof(IP));
+
+ if (!(ip.addr[0] == 169 && ip.addr[1] == 254))
+ {
+ has_ip = true;
+ }
+ }
+ }
+ IPToStr(ip_str, sizeof(ip_str), &ip);
+
+ if (has_ip == false)
+ {
+ if (a->UseDhcp)
+ {
+ NicInfoShowStatus(hWnd, info, _UU("NICINFO_1"), _UU("NICINFO_1_1"), ICO_NIC_OFFLINE, true);
+ }
+ else
+ {
+ NicInfoShowStatus(hWnd, info, _UU("NICINFO_1"), _UU("NICINFO_1_2"), ICO_NIC_OFFLINE, true);
+ }
+ }
+ else
+ {
+ if (a->UseDhcp)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("NICINFO_2_1"), ip_str);
+ NicInfoShowStatus(hWnd, info, _UU("NICINFO_2"), tmp, ICO_NIC_ONLINE, false);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("NICINFO_3_1"), ip_str);
+ NicInfoShowStatus(hWnd, info, _UU("NICINFO_3"), tmp, ICO_NIC_ONLINE, false);
+ }
+
+ NicInfoCloseAfterTime(hWnd, info, NICINFO_AUTOCLOSE_TIME_2);
+ }
+
+ MsFreeAdapter(a);
+}
+void NicInfoInit(HWND hWnd, UI_NICINFO *info)
+{
+ // Validate arguments
+ if (hWnd == NULL || info == NULL)
+ {
+ return;
+ }
+
+ if (MsIsWinXPOrWinVista())
+ {
+ // Show a progress bar for Windows XP or later
+ SendMsg(hWnd, P_BAR, PBM_SETMARQUEE, TRUE, 150);
+ SetStyle(hWnd, P_BAR, PBS_MARQUEE);
+ }
+
+ DlgFont(hWnd, S_STATUS1, 9, false);
+ DlgFont(hWnd, S_STATUS2, 11, false);
+
+ SetIcon(hWnd, 0, ICO_NIC_ONLINE);
+
+ FormatText(hWnd, 0, info->NicName);
+
+ NicInfoRefresh(hWnd, info);
+
+ NicInfoCloseAfterTime(hWnd, info, NICINFO_AUTOCLOSE_TIME_1);
+}
+void NicInfoOnTimer(HWND hWnd, UI_NICINFO *info)
+{
+ // Validate arguments
+ if (hWnd == NULL || info == NULL)
+ {
+ return;
+ }
+
+ if (info->Halt)
+ {
+ Close(hWnd);
+ return;
+ }
+
+ if (info->RouteChange != NULL &&
+ IsRouteChanged(info->RouteChange) == false)
+ {
+ return;
+ }
+
+ NicInfoRefresh(hWnd, info);
+}
+
+// Show the NIC information dialog
+void NicInfo(UI_NICINFO *info)
+{
+ // Validate arguments
+ if (info == NULL)
+ {
+ return;
+ }
+
+ info->RouteChange = NewRouteChange();
+
+ DialogEx2(NULL, D_NICINFO, NicInfoProc, info, true, true);
+
+ FreeRouteChange(info->RouteChange);
+ info->RouteChange = NULL;
+}
+
+// TCP connection thread
+void WinConnectDlgThread(THREAD *thread, void *param)
+{
+ SOCK *s;
+ WINCONNECT_DLG_DATA *d = (WINCONNECT_DLG_DATA *)param;
+ UINT nat_t_error_code;
+ char *nat_t_svc_name = NULL;
+ // Validate arguments
+ if (d == NULL || thread == NULL)
+ {
+ return;
+ }
+
+ // Socket connection
+ if (IsEmptyStr(d->nat_t_svc_name) == false)
+ {
+ nat_t_svc_name = d->nat_t_svc_name;
+ }
+
+ s = ConnectEx3(d->hostname, d->port, d->timeout, &d->cancel, nat_t_svc_name, &nat_t_error_code, d->try_start_ssl, d->ssl_no_tls, false);
+
+ d->ret_sock = s;
+ d->nat_t_error_code = nat_t_error_code;
+
+ PostMessageA(d->hWnd, WM_APP + 68, 0, 0);
+}
+
+// TCP connection dialog procedure
+UINT WinConnectDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ WINCONNECT_DLG_DATA *d = (WINCONNECT_DLG_DATA *)param;
+ // Validate arguments
+ if (hWnd == NULL || d == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // UI setting
+ CenterParent(hWnd);
+ SetText(hWnd, 0, d->caption);
+ SetText(hWnd, S_INFO, d->info);
+ SetIcon(hWnd, S_ICON, d->icon_id);
+ d->hWnd = hWnd;
+
+ if (MsIsWinXPOrWinVista())
+ {
+ // Show a progress bar for Windows XP or later
+ SendMsg(hWnd, IDC_PROGRESS1, PBM_SETMARQUEE, TRUE, 100);
+ SetStyle(hWnd, IDC_PROGRESS1, PBS_MARQUEE);
+ }
+ else
+ {
+ // Hide the progress bar in the case of pre-Windows 2000
+ Hide(hWnd, IDC_PROGRESS1);
+ }
+
+ // Create a thread
+ d->thread = NewThread(WinConnectDlgThread, d);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_APP + 68:
+ case WM_CLOSE:
+ if (d->cancel == false)
+ {
+ d->cancel = true;
+ Disable(hWnd, IDCANCEL);
+ if (d->ret_sock == NULL)
+ {
+ SetText(hWnd, S_INFO, _UU("CONNECTDLG_CANCELING"));
+ }
+ DoEvents(hWnd);
+ Refresh(hWnd);
+ WaitThread(d->thread, INFINITE);
+ ReleaseThread(d->thread);
+ EndDialog(hWnd, 0);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// TCP connection with showing the UI
+SOCK *WinConnectEx2(HWND hWnd, char *server, UINT port, UINT timeout, UINT icon_id, wchar_t *caption, wchar_t *info, bool try_start_ssl, bool ssl_no_tls)
+{
+ return WinConnectEx3(hWnd, server, port, timeout, icon_id, caption, info, NULL, false, try_start_ssl, ssl_no_tls);
+}
+SOCK *WinConnectEx3(HWND hWnd, char *server, UINT port, UINT timeout, UINT icon_id, wchar_t *caption, wchar_t *info, UINT *nat_t_error_code, char *nat_t_svc_name, bool try_start_ssl, bool ssl_no_tls)
+{
+ wchar_t tmp[MAX_SIZE];
+ wchar_t tmp2[MAX_SIZE];
+ WINCONNECT_DLG_DATA d;
+ // Validate arguments
+ if (server == NULL || port == 0)
+ {
+ return NULL;
+ }
+ if (icon_id == 0)
+ {
+ icon_id = ICO_USER_ADMIN;
+ }
+ if (caption == NULL)
+ {
+ if (hWnd == NULL)
+ {
+ caption = _UU("CONNECTDLG_CAPTION");
+ }
+ else
+ {
+ GetTxt(hWnd, 0, tmp2, sizeof(tmp2));
+ caption = tmp2;
+ }
+ }
+ if (info == NULL)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CONNECTDLG_MESSAGE"), server, port);
+
+ info = tmp;
+ }
+
+ Zero(&d, sizeof(d));
+
+ d.try_start_ssl = try_start_ssl;
+ d.ssl_no_tls = ssl_no_tls;
+ d.cancel = false;
+ d.caption = caption;
+ d.icon_id = icon_id;
+ d.info = info;
+ d.timeout = timeout;
+ d.hostname = server;
+ d.port = port;
+ StrCpy(d.nat_t_svc_name, sizeof(d.nat_t_svc_name), nat_t_svc_name);
+
+ Dialog(hWnd, D_CONNECT, WinConnectDlgProc, &d);
+
+ if (nat_t_error_code != NULL)
+ {
+ *nat_t_error_code = d.nat_t_error_code;
+ }
+
+ return d.ret_sock;
+}
+
+// Show the Windows Network Setup screen
+bool ShowWindowsNetworkConnectionDialog()
+{
+ wchar_t exe_name[MAX_SIZE];
+ void *proc;
+
+ CombinePathW(exe_name, sizeof(exe_name), MsGetSystem32DirW(), L"control.exe");
+
+ proc = Win32RunEx2W(exe_name, L"netconnections", false, NULL);
+
+ if (proc == NULL)
+ {
+ return false;
+ }
+
+ Win32CloseProcess(proc);
+
+ return true;
+}
+
+// Get the best Meiryo font name for the current OS
+char *GetMeiryoFontName()
+{
+ if (MsIsWindows7())
+ {
+ return "Meiryo UI";
+ }
+ else
+ {
+ if (MsIsVista())
+ {
+ return "Meiryo";
+ }
+ else
+ {
+ return "MS UI Gothic";
+ }
+ }
+}
+
+// Get the Meiryo font
+HFONT GetMeiryoFont()
+{
+ return GetMeiryoFontEx(0);
+}
+HFONT GetMeiryoFontEx(UINT font_size)
+{
+ return GetMeiryoFontEx2(font_size, false);
+}
+HFONT GetMeiryoFontEx2(UINT font_size, bool bold)
+{
+ if (_GETLANG() == 0)
+ {
+ return GetFont(GetMeiryoFontName(), font_size, bold, false, false, false);
+ }
+ else if (_GETLANG() == 2)
+ {
+ return GetFont("Microsoft YaHei", font_size, bold, false, false, false);
+ }
+ else
+ {
+ return GetFont(NULL, font_size, bold, false, false, false);
+ }
+}
+
+// Set font to Meiryo
+void SetFontMeiryo(HWND hWnd, UINT id, UINT font_size)
+{
+ SetFont(hWnd, id, GetMeiryoFontEx(font_size));
+}
+
+// Set as the default font
+void SetFontDefault(HWND hWnd, UINT id)
+{
+ SetFont(hWnd, id, GetDialogDefaultFont());
+}
+
+// Display the warning messages about bad process
+void ShowBadProcessWarning(HWND hWnd, BAD_PROCESS *bad)
+{
+ wchar_t title[MAX_SIZE];
+ wchar_t message[8192];
+ // Validate arguments
+ if (bad == NULL)
+ {
+ return;
+ }
+
+ UniFormat(title, sizeof(title), _UU("BAD_PROCESS_TITLE"), bad->Title);
+ UniFormat(message, sizeof(message), _UU("BAD_PROCESS_MESSAGE"),
+ bad->Title, bad->Title, bad->Title, bad->Title);
+
+ OnceMsg(hWnd, title, message, true, ICO_WARNING);
+}
+
+// If there is process which is included in incompatible anti-virus software list, show appropriate
+bool CheckBadProcesses(HWND hWnd)
+{
+ bool ret = true;
+ UINT i;
+ LIST *o;
+
+ o = MsGetProcessList();
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ MS_PROCESS *p = LIST_DATA(o, i);
+ char exe[MAX_PATH];
+ BAD_PROCESS *bad;
+
+ GetFileNameFromFilePath(exe, sizeof(exe), p->ExeFilename);
+
+ bad = IsBadProcess(exe);
+
+ if (bad != NULL)
+ {
+ // Display the message because a bad process have been found
+ ret = false;
+
+ ShowBadProcessWarning(hWnd, bad);
+ }
+ }
+
+ MsFreeProcessList(o);
+
+ return ret;
+}
+
+// Search whether the specified process name is the appropriate to a bad process
+BAD_PROCESS *IsBadProcess(char *exe)
+{
+ UINT i;
+ // Validate arguments
+ if (exe == NULL)
+ {
+ return NULL;
+ }
+
+ for (i = 0;i < num_bad_processes;i++)
+ {
+ BAD_PROCESS *bad = &bad_processes[i];
+
+ if (StrCmpi(bad->ExeName, exe) == 0)
+ {
+ return bad;
+ }
+ }
+
+ return NULL;
+}
+
+// Message display procedure
+UINT OnceMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ ONCEMSG_DLG *d = (ONCEMSG_DLG *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetText(hWnd, 0, d->Title);
+ SetText(hWnd, E_TEXT, d->Message);
+ SetShow(hWnd, C_DONTSHOWAGAIN, d->ShowCheckbox);
+ //DisableClose(hWnd);
+ Focus(hWnd, IDCANCEL);
+ if (d->Icon != 0)
+ {
+ SetIcon(hWnd, 0, d->Icon);
+ }
+
+ if (MsIsVista())
+ {
+ SetFont(hWnd, E_TEXT, GetMeiryoFont());
+ }
+ else
+ {
+ DlgFont(hWnd, E_TEXT, 11, false);
+ }
+
+ SetTimer(hWnd, 1, 50, NULL);
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ if (*d->halt)
+ {
+ Close(hWnd);
+ }
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ KillTimer(hWnd, 1);
+ d->Checked = IsChecked(hWnd, C_DONTSHOWAGAIN);
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Show a message
+void OnceMsg(HWND hWnd, wchar_t *title, wchar_t *message, bool show_checkbox, UINT icon)
+{
+ OnceMsgEx(hWnd, title, message, show_checkbox, icon, NULL);
+}
+void OnceMsgEx(HWND hWnd, wchar_t *title, wchar_t *message, bool show_checkbox, UINT icon, bool *halt)
+{
+ ONCEMSG_DLG d;
+ UINT hash;
+ char valuename[MAX_PATH];
+ bool b_dummy = false;
+ // Validate arguments
+ if (title == NULL)
+ {
+ title = title_bar;
+ }
+ if (message == NULL)
+ {
+ message = L"message";
+ }
+ if (halt == NULL)
+ {
+ halt = &b_dummy;
+ }
+
+ Zero(&d, sizeof(d));
+ d.Message = message;
+ d.Title = title;
+ d.ShowCheckbox = show_checkbox;
+ d.Icon = icon;
+ d.halt = halt;
+
+ hash = GetOnceMsgHash(title, message);
+ Format(valuename, sizeof(valuename), ONCE_MSG_REGVALUE, hash);
+
+ if (MsRegReadInt(REG_CURRENT_USER, ONCE_MSG_REGKEY, valuename) == 0)
+ {
+ switch (icon)
+ {
+ case ICO_WARNING:
+ MessageBeep(MB_ICONEXCLAMATION);
+ break;
+
+ case ICO_INFORMATION:
+ MessageBeep(MB_ICONASTERISK);
+ break;
+ }
+
+ Dialog(hWnd, D_ONCEMSG, OnceMsgProc, &d);
+
+ if (show_checkbox)
+ {
+ if (d.Checked)
+ {
+ MsRegWriteInt(REG_CURRENT_USER, ONCE_MSG_REGKEY, valuename, 1);
+ }
+ }
+ }
+}
+
+// Get the message hash
+UINT GetOnceMsgHash(wchar_t *title, wchar_t *message)
+{
+ BUF *b;
+ UCHAR hash[SHA1_SIZE];
+ UINT ret;
+ // Validate arguments
+ if (title == NULL)
+ {
+ title = title_bar;
+ }
+ if (message == NULL)
+ {
+ message = L"message";
+ }
+
+ b = NewBuf();
+ // 2013.5.19: Exclude the title from the hash calculation
+ //WriteBuf(b, title, UniStrSize(title));
+ WriteBuf(b, message, UniStrSize(message));
+ HashSha1(hash, b->Buf, b->Size);
+ FreeBuf(b);
+
+ Copy(&ret, hash, sizeof(UINT));
+
+ return ret;
+}
+
+// Set a theme for Windows Vista
+void InitVistaWindowTheme(HWND hWnd)
+{
+ static HINSTANCE hInstDll = NULL;
+ HRESULT (WINAPI *_SetWindowTheme)(HWND, LPCWSTR, LPCWSTR) = NULL;
+
+ if (MsIsVista() == false)
+ {
+ return;
+ }
+
+ if (hInstDll == NULL)
+ {
+ hInstDll = LoadLibraryA("uxtheme.dll");
+ }
+
+ if (hInstDll == NULL)
+ {
+ return;
+ }
+
+ if (_SetWindowTheme == NULL)
+ {
+ _SetWindowTheme = (HRESULT (WINAPI *)(HWND,LPCWSTR,LPCWSTR))GetProcAddress(hInstDll, "SetWindowTheme");
+ }
+
+ if (_SetWindowTheme == NULL)
+ {
+ return;
+ }
+
+ _SetWindowTheme(hWnd, L"explorer", NULL);
+}
+
+// Register all applications to be registered in the Windows firewall
+// that may be present in the current directory
+void RegistWindowsFirewallAll()
+{
+ char exedir[MAX_SIZE];
+
+ GetExeDir(exedir, sizeof(exedir));
+
+ RegistWindowsFirewallAllEx(exedir);
+}
+void RegistWindowsFirewallAllEx(char *dir)
+{
+ MsRegistWindowsFirewallEx2(CEDAR_CLIENT_STR, "vpnclient.exe", dir);
+ MsRegistWindowsFirewallEx2(CEDAR_CLIENT_STR, "vpnclient_x64.exe", dir);
+
+ MsRegistWindowsFirewallEx2(CEDAR_CLIENT_MANAGER_STR, "vpncmgr.exe", dir);
+ MsRegistWindowsFirewallEx2(CEDAR_CLIENT_MANAGER_STR, "vpncmgr_x64.exe", dir);
+
+ MsRegistWindowsFirewallEx2(CEDAR_MANAGER_STR, "vpnsmgr.exe", dir);
+ MsRegistWindowsFirewallEx2(CEDAR_MANAGER_STR, "vpnsmgr_x64.exe", dir);
+
+ MsRegistWindowsFirewallEx2(CEDAR_SERVER_STR, "vpnserver.exe", dir);
+ MsRegistWindowsFirewallEx2(CEDAR_SERVER_STR, "vpnserver_x64.exe", dir);
+
+ MsRegistWindowsFirewallEx2(CEDAR_BRIDGE_STR, "vpnbridge.exe", dir);
+ MsRegistWindowsFirewallEx2(CEDAR_BRIDGE_STR, "vpnbridge_x64.exe", dir);
+
+ MsRegistWindowsFirewallEx2(CEDAR_CUI_STR, "vpncmd.exe", dir);
+ MsRegistWindowsFirewallEx2(CEDAR_CUI_STR, "vpncmd_x64.exe", dir);
+
+ MsRegistWindowsFirewallEx2(CEDAR_PRODUCT_STR, "ham.exe", dir);
+ MsRegistWindowsFirewallEx2(CEDAR_PRODUCT_STR, "ham_x64.exe", dir);
+}
+
+// Check whether the notification service is already running
+bool Win32CnCheckAlreadyExists(bool lock)
+{
+ char tmp[MAX_SIZE];
+ HANDLE hMutex;
+
+ HashInstanceNameLocal(tmp, sizeof(tmp), CLIENT_NOTIFY_SERVICE_INSTANCENAME);
+
+ hMutex = OpenMutex(MUTEX_ALL_ACCESS, FALSE, tmp);
+ if (hMutex != NULL)
+ {
+ CloseHandle(hMutex);
+ return true;
+ }
+
+ if (lock == false)
+ {
+ return false;
+ }
+
+ hMutex = CreateMutex(NULL, FALSE, tmp);
+ if (hMutex == NULL)
+ {
+ CloseHandle(hMutex);
+ return true;
+ }
+
+ return false;
+}
+
+// Get whether it is set to not display the dialog about the free version
+bool IsRegistedToDontShowFreeEditionDialog(char *server_name)
+{
+ // Validate arguments
+ if (server_name == NULL)
+ {
+ return false;
+ }
+
+ if (MsRegReadInt(REG_LOCAL_MACHINE, FREE_REGKEY, server_name) != 0)
+ {
+ return true;
+ }
+
+ if (MsRegWriteInt(REG_LOCAL_MACHINE, FREE_REGKEY, "__test__", 1) == false)
+ {
+ return true;
+ }
+
+ MsRegDeleteValue(REG_LOCAL_MACHINE, FREE_REGKEY, "__test__");
+
+ return false;
+}
+
+// Set in the registry not to show a dialog about the free version
+void RegistToDontShowFreeEditionDialog(char *server_name)
+{
+ // Validate arguments
+ if (server_name == NULL)
+ {
+ return;
+ }
+
+ MsRegWriteInt(REG_LOCAL_MACHINE, FREE_REGKEY, server_name, 1);
+}
+
+// Free Edition dialog procedure
+UINT FreeInfoDialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ FREEINFO *info = (FREEINFO *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetIcon(hWnd, 0, ICO_HUB);
+ Top(hWnd);
+ info->hWnd = hWnd;
+ Set(info->Event);
+ FormatText(hWnd, S_INFO_2, info->ServerName);
+ DlgFont(hWnd, S_INFO_1, 13, true);
+ DlgFont(hWnd, S_INFO_3, 13, false);
+ DlgFont(hWnd, B_HIDE, 10, true);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ case IDCANCEL:
+ if (IsChecked(hWnd, B_HIDE))
+ {
+ RegistToDontShowFreeEditionDialog(info->ServerName);
+ }
+
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Display the dialog about the Free Edition
+void ShowFreeInfoDialog(HWND hWnd, FREEINFO *info)
+{
+ // Validate arguments
+ if (info == NULL)
+ {
+ return;
+ }
+
+ Dialog(hWnd, D_FREEINFO, FreeInfoDialogProc, info);
+ Set(info->Event);
+}
+
+// Free Edition dialog thread
+void FreeInfoThread(THREAD *thread, void *param)
+{
+ FREEINFO *info = (FREEINFO *)param;
+ // Validate arguments
+ if (thread == NULL || info == NULL)
+ {
+ return;
+ }
+
+ ShowFreeInfoDialog(NULL, info);
+}
+
+// Start the Free Edition Announcement dialog
+FREEINFO *StartFreeInfoDlg(char *server_name)
+{
+ FREEINFO *info;
+
+ if (IsRegistedToDontShowFreeEditionDialog(server_name))
+ {
+ return NULL;
+ }
+
+ info = ZeroMalloc(sizeof(FREEINFO));
+
+ StrCpy(info->ServerName, sizeof(info->ServerName), server_name);
+ info->Event = NewEvent();
+
+ info->Thread = NewThread(FreeInfoThread, info);
+ Wait(info->Event, INFINITE);
+ ReleaseEvent(info->Event);
+ info->Event = NULL;
+
+ return info;
+}
+
+// End the Free Edition Announcement dialog
+void EndFreeInfoDlg(FREEINFO *info)
+{
+ // Validate arguments
+ if (info == NULL)
+ {
+ return;
+ }
+
+ SendMsg(info->hWnd, 0, WM_CLOSE, 0, 0);
+ WaitThread(info->Thread, INFINITE);
+ ReleaseThread(info->Thread);
+
+ Free(info);
+}
+
+// Execute a EXE in the hamcore
+bool ExecuteHamcoreExe(char *name)
+{
+ BUF *b;
+ wchar_t tmp[MAX_PATH];
+ char tmp2[MAX_PATH];
+ UCHAR hash[MD5_SIZE];
+ // Validate arguments
+ if (name == NULL)
+ {
+ return false;
+ }
+
+ b = ReadDump(name);
+ if (b == NULL)
+ {
+ return false;
+ }
+
+ Hash(hash, name, StrLen(name), false);
+ BinToStr(tmp2, sizeof(tmp2), hash, sizeof(hash));
+ UniFormat(tmp, sizeof(tmp), L"%s\\tmp_%S.exe", MsGetMyTempDirW(), tmp2);
+ SeekBuf(b, 0, 0);
+ DumpBufW(b, tmp);
+
+ FreeBuf(b);
+
+ return RunW(tmp, NULL, false, false);
+}
+
+// Show the Easter Egg
+void ShowEasterEgg(HWND hWnd)
+{
+ ExecuteHamcoreExe("|egg1.exe");
+ ExecuteHamcoreExe("|egg2.exe");
+ ExecuteHamcoreExe("|egg3.exe");
+ ShellExecute(hWnd, "open", "http://www.softether.co.jp/jp/special/vpn3egg/", NULL, NULL, SW_SHOW);
+}
+
+void KakushiThread(THREAD *thread, void *param)
+{
+ KAKUSHI *k;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ k = (KAKUSHI *)param;
+
+ k->Thread = thread;
+ AddRef(k->Thread->ref);
+ NoticeThreadInit(thread);
+
+ Dialog(NULL, D_CM_KAKUSHI, KakushiDlgProc, k);
+ k->hWnd = NULL;
+}
+
+KAKUSHI *InitKakushi()
+{
+ THREAD *t;
+ KAKUSHI *k = ZeroMalloc(sizeof(KAKUSHI));
+
+ t = NewThread(KakushiThread, k);
+
+ WaitThreadInit(t);
+ ReleaseThread(t);
+
+ return k;
+}
+
+UINT KakushiDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ KAKUSHI *k = (KAKUSHI *)param;
+ UINT64 now;
+ bool b;
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetText(hWnd, S_INFO, _UU("CM_VLAN_CREATING"));
+
+ b = false;
+
+ if (MsIsVista())
+ {
+ if (_GETLANG() == 0)
+ {
+ SetFont(hWnd, S_INFO, GetFont(GetMeiryoFontName(), 11, false, false, false, false));
+ b = true;
+ }
+ else if (_GETLANG() == 2)
+ {
+ SetFont(hWnd, S_INFO, GetFont("Microsoft YaHei", 11, false, false, false, false));
+ b = true;
+ }
+ }
+
+ if (b == false)
+ {
+ DlgFont(hWnd, S_INFO, 11, false);
+ }
+
+ SetTimer(hWnd, 1, 50, NULL);
+ k->hWnd = hWnd;
+
+ k->Span = 20 * 1000;
+ k->StartTick = Tick64();
+
+ SetRange(hWnd, P_PROGRESS, 0, (UINT)k->Span);
+
+ case WM_APP + 9821:
+ now = Tick64();
+
+ if (((k->StartTick + k->Span) <= now) || k->Halt)
+ {
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ SetPos(hWnd, P_PROGRESS, (UINT)(now - k->StartTick));
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ AllowSetForegroundWindow(ASFW_ANY);
+ SetForegroundWindow(hWnd);
+ SetActiveWindow(hWnd);
+
+ now = Tick64();
+
+ if (((k->StartTick + k->Span) <= now) || k->Halt)
+ {
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ SetPos(hWnd, P_PROGRESS, (UINT)(now - k->StartTick));
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ return 1;
+ }
+
+ return 0;
+}
+
+// Release the Kakushi screen
+void FreeKakushi(KAKUSHI *k)
+{
+ // Validate arguments
+ if (k == NULL)
+ {
+ return;
+ }
+
+ k->Halt = true;
+
+ if (k->hWnd != NULL)
+ {
+ PostMessage(k->hWnd, WM_APP + 9821, 0, 0);
+ }
+
+ WaitThread(k->Thread, INFINITE);
+ ReleaseThread(k->Thread);
+
+ Free(k);
+}
+
+// TCP/IP optimization selection dialog procedure
+UINT TcpMsgDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ UINT ret;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetIcon(hWnd, 0, ICO_SETUP);
+ //DlgFont(hWnd, R_OPTIMIZE, 0, true);
+
+ Check(hWnd, R_NO, true);
+
+ if (g_tcpip_topmost)
+ {
+ Top(hWnd);
+ }
+
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ ret = 1;
+ if (IsChecked(hWnd, R_MANUAL))
+ {
+ ret = 2;
+ }
+ else if (IsChecked(hWnd, R_NO))
+ {
+ ret = 0;
+ }
+
+ EndDialog(hWnd, ret);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ return 1;
+ }
+
+ return 0;
+}
+
+// Initialize the dialog
+void TcpIpDlgInit(HWND hWnd)
+{
+ MS_TCP tcp;
+
+ SetIcon(hWnd, 0, ICO_SETUP);
+
+ MsGetTcpConfig(&tcp);
+
+ Check(hWnd, R_RECV_DISABLE, tcp.RecvWindowSize == 0);
+ Check(hWnd, R_RECV_ENABLE, tcp.RecvWindowSize != 0);
+ SetInt(hWnd, E_RECV, tcp.RecvWindowSize != 0 ? tcp.RecvWindowSize : DEFAULT_TCP_MAX_WINDOW_SIZE_RECV);
+
+ Check(hWnd, R_SEND_DISABLE, tcp.SendWindowSize == 0);
+ Check(hWnd, R_SEND_ENABLE, tcp.SendWindowSize != 0);
+ SetInt(hWnd, E_SEND, tcp.SendWindowSize != 0 ? tcp.SendWindowSize : DEFAULT_TCP_MAX_WINDOW_SIZE_SEND);
+
+ TcpIpDlgUpdate(hWnd);
+
+ Top(hWnd);
+}
+
+// Update the dialog
+void TcpIpDlgUpdate(HWND hWnd)
+{
+ bool ok = true;
+
+ SetEnable(hWnd, E_RECV, IsChecked(hWnd, R_RECV_ENABLE));
+ SetEnable(hWnd, S_RECV, IsChecked(hWnd, R_RECV_ENABLE));
+ SetEnable(hWnd, E_SEND, IsChecked(hWnd, R_SEND_ENABLE));
+ SetEnable(hWnd, S_SEND, IsChecked(hWnd, R_SEND_ENABLE));
+
+ if (IsChecked(hWnd, R_RECV_ENABLE) && GetInt(hWnd, E_RECV) < 1454)
+ {
+ ok = false;
+ }
+
+ if (IsChecked(hWnd, R_SEND_ENABLE) && GetInt(hWnd, E_SEND) < 1454)
+ {
+ ok = false;
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// TCP/IP dialog procedure
+UINT TcpIpDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ MS_TCP tcp, old;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TcpIpDlgInit(hWnd);
+
+ if (g_tcpip_topmost)
+ {
+ Top(hWnd);
+ }
+
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case R_RECV_DISABLE:
+ case R_RECV_ENABLE:
+ case R_SEND_DISABLE:
+ case R_SEND_ENABLE:
+ case E_RECV:
+ case E_SEND:
+ TcpIpDlgUpdate(hWnd);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ Zero(&tcp, sizeof(tcp));
+
+ if (IsChecked(hWnd, R_RECV_ENABLE))
+ {
+ tcp.RecvWindowSize = GetInt(hWnd, E_RECV);
+ }
+
+ if (IsChecked(hWnd, R_SEND_ENABLE))
+ {
+ tcp.SendWindowSize = GetInt(hWnd, E_SEND);
+ }
+
+ MsGetTcpConfig(&old);
+
+ MsSetTcpConfig(&tcp);
+ MsSaveTcpConfigReg(&tcp);
+
+ EndDialog(hWnd, true);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+
+ case R_RECV_ENABLE:
+ FocusEx(hWnd, E_RECV);
+ break;
+
+ case R_SEND_ENABLE:
+ FocusEx(hWnd, E_SEND);
+ break;
+
+ case B_RECV:
+ SetInt(hWnd, E_RECV, DEFAULT_TCP_MAX_WINDOW_SIZE_RECV);
+ Check(hWnd, R_RECV_DISABLE, false);
+ Check(hWnd, R_RECV_ENABLE, true);
+ TcpIpDlgUpdate(hWnd);
+ FocusEx(hWnd, E_RECV);
+ break;
+
+ case B_SEND:
+ SetInt(hWnd, E_SEND, DEFAULT_TCP_MAX_WINDOW_SIZE_SEND);
+ Check(hWnd, R_SEND_DISABLE, false);
+ Check(hWnd, R_SEND_ENABLE, true);
+ TcpIpDlgUpdate(hWnd);
+ FocusEx(hWnd, E_SEND);
+ break;
+
+ case B_DELETE:
+ Zero(&tcp, sizeof(tcp));
+ MsSetTcpConfig(&tcp);
+ MsDeleteTcpConfigReg();
+ EndDialog(hWnd, 0);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Warning dialog about 64-bit
+UINT Cpu64DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetIcon(hWnd, 0, ICO_WARNING);
+ DlgFont(hWnd, S_BOLD, 9, true);
+ SetTimer(hWnd, 1, 30 * 1000, NULL);
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+ Command(hWnd, IDOK);
+ break;
+ }
+
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// Display a warning dialog about 64-bit
+void ShowCpu64Warning()
+{
+ Dialog(NULL, D_CPU64_WARNING, Cpu64DlgProc, NULL);
+}
+
+// Show the TCP/IP configuration utility
+void ShowTcpIpConfigUtil(HWND hWnd, bool util_mode)
+{
+ if (MsIsTcpConfigSupported() == false)
+ {
+ if (util_mode)
+ {
+ // Show a message that is not supported by the current OS
+ if (MsIsAdmin() == false)
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("TCPOPT_NOT_ADMIN"));
+ }
+ else
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("TCPOPT_NOT_SUPPORTED"));
+ }
+ }
+ return;
+ }
+
+ if (util_mode == false)
+ {
+ // Exit immediately by start the vpncmd
+ wchar_t tmp[MAX_PATH];
+ wchar_t exedir[MAX_PATH];
+ HANDLE h;
+
+ GetExeDirW(exedir, sizeof(exedir));
+
+ if (IsX64())
+ {
+ UniFormat(tmp, sizeof(tmp), L"%s\\vpncmd_x64.exe", exedir);
+ }
+ else if (IsIA64())
+ {
+ UniFormat(tmp, sizeof(tmp), L"%s\\vpncmd_ia64.exe", exedir);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), L"%s\\vpncmd.exe", exedir);
+ }
+
+ if (IsFileW(tmp))
+ {
+ RunW(tmp, L"/tool /cmd:exit", true, false);
+ }
+
+ // Disable the task off-loading by netsh
+ if (MsIsVista())
+ {
+ DIRLIST *dl;
+ UINT i;
+ bool b = false;
+
+ dl = EnumDirW(exedir);
+
+ for (i = 0;i < dl->NumFiles;i++)
+ {
+ if (UniInStr(dl->File[i]->FileNameW, L"vpnbridge") ||
+ UniInStr(dl->File[i]->FileNameW, L"vpnserver"))
+ {
+ b = true;
+ }
+ }
+
+ FreeDir(dl);
+
+ if (b)
+ {
+ // Disable the off-loading
+ MsDisableNetworkOffloadingEtc();
+ }
+ }
+
+ // Windows Firewall registration
+ RegistWindowsFirewallAll();
+
+ SleepThread(1000);
+
+ // Start vpnclient.exe /uihelp
+ h = CmExecUiHelperMain();
+ if (h != NULL)
+ {
+ CloseHandle(h);
+ }
+
+ if (Is64() == false)
+ {
+ if (MsIs64BitWindows())
+ {
+ // Show a warning message if a 32-bit version is used in 64-bit Windows
+ ShowCpu64Warning();
+ }
+ }
+
+ if (MsIsAdmin())
+ {
+ if (MsIsVista())
+ {
+ // If installing on Windows Vista,
+ // dispel the network limitation of MMCSS
+ if (MsIsMMCSSNetworkThrottlingEnabled())
+ {
+ MsSetMMCSSNetworkThrottlingEnable(false);
+ }
+ }
+ }
+ }
+
+ if (util_mode == false && MsIsShouldShowTcpConfigApp() == false)
+ {
+ return;
+ }
+
+ if (util_mode == false)
+ {
+ // 2006.07.04 nobori
+ // I decided not to show TCP/IP optimization utility in the installer
+ return;
+ }
+
+ g_tcpip_topmost = util_mode ? false : true;
+
+ if (util_mode == false)
+ {
+ UINT ret = Dialog(hWnd, D_TCP_MSG, TcpMsgDlgProc, NULL);
+
+ if (ret == 0)
+ {
+ MS_TCP tcp;
+
+ Zero(&tcp, sizeof(tcp));
+ MsGetTcpConfig(&tcp);
+ MsSaveTcpConfigReg(&tcp);
+ return;
+ }
+ else if (ret == 1)
+ {
+ MS_TCP tcp;
+
+ Zero(&tcp, sizeof(tcp));
+
+ tcp.RecvWindowSize = DEFAULT_TCP_MAX_WINDOW_SIZE_RECV;
+ tcp.SendWindowSize = DEFAULT_TCP_MAX_WINDOW_SIZE_SEND;
+ MsSetTcpConfig(&tcp);
+ MsSaveTcpConfigReg(&tcp);
+
+ return;
+ }
+ }
+
+ Dialog(hWnd, D_TCP, TcpIpDlgProc, NULL);
+}
+
+// Internationalization of menu (Unicode)
+void InitMenuInternationalUni(HMENU hMenu, char *prefix)
+{
+ UINT i, num;
+ // Validate arguments
+ if (hMenu == NULL || prefix == NULL)
+ {
+ return;
+ }
+
+ // Get the number of items in the menu
+ num = GetMenuItemCount(hMenu);
+
+ // Enumerate the menu items
+ for (i = 0;i < num;i++)
+ {
+ HMENU hSubMenu = GetSubMenu(hMenu, i);
+ MENUITEMINFOW info;
+ wchar_t tmp[MAX_SIZE];
+
+ if (hSubMenu != NULL)
+ {
+ // If there is a sub-menu, call it recursively
+ InitMenuInternational(hSubMenu, prefix);
+ }
+
+ // Get the menu item
+ Zero(&info, sizeof(info));
+ info.cbSize = sizeof(info);
+ info.cch = sizeof(tmp);
+ info.dwTypeData = tmp;
+ info.fMask = MIIM_STRING;
+ Zero(tmp, sizeof(tmp));
+
+ if (GetMenuItemInfoW(hMenu, i, true, &info))
+ {
+ if (tmp[0] == L'@')
+ {
+ char name[256];
+ wchar_t *ret;
+
+ Format(name, sizeof(name), "%s@%S", prefix, &tmp[1]);
+
+ ret = _UU(name);
+ if (UniIsEmptyStr(ret) == false)
+ {
+ UniStrCpy(tmp, sizeof(tmp), ret);
+ info.cch = UniStrLen(tmp);
+
+ SetMenuItemInfoW(hMenu, i, true, &info);
+ }
+ }
+ }
+ }
+}
+
+// Internationalization of menu
+void InitMenuInternational(HMENU hMenu, char *prefix)
+{
+ UINT i, num;
+ // Validate arguments
+ if (hMenu == NULL || prefix == NULL)
+ {
+ return;
+ }
+
+ if (MsIsNt())
+ {
+ InitMenuInternationalUni(hMenu, prefix);
+ return;
+ }
+
+ // Get the number of items in the menu
+ num = GetMenuItemCount(hMenu);
+
+ // Enumerate the menu items
+ for (i = 0;i < num;i++)
+ {
+ HMENU hSubMenu = GetSubMenu(hMenu, i);
+ MENUITEMINFO info;
+ char tmp[MAX_SIZE];
+
+ if (hSubMenu != NULL)
+ {
+ // If there is a sub-menu, call it recursively
+ InitMenuInternational(hSubMenu, prefix);
+ }
+
+ // Get the menu item
+ Zero(&info, sizeof(info));
+ info.cbSize = sizeof(info);
+ info.cch = sizeof(tmp);
+ info.dwTypeData = tmp;
+ info.fMask = MIIM_STRING;
+ Zero(tmp, sizeof(tmp));
+
+ if (GetMenuItemInfo(hMenu, i, true, &info))
+ {
+ if (tmp[0] == '@')
+ {
+ char name[256];
+ char *ret;
+
+ Format(name, sizeof(name), "%s@%s", prefix, &tmp[1]);
+
+ ret = _SS(name);
+ if (IsEmptyStr(ret) == false)
+ {
+ StrCpy(tmp, sizeof(tmp), ret);
+ info.cch = StrLen(tmp);
+
+ SetMenuItemInfo(hMenu, i, true, &info);
+ }
+ }
+ }
+ }
+}
+
+// Get the default font for the dialog box
+HFONT GetDialogDefaultFont()
+{
+ return GetDialogDefaultFontEx(false);
+}
+HFONT GetDialogDefaultFontEx(bool meiryo)
+{
+ char *default_font_name = _SS("DEFAULT_FONT");
+ UINT default_font_size = _II("DEFAULT_FONT_SIZE");
+ char *win7_font = _SS("DEFAULT_FONT_WIN7");
+
+ if (meiryo)
+ {
+ if (_GETLANG() == 2)
+ {
+ default_font_name = "Microsoft YaHei";
+ }
+ else
+ {
+ default_font_name = GetMeiryoFontName();
+ }
+ }
+
+ if (MsIsWindows7())
+ {
+ if (IsEmptyStr(win7_font) == false)
+ {
+ default_font_name = win7_font;
+ }
+
+ if (GetTextScalingFactor() >= 1.44)
+ {
+ // Use a substitute font in the case of high-DPI in Windows 7 and later
+ char *alternative_font = _SS("DEFAULT_FONT_HIGHDPI");
+
+ if (IsEmptyStr(alternative_font) == false)
+ {
+ default_font_name = alternative_font;
+ }
+ }
+ }
+
+ if (IsEmptyStr(default_font_name))
+ {
+ default_font_name = font_name;
+ }
+
+ if (default_font_size == 0)
+ {
+ default_font_size = 9;
+ }
+
+ return GetFont(default_font_name, default_font_size, false, false, false, false);
+}
+
+// Get the adjustment scale between the control size and the window size
+void GetWindowAndControlSizeResizeScale(HWND hWnd, bool *need_resize, double *factor_x, double *factor_y)
+{
+ UINT dlgfont_x, dlgfont_y;
+ HFONT hDlgFont;
+ // Validate arguments
+ if (hWnd == NULL || need_resize == NULL || factor_x == NULL || factor_y == NULL)
+ {
+ return;
+ }
+
+ *need_resize = true;
+
+ // Get the font of the current window
+ hDlgFont = (HFONT)SendMsg(hWnd, 0, WM_GETFONT, 0, 0);
+
+ // Get the width and height of the font of the current window
+ CalcFontSize(hDlgFont, &dlgfont_x, &dlgfont_y);
+
+ if ((dlgfont_x == WINUI_DEFAULT_DIALOG_UNIT_X) &&
+ (dlgfont_y == WINUI_DEFAULT_DIALOG_UNIT_Y))
+ {
+ // There is no need to adjust
+ *need_resize = false;
+ *factor_x = 1.0;
+ *factor_y = 1.0;
+ return;
+ }
+
+ // Calculate the adjustment amount
+ *factor_x = (double)dlgfont_x / (double)WINUI_DEFAULT_DIALOG_UNIT_X;
+ *factor_y = (double)dlgfont_y / (double)WINUI_DEFAULT_DIALOG_UNIT_Y;
+}
+
+// Adjust the control size and window size
+void AdjustWindowAndControlSize(HWND hWnd, bool *need_resize, double *factor_x, double *factor_y)
+{
+ HFONT hDlgFont;
+ UINT dlgfont_x, dlgfont_y;
+ RECT rect, rect2;
+ LIST *o;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || need_resize == NULL || factor_x == NULL || factor_y == NULL)
+ {
+ return;
+ }
+
+ *need_resize = true;
+
+ // Get the font of the current window
+ hDlgFont = (HFONT)SendMsg(hWnd, 0, WM_GETFONT, 0, 0);
+
+ // Get the width and height of the font of the current window
+ CalcFontSize(hDlgFont, &dlgfont_x, &dlgfont_y);
+
+ if ((dlgfont_x == WINUI_DEFAULT_DIALOG_UNIT_X) &&
+ (dlgfont_y == WINUI_DEFAULT_DIALOG_UNIT_Y))
+ {
+ // There is no need to adjust
+ *need_resize = false;
+ *factor_x = 1.0;
+ *factor_y = 1.0;
+ return;
+ }
+
+ // Calculate the adjustment amount
+ *factor_x = (double)dlgfont_x / (double)WINUI_DEFAULT_DIALOG_UNIT_X;
+ *factor_y = (double)dlgfont_y / (double)WINUI_DEFAULT_DIALOG_UNIT_Y;
+
+ if (MsIsVista())
+ {
+ // In Windows Vista or later, trust the size expansion by the OS to follow this (not adjusted)
+ return;
+ }
+
+ // Adjust the size of the window
+ if (GetWindowRect(hWnd, &rect))
+ {
+ if (GetClientRect(hWnd, &rect2))
+ {
+ UINT width = rect2.right - rect2.left;
+ UINT height = rect2.bottom - rect2.top;
+
+ AdjustDialogXY(&width, &height, dlgfont_x, dlgfont_y);
+
+ width += (rect.right - rect.left) - (rect2.right - rect2.left);
+ height += (rect.bottom - rect.top) - (rect2.bottom - rect2.top);
+
+ if (true)
+ {
+ HWND hParent = GetParent(hWnd);
+
+ if (hParent != NULL)
+ {
+ RECT r;
+
+ Zero(&r, sizeof(r));
+
+ if (GetWindowRect(hParent, &r))
+ {
+ RECT r2;
+
+ rect.top = r.top + GetSystemMetrics(SM_CYCAPTION);
+
+ Zero(&r2, sizeof(r2));
+ if (SystemParametersInfo(SPI_GETWORKAREA, 0, &r2, 0))
+ {
+ if (r2.bottom < (rect.top + (int)height))
+ {
+ rect.top -= (rect.top + (int)height) - r2.bottom;
+
+ if (rect.top < 0)
+ {
+ rect.top = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ MoveWindow(hWnd, rect.left, rect.top, width, height, false);
+ }
+ }
+
+ // Enumerate the child windows
+ o = EnumAllChildWindowEx(hWnd, false, true, true);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ // Adjust the size of the child window
+ HWND h = *((HWND *)LIST_DATA(o, i));
+ HWND hWndParent = GetParent(h);
+ RECT current_rect;
+ char class_name[MAX_PATH];
+ bool is_image = false;
+
+ // Get the class name
+ Zero(class_name, sizeof(class_name));
+ GetClassNameA(h, class_name, sizeof(class_name));
+
+ if (StrCmpi(class_name, "static") == 0)
+ {
+ if (SendMsg(h, 0, STM_GETIMAGE, IMAGE_BITMAP, 0) != 0 ||
+ SendMsg(h, 0, STM_GETIMAGE, IMAGE_ICON, 0) != 0 ||
+ SendMsg(h, 0, STM_GETICON, 0, 0) != 0)
+ {
+ is_image = true;
+ }
+ }
+
+ // Get the position
+ if (GetWindowRect(h, &current_rect))
+ {
+ // Convert to client coordinates
+ POINT p1, p2;
+
+ p1.x = current_rect.left;
+ p1.y = current_rect.top;
+
+ p2.x = current_rect.right;
+ p2.y = current_rect.bottom;
+
+ ScreenToClient(hWndParent, &p1);
+ ScreenToClient(hWndParent, &p2);
+
+ // Adjust the position
+ AdjustDialogXY(&p1.x, &p1.y, dlgfont_x, dlgfont_y);
+ AdjustDialogXY(&p2.x, &p2.y, dlgfont_x, dlgfont_y);
+
+ if (is_image)
+ {
+ p2.x = p1.x + (current_rect.right - current_rect.left);
+ p2.y = p1.y + (current_rect.bottom - current_rect.top);
+ }
+
+ // Move
+ MoveWindow(h, p1.x, p1.y, p2.x - p1.x, p2.y - p1.y, false);
+ }
+ }
+
+ FreeWindowList(o);
+}
+
+// Adjust the values of x and y according to the font
+void AdjustDialogXY(UINT *x, UINT *y, UINT dlgfont_x, UINT dlgfont_y)
+{
+ if (x != NULL)
+ {
+ *x = (UINT)(((double)*x) * (double)WINUI_DEFAULT_DIALOG_UNIT_X / (double)dlgfont_x);
+ }
+
+ if (y != NULL)
+ {
+ *y = (UINT)(((double)*y) * (double)WINUI_DEFAULT_DIALOG_UNIT_Y / (double)dlgfont_y);
+ }
+}
+
+// Internationalizing process for the dialog box
+void InitDialogInternational(HWND hWnd, void *pparam)
+{
+ LIST *o;
+ UINT i;
+ bool is_managed_dialog = false;
+ char caption[MAX_PATH];
+ char *dialog_name;
+ DIALOG_PARAM *param = (DIALOG_PARAM *)pparam;
+ HDC hDC;
+ bool need_resize = false;
+ double factor_x = 0.0, factor_y = 0.0;
+ // Validate arguments
+ if (hWnd == NULL || param == NULL)
+ {
+ return;
+ }
+
+ hDC = CreateCompatibleDC(NULL);
+
+ AdjustWindowAndControlSize(hWnd, &need_resize, &factor_x, &factor_y);
+
+ GetTxtA(hWnd, 0, caption, sizeof(caption));
+ if (caption[0] == '@')
+ {
+ dialog_name = &caption[1];
+
+ is_managed_dialog = true;
+ }
+
+ // Enumerate all window handles
+ o = EnumAllChildWindow(hWnd);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ HWND hControl = *((HWND *)LIST_DATA(o, i));
+
+ if (hControl != NULL)
+ {
+ HFONT hFont = GetDialogDefaultFontEx(param && ((DIALOG_PARAM *)param)->meiryo);
+
+ SetFont(hControl, 0, hFont);
+
+ if (MsIsVista())
+ {
+ char classname[MAX_PATH];
+ GetClassNameA(hControl, classname, sizeof(classname));
+
+ if (StrCmpi(classname, "syslistview32") == 0)
+ {
+ InitVistaWindowTheme(hControl);
+ }
+ }
+
+ if (is_managed_dialog)
+ {
+ char str[MAX_PATH];
+
+ GetTxtA(hControl, 0, str, sizeof(str));
+ if (str[0] == '@')
+ {
+ char *control_name = &str[1];
+ char tmp[MAX_PATH];
+ wchar_t *ret;
+
+ StrCpy(tmp, sizeof(tmp), dialog_name);
+ StrCat(tmp, sizeof(tmp), "@");
+
+ if (hWnd == hControl)
+ {
+ StrCat(tmp, sizeof(tmp), "CAPTION");
+ }
+ else
+ {
+ StrCat(tmp, sizeof(tmp), control_name);
+ }
+
+ ret = _UU(tmp);
+
+ if (ret != NULL && UniIsEmptyStr(ret) == false)
+ {
+ SetText(hControl, 0, ret);
+ }
+ }
+ }
+ }
+ }
+
+ FreeWindowList(o);
+
+ if (MsIsVista() && need_resize)
+ {
+ // Since the window size is changed automatically by the OS by the dpi setting
+ // in Windows Vista or later, a static (bitmap) control needs to be expanded
+ // by anticipating the size after changing
+
+ // Enumerate all child window (not recursive)
+ o = EnumAllChildWindowEx(hWnd, true, false, true);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ HWND hControl = *((HWND *)LIST_DATA(o, i));
+
+ if (hControl != NULL)
+ {
+ char class_name[MAX_SIZE];
+
+ Zero(class_name, sizeof(class_name));
+ GetClassNameA(hControl, class_name, sizeof(class_name));
+
+ if (StrCmpi(class_name, "static") == 0)
+ {
+ UINT style = GetStyle(hControl, 0);
+
+ if (style & SS_BITMAP)
+ {
+ // Get the Bitmap
+ HBITMAP hBitmap = (HBITMAP)SendMessage(hControl, STM_GETIMAGE, IMAGE_BITMAP, 0);
+
+ if (hBitmap != NULL)
+ {
+ // Get the size of this bitmap
+ UINT src_x;
+ UINT src_y;
+
+ if (GetBitmapSize(hBitmap, &src_x, &src_y))
+ {
+ RECT ctl_rect;
+
+ Zero(&ctl_rect, sizeof(ctl_rect));
+
+ if (GetWindowRect(hControl, &ctl_rect))
+ {
+ // Use the smaller magnification of the height and the width
+ //double scale_factor = 1.5;
+ double scale_factor = MIN(factor_x, factor_y);
+ UINT dst_x = (UINT)((double)src_x * scale_factor);
+ UINT dst_y = (UINT)((double)src_y * scale_factor);
+
+ HBITMAP hDst = ResizeBitmap(hBitmap, src_x, src_y, dst_x, dst_y);
+
+ if (hDst != NULL)
+ {
+ Add(param->BitmapList, hDst);
+
+ SendMessage(hControl, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hDst);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ FreeWindowList(o);
+ }
+
+ DeleteDC(hDC);
+}
+
+// Get the size of the bitmap
+bool GetBitmapSize(void *bmp, UINT *x, UINT *y)
+{
+ BITMAP info;
+ // Validate arguments
+ if (bmp == NULL || x == NULL || y == NULL)
+ {
+ return false;
+ }
+
+ Zero(&info, sizeof(info));
+ if (GetObject((HANDLE)bmp, sizeof(info), &info) == 0)
+ {
+ return false;
+ }
+
+ *x = info.bmWidth;
+ *y = info.bmHeight;
+
+ return true;
+}
+
+// Resize the bitmap
+HBITMAP ResizeBitmap(HBITMAP hSrc, UINT src_x, UINT src_y, UINT dst_x, UINT dst_y)
+{
+ HDC hMemDC;
+ HDC hSrcDC;
+ HBITMAP ret = NULL;
+ BITMAPINFOHEADER h;
+ BITMAPINFO bi;
+ UCHAR *data = NULL;
+ // Validate arguments
+ if (hSrc == NULL)
+ {
+ return NULL;
+ }
+
+ hSrcDC = CreateCompatibleDC(NULL);
+ if (hSrcDC != NULL)
+ {
+ HBITMAP hOld = SelectObject(hSrcDC, hSrc);
+
+ if (hOld != NULL)
+ {
+ hMemDC = CreateCompatibleDC(NULL);
+
+ if (hMemDC != NULL)
+ {
+ HBITMAP hOld;
+ HBITMAP srcHbitMap;
+ UCHAR* srcData;
+ CT_RectF_c destRect;
+ CT_RectF_c srcRect;
+
+ Zero(&h, sizeof(h));
+ h.biSize = sizeof(h);
+ h.biWidth = src_x;
+ h.biHeight = src_y;
+ h.biPlanes = 1;
+ h.biBitCount = 32;
+ h.biXPelsPerMeter = 2834;
+ h.biYPelsPerMeter = 2834;
+ h.biCompression = BI_RGB;
+
+ // Copy once the transfer source
+ Zero(&bi, sizeof(bi));
+ Copy(&bi.bmiHeader, &h, sizeof(BITMAPINFOHEADER));
+ srcHbitMap = CreateDIBSection(hMemDC, &bi, DIB_RGB_COLORS, &srcData, NULL, 0);
+
+ hOld = SelectObject(hMemDC, srcHbitMap);
+
+ BitBlt(hMemDC,0,0,src_x,src_y,hSrcDC,0,0, SRCCOPY);
+
+ GdiFlush();
+
+
+
+ // Generate a resized version
+ if(src_x != dst_x || src_y != dst_y)
+ {
+ h.biWidth = dst_x;
+ h.biHeight = dst_y;
+ Zero(&bi, sizeof(bi));
+ Copy(&bi.bmiHeader, &h, sizeof(BITMAPINFOHEADER));
+
+ ret = CreateDIBSection(hMemDC, &bi, DIB_RGB_COLORS, &data, NULL, 0);
+
+ if(srcData != NULL && data != NULL)
+ {
+ destRect.X = 0; destRect.Y = 0;
+ destRect.Width = (float)dst_x; destRect.Height = (float)dst_y;
+ srcRect = destRect;
+ srcRect.Width = (float)src_x; srcRect.Height = (float)src_y;
+
+ CT_DrawImage((UCHAR*)data, destRect, dst_x,dst_y,
+ (UCHAR*)srcData, srcRect,src_x, src_y);
+ }
+
+ if(srcHbitMap != NULL)
+ {
+ DeleteObject(srcHbitMap);
+ }
+ }
+ else
+ {
+ ret = srcHbitMap;
+ }
+
+ SelectObject(hMemDC, hOld);
+
+ DeleteDC(hMemDC);
+ }
+
+ SelectObject(hSrcDC, hOld);
+ }
+
+ DeleteDC(hSrcDC);
+ }
+
+ return ret;
+}
+
+// Initialize the bitmap list
+LIST *NewBitmapList()
+{
+ LIST *o = NewListFast(NULL);
+
+ return o;
+}
+
+// Release the bitmap list
+void FreeBitmapList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ HBITMAP *h = LIST_DATA(o, i);
+
+ DeleteObject(h);
+ }
+
+ ReleaseList(o);
+}
+
+// Child window enumeration procedure
+// Initialize the dialog
+void StringDlgInit(HWND hWnd, STRING_DLG *s)
+{
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ SetText(hWnd, E_STRING, s->String);
+
+ SetIcon(hWnd, S_ICON, s->Icon);
+ SetText(hWnd, S_INFO, s->Info);
+ SetText(hWnd, 0, s->Title);
+
+ FocusEx(hWnd, E_STRING);
+
+ StringDlgUpdate(hWnd, s);
+}
+
+// Update the dialog control
+void StringDlgUpdate(HWND hWnd, STRING_DLG *s)
+{
+ wchar_t *tmp;
+ bool b = true;
+ // Validate arguments
+ if (hWnd == NULL || s == NULL)
+ {
+ return;
+ }
+
+ tmp = GetText(hWnd, E_STRING);
+
+ if (tmp != NULL)
+ {
+ if (s->AllowEmpty == false)
+ {
+ if (UniIsEmptyStr(tmp))
+ {
+ b = false;
+ }
+ }
+
+ if (s->AllowUnsafe == false)
+ {
+ if (IsSafeUniStr(tmp) == false)
+ {
+ b = false;
+ }
+ }
+
+ Free(tmp);
+ }
+
+ SetEnable(hWnd, IDOK, b);
+}
+
+// String dialog procedure
+UINT StringDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ STRING_DLG *s = (STRING_DLG *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ StringDlgInit(hWnd, s);
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case E_STRING:
+ StringDlgUpdate(hWnd, s);
+ break;
+ }
+
+ switch (wParam)
+ {
+ case IDOK:
+ GetTxt(hWnd, E_STRING, s->String, sizeof(s->String));
+ EndDialog(hWnd, true);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Show the string dialog
+wchar_t *StringDlg(HWND hWnd, wchar_t *title, wchar_t *info, wchar_t *def, UINT icon, bool allow_empty, bool allow_unsafe)
+{
+ STRING_DLG s;
+ // Validate arguments
+ if (title == NULL)
+ {
+ title = _UU("DLG_STRING_DEFTITLE");
+ }
+ if (info == NULL)
+ {
+ info = _UU("DLG_STRING_DEFINFO");
+ }
+ if (def == NULL)
+ {
+ def = L"";
+ }
+ if (icon == 0)
+ {
+ icon = ICO_NULL;
+ }
+
+ Zero(&s, sizeof(s));
+ s.Icon = icon;
+ s.Info = info;
+ s.Title = title;
+ s.Icon = icon;
+ UniStrCpy(s.String, sizeof(s.String), def);
+ s.AllowEmpty = allow_empty;
+ s.AllowUnsafe = allow_unsafe;
+
+ if (Dialog(hWnd, D_STRING, StringDlgProc, &s) == false)
+ {
+ return NULL;
+ }
+ else
+ {
+ return CopyUniStr(s.String);
+ }
+}
+char *StringDlgA(HWND hWnd, wchar_t *title, wchar_t *info, char *def, UINT icon, bool allow_empty, bool allow_unsafe)
+{
+ wchar_t unidef[MAX_SIZE];
+ wchar_t *tmp;
+ char *ret;
+ if (def == NULL)
+ {
+ def = "";
+ }
+
+ StrToUni(unidef, sizeof(unidef), def);
+
+ tmp = StringDlg(hWnd, title, info, unidef, icon, allow_empty, allow_unsafe);
+ if (tmp == NULL)
+ {
+ return NULL;
+ }
+
+ ret = CopyUniToStr(tmp);
+ Free(tmp);
+
+ return ret;
+}
+
+// Draw frame
+void LedDrawRect(LED *d)
+{
+ RECT r;
+ // Validate arguments
+ if (d == NULL)
+ {
+ return;
+ }
+
+ SetRect(&r, 0, 0, LED_WIDTH, LED_HEIGHT);
+ FrameRect(d->hDC, &r, GetStockObject(WHITE_BRUSH));
+}
+
+// Restarting dialog
+UINT Win9xRebootDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ WIN9X_REBOOT_DLG *d = (WIN9X_REBOOT_DLG *)param;
+ UINT64 now;
+ wchar_t tmp[MAX_PATH];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ d->StartTime = Tick64();
+ SetRange(hWnd, P_PROGRESS, 0, d->TotalTime);
+ SetTimer(hWnd, 1, 100, NULL);
+ goto UPDATE;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+UPDATE:
+ now = Tick64();
+ if ((d->StartTime + (UINT64)d->TotalTime) <= now)
+ {
+ KillTimer(hWnd, 1);
+ UniStrCpy(tmp, sizeof(tmp), _UU("DLG_REBOOT_INFO_2"));
+ SetText(hWnd, S_INFO, tmp);
+ if (MsShutdown(true, false) == false)
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("DLG_REBOOT_ERROR"));
+ }
+ EndDialog(hWnd, 0);
+ }
+ else
+ {
+ SetPos(hWnd, P_PROGRESS, (UINT)(now - d->StartTime));
+ UniFormat(tmp, sizeof(tmp), _UU("DLG_REBOOT_INFO"),
+ (UINT)((UINT64)d->TotalTime - (now - d->StartTime)) / 1000 + 1);
+ SetText(hWnd, S_INFO, tmp);
+ }
+
+ break;
+ }
+ break;
+ }
+ return 0;
+}
+
+// Restarting thread
+void Win9xRebootThread(THREAD *t, void *p)
+{
+ // Validate arguments
+ if (t == NULL)
+ {
+ return;
+ }
+
+ Win9xReboot(NULL);
+}
+
+// Restart automatically
+void Win9xReboot(HWND hWnd)
+{
+ WIN9X_REBOOT_DLG d;
+
+ Zero(&d, sizeof(d));
+ d.TotalTime = 10 * 1000;
+
+ Dialog(hWnd, D_WIN9X_REBOOT, Win9xRebootDlgProc, &d);
+}
+
+// Show a text file
+void ShowTextFile(HWND hWnd, char *filename, wchar_t *caption, UINT icon)
+{
+ BUF *b;
+ wchar_t *str;
+ // Validate arguments
+ if (filename == NULL || caption == NULL)
+ {
+ return;
+ }
+ if (icon == 0)
+ {
+ icon = ICO_NULL;
+ }
+
+ // Read the text file
+ b = ReadDump(filename);
+ if (b == NULL)
+ {
+ return;
+ }
+
+ SeekBufToEnd(b);
+ WriteBufChar(b, 0);
+
+ str = CopyUtfToUni(b->Buf);
+
+ OnceMsg(hWnd, caption, str, false, icon);
+
+ FreeBuf(b);
+ Free(str);
+}
+
+// Initialize the version information
+void AboutDlgInit(HWND hWnd, WINUI_ABOUT *a)
+{
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || a == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, ICO_INFORMATION);
+
+ UniFormat(tmp, sizeof(tmp), _UU("ABOUT_CAPTION"), a->ProductName);
+ SetText(hWnd, 0, tmp);
+
+ SetFont(hWnd, S_INFO1, GetFont("Arial", 12, false, false, false, false));
+ FormatText(hWnd, S_INFO1, CEDAR_VER / 100, CEDAR_VER / 100, CEDAR_VER % 100, CEDAR_BUILD);
+
+ SetFont(hWnd, S_INFO2, GetFont("Arial", 8, false, false, false, false));
+ FormatText(hWnd, S_INFO2, BUILD_DATE_Y, a->Cedar->BuildInfo);
+
+ SetFont(hWnd, S_INFO3, GetFont("Arial", 7, false, false, false, false));
+
+ //DlgFont(hWnd, S_INFO4, 8, false);
+
+ SetShow(hWnd, B_UPDATE_CONFIG, (a->Update != NULL));
+}
+
+// Version information procedure
+UINT AboutDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ WINUI_ABOUT *a = (WINUI_ABOUT *)param;
+ char tmp[MAX_PATH];
+ LANGLIST t;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ AboutDlgInit(hWnd, a);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ case IDCANCEL:
+ if ((GetKeyState(VK_SHIFT) & 0x8000) &&
+ (GetKeyState(VK_CONTROL) & 0x8000) &&
+ (GetKeyState(VK_MENU) & 0x8000))
+ {
+ ShowEasterEgg(hWnd);
+ }
+ EndDialog(hWnd, true);
+ break;
+ case B_WEB:
+ ShellExecute(hWnd, "open", _SS("SE_COMPANY_URL"), NULL, NULL, SW_SHOW);
+ break;
+ case B_EULA:
+ ShowTextFile(hWnd, "|eula.txt", _UU("SW_EULA_TITLE"), ICO_LOG);
+ break;
+ case B_IMPORTANT:
+ GetCurrentLang(&t);
+ Format(tmp, sizeof(tmp), "|warning_%s.txt", t.Name);
+ ShowTextFile(hWnd, tmp, _UU("SW_WARNING_TITLE"), ICO_LOG);
+ break;
+ case B_LEGAL:
+ ShowTextFile(hWnd, "|legal.txt", _UU("DLG_ABOUT_LEGAL"), ICO_LOG);
+ break;
+ case B_UPDATE_CONFIG:
+ ConfigUpdateUi(a->Update, hWnd);
+ break;
+ case B_LANGUAGE:
+ // Language settings
+ if (true)
+ {
+ wchar_t path[MAX_SIZE];
+
+ CombinePathW(path, sizeof(path), MsGetExeDirNameW(), L"vpnsetup.exe");
+
+ if (MsExecuteW(path, L"/language:yes") == false)
+ {
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("SW_CHILD_PROCESS_ERROR"));
+ }
+ }
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Version information
+void About(HWND hWnd, CEDAR *cedar, wchar_t *product_name)
+{
+ AboutEx(hWnd, cedar, product_name, NULL);
+}
+void AboutEx(HWND hWnd, CEDAR *cedar, wchar_t *product_name, WINUI_UPDATE *u)
+{
+ WINUI_ABOUT a;
+ // Validate arguments
+ if (cedar == NULL || product_name == NULL)
+ {
+ return;
+ }
+
+ Zero(&a, sizeof(a));
+ a.Cedar = cedar;
+ a.ProductName = product_name;
+ a.Update = u;
+
+ Dialog(hWnd, D_ABOUT, AboutDlgProc, &a);
+}
+
+// Test
+void UiTest()
+{
+}
+
+// Examine the number of fields that an IP address is entered
+UINT IpGetFilledNum(HWND hWnd, UINT id)
+{
+ UINT ret;
+ DWORD value;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ ret = SendMsg(hWnd, id, IPM_GETADDRESS, 0, (LPARAM)&value);
+
+ return ret;
+}
+
+// Examine whether an IP address has been entered
+bool IpIsFilled(HWND hWnd, UINT id)
+{
+ UINT ret;
+ DWORD value;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ ret = SendMsg(hWnd, id, IPM_GETADDRESS, 0, (LPARAM)&value);
+
+ if (ret != 4)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+// Clear the IP address
+void IpClear(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SendMsg(hWnd, id, IPM_CLEARADDRESS, 0, 0);
+}
+
+// Get an IP address
+UINT IpGet(HWND hWnd, UINT id)
+{
+ UINT ret;
+ DWORD value;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ ret = SendMsg(hWnd, id, IPM_GETADDRESS, 0, (LPARAM)&value);
+
+ if (ret != 4)
+ {
+ return 0;
+ }
+ else
+ {
+ return Endian32((UINT)value);
+ }
+}
+
+// Set the IP addresses
+void IpSet(HWND hWnd, UINT id, UINT ip)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SendMsg(hWnd, id, IPM_SETADDRESS, 0, Endian32(ip));
+}
+
+// Write the candidates to the registry
+void WriteCandidateToReg(UINT root, char *key, LIST *o, char *name)
+{
+ BUF *b;
+ // Validate arguments
+ if (key == NULL || o == NULL || name == NULL)
+ {
+ return;
+ }
+
+ b = CandidateToBuf(o);
+ if (b == NULL)
+ {
+ return;
+ }
+
+ MsRegWriteBin(root, key, name, b->Buf, b->Size);
+
+ FreeBuf(b);
+}
+
+// Read the candidates from the registry
+LIST *ReadCandidateFromReg(UINT root, char *key, char *name)
+{
+ BUF *b;
+ // Validate arguments
+ if (key == NULL || name == NULL)
+ {
+ return NULL;
+ }
+
+ b = MsRegReadBin(root, key, name);
+ if (b == NULL)
+ {
+ return NewCandidateList();
+ }
+ else
+ {
+ LIST *o = BufToCandidate(b);
+ FreeBuf(b);
+
+ return o;
+ }
+}
+
+// initialize the remote connection dialog
+void RemoteDlgInit(HWND hWnd, WINUI_REMOTE *r)
+{
+ LIST *o;
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ SetIcon(hWnd, 0, r->Icon);
+
+ SetText(hWnd, 0, r->Caption);
+ SetText(hWnd, S_TITLE, r->Title);
+ SetIcon(hWnd, S_ICON, r->Icon);
+
+ // Read candidates
+ o = ReadCandidateFromReg(REG_CURRENT_USER, r->RegKeyName, "RemoteHostCandidate");
+ r->CandidateList = o;
+
+ // Show the candidates
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ CANDIDATE *c = LIST_DATA(o, i);
+ CbAddStr(hWnd, C_HOSTNAME, c->Str, 0);
+ }
+
+ if (r->DefaultHostname != NULL)
+ {
+ SetTextA(hWnd, C_HOSTNAME, r->DefaultHostname);
+ }
+
+ FocusEx(hWnd, C_HOSTNAME);
+
+ RemoteDlgRefresh(hWnd, r);
+}
+
+// Remote connection dialog update
+void RemoteDlgRefresh(HWND hWnd, WINUI_REMOTE *r)
+{
+ char *s;
+ bool ok = true;
+ bool localhost_mode = false;
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ s = GetTextA(hWnd, C_HOSTNAME);
+ if (s != NULL)
+ {
+ Trim(s);
+ if (StrCmpi(s, "localhost") == 0 || StartWith(s, "127."))
+ {
+ localhost_mode = true;
+ }
+ Free(s);
+ }
+
+ if (localhost_mode == false)
+ {
+ Enable(hWnd, C_HOSTNAME);
+ Enable(hWnd, S_HOSTNAME);
+ Check(hWnd, R_LOCAL, false);
+ }
+ else
+ {
+ if (r->Title != _UU("NM_CONNECT_TITLE"))
+ {
+ Disable(hWnd, C_HOSTNAME);
+ Disable(hWnd, S_HOSTNAME);
+ }
+ Check(hWnd, R_LOCAL, true);
+ SetTextA(hWnd, C_HOSTNAME, "localhost");
+
+ if (r->flag1 == false)
+ {
+ Focus(hWnd, IDOK);
+ }
+ }
+
+ if (IsEmpty(hWnd, C_HOSTNAME))
+ {
+ ok = false;
+ }
+
+ SetEnable(hWnd, IDOK, ok);
+
+ r->flag1 = true;
+}
+
+// Remote connection dialog OK button
+void RemoteDlgOnOk(HWND hWnd, WINUI_REMOTE *r)
+{
+ char *hostname;
+ wchar_t *s;
+ LIST *o;
+ // Validate arguments
+ if (hWnd == NULL || r == NULL)
+ {
+ return;
+ }
+
+ // Get the entered host name
+ hostname = GetTextA(hWnd, C_HOSTNAME);
+ if (hostname == NULL)
+ {
+ return;
+ }
+ Trim(hostname);
+
+ // Add a candidate
+ o = r->CandidateList;
+ s = CopyStrToUni(hostname);
+ AddCandidate(o, s, 64);
+ Free(s);
+
+ // Write the candidates
+ WriteCandidateToReg(REG_CURRENT_USER, r->RegKeyName, o, "RemoteHostCandidate");
+ FreeCandidateList(o);
+
+ r->Hostname = hostname;
+
+ EndDialog(hWnd, true);
+}
+
+// Remote connection dialog procedure
+UINT RemoteDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ WINUI_REMOTE *r = (WINUI_REMOTE *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ RemoteDlgInit(hWnd, r);
+ SetTimer(hWnd, 1, 100, NULL);
+ break;
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+ RemoteDlgRefresh(hWnd, r);
+ SetTimer(hWnd, 1, 100, NULL);
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case R_LOCAL:
+ if (IsChecked(hWnd, R_LOCAL) == false)
+ {
+ SetTextA(hWnd, C_HOSTNAME, "");
+ RemoteDlgRefresh(hWnd, r);
+ FocusEx(hWnd, C_HOSTNAME);
+ }
+ else
+ {
+ SetTextA(hWnd, C_HOSTNAME, "localhost");
+ RemoteDlgRefresh(hWnd, r);
+ Focus(hWnd, IDOK);
+ }
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ case IDOK:
+ RemoteDlgOnOk(hWnd, r);
+ break;
+ }
+ switch (LOWORD(wParam))
+ {
+ case R_LOCAL:
+ case C_HOSTNAME:
+ RemoteDlgRefresh(hWnd, r);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ FreeCandidateList(r->CandidateList);
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Remote connection dialog
+char *RemoteDlg(HWND hWnd, char *regkey, UINT icon, wchar_t *caption, wchar_t *title, char *default_host)
+{
+ WINUI_REMOTE r;
+ // Validate arguments
+ if (regkey == NULL)
+ {
+ regkey = "Software\\" GC_REG_COMPANY_NAME "\\" CEDAR_PRODUCT_STR " VPN\\WinUI Common Module";
+ }
+ if (caption == NULL)
+ {
+ caption = _UU("REMOTE_DEF_CAPTION");
+ }
+ if (title == NULL)
+ {
+ title = _UU("REMOTE_DEF_TITLE");
+ }
+ if (icon == 0)
+ {
+ icon = ICO_INTERNET;
+ }
+
+ Zero(&r, sizeof(r));
+ r.RegKeyName = regkey;
+ r.Caption = caption;
+ r.Title = title;
+ r.Icon = icon;
+ r.DefaultHostname = default_host;
+
+ if (Dialog(hWnd, D_REMOTE, RemoteDlgProc, &r) == false)
+ {
+ return NULL;
+ }
+
+ return r.Hostname;
+}
+
+// Window Searching procedure
+bool CALLBACK SearchWindowEnumProc(HWND hWnd, LPARAM lParam)
+{
+ if (hWnd != NULL && lParam != 0)
+ {
+ wchar_t *s = GetText(hWnd, 0);
+ SEARCH_WINDOW_PARAM *p = (SEARCH_WINDOW_PARAM *)lParam;
+ if (s != NULL)
+ {
+ if (UniStrCmpi(p->caption, s) == 0)
+ {
+ p->hWndFound = hWnd;
+ }
+ Free(s);
+ }
+ }
+ return true;
+}
+
+// Search for the window
+HWND SearchWindow(wchar_t *caption)
+{
+ SEARCH_WINDOW_PARAM p;
+ // Validate arguments
+ if (caption == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&p, sizeof(p));
+ p.caption = caption;
+ p.hWndFound = NULL;
+
+ EnumWindows(SearchWindowEnumProc, (LPARAM)&p);
+
+ return p.hWndFound;
+}
+
+// Allow for the specified process to become the foreground window
+void AllowFGWindow(UINT process_id)
+{
+ if (process_id == 0)
+ {
+ return;
+ }
+
+ if (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) &&
+ GET_KETA(GetOsInfo()->OsType, 100) >= 2)
+ {
+ AllowSetForegroundWindow(process_id);
+ }
+}
+
+// Rename the item
+void LvRename(HWND hWnd, UINT id, UINT pos)
+{
+ // Validate arguments
+ if (hWnd == NULL || pos == INFINITE)
+ {
+ return;
+ }
+
+ ListView_EditLabel(DlgItem(hWnd, id), pos);
+}
+
+// Show the menu
+void PrintMenu(HWND hWnd, HMENU hMenu)
+{
+ POINT p;
+ // Validate arguments
+ if (hMenu == NULL || hWnd == NULL)
+ {
+ return;
+ }
+
+ GetCursorPos(&p);
+
+ TrackPopupMenu(hMenu, TPM_LEFTALIGN, p.x, p.y, 0, hWnd, NULL);
+}
+
+// Remove a shortcut string from the menu
+void RemoveShortcutKeyStrFromMenu(HMENU hMenu)
+{
+ UINT i, num;
+ // Validate arguments
+ if (hMenu == NULL)
+ {
+ return;
+ }
+
+ num = GetMenuNum(hMenu);
+ for (i = 0;i < num;i++)
+ {
+ wchar_t *str = GetMenuStr(hMenu, i);
+ if (str != NULL)
+ {
+ UINT j, len;
+ len = UniStrLen(str);
+ for (j = 0;j < len;j++)
+ {
+ if (str[j] == L'\t')
+ {
+ str[j] = 0;
+ }
+ }
+ SetMenuStr(hMenu, i, str);
+ Free(str);
+ }
+ }
+}
+
+// Get the number of items in the menu
+UINT GetMenuNum(HMENU hMenu)
+{
+ UINT ret;
+ // Validate arguments
+ if (hMenu == NULL)
+ {
+ return 0;
+ }
+
+ ret = GetMenuItemCount(hMenu);
+ if (ret == INFINITE)
+ {
+ return 0;
+ }
+ else
+ {
+ return ret;
+ }
+}
+
+// Set the string into the menu
+void SetMenuStr(HMENU hMenu, UINT pos, wchar_t *str)
+{
+ MENUITEMINFOW info;
+ // Validate arguments
+ if (hMenu == NULL || pos == INFINITE || str == NULL)
+ {
+ return;
+ }
+
+ if (MsIsNt() == false)
+ {
+ char *s = CopyUniToStr(str);
+ SetMenuStrA(hMenu, pos, s);
+ Free(s);
+ return;
+ }
+
+ Zero(&info, sizeof(info));
+ info.cbSize = sizeof(info);
+ info.fMask = MIIM_STRING;
+ info.dwTypeData = str;
+ SetMenuItemInfoW(hMenu, pos, true, &info);
+}
+void SetMenuStrA(HMENU hMenu, UINT pos, char *str)
+{
+ MENUITEMINFOA info;
+ // Validate arguments
+ if (hMenu == NULL || pos == INFINITE || str == NULL)
+ {
+ return;
+ }
+
+ Zero(&info, sizeof(info));
+ info.cbSize = sizeof(info);
+ info.fMask = MIIM_STRING;
+ info.dwTypeData = str;
+ SetMenuItemInfoA(hMenu, pos, true, &info);
+}
+
+// Get a string in the menu
+wchar_t *GetMenuStr(HMENU hMenu, UINT pos)
+{
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (hMenu == NULL || pos == INFINITE)
+ {
+ return NULL;
+ }
+ if (MsIsNt() == false)
+ {
+ char *s = GetMenuStrA(hMenu, pos);
+ if (s == NULL)
+ {
+ return NULL;
+ }
+ else
+ {
+ wchar_t *ret = CopyStrToUni(s);
+ Free(s);
+ return ret;
+ }
+ }
+
+ if (GetMenuStringW(hMenu, pos, tmp, sizeof(tmp), MF_BYPOSITION) == 0)
+ {
+ return NULL;
+ }
+
+ return UniCopyStr(tmp);
+}
+char *GetMenuStrA(HMENU hMenu, UINT pos)
+{
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hMenu == NULL || pos == INFINITE)
+ {
+ return NULL;
+ }
+
+ if (GetMenuString(hMenu, pos, tmp, sizeof(tmp), MF_BYPOSITION) == 0)
+ {
+ return NULL;
+ }
+
+ return CopyStr(tmp);
+}
+
+// Bold the menu item
+void SetMenuItemBold(HMENU hMenu, UINT pos, bool bold)
+{
+ MENUITEMINFO info;
+ // Validate arguments
+ if (hMenu == NULL || pos == INFINITE)
+ {
+ return;
+ }
+
+ Zero(&info, sizeof(info));
+ info.cbSize = sizeof(info);
+ info.fMask = MIIM_STATE;
+
+ if (GetMenuItemInfo(hMenu, pos, true, &info) == false)
+ {
+ return;
+ }
+
+ if (bold)
+ {
+ info.fState |= MFS_DEFAULT;
+ }
+ else
+ {
+ info.fState = info.fState & ~MFS_DEFAULT;
+ }
+
+ SetMenuItemInfo(hMenu, pos, true, &info);
+}
+
+// Enable / disable the menu item
+void SetMenuItemEnable(HMENU hMenu, UINT pos, bool enable)
+{
+ MENUITEMINFO info;
+ // Validate arguments
+ if (hMenu == NULL || pos == INFINITE)
+ {
+ return;
+ }
+
+ Zero(&info, sizeof(info));
+ info.cbSize = sizeof(info);
+ info.fMask = MIIM_STATE;
+
+ if (GetMenuItemInfo(hMenu, pos, true, &info) == false)
+ {
+ return;
+ }
+
+ if (enable)
+ {
+ info.fState |= MFS_ENABLED;
+ info.fState = info.fState & ~MFS_DISABLED;
+ }
+ else
+ {
+ info.fState |= MFS_DISABLED;
+ info.fState = info.fState & ~MFS_ENABLED;
+ }
+
+ SetMenuItemInfo(hMenu, pos, true, &info);
+}
+
+// Remove a menu item
+void DeleteMenuItem(HMENU hMenu, UINT pos)
+{
+ // Validate arguments
+ if (hMenu == NULL || pos == INFINITE)
+ {
+ return;
+ }
+
+ DeleteMenu(hMenu, pos, MF_BYPOSITION);
+}
+
+// Get the position from the ID in the menu
+UINT GetMenuItemPos(HMENU hMenu, UINT id)
+{
+ UINT num, i;
+ // Validate arguments
+ if (hMenu == NULL)
+ {
+ return INFINITE;
+ }
+
+ num = GetMenuItemCount(hMenu);
+ if (num == INFINITE)
+ {
+ return INFINITE;
+ }
+
+ for (i = 0;i < num;i++)
+ {
+ if (GetMenuItemID(hMenu, i) == id)
+ {
+ return i;
+ }
+ }
+
+ return INFINITE;
+}
+
+// Get a sub-menu
+HMENU LoadSubMenu(UINT menu_id, UINT pos, HMENU *parent_menu)
+{
+ HMENU h = LoadMenu(hDll, MAKEINTRESOURCE(menu_id));
+ HMENU ret;
+ if (h == NULL)
+ {
+ return NULL;
+ }
+
+ ret = GetSubMenu(h, pos);
+
+ if (parent_menu != NULL)
+ {
+ *parent_menu = h;
+ }
+
+ return ret;
+}
+
+// Get the DLL of the user interface
+HINSTANCE GetUiDll()
+{
+ return hDll;
+}
+
+// Connection Error dialog procedure
+UINT ConnectErrorDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ UI_CONNECTERROR_DLG *p = (UI_CONNECTERROR_DLG *)param;
+ wchar_t tmp[1024];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ if (p->Err == ERR_DISCONNECTED || p->Err == ERR_SESSION_TIMEOUT)
+ {
+ // Message indicating that the connection has been disconnected
+ SetText(hWnd, S_TITLE, _UU("ERRDLG_DISCONNECTED_MSG"));
+ }
+ if (p->HideWindow)
+ {
+ Hide(hWnd, R_HIDE);
+ }
+ FormatText(hWnd, 0, p->AccountName);
+ FormatText(hWnd, S_TITLE, p->ServerName);
+ UniFormat(tmp, sizeof(tmp), _UU("ERRDLG_ERRMSG"), p->Err, _E(p->Err));
+ SetText(hWnd, E_ERROR, tmp);
+
+ SetIcon(hWnd, 0, ICO_SERVER_OFFLINE);
+
+ if (p->RetryIntervalSec == 0)
+ {
+ SetText(hWnd, S_COUNTDOWN, _UU("ERRDLG_INFORMATION"));
+ Hide(hWnd, P_PROGRESS);
+ Hide(hWnd, S_RETRYINFO);
+ }
+ else
+ {
+ if (p->RetryLimit != INFINITE)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("ERRDLG_RETRY_INFO_1"), p->CurrentRetryCount, p->RetryLimit);
+ }
+ else
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("ERRDLG_RETRY_INFO_2"), p->CurrentRetryCount);
+ }
+ SetText(hWnd, S_RETRYINFO, tmp);
+ SetRange(hWnd, P_PROGRESS, 0, p->RetryIntervalSec);
+ SetPos(hWnd, P_PROGRESS, 0);
+ SetTimer(hWnd, 1, 10, NULL);
+ p->StartTick = Tick64();
+ }
+ SetTimer(hWnd, 2, 10, NULL);
+ Focus(hWnd, IDOK);
+ break;
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ if (p->RetryIntervalSec != 0)
+ {
+ UINT64 start, end, now;
+ now = Tick64();
+ start = p->StartTick;
+ end = start + (UINT64)p->RetryIntervalSec;
+
+ if (end > now)
+ {
+ SetPos(hWnd, P_PROGRESS, (UINT)(now - start));
+ UniFormat(tmp, sizeof(tmp), _UU("ERRDLG_RETRYCOUNT"), ((UINT)(end - now)) / 1000);
+ SetText(hWnd, S_COUNTDOWN, tmp);
+ }
+ else
+ {
+ Command(hWnd, IDOK);
+ }
+ }
+ break;
+ case 2:
+ if (p->CancelEvent != NULL)
+ {
+ if (WaitForSingleObject((HANDLE)p->CancelEvent->pData, 0) != WAIT_TIMEOUT)
+ {
+ // Forced Cancel
+ Close(hWnd);
+ }
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case R_HIDE:
+ p->HideWindow = IsChecked(hWnd, R_HIDE);
+ break;
+ }
+ switch (wParam)
+ {
+ case IDOK:
+ EndDialog(hWnd, true);
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Show the connection error dialog
+bool ConnectErrorDlg(UI_CONNECTERROR_DLG *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return false;
+ }
+
+ return DialogEx2(NULL, D_CONNECTERROR, ConnectErrorDlgProc, p, true, true);
+}
+
+// Display the contents of the certificate
+void PrintCheckCertInfo(HWND hWnd, UI_CHECKCERT *p)
+{
+ wchar_t tmp[MAX_SIZE];
+ char tmp2[MAX_SIZE];
+ UCHAR md5[MD5_SIZE];
+ UCHAR sha1[SHA1_SIZE];
+ X *x;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ x = p->x;
+
+ GetAllNameFromNameEx(tmp, sizeof(tmp), x->subject_name);
+ SetText(hWnd, E_SUBJECT, tmp);
+
+ GetAllNameFromNameEx(tmp, sizeof(tmp), x->issuer_name);
+ SetText(hWnd, E_ISSUER, tmp);
+
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(x->notAfter), NULL);
+ SetText(hWnd, E_EXPIRES, tmp);
+
+ GetXDigest(x, md5, false);
+ BinToStr(tmp2, sizeof(tmp2), md5, sizeof(md5));
+ SetTextA(hWnd, E_MD5, tmp2);
+
+ GetXDigest(x, sha1, true);
+ BinToStr(tmp2, sizeof(tmp2), sha1, sizeof(sha1));
+ SetTextA(hWnd, E_SHA1, tmp2);
+
+ SetFont(hWnd, E_MD5, GetFont("Arial", 8, false, false, false, false));
+ SetFont(hWnd, E_SHA1, GetFont("Arial", 8, false, false, false, false));
+}
+
+// Warn that the certificate is different
+void ShowDlgDiffWarning(HWND hWnd, UI_CHECKCERT *p)
+{
+ UCHAR sha1_new[SHA1_SIZE], sha1_old[SHA1_SIZE];
+ UCHAR md5_new[MD5_SIZE], md5_old[MD5_SIZE];
+ char sha1_new_str[MAX_SIZE], sha1_old_str[MAX_SIZE];
+ char md5_new_str[MAX_SIZE], md5_old_str[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL || p == NULL || p->x == NULL || p->old_x == NULL)
+ {
+ return;
+ }
+
+ GetXDigest(p->x, sha1_new, true);
+ GetXDigest(p->x, md5_new, false);
+
+ GetXDigest(p->old_x, sha1_old, true);
+ GetXDigest(p->old_x, md5_old, false);
+
+ BinToStrEx(sha1_new_str, sizeof(sha1_new_str), sha1_new, sizeof(sha1_new));
+ BinToStrEx(md5_new_str, sizeof(md5_new_str), md5_new, sizeof(md5_new));
+ BinToStrEx(sha1_old_str, sizeof(sha1_old_str), sha1_old, sizeof(sha1_old));
+ BinToStrEx(md5_old_str, sizeof(md5_old_str), md5_old, sizeof(md5_old));
+
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("CC_DANGEROUS_MSG"),
+ p->ServerName, md5_old_str, sha1_old_str, md5_new_str, sha1_new_str);
+}
+
+// [OK] button is pressed
+void CheckCertDialogOnOk(HWND hWnd, UI_CHECKCERT *p)
+{
+ UCHAR sha1_new[SHA1_SIZE];
+ UCHAR md5_new[MD5_SIZE];
+ char sha1_new_str[MAX_SIZE];
+ char md5_new_str[MAX_SIZE];
+ UINT ret;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ GetXDigest(p->x, sha1_new, true);
+ GetXDigest(p->x, md5_new, false);
+ BinToStrEx(sha1_new_str, sizeof(sha1_new_str), sha1_new, sizeof(sha1_new));
+ BinToStrEx(md5_new_str, sizeof(md5_new_str), md5_new, sizeof(md5_new));
+
+ ret = MsgBoxEx(hWnd, MB_ICONQUESTION | MB_YESNOCANCEL | MB_DEFBUTTON2,
+ _UU("CC_WARNING_MSG"),
+ p->AccountName, sha1_new_str, md5_new_str);
+
+ if (ret == IDYES)
+ {
+ p->SaveServerCert = true;
+ }
+
+ if (ret == IDCANCEL)
+ {
+ return;
+ }
+
+ p->Ok = true;
+ EndDialog(hWnd, true);
+}
+
+// Certificate dialog procedure
+UINT CheckCertDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ UI_CHECKCERT *p = (UI_CHECKCERT *)param;
+ // Validate arguments
+ if (hWnd == NULL || param == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ FormatText(hWnd, 0, p->AccountName);
+ FormatText(hWnd, S_TITLE, p->ServerName);
+ FormatText(hWnd, S_MSG1, p->ServerName);
+
+ PrintCheckCertInfo(hWnd, p);
+
+ Focus(hWnd, IDCANCEL);
+
+ SetIcon(hWnd, 0, ICO_WARNING);
+
+ if (p->DiffWarning)
+ {
+ SetTimer(hWnd, 1, 1, NULL);
+ }
+
+ SetTimer(hWnd, 2, 100, NULL);
+
+ break;
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+ ShowDlgDiffWarning(hWnd, p);
+ break;
+ case 2:
+ if ((p->Session != NULL && p->Session->Halt) ||
+ (p->Halt))
+ {
+ p->Ok = false;
+ EndDialog(hWnd, false);
+ }
+ break;
+ }
+ break;
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_SHOW:
+ CertDlg(hWnd, p->x, p->parent_x, false);
+ break;
+ case IDOK:
+ CheckCertDialogOnOk(hWnd, p);
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ p->Ok = false;
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Certificate Check dialog
+void CheckCertDlg(UI_CHECKCERT *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return;
+ }
+
+ Dialog(NULL, D_CHECKCERT, CheckCertDlgProc, p);
+}
+
+// Get the image list ID from the icon ID
+UINT GetIcon(UINT icon_id)
+{
+ IMAGELIST_ICON *c, t;
+ t.id = icon_id;
+
+ c = Search(icon_list, &t);
+ if (c == NULL)
+ {
+ if (icon_id != ICO_NULL)
+ {
+ return GetIcon(ICO_NULL);
+ }
+ else
+ {
+ return INFINITE;
+ }
+ }
+ else
+ {
+ return c->Index;
+ }
+}
+
+// Load an icon for the image list
+IMAGELIST_ICON *LoadIconForImageList(UINT id)
+{
+ IMAGELIST_ICON *ret = ZeroMalloc(sizeof(IMAGELIST_ICON));
+ HICON small_icon, large_icon;
+
+ ret->id = id;
+
+ large_icon = LoadLargeIcon(id);
+ if (large_icon == NULL)
+ {
+ large_icon = LoadSmallIcon(id);
+ }
+
+ small_icon = LoadSmallIcon(id);
+ if (small_icon == NULL)
+ {
+ small_icon = LoadLargeIcon(id);
+ }
+
+ ret->hSmallImage = small_icon;
+ ret->hLargeImage = large_icon;
+ ret->Index = ImageList_AddIcon(large_image_list, large_icon);
+ ImageList_AddIcon(small_image_list, small_icon);
+
+ return ret;
+}
+
+// Comparison of the image list icons
+int CompareImageListIcon(void *p1, void *p2)
+{
+ IMAGELIST_ICON *c1, *c2;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ c1 = *(IMAGELIST_ICON **)p1;
+ c2 = *(IMAGELIST_ICON **)p2;
+ if (c1 == NULL || c2 == NULL)
+ {
+ return 0;
+ }
+
+ if (c1->id > c2->id)
+ {
+ return 1;
+ }
+ else if (c1->id < c2->id)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// Initialize thr image list
+void InitImageList()
+{
+ large_image_list = ImageList_Create(32, 32, ILC_COLOR32 | ILC_MASK, 1, 0);
+ ImageList_SetBkColor(large_image_list, RGB(255, 255, 255));
+ small_image_list = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 1, 0);
+ ImageList_SetBkColor(small_image_list, RGB(255, 255, 255));
+ icon_list = NewList(CompareImageListIcon);
+
+ // Enumeration
+ EnumResourceNames(hDll, RT_GROUP_ICON, EnumResNameProc, 0);
+}
+
+// Icon resource enumeration procedure
+BOOL CALLBACK EnumResNameProc(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam)
+{
+ if (IS_INTRESOURCE(lpszName))
+ {
+ UINT icon_id = (UINT)lpszName;
+ IMAGELIST_ICON *img = LoadIconForImageList(icon_id);
+
+ Add(icon_list, img);
+ }
+
+ return TRUE;
+}
+
+// Release the image list
+void FreeImageList()
+{
+ UINT i;
+ ImageList_Destroy(large_image_list);
+ ImageList_Destroy(small_image_list);
+ large_image_list = small_image_list = NULL;
+
+ for (i = 0;i < LIST_NUM(icon_list);i++)
+ {
+ IMAGELIST_ICON *c = LIST_DATA(icon_list, i);
+ Free(c);
+ }
+
+ ReleaseList(icon_list);
+ icon_list = NULL;
+}
+
+// Get the width of the column of the list view
+UINT LvGetColumnWidth(HWND hWnd, UINT id, UINT index)
+{
+ return (UINT)((double)ListView_GetColumnWidth(DlgItem(hWnd, id), index) / GetTextScalingFactor());
+}
+
+// Insert the column into the list view
+void LvInsertColumn(HWND hWnd, UINT id, UINT index, wchar_t *str, UINT width)
+{
+ LVCOLUMNW c;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return;
+ }
+
+ width = (UINT)((double)width * GetTextScalingFactor());
+
+ Zero(&c, sizeof(c));
+ c.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
+
+ c.pszText = str;
+ c.iSubItem = index;
+ c.cx = width;
+
+ SendMsg(hWnd, id, LVM_INSERTCOLUMNW, index, (LPARAM)&c);
+}
+
+// Remove all items from list view
+void LvReset(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ ListView_DeleteAllItems(DlgItem(hWnd, id));
+}
+
+// Initialize the list view
+void LvInitEx(HWND hWnd, UINT id, bool no_image)
+{
+ LvInitEx2(hWnd, id, no_image, false);
+}
+void LvInitEx2(HWND hWnd, UINT id, bool no_image, bool large_icon)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ ListView_SetUnicodeFormat(DlgItem(hWnd, id), true);
+
+ if (no_image == false)
+ {
+ ListView_SetImageList(DlgItem(hWnd, id), large_image_list, LVSIL_NORMAL);
+ ListView_SetImageList(DlgItem(hWnd, id), large_icon ? large_image_list : small_image_list, LVSIL_SMALL);
+ }
+
+ ListView_SetExtendedListViewStyle(DlgItem(hWnd, id), LVS_EX_FULLROWSELECT);
+
+ if (MsIsVista())
+ {
+ LvSetStyle(hWnd, id, LVS_EX_DOUBLEBUFFER);
+ }
+}
+void LvInit(HWND hWnd, UINT id)
+{
+ LvInitEx(hWnd, id, false);
+}
+
+// Adding batch complete (high-speed)
+void LvInsertEnd(LVB *b, HWND hWnd, UINT id)
+{
+ LvInsertEndEx(b, hWnd, id, false);
+}
+void LvInsertEndEx(LVB *b, HWND hWnd, UINT id, bool force_reset)
+{
+ UINT i, num;
+ LIST *new_list, *exist_list;
+ wchar_t *last_selected = NULL;
+ // Validate arguments
+ if (b == NULL || hWnd == NULL)
+ {
+ return;
+ }
+
+ new_list = NewListFast(CompareUniStr);
+
+ for (i = 0;i < LIST_NUM(b->ItemList);i++)
+ {
+ LVB_ITEM *t = LIST_DATA(b->ItemList, i);
+ Add(new_list, t->Strings[0]);
+ }
+
+ Sort(new_list);
+
+ if ((LIST_NUM(b->ItemList) >= LV_INSERT_RESET_ALL_ITEM_MIN) || force_reset)
+ {
+ last_selected = LvGetFocusedStr(hWnd, id, 0);
+ LvReset(hWnd, id);
+ }
+
+ exist_list = NewListFast(CompareUniStr);
+
+ num = LvNum(hWnd, id);
+
+ // Delete the items which isn't contained in the batch list of existing items
+ for (i = 0;i < num;i++)
+ {
+ bool exists = false;
+ wchar_t *s = LvGetStr(hWnd, id, i, 0);
+ if (Search(new_list, s) != NULL)
+ {
+ exists = true;
+ }
+ if (exists == false)
+ {
+ // Remove items that don't exist in the batch list of the adding plan from the list view
+ LvDeleteItem(hWnd, id, i);
+ num = LvNum(hWnd, id);
+ i--;
+ Free(s);
+ }
+ else
+ {
+ Add(exist_list, s);
+ }
+ }
+
+ Sort(exist_list);
+
+ // Add items in the batch one by one
+ for (i = 0;i < LIST_NUM(b->ItemList);i++)
+ {
+ LVB_ITEM *t = LIST_DATA(b->ItemList, i);
+ UINT index;
+ UINT j;
+ bool exists = false;
+
+ if (Search(exist_list, t->Strings[0]) != NULL)
+ {
+ index = LvSearchStr(hWnd, id, 0, t->Strings[0]);
+ }
+ else
+ {
+ index = INFINITE;
+ }
+
+ if (index != INFINITE)
+ {
+ UINT j;
+ // If an item with the string same to adding item already exists,
+ // update instead of adding
+ for (j = 0;j < t->NumStrings;j++)
+ {
+ LvSetItem(hWnd, id, index, j, t->Strings[j]);
+ }
+ LvSetItemImageByImageListId(hWnd, id, index, t->Image);
+ LvSetItemParam(hWnd, id, index, t->Param);
+ }
+ else
+ {
+ // Add newly
+ UINT index = INFINITE;
+ UINT j;
+ for (j = 0;j < t->NumStrings;j++)
+ {
+ if (j == 0)
+ {
+ index = LvInsertItemByImageListId(hWnd, id, t->Image, t->Param, t->Strings[j]);
+ }
+ else
+ {
+ LvSetItem(hWnd, id, index, j, t->Strings[j]);
+ }
+ }
+ }
+
+ // Release the memory
+ for (j = 0;j < t->NumStrings;j++)
+ {
+ Free(t->Strings[j]);
+ }
+ Free(t->Strings);
+ Free(t);
+ }
+
+ // Release the list
+ ReleaseList(b->ItemList);
+
+ // Release the memory
+ Free(b);
+
+ ReleaseList(new_list);
+
+ for (i = 0;i < LIST_NUM(exist_list);i++)
+ {
+ Free(LIST_DATA(exist_list, i));
+ }
+ ReleaseList(exist_list);
+
+ if (last_selected != NULL)
+ {
+ UINT pos = LvSearchStr(hWnd, id, 0, last_selected);
+
+ if (pos != INFINITE)
+ {
+ LvSelect(hWnd, id, pos);
+ }
+
+ Free(last_selected);
+ }
+}
+
+// Get the number of columns of the list view
+UINT LvGetColumnNum(HWND hWnd, UINT id)
+{
+ UINT i;
+ LVCOLUMN c;
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ for (i = 0;;i++)
+ {
+ Zero(&c, sizeof(c));
+ c.mask = LVCF_SUBITEM;
+ if (ListView_GetColumn(DlgItem(hWnd, id), i, &c) == false)
+ {
+ break;
+ }
+ }
+
+ return i;
+}
+
+// List-view sort function
+int CALLBACK LvSortProc(LPARAM param1, LPARAM param2, LPARAM sort_param)
+{
+ WINUI_LV_SORT *sort = (WINUI_LV_SORT *)sort_param;
+ HWND hWnd;
+ UINT id;
+ UINT i1, i2;
+ int ret = 0;
+ wchar_t *s1, *s2;
+ if (sort == NULL)
+ {
+ return 0;
+ }
+
+ hWnd = sort->hWnd;
+ id = sort->id;
+
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ i1 = (UINT)param1;
+ i2 = (UINT)param2;
+
+ s1 = LvGetStr(hWnd, id, i1, sort->subitem);
+ if (s1 == NULL)
+ {
+ return 0;
+ }
+
+ s2 = LvGetStr(hWnd, id, i2, sort->subitem);
+ if (s2 == NULL)
+ {
+ Free(s1);
+ return 0;
+ }
+
+ if (sort->numeric == false)
+ {
+ if (UniStrCmpi(s1, _UU("CM_NEW_ICON")) == 0 || UniStrCmpi(s1, _UU("CM_VGC_ICON")) == 0 || UniStrCmpi(s1, _UU("CM_VGC_LINK")) == 0)
+ {
+ ret = -1;
+ }
+ else if (UniStrCmpi(s2, _UU("CM_NEW_ICON")) == 0 || UniStrCmpi(s2, _UU("CM_VGC_ICON")) == 0 || UniStrCmpi(s1, _UU("CM_VGC_LINK")) == 0)
+ {
+ ret = 1;
+ }
+ else
+ {
+ ret = UniStrCmpi(s1, s2);
+ }
+ }
+ else
+ {
+ UINT64 v1, v2;
+ v1 = UniToInt64(s1);
+ v2 = UniToInt64(s2);
+ if (v1 > v2)
+ {
+ ret = 1;
+ }
+ else if (v1 < v2)
+ {
+ ret = -1;
+ }
+ else
+ {
+ ret = 0;
+ }
+ }
+
+ Free(s1);
+ Free(s2);
+
+ if (sort->desc)
+ {
+ ret = -ret;
+ }
+
+ return ret;
+}
+
+// Standard handler
+void LvStandardHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT id)
+{
+ NMHDR *n;
+ NMLVKEYDOWN *key;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ LvSortHander(hWnd, msg, wParam, lParam, id);
+
+ switch (msg)
+ {
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ if (n->idFrom == id)
+ {
+ switch (n->code)
+ {
+ case NM_DBLCLK:
+ Command(hWnd, IDOK);
+ break;
+ case LVN_KEYDOWN:
+ key = (NMLVKEYDOWN *)n;
+ if (key != NULL)
+ {
+ UINT code = key->wVKey;
+ switch (code)
+ {
+ case VK_DELETE:
+ Command(hWnd, B_DELETE);
+ break;
+
+ case VK_RETURN:
+ Command(hWnd, IDOK);
+ break;
+
+ case VK_F5:
+ Command(hWnd, B_REFRESH);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+}
+
+// Sort header handler
+void LvSortHander(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT id)
+{
+ NMHDR *nmhdr;
+ UINT subitem;
+ bool desc;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ switch (msg)
+ {
+ case WM_NOTIFY:
+ nmhdr = (NMHDR *)lParam;
+
+ if (nmhdr != NULL)
+ {
+ if (nmhdr->idFrom == id)
+ {
+ NMLISTVIEW *v;
+ switch (nmhdr->code)
+ {
+ case LVN_COLUMNCLICK:
+ desc = false;
+ v = (NMLISTVIEW *)lParam;
+ subitem = v->iSubItem;
+
+ if ((GetStyle(hWnd, id) & LVS_SORTDESCENDING) == 0)
+ {
+ desc = true;
+ SetStyle(hWnd, id, LVS_SORTDESCENDING);
+ RemoveStyle(hWnd, id, LVS_SORTASCENDING);
+ }
+ else
+ {
+ SetStyle(hWnd, id, LVS_SORTASCENDING);
+ RemoveStyle(hWnd, id, LVS_SORTDESCENDING);
+ }
+
+ LvSort(hWnd, id, subitem, desc);
+ break;
+ }
+ }
+ }
+ break;
+ }
+}
+
+// Do sort
+void LvSort(HWND hWnd, UINT id, UINT subitem, bool desc)
+{
+ UINT i, num;
+ bool numeric = true;
+ wchar_t na[2] = {0xff0d, 0x0, };
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ num = LvNum(hWnd, id);
+ for (i = 0;i < num;i++)
+ {
+ wchar_t *s = LvGetStr(hWnd, id, i, subitem);
+ if (s != NULL)
+ {
+ if (UniIsNum(s) == false && UniStrCmp(s, na) != 0)
+ {
+ numeric = false;
+ Free(s);
+ break;
+ }
+ Free(s);
+ }
+ else
+ {
+ numeric = false;
+ break;
+ }
+ }
+
+ LvSortEx(hWnd, id, subitem, desc, numeric);
+}
+
+void LvSortEx(HWND hWnd, UINT id, UINT subitem, bool desc, bool numeric)
+{
+ WINUI_LV_SORT s;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+ if (subitem >= LvGetColumnNum(hWnd, id))
+ {
+ return;
+ }
+
+ Zero(&s, sizeof(s));
+ s.desc = desc;
+ s.numeric = numeric;
+ s.id = id;
+ s.hWnd = hWnd;
+ s.subitem = subitem;
+
+ ListView_SortItemsEx(DlgItem(hWnd, id), LvSortProc, (LPARAM)&s);
+}
+
+// Add an item to adding batch
+void LvInsertAdd(LVB *b, UINT icon, void *param, UINT num_str, ...)
+{
+ UINT i;
+ va_list va;
+ UINT index = 0;
+ LVB_ITEM *t;
+ // Validate arguments
+ if (b == NULL || num_str == 0)
+ {
+ return;
+ }
+
+ t = ZeroMalloc(sizeof(LVB_ITEM));
+
+ va_start(va, num_str);
+
+ t->Strings = (wchar_t **)ZeroMalloc(sizeof(wchar_t *) * num_str);
+ t->NumStrings = num_str;
+
+ for (i = 0;i < num_str;i++)
+ {
+ wchar_t *s = va_arg(va, wchar_t *);
+
+ t->Strings[i] = UniCopyStr(s);
+ }
+
+ t->Param = param;
+ t->Image = GetIcon(icon);
+
+ Add(b->ItemList, t);
+
+ va_end(va);
+}
+
+// Start the item adding batch
+LVB *LvInsertStart()
+{
+ LVB *b = ZeroMalloc(sizeof(LVB));
+ b->ItemList = NewListFast(NULL);
+
+ return b;
+}
+
+// Add items to the list view
+void LvInsert(HWND hWnd, UINT id, UINT icon, void *param, UINT num_str, ...)
+{
+ UINT i;
+ va_list va;
+ UINT index = 0;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ va_start(va, num_str);
+
+ for (i = 0;i < num_str;i++)
+ {
+ wchar_t *s = va_arg(va, wchar_t *);
+ if (i == 0)
+ {
+ index = LvInsertItem(hWnd, id, icon, param, s);
+ }
+ else
+ {
+ LvSetItem(hWnd, id, index, i, s);
+ }
+ }
+
+ va_end(va);
+}
+
+// Adjust the item size automatically
+void LvAutoSize(HWND hWnd, UINT id)
+{
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ i = 0;
+ while (true)
+ {
+ if (ListView_SetColumnWidth(DlgItem(hWnd, id), i, LVSCW_AUTOSIZE) == false)
+ {
+ break;
+ }
+ i++;
+ }
+}
+
+// Add an item
+UINT LvInsertItem(HWND hWnd, UINT id, UINT icon, void *param, wchar_t *str)
+{
+ return LvInsertItemByImageListId(hWnd, id, GetIcon(icon), param, str);
+}
+UINT LvInsertItemByImageListId(HWND hWnd, UINT id, UINT image, void *param, wchar_t *str)
+{
+ LVITEMW t;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return INFINITE;
+ }
+ if (MsIsNt() == false)
+ {
+ char *s = CopyUniToStr(str);
+ UINT ret;
+ ret = LvInsertItemByImageListIdA(hWnd, id, image, param, s);
+ Free(s);
+ return ret;
+ }
+
+ Zero(&t, sizeof(t));
+ t.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_TEXT;
+ t.pszText = str;
+ t.iImage = image;
+ t.lParam = (LPARAM)param;
+ t.iItem = LvNum(hWnd, id);
+
+ return SendMsg(hWnd, id, LVM_INSERTITEMW, 0, (LPARAM)&t);
+}
+UINT LvInsertItemByImageListIdA(HWND hWnd, UINT id, UINT image, void *param, char *str)
+{
+ LVITEM t;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return INFINITE;
+ }
+
+ Zero(&t, sizeof(t));
+ t.mask = LVIF_IMAGE | LVIF_PARAM | LVIF_TEXT;
+ t.pszText = str;
+ t.iImage = image;
+ t.lParam = (LPARAM)param;
+ t.iItem = LvNum(hWnd, id);
+
+ return SendMsg(hWnd, id, LVM_INSERTITEM, 0, (LPARAM)&t);
+}
+
+// Change the image
+void LvSetItemImage(HWND hWnd, UINT id, UINT index, UINT icon)
+{
+ LvSetItemImageByImageListId(hWnd, id, index, GetIcon(icon));
+}
+void LvSetItemImageByImageListId(HWND hWnd, UINT id, UINT index, UINT image)
+{
+ LVITEM t;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ t.mask = LVIF_IMAGE;
+ t.iImage = image;
+ t.iItem = index;
+
+ SendMsg(hWnd, id, LVM_SETITEM, 0, (LPARAM)&t);
+}
+
+// Set the parameters of the item
+void LvSetItemParam(HWND hWnd, UINT id, UINT index, void *param)
+{
+ LvSetItemParamEx(hWnd, id, index, 0, param);
+}
+void LvSetItemParamEx(HWND hWnd, UINT id, UINT index, UINT subitem, void *param)
+{
+ LVITEM t;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ t.mask = LVIF_PARAM;
+ t.iItem = index;
+ t.iSubItem = subitem;
+ t.lParam = (LPARAM)param;
+
+ SendMsg(hWnd, id, LVM_SETITEM, 0, (LPARAM)&t);
+}
+
+// Set the item
+void LvSetItem(HWND hWnd, UINT id, UINT index, UINT pos, wchar_t *str)
+{
+ LVITEMW t;
+ wchar_t *old_str;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return;
+ }
+ if (MsIsNt() == false)
+ {
+ char *s = CopyUniToStr(str);
+ LvSetItemA(hWnd, id, index, pos, s);
+ Free(s);
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ t.mask = LVIF_TEXT;
+ t.pszText = str;
+ t.iItem = index;
+ t.iSubItem = pos;
+
+ old_str = LvGetStr(hWnd, id, index, pos);
+
+ if (UniStrCmp(old_str, str) != 0)
+ {
+ SendMsg(hWnd, id, LVM_SETITEMW, 0, (LPARAM)&t);
+ }
+
+ Free(old_str);
+}
+void LvSetItemA(HWND hWnd, UINT id, UINT index, UINT pos, char *str)
+{
+ LVITEM t;
+ wchar_t *old_str;
+ char *old_str_2;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return;
+ }
+
+ Zero(&t, sizeof(t));
+ t.mask = LVIF_TEXT;
+ t.pszText = str;
+ t.iItem = index;
+ t.iSubItem = pos;
+
+ old_str = LvGetStr(hWnd, id, index, pos);
+ old_str_2 = CopyUniToStr(old_str);
+
+ if (StrCmp(old_str_2, str) != 0)
+ {
+ SendMsg(hWnd, id, LVM_SETITEM, 0, (LPARAM)&t);
+ }
+
+ Free(old_str_2);
+ Free(old_str);
+}
+
+// Set the view of the list box
+void LvSetView(HWND hWnd, UINT id, bool details)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (details)
+ {
+ RemoveStyle(hWnd, id, LVS_ICON);
+ SetStyle(hWnd, id, LVS_REPORT);
+ }
+ else
+ {
+ RemoveStyle(hWnd, id, LVS_REPORT);
+ SetStyle(hWnd, id, LVS_ICON);
+ }
+}
+
+// Ensure that the specified item is visible
+void LvShow(HWND hWnd, UINT id, UINT index)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ ListView_EnsureVisible(DlgItem(hWnd, id), index, false);
+}
+
+// Get whether there is currently selected item
+bool LvIsSelected(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return false;
+ }
+
+ if (LvGetSelected(hWnd, id) == INFINITE)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Get the currently selected item
+UINT LvGetFocused(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return INFINITE;
+ }
+
+ return ListView_GetNextItem(DlgItem(hWnd, id), -1, LVNI_FOCUSED);
+}
+
+// Get the parameter of the currently selected item
+void *LvGetSelectedParam(HWND hWnd, UINT id)
+{
+ UINT index;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return NULL;
+ }
+
+ index = LvGetSelected(hWnd, id);
+
+ if (index == INFINITE)
+ {
+ return NULL;
+ }
+
+ return LvGetParam(hWnd, id, index);
+}
+
+// Get a string that is currently selected
+wchar_t *LvGetFocusedStr(HWND hWnd, UINT id, UINT pos)
+{
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return NULL;
+ }
+
+ i = LvGetFocused(hWnd, id);
+ if (i == INFINITE)
+ {
+ return NULL;
+ }
+
+ return LvGetStr(hWnd, id, i, pos);
+}
+
+// Get the currently selected item
+UINT LvGetSelected(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return INFINITE;
+ }
+
+ return ListView_GetNextItem(DlgItem(hWnd, id), -1, LVNI_FOCUSED | LVNI_SELECTED);
+}
+
+// Get a string that is currently selected
+wchar_t *LvGetSelectedStr(HWND hWnd, UINT id, UINT pos)
+{
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return NULL;
+ }
+
+ i = LvGetSelected(hWnd, id);
+ if (i == INFINITE)
+ {
+ return NULL;
+ }
+
+ return LvGetStr(hWnd, id, i, pos);
+}
+char *LvGetSelectedStrA(HWND hWnd, UINT id, UINT pos)
+{
+ char *ret;
+ wchar_t *tmp = LvGetSelectedStr(hWnd, id, pos);
+ if (tmp == NULL)
+ {
+ return NULL;
+ }
+ ret = CopyUniToStr(tmp);
+ Free(tmp);
+ return ret;
+}
+
+// Get whether two or more items are masked
+bool LvIsMultiMasked(HWND hWnd, UINT id)
+{
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return false;
+ }
+
+ i = INFINITE;
+ i = LvGetNextMasked(hWnd, id, i);
+ if (i != INFINITE)
+ {
+ if (LvGetNextMasked(hWnd, id, i) != INFINITE)
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Examine whether just only one item is selected
+bool LvIsSingleSelected(HWND hWnd, UINT id)
+{
+ return LvIsSelected(hWnd, id) && (LvIsMultiMasked(hWnd, id) == false);
+}
+
+// Get whether there are items that are currently masked
+bool LvIsMasked(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return false;
+ }
+
+ if (LvGetNextMasked(hWnd, id, INFINITE) == INFINITE)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Get the number of items that are currently masked
+UINT LvGetMaskedNum(HWND hWnd, UINT id)
+{
+ UINT i = INFINITE;
+ UINT num = 0;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ while (true)
+ {
+ i = LvGetNextMasked(hWnd, id, i);
+ if (i == INFINITE)
+ {
+ break;
+ }
+
+ num++;
+ }
+
+ return num;
+}
+
+// Get the items that is currently masked
+UINT LvGetNextMasked(HWND hWnd, UINT id, UINT start)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return INFINITE;
+ }
+
+ return ListView_GetNextItem(DlgItem(hWnd, id), start, LVNI_SELECTED);
+}
+
+// Search an item with the specified string
+UINT LvSearchStr_(HWND hWnd, UINT id, UINT pos, wchar_t *str)
+{
+ UINT ret;
+ LVFINDINFOW t;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return INFINITE;
+ }
+
+ Zero(&t, sizeof(t));
+ t.flags = LVFI_STRING;
+ t.psz = str;
+ t.vkDirection = VK_DOWN;
+
+ ret = SendMsg(hWnd, id, LVM_FINDITEMW, -1, (LPARAM)&t);
+
+ return ret;
+}
+
+// Search an item with the specified string
+UINT LvSearchStr(HWND hWnd, UINT id, UINT pos, wchar_t *str)
+{
+ UINT i, num;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return INFINITE;
+ }
+
+ num = LvNum(hWnd, id);
+
+ for (i = 0;i < num;i++)
+ {
+ wchar_t *s = LvGetStr(hWnd, id, i, pos);
+ if (s != NULL)
+ {
+ if (UniStrCmpi(s, str) == 0)
+ {
+ Free(s);
+ return i;
+ }
+ else
+ {
+ Free(s);
+ }
+ }
+ }
+
+ return INFINITE;
+}
+UINT LvSearchStrA(HWND hWnd, UINT id, UINT pos, char *str)
+{
+ wchar_t *tmp = CopyStrToUni(str);
+ UINT ret = LvSearchStr(hWnd, id, pos, tmp);
+ Free(tmp);
+ return ret;
+}
+
+// Search for item that have a specified param
+UINT LvSearchParam(HWND hWnd, UINT id, void *param)
+{
+ UINT i, num;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return INFINITE;
+ }
+
+ num = LvNum(hWnd, id);
+
+ for (i = 0;i < num;i++)
+ {
+ if (LvGetParam(hWnd, id, i) == param)
+ {
+ return i;
+ }
+ }
+
+ return INFINITE;
+}
+
+// Get the number of items
+UINT LvNum(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ return ListView_GetItemCount(DlgItem(hWnd, id));
+}
+
+// Remove an item
+void LvDeleteItem(HWND hWnd, UINT id, UINT index)
+{
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ ListView_DeleteItem(DlgItem(hWnd, id), index);
+
+ i = LvGetSelected(hWnd, id);
+ if (i != INFINITE)
+ {
+ LvSelect(hWnd, id, i);
+ }
+}
+
+// Get the data from the item
+void *LvGetParam(HWND hWnd, UINT id, UINT index)
+{
+ return LvGetParamEx(hWnd, id, index, 0);
+}
+void *LvGetParamEx(HWND hWnd, UINT id, UINT index, UINT subitem)
+{
+ LVITEM t;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return NULL;
+ }
+ if (index == INFINITE)
+ {
+ return NULL;
+ }
+
+ Zero(&t, sizeof(t));
+ t.mask = LVIF_PARAM;
+ t.iItem = index;
+ t.iSubItem = subitem;
+
+ if (ListView_GetItem(DlgItem(hWnd, id), &t) == false)
+ {
+ return NULL;
+ }
+
+ return (void *)t.lParam;
+}
+
+// Get the string of item
+wchar_t *LvGetStr(HWND hWnd, UINT id, UINT index, UINT pos)
+{
+ wchar_t *tmp;
+ UINT size;
+ LVITEMW t;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return NULL;
+ }
+ if (MsIsNt() == false)
+ {
+ char *s = LvGetStrA(hWnd, id, index, pos);
+ if (s == NULL)
+ {
+ return NULL;
+ }
+ else
+ {
+ wchar_t *ret = CopyStrToUni(s);
+ Free(s);
+
+ return ret;
+ }
+ }
+
+ size = 65536;
+ tmp = Malloc(size);
+
+ Zero(&t, sizeof(t));
+ t.mask = LVIF_TEXT;
+ t.iItem = index;
+ t.iSubItem = pos;
+ t.pszText = tmp;
+ t.cchTextMax = size;
+
+ if (SendMsg(hWnd, id, LVM_GETITEMTEXTW, index, (LPARAM)&t) <= 0)
+ {
+ Free(tmp);
+ return UniCopyStr(L"");
+ }
+ else
+ {
+ wchar_t *ret = UniCopyStr(tmp);
+ Free(tmp);
+ return ret;
+ }
+}
+char *LvGetStrA(HWND hWnd, UINT id, UINT index, UINT pos)
+{
+ char *tmp;
+ UINT size;
+ LVITEM t;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return NULL;
+ }
+
+ size = 65536;
+ tmp = Malloc(size);
+
+ Zero(&t, sizeof(t));
+ t.mask = LVIF_TEXT;
+ t.iItem = index;
+ t.iSubItem = pos;
+ t.pszText = tmp;
+ t.cchTextMax = size;
+
+ if (SendMsg(hWnd, id, LVM_GETITEMTEXT, index, (LPARAM)&t) <= 0)
+ {
+ Free(tmp);
+ return CopyStr("");
+ }
+ else
+ {
+ char *ret = CopyStr(tmp);
+ Free(tmp);
+ return ret;
+ }
+}
+
+// Set the style
+void LvSetStyle(HWND hWnd, UINT id, UINT style)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if ((ListView_GetExtendedListViewStyle(DlgItem(hWnd, id)) & style) == 0)
+ {
+ ListView_SetExtendedListViewStyleEx(DlgItem(hWnd, id), style, style);
+ }
+}
+
+// Remove the style
+void LvRemoveStyle(HWND hWnd, UINT id, UINT style)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if ((ListView_GetExtendedListViewStyle(DlgItem(hWnd, id)) & style) != 0)
+ {
+ ListView_SetExtendedListViewStyleEx(DlgItem(hWnd, id), style, 0);
+ }
+}
+
+// Invert the selection of items
+void LvSwitchSelect(HWND hWnd, UINT id)
+{
+ UINT i, num;
+ bool *states;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ num = LvNum(hWnd, id);
+ states = ZeroMalloc(sizeof(bool) * num);
+
+ i = INFINITE;
+ while (true)
+ {
+ i = LvGetNextMasked(hWnd, id, i);
+ if (i == INFINITE)
+ {
+ break;
+ }
+
+ states[i] = true;
+ }
+
+ for (i = 0;i < num;i++)
+ {
+ if (states[i] == false)
+ {
+ ListView_SetItemState(DlgItem(hWnd, id), i, LVIS_SELECTED, LVIS_SELECTED);
+ }
+ else
+ {
+ ListView_SetItemState(DlgItem(hWnd, id), i, 0, LVIS_SELECTED);
+ }
+ }
+
+ Free(states);
+}
+
+// Select all items
+void LvSelectAll(HWND hWnd, UINT id)
+{
+ UINT i, num;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ num = LvNum(hWnd, id);
+ for (i = 0;i < num;i++)
+ {
+ ListView_SetItemState(DlgItem(hWnd, id), i, LVIS_SELECTED, LVIS_SELECTED);
+ }
+}
+
+// Select the item by specifying the parameter
+void LvSelectByParam(HWND hWnd, UINT id, void *param)
+{
+ UINT index;
+ // Validate arguments
+ if (hWnd == NULL || param == NULL)
+ {
+ return;
+ }
+
+ index = LvSearchParam(hWnd, id, param);
+ if (index == INFINITE)
+ {
+ return;
+ }
+
+ LvSelect(hWnd, id, index);
+}
+
+// Select an item
+void LvSelect(HWND hWnd, UINT id, UINT index)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (index == INFINITE)
+ {
+ UINT i, num;
+ // Deselect all
+ num = LvNum(hWnd, id);
+ for (i = 0;i < num;i++)
+ {
+ ListView_SetItemState(DlgItem(hWnd, id), i, 0, LVIS_SELECTED);
+ }
+ }
+ else
+ {
+ // Select
+ ListView_SetItemState(DlgItem(hWnd, id), index, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED);
+ ListView_EnsureVisible(DlgItem(hWnd, id), index, true);
+ }
+}
+
+// Show the certificate information
+void PrintCertInfo(HWND hWnd, CERT_DLG *p)
+{
+ X *x;
+ char *serial_tmp;
+ UINT serial_size;
+ wchar_t *wchar_tmp;
+ wchar_t tmp[1024 * 5];
+ UCHAR md5[MD5_SIZE];
+ UCHAR sha1[SHA1_SIZE];
+ char *s_tmp;
+ K *k;
+ // Validate arguments
+ if (p == NULL || hWnd == NULL)
+ {
+ return;
+ }
+
+ x = p->x;
+
+ // Serial number
+ if (x->serial != NULL)
+ {
+ serial_size = x->serial->size * 3 + 1;
+ serial_tmp = ZeroMalloc(serial_size);
+ BinToStrEx(serial_tmp, serial_size, x->serial->data, x->serial->size);
+ wchar_tmp = CopyStrToUni(serial_tmp);
+ Free(serial_tmp);
+ }
+ else
+ {
+ wchar_tmp = CopyUniStr(_UU("CERT_NO_SERIAL"));
+ }
+ LvInsert(hWnd, L_CERTINFO, ICO_CERT, NULL, 2, _UU("CERT_SERIAL"), wchar_tmp);
+
+ // Issuer
+ GetAllNameFromName(tmp, sizeof(tmp), x->issuer_name);
+ LvInsert(hWnd, L_CERTINFO, ICO_CERT, NULL, 2, _UU("CERT_ISSUER"), tmp);
+
+ // Subject
+ GetAllNameFromName(tmp, sizeof(tmp), x->subject_name);
+ LvInsert(hWnd, L_CERTINFO, ICO_CERT, NULL, 2, _UU("CERT_SUBJECT"), tmp);
+
+ // Not available before
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(x->notBefore), NULL);
+ LvInsert(hWnd, L_CERTINFO, ICO_CERT, NULL, 2, _UU("CERT_NOT_BEFORE"), tmp);
+
+ // Not available after
+ GetDateTimeStrEx64(tmp, sizeof(tmp), SystemToLocal64(x->notAfter), NULL);
+ LvInsert(hWnd, L_CERTINFO, ICO_CERT, NULL, 2, _UU("CERT_NOT_AFTER"), tmp);
+
+ // Number of bits
+ if (x->is_compatible_bit)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("CERT_BITS_FORMAT"), x->bits);
+ LvInsert(hWnd, L_CERTINFO, ICO_CERT, NULL, 2, _UU("CERT_BITS"), tmp);
+ }
+
+ // Public key
+ k = GetKFromX(x);
+ if (k != NULL)
+ {
+ BUF *b = KToBuf(k, false, NULL);
+ s_tmp = CopyBinToStrEx(b->Buf, b->Size);
+ StrToUni(tmp, sizeof(tmp), s_tmp);
+ Free(s_tmp);
+ LvInsert(hWnd, L_CERTINFO, ICO_KEY, NULL, 2, _UU("CERT_PUBLIC_KEY"), tmp);
+ FreeBuf(b);
+ }
+ FreeK(k);
+
+ GetXDigest(x, md5, false);
+ GetXDigest(x, sha1, true);
+
+ // Digest (MD5)
+ s_tmp = CopyBinToStrEx(md5, sizeof(md5));
+ StrToUni(tmp, sizeof(tmp), s_tmp);
+ Free(s_tmp);
+ LvInsert(hWnd, L_CERTINFO, ICO_KEY, NULL, 2, _UU("CERT_DIGEST_MD5"), tmp);
+
+ // Digest (SHA-1)
+ s_tmp = CopyBinToStrEx(sha1, sizeof(sha1));
+ StrToUni(tmp, sizeof(tmp), s_tmp);
+ Free(s_tmp);
+ LvInsert(hWnd, L_CERTINFO, ICO_KEY, NULL, 2, _UU("CERT_DIGEST_SHA1"), tmp);
+
+ Free(wchar_tmp);
+
+ LvSelect(hWnd, L_CERTINFO, 0);
+}
+
+// Update the display
+void CertDlgUpdate(HWND hWnd, CERT_DLG *p)
+{
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ if (LvIsSelected(hWnd, L_CERTINFO) == false)
+ {
+ SetText(hWnd, E_DETAIL, L"");
+ }
+ else
+ {
+ UINT i = LvGetSelected(hWnd, L_CERTINFO);
+ wchar_t *tmp = LvGetStr(hWnd, L_CERTINFO, i, 1);
+ SetText(hWnd, E_DETAIL, tmp);
+ Free(tmp);
+ }
+}
+
+// Save the certificate
+void CertDlgSave(HWND hWnd, CERT_DLG *p)
+{
+ wchar_t *name;
+ X *x;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ // Save to a file
+ name = SaveDlg(hWnd, _UU("DLG_CERT_FILES"), _UU("DLG_SAVE_CERT"), NULL, L".cer");
+ x = p->x;
+ if (name != NULL)
+ {
+ wchar_t str[MAX_SIZE];
+ UniStrCpy(str, sizeof(str), name);
+ if (XToFileW(x, str, true))
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("DLG_CERT_SAVE_OK"));
+ }
+ else
+ {
+ MsgBox(hWnd, MB_ICONSTOP, _UU("DLG_CERT_SAVE_ERROR"));
+ }
+ Free(name);
+ }
+}
+
+// Certificate display dialog procedure
+UINT CertDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ CERT_DLG *p = (CERT_DLG *)param;
+ X *x;
+ wchar_t tmp[MAX_SIZE];
+ NMHDR *n;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetIcon(hWnd, 0, ICO_CERT);
+ x = p->x;
+ GetAllNameFromNameEx(tmp, sizeof(tmp), x->subject_name);
+ SetText(hWnd, E_SUBJECT, tmp);
+ GetAllNameFromNameEx(tmp, sizeof(tmp), x->issuer_name);
+ SetText(hWnd, E_ISSUER, tmp);
+ GetDateStrEx64(tmp, sizeof(tmp), SystemToLocal64(x->notAfter), NULL);
+ SetText(hWnd, E_EXPIRES, tmp);
+ SetFont(hWnd, E_SUBJECT, Font(0, 1));
+ SetFont(hWnd, E_ISSUER, Font(0, 1));
+ SetFont(hWnd, E_EXPIRES, Font(0, 1));
+ SetIcon(hWnd, B_PARENT, ICO_CERT);
+ if (x->root_cert)
+ {
+ // Root certificate
+ Hide(hWnd, S_WARNING_ICON);
+ SetText(hWnd, S_PARENT, _UU("CERT_ROOT"));
+ Hide(hWnd, B_PARENT);
+ Hide(hWnd, S_PARENT_BUTTON_STR);
+ }
+ else if (p->issuer_x != NULL)
+ {
+ // Parent certificate exists
+ Hide(hWnd, S_WARNING_ICON);
+ }
+ else
+ {
+ // There is no parent certificate
+ Hide(hWnd, S_CERT_ICON);
+ Hide(hWnd, B_PARENT);
+ Hide(hWnd, S_PARENT_BUTTON_STR);
+ SetText(hWnd, S_PARENT, _UU("CERT_NOT_FOUND"));
+ if (p->ManagerMode)
+ {
+ Hide(hWnd, IDC_STATIC1);
+ Hide(hWnd, S_PARENT);
+ Hide(hWnd, S_WARNING_ICON);
+ Hide(hWnd, S_CERT_ICON);
+ Hide(hWnd, B_PARENT);
+ Hide(hWnd, S_PARENT_BUTTON_STR);
+ }
+ }
+
+
+ LvInit(hWnd, L_CERTINFO);
+ LvInsertColumn(hWnd, L_CERTINFO, 0, _UU("CERT_LV_C1"), 130);
+ LvInsertColumn(hWnd, L_CERTINFO, 1, _UU("CERT_LV_C2"), 250);
+
+ PrintCertInfo(hWnd, p);
+ Focus(hWnd, L_CERTINFO);
+
+ CertDlgUpdate(hWnd, p);
+
+ if (p->ManagerMode)
+ {
+ Show(hWnd, B_SAVE);
+ }
+ else
+ {
+ // Hide for security
+ Hide(hWnd, B_SAVE);
+ }
+
+ break;
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ case B_PARENT:
+ CertDlg(hWnd, p->issuer_x, NULL, p->ManagerMode);
+ break;
+ case B_SAVE:
+ // Save to the file
+ CertDlgSave(hWnd, p);
+ break;
+ }
+ break;
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ case WM_NOTIFY:
+ n = (NMHDR *)lParam;
+ switch (n->idFrom)
+ {
+ case L_CERTINFO:
+ switch (n->code)
+ {
+ case LVN_ITEMCHANGED:
+ CertDlgUpdate(hWnd, p);
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ LvSortHander(hWnd, msg, wParam, lParam, L_CERTINFO);
+
+ return 0;
+}
+
+// Certificate display dialog
+void CertDlg(HWND hWnd, X *x, X *issuer_x, bool manager)
+{
+ CERT_DLG p;
+ // Validate arguments
+ if (x == NULL)
+ {
+ return;
+ }
+
+ Zero(&p, sizeof(p));
+ p.x = x;
+ if (CompareX(x, issuer_x) == false)
+ {
+ p.issuer_x = issuer_x;
+ }
+ p.ManagerMode = manager;
+ Dialog(hWnd, D_CERT, CertDlgProc, &p);
+}
+
+// Status window dialog
+UINT StatusPrinterWindowDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ STATUS_WINDOW_PARAM *p = (STATUS_WINDOW_PARAM *)param;
+ PACK *pack;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ // Initialize
+ SetIcon(hWnd, 0, ICO_SERVER_ONLINE);
+ RemoveExStyle(hWnd, 0, WS_EX_APPWINDOW);
+ p->hWnd = hWnd;
+ NoticeThreadInit(p->Thread);
+ FormatText(hWnd, 0, p->AccountName);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ case IDCANCEL:
+ // Cancel button
+ Close(hWnd);
+ break;
+ }
+
+ break;
+
+ case WM_APP + 1:
+ // Set a string
+ SetText(hWnd, S_STATUS, (wchar_t *)lParam);
+ break;
+
+ case WM_APP + 2:
+ // Close this window
+ EndDialog(hWnd, false);
+ break;
+
+ case WM_CLOSE:
+ // End the session
+ pack = NewPack();
+ SendPack(p->Sock, pack);
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// Status window control thread
+void StatusPrinterWindowThread(THREAD *thread, void *param)
+{
+ STATUS_WINDOW_PARAM *p = (STATUS_WINDOW_PARAM *)param;
+ // Validate arguments
+ if (thread == NULL || param == NULL)
+ {
+ return;
+ }
+
+ p->Thread = thread;
+ DialogEx2(NULL, D_STATUS, StatusPrinterWindowDlg, p, true, true);
+
+ Free(p);
+}
+
+// Show a message in the status window
+void StatusPrinterWindowPrint(STATUS_WINDOW *sw, wchar_t *str)
+{
+ // Validate arguments
+ if (sw == NULL)
+ {
+ return;
+ }
+
+ SendMessage(sw->hWnd, WM_APP + 1, 0, (LPARAM)str);
+}
+
+// End and release the status window
+void StatusPrinterWindowStop(STATUS_WINDOW *sw)
+{
+ // Validate arguments
+ if (sw == NULL)
+ {
+ return;
+ }
+
+ // Send stop message
+ SendMessage(sw->hWnd, WM_APP + 2, 0, 0);
+
+ // Wait until the thread terminates
+ WaitThread(sw->Thread, INFINITE);
+
+ // Release the memory
+ ReleaseThread(sw->Thread);
+ Free(sw);
+}
+
+// Initialize the status window
+STATUS_WINDOW *StatusPrinterWindowStart(SOCK *s, wchar_t *account_name)
+{
+ STATUS_WINDOW_PARAM *p;
+ STATUS_WINDOW *sw;
+ THREAD *t;
+ // Validate arguments
+ if (s == NULL || account_name == NULL)
+ {
+ return NULL;
+ }
+
+ p = ZeroMalloc(sizeof(STATUS_WINDOW_PARAM));
+ p->Sock = s;
+ UniStrCpy(p->AccountName, sizeof(p->AccountName), account_name);
+
+ // Create a thread
+ t = NewThread(StatusPrinterWindowThread, p);
+ WaitThreadInit(t);
+
+ sw = ZeroMalloc(sizeof(STATUS_WINDOW));
+ sw->hWnd = p->hWnd;
+ sw->Thread = t;
+
+ return sw;
+}
+
+// Get the string
+wchar_t *LbGetStr(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return NULL;
+ }
+
+ return GetText(hWnd, id);
+}
+
+// String search
+UINT LbFindStr(HWND hWnd, UINT id, wchar_t *str)
+{
+ UINT ret;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return INFINITE;
+ }
+
+ ret = SendMsg(hWnd, id, LB_FINDSTRING, -1, (LPARAM)str);
+
+ return ret;
+}
+
+// Get the number of items
+UINT LbNum(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return INFINITE;
+ }
+
+ return SendMsg(hWnd, id, LB_GETCOUNT, 0, 0);
+}
+
+// Add a string
+UINT LbAddStr(HWND hWnd, UINT id, wchar_t *str, UINT data)
+{
+ UINT ret;
+
+ if (MsIsNt() == false)
+ {
+ char *s = CopyUniToStr(str);
+ ret = LbAddStrA(hWnd, id, s, data);
+ Free(s);
+ return ret;
+ }
+
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return INFINITE;
+ }
+
+ ret = SendMsg(hWnd, id, LB_ADDSTRING, 0, (LPARAM)str);
+ SendMsg(hWnd, id, LB_SETITEMDATA, ret, (LPARAM)data);
+
+ if (LbNum(hWnd, id) == 1)
+ {
+ LbSelectIndex(hWnd, id, 0);
+ }
+
+ return ret;
+}
+UINT LbAddStrA(HWND hWnd, UINT id, char *str, UINT data)
+{
+ UINT ret;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return INFINITE;
+ }
+
+ ret = SendMsg(hWnd, id, LB_ADDSTRING, 0, (LPARAM)str);
+ SendMsg(hWnd, id, LB_SETITEMDATA, ret, (LPARAM)data);
+
+ if (LbNum(hWnd, id) == 1)
+ {
+ LbSelectIndex(hWnd, id, 0);
+ }
+
+ return ret;
+}
+
+// Insert a string
+UINT LbInsertStr(HWND hWnd, UINT id, UINT index, wchar_t *str, UINT data)
+{
+ UINT ret;
+
+ if (MsIsNt() == false)
+ {
+ char *s = CopyUniToStr(str);
+ ret = LbInsertStrA(hWnd, id, index, s, data);
+ Free(s);
+ return ret;
+ }
+
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return INFINITE;
+ }
+
+ ret = SendMsg(hWnd, id, LB_INSERTSTRING, index, (LPARAM)str);
+ SendMsg(hWnd, id, LB_SETITEMDATA, ret, (LPARAM)data);
+
+ if (LbNum(hWnd, id) == 1)
+ {
+ LbSelect(hWnd, id, 0);
+ }
+
+ return ret;
+}
+UINT LbInsertStrA(HWND hWnd, UINT id, UINT index, char *str, UINT data)
+{
+ UINT ret;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return INFINITE;
+ }
+
+ ret = SendMsg(hWnd, id, LB_INSERTSTRING, index, (LPARAM)str);
+ SendMsg(hWnd, id, LB_SETITEMDATA, ret, (LPARAM)data);
+
+ if (LbNum(hWnd, id) == 1)
+ {
+ LbSelect(hWnd, id, 0);
+ }
+
+ return ret;
+}
+
+// Remove all
+void LbReset(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SendMsg(hWnd, id, LB_RESETCONTENT, 0, 0);
+}
+
+// Select by specifying the index
+void LbSelectIndex(HWND hWnd, UINT id, UINT index)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SendMsg(hWnd, id, LB_SETCURSEL, index, 0);
+}
+
+// Get the data
+UINT LbGetData(HWND hWnd, UINT id, UINT index)
+{
+ // Validate arguments
+ if (hWnd == NULL || index == INFINITE)
+ {
+ return INFINITE;
+ }
+
+ return SendMsg(hWnd, id, LB_GETITEMDATA, index, 0);
+}
+
+// Search for the data
+UINT LbFindData(HWND hWnd, UINT id, UINT data)
+{
+ UINT i, num;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return INFINITE;
+ }
+
+ num = LbNum(hWnd, id);
+ if (num == INFINITE)
+ {
+ return INFINITE;
+ }
+
+ for (i = 0;i < num;i++)
+ {
+ if (LbGetData(hWnd, id, i) == data)
+ {
+ return i;
+ }
+ }
+
+ return INFINITE;
+}
+
+// Set the height of the item
+void LbSetHeight(HWND hWnd, UINT id, UINT value)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SendMsg(hWnd, id, LB_SETITEMHEIGHT, 0, (UINT)(GetTextScalingFactor() * (double)value));
+}
+
+// Search by specifying the data
+void LbSelect(HWND hWnd, UINT id, int data)
+{
+ UINT index;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (data == INFINITE)
+ {
+ // Get the first item
+ LbSelectIndex(hWnd, id, 0);
+ return;
+ }
+
+ index = LbFindData(hWnd, id, data);
+ if (index == INFINITE)
+ {
+ // Can not be found
+ return;
+ }
+
+ // Select
+ LbSelectIndex(hWnd, id, index);
+}
+
+// Get the currently selected item
+UINT LbGetSelectIndex(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return INFINITE;
+ }
+
+ return SendMsg(hWnd, id, LB_GETCURSEL, 0, 0);
+}
+
+// Get the value that is currently selected
+UINT LbGetSelect(HWND hWnd, UINT id)
+{
+ UINT index;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return INFINITE;
+ }
+
+ index = LbGetSelectIndex(hWnd, id);
+ if (index == INFINITE)
+ {
+ return INFINITE;
+ }
+
+ return LbGetData(hWnd, id, index);
+}
+
+// Password input dialog state change
+void PasswordDlgProcChange(HWND hWnd, UI_PASSWORD_DLG *p)
+{
+ bool b;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ b = true;
+ if (IsEmpty(hWnd, E_USERNAME))
+ {
+ b = false;
+ }
+
+ SetEnable(hWnd, IDOK, b);
+
+ p->StartTick = Tick64();
+ if (p->RetryIntervalSec)
+ {
+ KillTimer(hWnd, 1);
+ Hide(hWnd, P_PROGRESS);
+ Hide(hWnd, S_COUNTDOWN);
+ }
+}
+
+// Get the string
+wchar_t *CbGetStr(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return NULL;
+ }
+
+ return GetText(hWnd, id);
+}
+
+// String search
+UINT CbFindStr(HWND hWnd, UINT id, wchar_t *str)
+{
+ UINT ret;
+ if (MsIsNt() == false)
+ {
+ char *tmp = CopyUniToStr(str);
+ ret = CbFindStr9xA(hWnd, id, tmp);
+ Free(tmp);
+ return ret;
+ }
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return INFINITE;
+ }
+
+ ret = SendMsg(hWnd, id, CB_FINDSTRINGEXACT, -1, (LPARAM)str);
+
+ return ret;
+}
+UINT CbFindStr9xA(HWND hWnd, UINT id, char *str)
+{
+ UINT ret;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return INFINITE;
+ }
+
+ ret = SendMsg(hWnd, id, CB_FINDSTRINGEXACT, -1, (LPARAM)str);
+
+ return ret;
+}
+
+// Get the number of items
+UINT CbNum(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return INFINITE;
+ }
+
+ return SendMsg(hWnd, id, CB_GETCOUNT, 0, 0);
+}
+
+// Add a string
+UINT CbAddStrA(HWND hWnd, UINT id, char *str, UINT data)
+{
+ wchar_t *tmp;
+ UINT ret;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return INFINITE;
+ }
+ tmp = CopyStrToUni(str);
+ ret = CbAddStr(hWnd, id, tmp, data);
+ Free(tmp);
+ return ret;
+}
+UINT CbAddStr(HWND hWnd, UINT id, wchar_t *str, UINT data)
+{
+ UINT ret;
+ if (MsIsNt() == false)
+ {
+ char *s = CopyUniToStr(str);
+ ret = CbAddStr9xA(hWnd, id, s, data);
+ Free(s);
+ return ret;
+ }
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return INFINITE;
+ }
+
+ ret = SendMsg(hWnd, id, CB_ADDSTRING, 0, (LPARAM)str);
+ SendMsg(hWnd, id, CB_SETITEMDATA, ret, (LPARAM)data);
+
+ if (CbNum(hWnd, id) == 1)
+ {
+ wchar_t tmp[MAX_SIZE];
+ GetTxt(hWnd, id, tmp, sizeof(tmp));
+ if (UniStrLen(tmp) == 0)
+ {
+ CbSelectIndex(hWnd, id, 0);
+ }
+ }
+
+ return ret;
+}
+UINT CbAddStr9xA(HWND hWnd, UINT id, char *str, UINT data)
+{
+ UINT ret;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return INFINITE;
+ }
+
+ ret = SendMsg(hWnd, id, CB_ADDSTRING, 0, (LPARAM)str);
+ SendMsg(hWnd, id, CB_SETITEMDATA, ret, (LPARAM)data);
+
+ if (CbNum(hWnd, id) == 1)
+ {
+ wchar_t tmp[MAX_SIZE];
+ GetTxt(hWnd, id, tmp, sizeof(tmp));
+ if (UniStrLen(tmp) == 0)
+ {
+ CbSelectIndex(hWnd, id, 0);
+ }
+ }
+
+ return ret;
+}
+
+// Insert a string
+UINT CbInsertStrA(HWND hWnd, UINT id, UINT index, char *str, UINT data)
+{
+ wchar_t *tmp;
+ UINT ret;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return INFINITE;
+ }
+ tmp = CopyStrToUni(str);
+ ret = CbInsertStr(hWnd, id, index, tmp, data);
+ Free(tmp);
+ return ret;
+}
+UINT CbInsertStr(HWND hWnd, UINT id, UINT index, wchar_t *str, UINT data)
+{
+ UINT ret;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return INFINITE;
+ }
+
+ if (MsIsNt() == false)
+ {
+ char *s = CopyUniToStr(str);
+ ret = CbInsertStr9xA(hWnd, id, index, s, data);
+ Free(s);
+ return ret;
+ }
+
+ ret = SendMsg(hWnd, id, CB_INSERTSTRING, index, (LPARAM)str);
+ SendMsg(hWnd, id, CB_SETITEMDATA, ret, (LPARAM)data);
+
+ if (CbNum(hWnd, id) == 1)
+ {
+ CbSelect(hWnd, id, 0);
+ }
+
+ return ret;
+}
+UINT CbInsertStr9xA(HWND hWnd, UINT id, UINT index, char *str, UINT data)
+{
+ UINT ret;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return INFINITE;
+ }
+
+ ret = SendMsg(hWnd, id, CB_INSERTSTRING, index, (LPARAM)str);
+ SendMsg(hWnd, id, CB_SETITEMDATA, ret, (LPARAM)data);
+
+ if (CbNum(hWnd, id) == 1)
+ {
+ CbSelect(hWnd, id, 0);
+ }
+
+ return ret;
+}
+
+// Remove all
+void CbReset(HWND hWnd, UINT id)
+{
+ wchar_t *s;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ s = GetText(hWnd, id);
+
+ SendMsg(hWnd, id, CB_RESETCONTENT, 0, 0);
+
+ if (s != NULL)
+ {
+ SetText(hWnd, id, s);
+ Free(s);
+ }
+}
+
+// Select by specifying the index
+void CbSelectIndex(HWND hWnd, UINT id, UINT index)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SendMsg(hWnd, id, CB_SETCURSEL, index, 0);
+}
+
+// Get the data
+UINT CbGetData(HWND hWnd, UINT id, UINT index)
+{
+ // Validate arguments
+ if (hWnd == NULL || index == INFINITE)
+ {
+ return INFINITE;
+ }
+
+ return SendMsg(hWnd, id, CB_GETITEMDATA, index, 0);
+}
+
+// Search for the data
+UINT CbFindData(HWND hWnd, UINT id, UINT data)
+{
+ UINT i, num;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return INFINITE;
+ }
+
+ num = CbNum(hWnd, id);
+ if (num == INFINITE)
+ {
+ return INFINITE;
+ }
+
+ for (i = 0;i < num;i++)
+ {
+ if (CbGetData(hWnd, id, i) == data)
+ {
+ return i;
+ }
+ }
+
+ return INFINITE;
+}
+
+// Set the height of the item
+void CbSetHeight(HWND hWnd, UINT id, UINT value)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SendMsg(hWnd, id, CB_SETITEMHEIGHT, 0, (UINT)(GetTextScalingFactor() * (double)value));
+}
+
+// Search by specifying the data
+void CbSelect(HWND hWnd, UINT id, int data)
+{
+ UINT index;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (data == INFINITE)
+ {
+ // Get the first item
+ CbSelectIndex(hWnd, id, 0);
+ return;
+ }
+
+ index = CbFindData(hWnd, id, data);
+ if (index == INFINITE)
+ {
+ // Can not be found
+ return;
+ }
+
+ // Select
+ CbSelectIndex(hWnd, id, index);
+}
+
+// Get the currently selected item
+UINT CbGetSelectIndex(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return INFINITE;
+ }
+
+ return SendMsg(hWnd, id, CB_GETCURSEL, 0, 0);
+}
+
+// Get the value that is currently selected
+UINT CbGetSelect(HWND hWnd, UINT id)
+{
+ UINT index;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return INFINITE;
+ }
+
+ index = CbGetSelectIndex(hWnd, id);
+ if (index == INFINITE)
+ {
+ return INFINITE;
+ }
+
+ return CbGetData(hWnd, id, index);
+}
+
+// OK button is pressed
+void PasswordDlgOnOk(HWND hWnd, UI_PASSWORD_DLG *p)
+{
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ GetTxtA(hWnd, E_USERNAME, p->Username, sizeof(p->Username));
+ GetTxtA(hWnd, E_PASSWORD, p->Password, sizeof(p->Password));
+ p->Type = CbGetSelect(hWnd, C_TYPE);
+
+ if (p->ShowNoSavePassword)
+ {
+ p->NoSavePassword = IsChecked(hWnd, R_NO_SAVE_PASSWORD);
+ }
+
+ EndDialog(hWnd, true);
+}
+
+// Password input dialog procedure
+UINT PasswordDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ UI_PASSWORD_DLG *p = (UI_PASSWORD_DLG *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ SetIcon(hWnd, 0, ICO_KEY);
+ CbSetHeight(hWnd, C_TYPE, 18);
+ if (p->ServerName != NULL)
+ {
+ FormatText(hWnd, 0, p->ServerName);
+ }
+ else
+ {
+ SetText(hWnd, 0, _UU("PW_LOGIN_DLG_TITLE"));
+ }
+
+ if (p->ProxyServer == false)
+ {
+ FormatText(hWnd, S_TITLE, p->ServerName == NULL ? "" : p->ServerName);
+ }
+ else
+ {
+ wchar_t tmp[MAX_SIZE];
+ UniFormat(tmp, sizeof(tmp), _UU("PW_MSG_PROXY"), p->ServerName == NULL ? "" : p->ServerName);
+ SetText(hWnd, S_TITLE, tmp);
+ }
+
+ // Enumerate the connection methods
+ SendMsg(hWnd, C_TYPE, CBEM_SETUNICODEFORMAT, true, 0);
+
+ if (StrCmpi(p->Username, WINUI_PASSWORD_NULL_USERNAME) != 0)
+ {
+ SetTextA(hWnd, E_USERNAME, p->Username);
+ SetTextA(hWnd, E_PASSWORD, p->Password);
+ }
+ else
+ {
+ p->RetryIntervalSec = 0;
+ SetTextA(hWnd, E_USERNAME, "");
+ SetTextA(hWnd, E_PASSWORD, "");
+ }
+
+ if (p->AdminMode == false)
+ {
+ if (p->ProxyServer == false)
+ {
+ CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_1"), CLIENT_AUTHTYPE_PASSWORD);
+ CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_2"), CLIENT_AUTHTYPE_PLAIN_PASSWORD);
+ }
+ else
+ {
+ CbAddStr(hWnd, C_TYPE, _UU("PW_TYPE_PROXY"), 0);
+ Disable(hWnd, C_TYPE);
+ }
+
+ CbSelect(hWnd, C_TYPE, p->Type);
+ }
+ else
+ {
+ CbAddStr(hWnd, C_TYPE, _UU("SM_PASSWORD_TYPE_STR"), 0);
+ Disable(hWnd, C_TYPE);
+ SetTextA(hWnd, E_USERNAME, "Administrator");
+ Disable(hWnd, E_USERNAME);
+ }
+
+ if (IsEmpty(hWnd, E_USERNAME))
+ {
+ FocusEx(hWnd, E_USERNAME);
+ }
+ else
+ {
+ FocusEx(hWnd, E_PASSWORD);
+ }
+ LimitText(hWnd, E_USERNAME, MAX_USERNAME_LEN);
+ LimitText(hWnd, E_PASSWORD, MAX_PASSWORD_LEN);
+
+ PasswordDlgProcChange(hWnd, p);
+
+ if (p->RetryIntervalSec != 0)
+ {
+ SetTimer(hWnd, 1, 50, NULL);
+ FormatText(hWnd, S_COUNTDOWN, p->RetryIntervalSec);
+ Show(hWnd, S_COUNTDOWN);
+ Show(hWnd, P_PROGRESS);
+ SetRange(hWnd, P_PROGRESS, 0, p->RetryIntervalSec * 1000);
+ }
+ else
+ {
+ Hide(hWnd, S_COUNTDOWN);
+ Hide(hWnd, P_PROGRESS);
+ }
+
+ if (p->ShowNoSavePassword)
+ {
+ Show(hWnd, R_NO_SAVE_PASSWORD);
+ Check(hWnd, R_NO_SAVE_PASSWORD, p->NoSavePassword);
+ }
+ else
+ {
+ Hide(hWnd, R_NO_SAVE_PASSWORD);
+ }
+
+ p->StartTick = Tick64();
+
+ if (p->CancelEvent != NULL)
+ {
+ SetTimer(hWnd, 2, 50, NULL);
+ }
+
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ if (p->RetryIntervalSec != 0)
+ {
+ wchar_t tmp[MAX_SIZE];
+ UINT64 end, now, start;
+ start = p->StartTick;
+ end = p->StartTick + (UINT64)(p->RetryIntervalSec * 1000);
+ now = Tick64();
+
+ if (now <= end)
+ {
+ UniFormat(tmp, sizeof(tmp), _UU("PW_RETRYCOUNT"), (UINT)((end - now) / 1000));
+ SetText(hWnd, S_COUNTDOWN, tmp);
+ SetPos(hWnd, P_PROGRESS, (UINT)(now - start));
+ }
+ else
+ {
+ EndDialog(hWnd, true);
+ }
+ }
+ break;
+
+ case 2:
+ if (p->CancelEvent != NULL)
+ {
+ // Wait for the end event
+ HANDLE hEvent = (HANDLE)p->CancelEvent->pData;
+ UINT ret = WaitForSingleObject(hEvent, 0);
+ if (ret != WAIT_TIMEOUT)
+ {
+ // Forced termination event is set
+ Close(hWnd);
+ }
+ }
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ PasswordDlgOnOk(hWnd, p);
+ break;
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ switch (HIWORD(wParam))
+ {
+ case EN_CHANGE:
+ switch (LOWORD(wParam))
+ {
+ case E_USERNAME:
+ case E_PASSWORD:
+ PasswordDlgProcChange(hWnd, p);
+ break;
+ }
+ break;
+ case CBN_SELCHANGE:
+ switch (LOWORD(wParam))
+ {
+ case C_TYPE:
+ PasswordDlgProcChange(hWnd, p);
+ if (IsEmpty(hWnd, E_USERNAME))
+ {
+ FocusEx(hWnd, E_USERNAME);
+ }
+ else
+ {
+ FocusEx(hWnd, E_PASSWORD);
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Set the position of the progress bar
+void SetPos(HWND hWnd, UINT id, UINT pos)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SendMsg(hWnd, id, PBM_SETPOS, pos, 0);
+}
+
+// Set the range of the progress bar
+void SetRange(HWND hWnd, UINT id, UINT start, UINT end)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SendMsg(hWnd, id, PBM_SETRANGE32, start, end);
+}
+
+// Password input dialog
+bool PasswordDlg(HWND hWnd, UI_PASSWORD_DLG *p)
+{
+ // Validate arguments
+ if (p == NULL)
+ {
+ return false;
+ }
+
+ p->StartTick = Tick64();
+
+ return Dialog(hWnd, D_PASSWORD, PasswordDlgProc, p);
+}
+
+// Passphrase input dialog
+bool PassphraseDlg(HWND hWnd, char *pass, UINT pass_size, BUF *buf, bool p12)
+{
+ PASSPHRASE_DLG p;
+ // Validate arguments
+ if (pass == NULL || buf == NULL)
+ {
+ return false;
+ }
+
+ Zero(&p, sizeof(PASSPHRASE_DLG));
+
+ p.buf = buf;
+ p.p12 = p12;
+
+ // Examine whether it is encrypted first
+ if (p12 == false)
+ {
+ // Secret key
+ if (IsEncryptedK(buf, true) == false)
+ {
+ // Unencrypted
+ StrCpy(pass, pass_size, "");
+ return true;
+ }
+ }
+ else
+ {
+ // PKCS#12
+ P12 *p12 = BufToP12(buf);
+ if (p12 == NULL)
+ {
+ // It is in unknown format, but not encrypted
+ StrCpy(pass, pass_size, "");
+ return true;
+ }
+
+ if (IsEncryptedP12(p12) == false)
+ {
+ // Unencrypted
+ StrCpy(pass, pass_size, "");
+ FreeP12(p12);
+ return true;
+ }
+ FreeP12(p12);
+ }
+
+ // Show the dialog
+ if (Dialog(hWnd, D_PASSPHRASE, PassphraseDlgProc, &p) == false)
+ {
+ // Cancel
+ return false;
+ }
+
+ StrCpy(pass, pass_size, p.pass);
+
+ return true;
+}
+
+// WM_COMMAND handler
+void PassphraseDlgProcCommand(HWND hWnd, PASSPHRASE_DLG *p)
+{
+ char *pass;
+ bool ok;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL)
+ {
+ return;
+ }
+
+ pass = GetTextA(hWnd, E_PASSPHRASE);
+ if (pass == NULL)
+ {
+ return;
+ }
+
+ ok = false;
+
+ if (p->p12 == false)
+ {
+ K *k;
+ k = BufToK(p->buf, true, true, pass);
+ if (k != NULL)
+ {
+ ok = true;
+ FreeK(k);
+ }
+ }
+ else
+ {
+ X *x;
+ K *k;
+ P12 *p12;
+ p12 = BufToP12(p->buf);
+ if (p12 != NULL)
+ {
+ if (ParseP12(p12, &x, &k, pass))
+ {
+ FreeX(x);
+ FreeK(k);
+ ok = true;
+ }
+ FreeP12(p12);
+ }
+ }
+
+ Free(pass);
+
+ SetEnable(hWnd, IDOK, ok);
+}
+
+// Passphrase input dialog procedure
+UINT PassphraseDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ PASSPHRASE_DLG *p = (PASSPHRASE_DLG *)param;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ PassphraseDlgProcCommand(hWnd, p);
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ GetTxtA(hWnd, E_PASSPHRASE, p->pass, sizeof(p->pass));
+ EndDialog(hWnd, true);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+
+ switch (LOWORD(wParam))
+ {
+ case E_PASSPHRASE:
+ PassphraseDlgProcCommand(hWnd, p);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, false);
+ break;
+ }
+
+ return 0;
+}
+
+// PKCS utility
+void PkcsUtil()
+{
+ InitWinUi(_UU("PKCS_UTIL_TITLE"), _SS("DEFAULT_FONT"), _II("DEFAULT_FONT_SIZE"));
+ Dialog(NULL, D_PKCSUTIL, PkcsUtilProc, NULL);
+ FreeWinUi();
+}
+
+// PKCS writing
+void PkcsUtilWrite(HWND hWnd)
+{
+ wchar_t *filename;
+ BUF *in_buf;
+ char filename_ansi[MAX_SIZE];
+ char pass[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ filename = OpenDlg(hWnd, _UU("DLG_PKCS12_FILTER"), _UU("PKCS_UTIL_SAVEDLG_TITLE"));
+ if (filename == NULL)
+ {
+ return;
+ }
+
+ UniToStr(filename_ansi, sizeof(filename_ansi), filename);
+
+ in_buf = ReadDump(filename_ansi);
+
+ if (in_buf == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("PKCS_UTIL_READ_ERROR"), filename);
+ }
+ else
+ {
+ if (PassphraseDlg(hWnd, pass, sizeof(pass), in_buf, true))
+ {
+ P12 *p12 = BufToP12(in_buf);
+ if (p12 == NULL)
+ {
+ MsgBox(hWnd, MB_ICONEXCLAMATION, _UU("PKCS_UTIL_BAD_FILE"));
+ }
+ else
+ {
+ X *x = NULL;
+ K *k = NULL;
+ BUF *b;
+ ParseP12(p12, &x, &k, pass);
+ FreeP12(p12);
+ p12 = NewP12(x, k, NULL);
+ FreeX(x);
+ FreeK(k);
+ b = P12ToBuf(p12);
+ FreeP12(p12);
+ if (b != NULL)
+ {
+ // Batch processing
+ WINUI_SECURE_BATCH batch[] =
+ {
+ {WINUI_SECURE_WRITE_DATA, _SS("PKCS_UTIL_SECA_FILENAME"), false,
+ b, NULL, NULL, NULL, NULL, NULL},
+ };
+
+ if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), 2, 0))
+ {
+ MsgBoxEx(hWnd, MB_ICONINFORMATION, _UU("PKCS_UTIL_WRITE_OK_MSG"), filename);
+ }
+ }
+ FreeBuf(b);
+ }
+ }
+
+ FreeBuf(in_buf);
+ }
+
+ Free(filename);
+}
+
+// PKCS erase
+void PkcsUtilErase(HWND hWnd)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (MsgBox(hWnd, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
+ _UU("PKCS_MAKE_SURE")) == IDYES)
+ {
+ // Batch processing
+ WINUI_SECURE_BATCH batch[] =
+ {
+ {WINUI_SECURE_DELETE_OBJECT, _SS("PKCS_UTIL_SECA_FILENAME"), false,
+ NULL, NULL, NULL, NULL, NULL, NULL},
+ };
+
+ if (SecureDeviceWindow(hWnd, batch, sizeof(batch) / sizeof(batch[0]), 2, 0))
+ {
+ MsgBox(hWnd, MB_ICONINFORMATION, _UU("PKCS_UTIL_DELETE_OK_MSG"));
+ }
+ }
+}
+
+// PKCS Utility dialog
+UINT PkcsUtilProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ DlgFont(hWnd, S_TITLE, 12, true);
+ SetIcon(hWnd, 0, ICO_CERT);
+ SetFont(hWnd, S_COPYRIGHT, GetFont("Arial", 8, false, false, false, false));
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case B_WRITE:
+ PkcsUtilWrite(hWnd);
+ break;
+
+ case B_ERASE:
+ PkcsUtilErase(hWnd);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ return 0;
+}
+
+// [Save File] dialog
+wchar_t *SaveDlg(HWND hWnd, wchar_t *filter, wchar_t *title, wchar_t *default_name, wchar_t *default_ext)
+{
+ wchar_t *filter_str;
+ wchar_t tmp[MAX_SIZE];
+ OPENFILENAMEW o;
+
+ if (MsIsNt() == false)
+ {
+ char *ret, *s1, *s2, *s3, *s4;
+ wchar_t *wr;
+ s1 = CopyUniToStr(filter);
+ s2 = CopyUniToStr(title);
+ s3 = CopyUniToStr(default_name);
+ s4 = CopyUniToStr(default_ext);
+ ret = SaveDlgA(hWnd, s1, s2, s3, s4);
+ Free(s1);
+ Free(s2);
+ Free(s3);
+ Free(s4);
+ wr = CopyStrToUni(ret);
+ Free(ret);
+ return wr;
+ }
+
+ // Validate arguments
+ if (filter == NULL)
+ {
+ filter = _UU("DLG_ALL_FILES");
+ }
+
+ filter_str = MakeFilter(filter);
+
+ Zero(&o, sizeof(o));
+ Zero(tmp, sizeof(tmp));
+
+ if (default_name != NULL)
+ {
+ UniStrCpy(tmp, sizeof(tmp), default_name);
+ }
+
+ o.lStructSize = sizeof(o);
+
+ if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType) || (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) && GET_KETA(GetOsInfo()->OsType, 100) <= 1))
+ {
+ o.lStructSize = OPENFILENAME_SIZE_VERSION_400W;
+ }
+
+ o.hwndOwner = hWnd;
+ o.hInstance = GetModuleHandle(NULL);
+ o.lpstrFile = tmp;
+ o.lpstrTitle = title;
+ o.lpstrFilter = filter_str;
+ o.nMaxFile = sizeof(tmp);
+ o.Flags = OFN_OVERWRITEPROMPT;
+ o.lpstrDefExt = default_ext;
+
+ if (GetSaveFileNameW(&o) == false)
+ {
+ Free(filter_str);
+ return NULL;
+ }
+
+ Free(filter_str);
+
+ return UniCopyStr(tmp);
+}
+char *SaveDlgA(HWND hWnd, char *filter, char *title, char *default_name, char *default_ext)
+{
+ char *filter_str;
+ char tmp[MAX_SIZE];
+ OPENFILENAME o;
+ // Validate arguments
+ if (filter == NULL)
+ {
+ filter = _SS("DLG_ALL_FILES");
+ }
+
+ filter_str = MakeFilterA(filter);
+
+ Zero(&o, sizeof(o));
+ Zero(tmp, sizeof(tmp));
+
+ if (default_name != NULL)
+ {
+ StrCpy(tmp, sizeof(tmp), default_name);
+ }
+
+ o.lStructSize = sizeof(o);
+
+ if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType) || (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) && GET_KETA(GetOsInfo()->OsType, 100) <= 1))
+ {
+ o.lStructSize = OPENFILENAME_SIZE_VERSION_400A;
+ }
+
+ o.hwndOwner = hWnd;
+ o.hInstance = GetModuleHandle(NULL);
+ o.lpstrFile = tmp;
+ o.lpstrTitle = title;
+ o.lpstrFilter = filter_str;
+ o.nMaxFile = sizeof(tmp);
+ o.Flags = OFN_OVERWRITEPROMPT;
+ o.lpstrDefExt = default_ext;
+
+ if (GetSaveFileName(&o) == false)
+ {
+ Free(filter_str);
+ return NULL;
+ }
+
+ Free(filter_str);
+
+ return CopyStr(tmp);
+}
+
+// [Open File] dialog
+wchar_t *OpenDlg(HWND hWnd, wchar_t *filter, wchar_t *title)
+{
+ wchar_t *filter_str;
+ wchar_t tmp[MAX_SIZE];
+ OPENFILENAMEW o;
+
+ if (MsIsNt() == false)
+ {
+ char *ret;
+ char *filter_a;
+ char *title_a;
+ wchar_t *w;
+ filter_a = CopyUniToStr(filter);
+ title_a = CopyUniToStr(title);
+ ret = OpenDlgA(hWnd, filter_a, title_a);
+ Free(filter_a);
+ Free(title_a);
+ w = CopyStrToUni(ret);
+ Free(ret);
+ return w;
+ }
+
+ // Validate arguments
+ if (filter == NULL)
+ {
+ filter = _UU("DLG_ALL_FILES");
+ }
+
+ filter_str = MakeFilter(filter);
+
+ Zero(&o, sizeof(OPENFILENAMEW));
+ Zero(tmp, sizeof(tmp));
+
+ o.lStructSize = sizeof(o);
+
+
+ if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType) || (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) && GET_KETA(GetOsInfo()->OsType, 100) <= 1))
+ {
+ o.lStructSize = OPENFILENAME_SIZE_VERSION_400W;
+ }
+
+
+ o.hwndOwner = hWnd;
+ o.hInstance = GetModuleHandle(NULL);
+ o.lpstrFilter = filter_str;
+ o.lpstrFile = tmp;
+ o.nMaxFile = sizeof(tmp);
+ o.lpstrTitle = title;
+ o.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+
+ if (GetOpenFileNameW(&o) == false)
+ {
+ Free(filter_str);
+ return NULL;
+ }
+
+ Free(filter_str);
+
+ return UniCopyStr(tmp);
+}
+char *OpenDlgA(HWND hWnd, char *filter, char *title)
+{
+ char *filter_str;
+ char tmp[MAX_SIZE];
+ OPENFILENAME o;
+ // Validate arguments
+ if (filter == NULL)
+ {
+ filter = _SS("DLG_ALL_FILES");
+ }
+
+ filter_str = MakeFilterA(filter);
+
+ Zero(&o, sizeof(OPENFILENAME));
+ Zero(tmp, sizeof(tmp));
+
+ o.lStructSize = sizeof(o);
+
+ if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType) || (OS_IS_WINDOWS_NT(GetOsInfo()->OsType) && GET_KETA(GetOsInfo()->OsType, 100) <= 1))
+ {
+ o.lStructSize = OPENFILENAME_SIZE_VERSION_400A;
+ }
+
+ o.hwndOwner = hWnd;
+ o.hInstance = GetModuleHandle(NULL);
+ o.lpstrFilter = filter_str;
+ o.lpstrFile = tmp;
+ o.nMaxFile = sizeof(tmp);
+ o.lpstrTitle = title;
+ o.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
+
+ if (GetOpenFileName(&o) == false)
+ {
+ Free(filter_str);
+ return NULL;
+ }
+
+ Free(filter_str);
+
+ return CopyStr(tmp);
+}
+
+// Generate the filter string
+wchar_t *MakeFilter(wchar_t *str)
+{
+ UINT i;
+ wchar_t *ret;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return NULL;
+ }
+
+ ret = ZeroMalloc(UniStrSize(str) + 32);
+
+ for (i = 0;i < UniStrLen(str);i++)
+ {
+ if (str[i] == L'|')
+ {
+ ret[i] = L'\0';
+ }
+ else
+ {
+ ret[i] = str[i];
+ }
+ }
+
+ return ret;
+}
+char *MakeFilterA(char *str)
+{
+ UINT i;
+ char *ret;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return NULL;
+ }
+
+ ret = ZeroMalloc(StrSize(str) + 32);
+
+ for (i = 0;i < StrLen(str);i++)
+ {
+ if (str[i] == '|')
+ {
+ ret[i] = '\0';
+ }
+ else
+ {
+ ret[i] = str[i];
+ }
+ }
+
+ return ret;
+}
+
+// Execution of batch
+bool ExecuteSecureDeviceBatch(HWND hWnd, SECURE *sec, SECURE_DEVICE_THREAD *p, SECURE_DEVICE *dev, WINUI_SECURE_BATCH *batch)
+{
+ LIST *o;
+ void *buf;
+ UINT size = 10 * 1024; // Maximum size of the data
+ UINT type = INFINITE;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL || dev == NULL || batch == NULL || sec == NULL)
+ {
+ return false;
+ }
+
+ switch (batch->Type)
+ {
+ case WINUI_SECURE_DELETE_CERT:
+ type = SEC_X;
+ goto DELETE_OBJECT;
+
+ case WINUI_SECURE_DELETE_KEY:
+ type = SEC_K;
+ goto DELETE_OBJECT;
+
+ case WINUI_SECURE_DELETE_DATA:
+ type = SEC_DATA;
+ goto DELETE_OBJECT;
+
+ case WINUI_SECURE_DELETE_OBJECT:
+ // Delete the object
+DELETE_OBJECT:
+ SetText(hWnd, S_STATUS, _UU("SEC_DELETE"));
+ if (DeleteSecObjectByName(sec, batch->Name, type) == false)
+ {
+ p->ErrorMessage = UniCopyStr(_UU("SEC_ERROR_DELETE"));
+ return false;
+ }
+ break;
+
+ case WINUI_SECURE_ENUM_OBJECTS:
+ // Enumerate objects
+ SetText(hWnd, S_STATUS, _UU("SEC_ENUM"));
+ o = EnumSecObject(sec);
+ if (o == NULL)
+ {
+ p->ErrorMessage = UniCopyStr(_UU("SEC_ERROR_ENUM"));
+ return false;
+ }
+
+ batch->EnumList = o;
+ break;
+
+ case WINUI_SECURE_WRITE_DATA:
+ // Write the data
+ SetText(hWnd, S_STATUS, _UU("SEC_WRITE_DATA"));
+ if (WriteSecData(sec, batch->Private, batch->Name, batch->InputData->Buf, batch->InputData->Size) == false)
+ {
+ p->ErrorMessage = UniCopyStr(dev->Type != SECURE_USB_TOKEN ?
+ _UU("SEC_ERROR_WRITE_1") : _UU("SEC_ERROR_WRITE_2"));
+ return false;
+ }
+ break;
+
+ case WINUI_SECURE_READ_DATA:
+ // Read the data
+ SetText(hWnd, S_STATUS, _UU("SEC_READ_DATA"));
+ buf = MallocEx(size, true);
+ size = ReadSecData(sec, batch->Name, buf, size);
+ if (size == 0)
+ {
+ Free(buf);
+ p->ErrorMessage = UniCopyStr(dev->Type != SECURE_USB_TOKEN ?
+ _UU("SEC_ERROR_NOT_FOUND_1") : _UU("SEC_ERROR_NOT_FOUND_2"));
+ return false;
+ }
+ batch->OutputData = NewBuf();
+ WriteBuf(batch->OutputData, buf, size);
+ SeekBuf(batch->OutputData, 0, 0);
+ Free(buf);
+ break;
+
+ case WINUI_SECURE_WRITE_CERT:
+ // Write the certificate
+ SetText(hWnd, S_STATUS, _UU("SEC_WRITE_CERT"));
+ if (WriteSecCert(sec, batch->Private, batch->Name, batch->InputX) == false)
+ {
+ p->ErrorMessage = UniCopyStr(dev->Type != SECURE_USB_TOKEN ?
+ _UU("SEC_ERROR_WRITE_1") : _UU("SEC_ERROR_WRITE_2"));
+ return false;
+ }
+ break;
+
+ case WINUI_SECURE_READ_CERT:
+ // Read the certificate
+ SetText(hWnd, S_STATUS, _UU("SEC_READ_CERT"));
+ batch->OutputX = ReadSecCert(sec, batch->Name);
+ if (batch->OutputX == NULL)
+ {
+ p->ErrorMessage = UniCopyStr(dev->Type != SECURE_USB_TOKEN ?
+ _UU("SEC_ERROR_NOT_FOUND_1") : _UU("SEC_ERROR_NOT_FOUND_2"));
+ return false;
+ }
+ break;
+
+ case WINUI_SECURE_WRITE_KEY:
+ // Write the secret key
+ SetText(hWnd, S_STATUS, _UU("SEC_WRITE_KEY"));
+ if (WriteSecKey(sec, batch->Private, batch->Name, batch->InputK) == false)
+ {
+ p->ErrorMessage = UniCopyStr(dev->Type != SECURE_USB_TOKEN ?
+ _UU("SEC_ERROR_WRITE_1") : _UU("SEC_ERROR_WRITE_2"));
+ return false;
+ }
+ break;
+
+ case WINUI_SECURE_SIGN_WITH_KEY:
+ // Signature
+ SetText(hWnd, S_STATUS, _UU("SEC_SIGN"));
+ if (SignSec(sec, batch->Name, batch->OutputSign, batch->InputData->Buf, batch->InputData->Size) == false)
+ {
+ p->ErrorMessage = UniCopyStr(dev->Type != SECURE_USB_TOKEN ?
+ _UU("SEC_ERROR_SIGN_1") : _UU("SEC_ERROR_SIGN_2"));
+ return false;
+ }
+ break;
+ }
+
+ return true;
+}
+
+// Run the secure device operations as a batch job
+void SecureDeviceBatch(HWND hWnd, SECURE *sec, SECURE_DEVICE_THREAD *p, SECURE_DEVICE *dev)
+{
+ UINT i;
+ // Validate arguments
+ if (hWnd == NULL || p == NULL || dev == NULL || sec == NULL)
+ {
+ return;
+ }
+
+ // Sequential processing
+ for (i = 0;i < p->w->num_batch;i++)
+ {
+ WINUI_SECURE_BATCH *batch = &p->w->batch[i];
+
+ if (ExecuteSecureDeviceBatch(hWnd, sec, p, dev, batch) == false)
+ {
+ // If fail even one, abort immediately
+ return;
+ }
+ }
+
+ // All batch job succeeded
+ p->Succeed = true;
+}
+
+// Thread to perform a secure device operation
+void SecureDeviceThread(THREAD *t, void *param)
+{
+ SECURE *sec;
+ SECURE_DEVICE_THREAD *p = (SECURE_DEVICE_THREAD *)param;
+ SECURE_DEVICE *dev;
+ HWND hWnd;
+ // Validate arguments
+ if (t == NULL || param == NULL)
+ {
+ return;
+ }
+
+ p->Succeed = false;
+ p->ErrorMessage = NULL;
+
+ hWnd = p->hWnd;
+
+ // Open the device
+ dev = GetSecureDevice(p->w->device_id);
+ SetText(hWnd, S_STATUS, _UU("SEC_OPENING"));
+ sec = OpenSec(p->w->device_id);
+ if (sec == NULL)
+ {
+ // Device open failure
+ if (p->w->device_id != 9)
+ {
+ p->ErrorMessage = CopyUniFormat(_UU("SEC_ERROR_OPEN_DEVICE"), dev->DeviceName);
+ }
+ else
+ {
+ p->ErrorMessage = CopyUniFormat(_UU("SEC_ERROR_OPEN_DEVICEEX"), dev->DeviceName);
+ }
+ }
+ else
+ {
+ // Open the session
+ SetText(hWnd, S_STATUS, _UU("SEC_OPEN_SESSION"));
+ if (OpenSecSession(sec, 0) == false)
+ {
+ // Session initialization failure
+ p->ErrorMessage = CopyUniFormat(_UU("SEC_ERROR_OPEN_SESSION"), dev->DeviceName);
+ }
+ else
+ {
+ // Login
+ SetText(hWnd, S_STATUS, _UU("SEC_LOGIN"));
+ if (LoginSec(sec, p->pin) == false)
+ {
+ // Login failure
+ p->ErrorMessage =UniCopyStr(_UU("SEC_ERROR_LOGIN"));
+ }
+ else
+ {
+ // Batch processing main
+ SetText(hWnd, S_STATUS, _UU("SEC_INIT_BATCH"));
+ SecureDeviceBatch(hWnd, sec, p, dev);
+
+ // Logout
+ SetText(hWnd, S_STATUS, _UU("SEC_LOGOUT"));
+ LogoutSec(sec);
+ }
+
+ // Close the session
+ SetText(hWnd, S_STATUS, _UU("SEC_CLOSE_SESSION"));
+ CloseSecSession(sec);
+ }
+
+ // Close the device
+ SetText(hWnd, S_STATUS, _UU("SEC_CLOSING"));
+ CloseSec(sec);
+ }
+
+ if (p->Succeed)
+ {
+ // If successful, show the message for 150ms (service)
+ SetText(hWnd, S_STATUS, _UU("SEC_FINISHED"));
+ SleepThread(150);
+ }
+
+ SendMessage(p->hWnd, WM_APP + 1, 0, 0);
+}
+
+// Start a secure device operation
+void StartSecureDevice(HWND hWnd, SECURE_DEVICE_WINDOW *w)
+{
+ SECURE_DEVICE_THREAD *p;
+ // Validate arguments
+ if (hWnd == NULL || w == NULL)
+ {
+ return;
+ }
+
+ // Disable the control
+ EnableSecureDeviceWindowControls(hWnd, false);
+
+ // Start the thread
+ p = ZeroMalloc(sizeof(SECURE_DEVICE_THREAD));
+ p->w = w;
+ p->hWnd = hWnd;
+ w->p = p;
+ p->pin = GetTextA(hWnd, E_PIN);
+ ReleaseThread(NewThread(SecureDeviceThread, p));
+}
+
+// Enable or disable the control of the secure device operation window
+void EnableSecureDeviceWindowControls(HWND hWnd, bool enable)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (enable)
+ {
+ Show(hWnd, S_PIN_CODE);
+ Show(hWnd, E_PIN);
+ Show(hWnd, S_WARNING);
+ }
+ else
+ {
+ Hide(hWnd, S_PIN_CODE);
+ Hide(hWnd, E_PIN);
+ Hide(hWnd, S_WARNING);
+ }
+
+ SetEnable(hWnd, IDOK, enable);
+ SetEnable(hWnd, IDCANCEL, enable);
+ SetEnable(hWnd, S_TITLE, enable);
+ SetEnable(hWnd, S_DEVICE_INFO, enable);
+ SetEnable(hWnd, S_INSERT_SECURE, enable);
+
+ if (enable == false)
+ {
+ DisableClose(hWnd);
+ SetText(hWnd, S_STATUS, L"");
+ Show(hWnd, S_STATUS);
+ PlayAvi(hWnd, A_PROGRESS, true);
+ }
+ else
+ {
+ EnableClose(hWnd);
+ SetText(hWnd, S_STATUS, L"");
+ Hide(hWnd, S_STATUS);
+ StopAvi(hWnd, A_PROGRESS);
+ }
+}
+
+// Secure device operation window procedure
+UINT SecureDeviceWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
+{
+ SECURE_DEVICE_WINDOW *w = (SECURE_DEVICE_WINDOW *)param;
+ SECURE_DEVICE *dev = GetSecureDevice(w->device_id);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ if (dev == NULL)
+ {
+ MsgBoxEx(hWnd, MB_ICONEXCLAMATION, _UU("SEC_ERROR_INVALID_ID"), w->device_id);
+ EndDialog(hWnd, 0);
+ break;
+ }
+
+ if (IsJPKI(dev->Id))
+ {
+ // Juki card
+ Hide(hWnd, S_IMAGE);
+ Show(hWnd, S_IMAGE2);
+ Hide(hWnd, S_IMAGE_TSUKUBA);
+ }
+ else
+ {
+ // Regular card
+ Hide(hWnd, S_IMAGE2);
+
+ if (w->BitmapId != 0)
+ {
+ // For University of Tsukuba
+ Hide(hWnd, S_IMAGE);
+ Show(hWnd, S_IMAGE_TSUKUBA);
+ }
+ else
+ {
+ // For general use
+ Show(hWnd, S_IMAGE);
+ Hide(hWnd, S_IMAGE_TSUKUBA);
+ }
+ }
+
+ FormatText(hWnd, 0, dev->Type != SECURE_USB_TOKEN ? _UU("SEC_SMART_CARD") : _UU("SEC_USB_TOKEN"),
+ dev->DeviceName);
+ FormatText(hWnd, S_TITLE, dev->DeviceName);
+ FormatText(hWnd, S_INSERT_SECURE,
+ dev->Type != SECURE_USB_TOKEN ? _UU("SEC_INIT_MSG_1") : _UU("SEC_INIT_MSG_2"));
+ FormatText(hWnd, S_DEVICE_INFO,
+ dev->DeviceName, dev->Manufacturer, dev->ModuleName);
+
+ DlgFont(hWnd, S_SOFTWARE_TITLE, 11, 0);
+ SetText(hWnd, S_SOFTWARE_TITLE, title_bar);
+
+ DlgFont(hWnd, S_TITLE, 14, true);
+ DlgFont(hWnd, S_DEVICE_INFO, 11, false);
+ DlgFont(hWnd, S_STATUS, 13, true);
+ EnableSecureDeviceWindowControls(hWnd, true);
+ OpenAvi(hWnd, A_PROGRESS, AVI_PROGRESS);
+
+ SetIcon(hWnd, 0, ICO_KEY);
+
+ // Initial PIN
+ if ((w->default_pin != NULL && StrLen(w->default_pin) != 0) || (cached_pin_code_expires >= Tick64()))
+ {
+ if (w->default_pin != NULL && StrLen(w->default_pin) != 0)
+ {
+ SetTextA(hWnd, E_PIN, w->default_pin);
+ }
+ else
+ {
+ SetTextA(hWnd, E_PIN, cached_pin_code);
+ }
+ SetTimer(hWnd, 1, 1, NULL);
+ }
+
+ break;
+
+ case WM_TIMER:
+ switch (wParam)
+ {
+ case 1:
+ KillTimer(hWnd, 1);
+ Command(hWnd, IDOK);
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDOK:
+ StartSecureDevice(hWnd, w);
+ break;
+
+ case IDCANCEL:
+ Close(hWnd);
+ break;
+ }
+ break;
+
+ case WM_CLOSE:
+ if (IsEnable(hWnd, IDCANCEL))
+ {
+ CloseAvi(hWnd, A_PROGRESS);
+ EndDialog(hWnd, false);
+ }
+ break;
+
+ case WM_APP + 1:
+ // There is a response from the thread
+ if (w->p != NULL)
+ {
+ if (w->p->Succeed)
+ {
+ // Success
+ if (w->default_pin != NULL)
+ {
+ StrCpy(w->default_pin, 128, w->p->pin);
+ }
+ StrCpy(cached_pin_code, sizeof(cached_pin_code), w->p->pin);
+ cached_pin_code_expires = Tick64() + (UINT64)WINUI_SECUREDEVICE_PIN_CACHE_TIME;
+ Free(w->p->pin);
+ Free(w->p);
+ EndDialog(hWnd, true);
+ }
+ else
+ {
+ // Failure
+ cached_pin_code_expires = 0;
+ EnableSecureDeviceWindowControls(hWnd, true);
+ FocusEx(hWnd, E_PIN);
+ MsgBox(hWnd, MB_ICONEXCLAMATION, w->p->ErrorMessage);
+ Free(w->p->pin);
+ Free(w->p->ErrorMessage);
+ Free(w->p);
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Send a WM_COMMAND
+void Command(HWND hWnd, UINT id)
+{
+ SendMessage(hWnd, WM_COMMAND, id, 0);
+}
+
+// Show the secure device window
+bool SecureDeviceWindow(HWND hWnd, WINUI_SECURE_BATCH *batch, UINT num_batch, UINT device_id, UINT bitmap_id)
+{
+ SECURE_DEVICE_WINDOW w;
+ UINT i;
+ // Validate arguments
+ if (batch == NULL || num_batch == 0 || device_id == 0)
+ {
+ return false;
+ }
+
+ // Initialize the success flag
+ for (i = 0;i < num_batch;i++)
+ {
+ batch[i].Succeed = false;
+ }
+
+ Zero(&w, sizeof(w));
+ w.batch = batch;
+ w.device_id = device_id;
+ w.num_batch = num_batch;
+ w.BitmapId = bitmap_id;
+
+ // Open a dialog
+ return (bool)Dialog(hWnd, D_SECURE, SecureDeviceWindowProc, &w);
+}
+
+// Stop playing the AVI
+void StopAvi(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ Animate_Stop(DlgItem(hWnd, id));
+ Hide(hWnd, id);
+}
+
+// Play an AVI
+void PlayAvi(HWND hWnd, UINT id, bool repeat)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ Show(hWnd, id);
+ Animate_Play(DlgItem(hWnd, id), 0, -1, (repeat ? -1 : 0));
+}
+
+// Close the AVI file
+void CloseAvi(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ StopAvi(hWnd, id);
+ Animate_Close(DlgItem(hWnd, id));
+}
+
+// Open an AVI file
+void OpenAvi(HWND hWnd, UINT id, UINT avi_id)
+{
+ // Validate arguments
+ if (hWnd == NULL || avi_id == 0)
+ {
+ return;
+ }
+
+ Hide(hWnd, id);
+ Animate_OpenEx(DlgItem(hWnd, id), hDll, MAKEINTRESOURCE(avi_id));
+}
+
+// Set the font to the control
+void DlgFont(HWND hWnd, UINT id, UINT size, UINT bold)
+{
+ DIALOG_PARAM *param = (DIALOG_PARAM *)GetParam(hWnd);
+
+ if (param == NULL || param->meiryo == false)
+ {
+ SetFont(hWnd, id, Font(size, bold));
+ }
+ else
+ {
+ SetFont(hWnd, id, GetFont((_GETLANG() == 2 ? "Microsoft YaHei" : GetMeiryoFontName()), size, bold, false, false, false));
+ }
+}
+
+// Generate a standard font
+HFONT Font(UINT size, UINT bold)
+{
+ return GetFont(NULL, size, bold, false, false, false);
+}
+
+// Dialog procedure for internal management
+UINT CALLBACK InternalDialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ DIALOG_PARAM *param = (DIALOG_PARAM *)GetParam(hWnd);
+ void *app_param = NULL;
+ bool white_flag = false;
+ UINT ret;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ if (msg == WM_INITDIALOG)
+ {
+ DoEvents(hWnd);
+ }
+
+ if (param == NULL)
+ {
+ if (msg == WM_INITDIALOG)
+ {
+ param = (void *)lParam;
+ InitDialogInternational(hWnd, param);
+ }
+ }
+ if (param != NULL)
+ {
+ app_param = param->param;
+ white_flag = param->white;
+ }
+
+ ret = DlgProc(hWnd, msg, wParam, lParam, white_flag);
+ if (ret != 0)
+ {
+ return ret;
+ }
+
+ ret = 0;
+
+ if (param != NULL)
+ {
+ if (param->proc != NULL)
+ {
+ ret = param->proc(hWnd, msg, wParam, lParam, app_param);
+ }
+ else
+ {
+ if (msg == WM_CLOSE)
+ {
+ EndDialog(hWnd, 0);
+ }
+ else if (msg == WM_COMMAND && (wParam == IDOK || wParam == IDCANCEL))
+ {
+ Close(hWnd);
+ }
+ }
+ }
+
+ if (msg == WM_INITDIALOG)
+ {
+ SetForegroundWindow(hWnd);
+ SetActiveWindow(hWnd);
+ }
+
+ return ret;
+}
+
+// Show a dialog box
+UINT Dialog(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param)
+{
+ bool white = true;
+
+ return DialogEx(hWnd, id, proc, param, white);
+}
+UINT DialogEx(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param, bool white)
+{
+ return DialogEx2(hWnd, id, proc, param, white, false);
+}
+UINT DialogEx2(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param, bool white, bool meiryo)
+{
+ UINT ret;
+ DIALOG_PARAM p;
+ // Validate arguments
+ if (id == 0)
+ {
+ return 0;
+ }
+
+ Zero(&p, sizeof(p));
+ p.param = param;
+ p.white = white;
+ p.proc = proc;
+
+ p.BitmapList = NewBitmapList();
+
+ if (MsIsVista())
+ {
+ p.meiryo = meiryo;
+ }
+
+ ret = DialogInternal(hWnd, id, InternalDialogProc, &p);
+
+ FreeBitmapList(p.BitmapList);
+
+ return ret;
+}
+
+// Create a modeless dialog
+HWND DialogCreateEx(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param, bool white)
+{
+ HWND ret = NULL;
+ DIALOG_PARAM p;
+ // Validate arguments
+ if (id == 0)
+ {
+ return 0;
+ }
+
+ Zero(&p, sizeof(p));
+ p.param = param;
+ p.white = white;
+ p.proc = proc;
+
+ if (MsIsNt() == false)
+ {
+ // Win9x
+ ret = CreateDialogParamA(hDll, MAKEINTRESOURCEA(id), hWnd,
+ (DLGPROC)proc, (LPARAM)param);
+ }
+ else
+ {
+ // WinNT
+ ret = CreateDialogParamW(hDll, MAKEINTRESOURCEW(id), hWnd,
+ (DLGPROC)proc, (LPARAM)param);
+ }
+
+ return ret;
+}
+
+// Set the bitmap to the button
+void SetBitmap(HWND hWnd, UINT id, UINT bmp_id)
+{
+ HBITMAP bmp;
+ char *class_name;
+ DIALOG_PARAM *dialog_param = NULL;
+ bool need_resize = 0;
+ double resize_x = 1.0;
+ double resize_y = 1.0;
+ bool add_to_free_list = false;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ bmp = LoadImage(hDll, MAKEINTRESOURCE(bmp_id), IMAGE_BITMAP, 0, 0, (MsIsNt() ? LR_SHARED : 0) | LR_VGACOLOR);
+ if (bmp == NULL)
+ {
+ return;
+ }
+
+ dialog_param = GetParam(hWnd);
+
+ // Determine the need for resizing
+ if (dialog_param)
+ {
+ if (MsIsVista())
+ {
+ GetWindowAndControlSizeResizeScale(hWnd, &need_resize, &resize_x, &resize_y);
+
+ if (need_resize)
+ {
+ // Resize
+ UINT src_x, src_y, dst_x, dst_y;
+
+ if (GetBitmapSize(bmp, &src_x, &src_y))
+ {
+ HBITMAP new_bmp;
+ double scale_factor = MIN(resize_x, resize_y);
+
+ dst_x = (UINT)((double)src_x * scale_factor);
+ dst_y = (UINT)((double)src_y * scale_factor);
+
+ new_bmp = ResizeBitmap(bmp, src_x, src_y, dst_x, dst_y);
+
+ if (new_bmp != NULL)
+ {
+ bmp = new_bmp;
+
+ add_to_free_list = true;
+ }
+ }
+ }
+ }
+ }
+
+ class_name = GetClassA(hWnd, id);
+
+ if (StrCmpi(class_name, "Static") != 0)
+ {
+ SendMsg(hWnd, id, BM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bmp);
+ }
+ else
+ {
+ SendMsg(hWnd, id, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bmp);
+ }
+
+ Free(class_name);
+
+ if (add_to_free_list)
+ {
+ Add(dialog_param->BitmapList, bmp);
+ }
+}
+
+// Initialize the icon cache
+void InitIconCache()
+{
+ if (icon_cache_list != NULL)
+ {
+ return;
+ }
+
+ icon_cache_list = NewList(NULL);
+}
+
+// Release the icon cache
+void FreeIconCache()
+{
+ UINT i;
+ if (icon_cache_list == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(icon_cache_list);i++)
+ {
+ ICON_CACHE *c = LIST_DATA(icon_cache_list, i);
+ DestroyIcon(c->hIcon);
+ Free(c);
+ }
+
+ ReleaseList(icon_cache_list);
+ icon_cache_list = NULL;
+}
+
+// Get the Icon
+HICON LoadIconEx(UINT id, bool small_icon)
+{
+ HICON h = NULL;
+ UINT i;
+ if (icon_cache_list == NULL)
+ {
+ return small_icon == false ? LoadLargeIconInner(id) : LoadSmallIconInner(id);
+ }
+
+ LockList(icon_cache_list);
+ {
+ for (i = 0;i < LIST_NUM(icon_cache_list);i++)
+ {
+ ICON_CACHE *c = LIST_DATA(icon_cache_list, i);
+ if (c->id == id && c->small_icon == small_icon)
+ {
+ h = c->hIcon;
+ break;
+ }
+ }
+
+ if (h == NULL)
+ {
+ h = small_icon == false ? LoadLargeIconInner(id) : LoadSmallIconInner(id);
+ if (h != NULL)
+ {
+ ICON_CACHE *c = ZeroMalloc(sizeof(ICON_CACHE));
+ c->hIcon = h;
+ c->id = id;
+ c->small_icon = small_icon;
+ Add(icon_cache_list, c);
+ }
+ }
+ }
+ UnlockList(icon_cache_list);
+
+ return h;
+}
+
+// Get a large Icon
+HICON LoadLargeIcon(UINT id)
+{
+ return LoadIconEx(id, false);
+}
+
+// Get a small icon
+HICON LoadSmallIcon(UINT id)
+{
+ return LoadIconEx(id, true);
+}
+
+// Get a large icon
+HICON LoadLargeIconInner(UINT id)
+{
+ HICON ret;
+ ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 32, 32, 0);
+ if (ret == NULL)
+ {
+ ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 32, 32, LR_VGACOLOR);
+ if (ret == NULL)
+ {
+ ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, 0);
+ if (ret == NULL)
+ {
+ ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, LR_VGACOLOR);
+ if (ret == NULL)
+ {
+ ret = LoadIcon(hDll, MAKEINTRESOURCE(id));
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+// Get a small icon
+HICON LoadSmallIconInner(UINT id)
+{
+ HICON ret;
+ ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 16, 16, 0);
+ if (ret == NULL)
+ {
+ ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 16, 16, LR_VGACOLOR);
+ if (ret == NULL)
+ {
+ ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, 0);
+ if (ret == NULL)
+ {
+ ret = LoadImage(hDll, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, LR_VGACOLOR);
+ if (ret == NULL)
+ {
+ ret = LoadLargeIconInner(id);
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+// Set the icon to the button or window
+void SetIcon(HWND hWnd, UINT id, UINT icon_id)
+{
+ HICON icon1, icon2;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ icon1 = LoadLargeIcon(icon_id);
+ if (icon1 == NULL)
+ {
+ return;
+ }
+
+ if (id == 0)
+ {
+ SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)icon1);
+ icon2 = LoadSmallIcon(icon_id);
+ if (icon2 == NULL)
+ {
+ icon2 = icon1;
+ }
+ SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)icon2);
+ }
+ else
+ {
+ bool is_btn = true;
+ wchar_t *s = GetClass(hWnd, id);
+ if (s != NULL)
+ {
+ if (UniStrCmpi(s, L"Static") == 0)
+ {
+ is_btn = false;
+ }
+ Free(s);
+ }
+
+ if (is_btn)
+ {
+ SendMsg(hWnd, id, BM_SETIMAGE, IMAGE_ICON, (LPARAM)icon1);
+ }
+ else
+ {
+ SendMsg(hWnd, id, STM_SETICON, (WPARAM)icon1, 0);
+ }
+ }
+}
+
+// Check whether the radio button is checked
+bool IsChecked(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return false;
+ }
+
+ return IsDlgButtonChecked(hWnd, id) == BST_CHECKED ? true : false;
+}
+
+// Check the radio button
+void Check(HWND hWnd, UINT id, bool b)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if ((!(!IsChecked(hWnd, id))) != (!(!b)))
+ {
+ CheckDlgButton(hWnd, id, b ? BST_CHECKED : BST_UNCHECKED);
+ }
+}
+
+// Confirm that the character size of the text-box is less than or equal to specified size
+bool CheckTextSize(HWND hWnd, UINT id, UINT size, bool unicode)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return false;
+ }
+
+ if (GetTextSize(hWnd, id, unicode) <= size)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// Confirm that a length of the string in the text-box is less than or equal to the specified size
+bool CheckTextLen(HWND hWnd, UINT id, UINT len, bool unicode)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return false;
+ }
+
+ if (GetTextLen(hWnd, id, unicode) <= len)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// Limit the number of characters that can be entered into the text-box
+void LimitText(HWND hWnd, UINT id, UINT count)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SendMsg(hWnd, id, EM_LIMITTEXT, count, 0);
+}
+
+// Font settings
+void SetFont(HWND hWnd, UINT id, HFONT hFont)
+{
+ SetFontEx(hWnd, id, hFont, false);
+}
+void SetFontEx(HWND hWnd, UINT id, HFONT hFont, bool no_adjust_font_size)
+{
+ // Validate arguments
+ if (hWnd == NULL || hFont == NULL)
+ {
+ return;
+ }
+
+ SendMessage(DlgItem(hWnd, id), WM_SETFONT, (WPARAM)hFont, true);
+
+ if (no_adjust_font_size == false)
+ {
+ AdjustFontSize(hWnd, id);
+ }
+}
+
+// Get the font size
+bool GetFontSize(HFONT hFont, UINT *x, UINT *y)
+{
+ bool ret = false;
+ UINT xx = 0;
+ UINT yy = 0;
+
+ // Search for the font handle
+ LockList(font_list);
+ {
+ UINT i;
+
+ for (i = 0;i < LIST_NUM(font_list);i++)
+ {
+ FONT *f = LIST_DATA(font_list, i);
+
+ if (f->hFont == hFont)
+ {
+ xx = f->x;
+ yy = f->y;
+
+ ret = true;
+ break;
+ }
+ }
+ }
+ UnlockList(font_list);
+
+ if (ret == false)
+ {
+ ret = CalcFontSize(hFont, &xx, &yy);
+ }
+
+ if (xx == 0 || yy == 0)
+ {
+ xx = 8;
+ yy = 16;
+ }
+
+ if (x != NULL)
+ {
+ *x = xx;
+ }
+
+ if (y != NULL)
+ {
+ *y = yy;
+ }
+
+ return ret;
+}
+
+// Calculate the font size
+bool CalcFontSize(HFONT hFont, UINT *x, UINT *y)
+{
+ UINT xx = 0, yy = 0;
+ TEXTMETRIC tm;
+ SIZE sz;
+ bool ret = false;
+ HDC hDC;
+
+ hDC = CreateCompatibleDC(NULL);
+
+ SelectObject(hDC, hFont);
+
+ Zero(&tm, sizeof(tm));
+ Zero(&sz, sizeof(sz));
+
+ if (GetTextMetrics(hDC, &tm))
+ {
+ xx = tm.tmAveCharWidth;
+ yy = tm.tmHeight;
+
+ ret = true;
+
+ if (GetTextExtentPoint32(hDC,
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
+ 52, &sz))
+ {
+ xx = (sz.cx / 26 + 1) / 2;
+ }
+ }
+
+ if (x != NULL)
+ {
+ *x = xx;
+ }
+
+ if (y != NULL)
+ {
+ *y = yy;
+ }
+
+ DeleteDC(hDC);
+
+ return ret;
+}
+
+// Get the font magnification
+double GetTextScalingFactor()
+{
+ static int cached_dpi = 0;
+ double ret = 1.0;
+
+ if (MsIsVista() == false)
+ {
+ // It's always 1.0 in Windows XP or earlier
+ return 1.0;
+ }
+
+ if (cached_dpi == 0)
+ {
+ HDC hDC = CreateCompatibleDC(NULL);
+
+ if (hDC != NULL)
+ {
+ cached_dpi = GetDeviceCaps(hDC, LOGPIXELSY);
+
+ DeleteDC(hDC);
+ }
+ }
+
+ if (cached_dpi != 0)
+ {
+ ret = (double)cached_dpi / 96.0;
+
+ if (ret < 0)
+ {
+ ret = -ret;
+ }
+ }
+
+ return ret;
+}
+
+// Get the parameters of the font that was created in the past
+bool GetFontParam(HFONT hFont, struct FONT *f)
+{
+ bool ret = false;
+ // Validate arguments
+ if (hFont == NULL || f == NULL)
+ {
+ return false;
+ }
+
+ // Search for the existing font
+ LockList(font_list);
+ {
+ UINT i;
+
+ for (i = 0;i < LIST_NUM(font_list);i++)
+ {
+ FONT *n = LIST_DATA(font_list, i);
+
+ if (n->hFont == hFont)
+ {
+ Copy(f, n, sizeof(FONT));
+
+ ret = true;
+
+ break;
+ }
+ }
+ }
+ UnlockList(font_list);
+
+ return ret;
+}
+
+// Get the font
+HFONT GetFont(char *name, UINT size, bool bold, bool italic, bool underline, bool strikeout)
+{
+ HFONT hFont;
+ HDC hDC;
+ // Validate arguments
+ if (name == NULL)
+ {
+ name = font_name;
+ }
+ if (size == 0)
+ {
+ size = font_size;
+ if (size == 0)
+ {
+ size = 9;
+ }
+ }
+
+ // Search for the existing font
+ LockList(font_list);
+ {
+ FONT *f, t;
+ DWORD font_quality = ANTIALIASED_QUALITY;
+ OS_INFO *os = GetOsInfo();
+ UINT x = 0;
+ UINT y = 0;
+ int rotate = 0;
+ UINT dpi;
+
+ Zero(&t, sizeof(t));
+ t.Bold = bold;
+ t.Italic = italic;
+ t.Size = size;
+ t.StrikeOut = strikeout;
+ t.UnderLine = underline;
+ t.Name = CopyStr(name);
+ f = Search(font_list, &t);
+ Free(t.Name);
+
+ if (f != NULL)
+ {
+ // Font is found
+ UnlockList(font_list);
+ return f->hFont;
+ }
+
+ // Create a new font
+ hDC = CreateCompatibleDC(NULL);
+
+ // Specify the ClearType in Windows XP or later
+ if (OS_IS_WINDOWS_NT(os->OsType) && GET_KETA(os->OsType, 100) >= 3)
+ {
+ font_quality = CLEARTYPE_NATURAL_QUALITY;
+ rotate = 3600;
+ }
+
+ if (MsIsVista())
+ {
+ dpi = GetDeviceCaps(hDC, LOGPIXELSY);
+ }
+ else
+ {
+ dpi = 96;
+ }
+
+ // Create a font
+ hFont = CreateFontA(-MulDiv(size, dpi, 72),
+ 0, rotate, rotate, (bold == false ? 500 : FW_BOLD),
+ italic, underline, strikeout, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
+ CLIP_DEFAULT_PRECIS, font_quality, DEFAULT_PITCH, name);
+
+ if (hFont == NULL)
+ {
+ // Failure
+ DeleteDC(hDC);
+ UnlockList(font_list);
+
+ return NULL;
+ }
+
+ CalcFontSize(hFont, &x, &y);
+
+ // Add to the table
+ f = ZeroMalloc(sizeof(FONT));
+ f->Bold = bold;
+ f->hFont = hFont;
+ f->Italic = italic;
+ f->Name = CopyStr(name);
+ f->Size = size;
+ f->StrikeOut = strikeout;
+ f->UnderLine = underline;
+ f->x = x;
+ f->y = y;
+
+ Insert(font_list, f);
+
+ DeleteDC(hDC);
+ }
+ UnlockList(font_list);
+
+ return hFont;
+}
+
+// Comparison of the font
+int CompareFont(void *p1, void *p2)
+{
+ FONT *f1, *f2;
+ UINT r;
+ if (p1 == NULL || p2 == NULL)
+ {
+ return 0;
+ }
+ f1 = *(FONT **)p1;
+ f2 = *(FONT **)p2;
+ if (f1 == NULL || f2 == NULL)
+ {
+ return 0;
+ }
+ r = StrCmpi(f1->Name, f2->Name);
+ if (r != 0)
+ {
+ return r;
+ }
+ else
+ {
+ if (f1->Bold > f2->Bold)
+ {
+ return 1;
+ }
+ else if (f1->Bold < f2->Bold)
+ {
+ return -1;
+ }
+ else if (f1->Italic > f2->Italic)
+ {
+ return 1;
+ }
+ else if (f1->Italic < f2->Italic)
+ {
+ return -1;
+ }
+ else if (f1->Size > f2->Size)
+ {
+ return 1;
+ }
+ else if (f1->Size < f2->Size)
+ {
+ return -1;
+ }
+ else if (f1->StrikeOut > f2->StrikeOut)
+ {
+ return 1;
+ }
+ else if (f1->StrikeOut < f2->StrikeOut)
+ {
+ return -1;
+ }
+ else if (f1->UnderLine > f2->UnderLine)
+ {
+ return 1;
+ }
+ else if (f1->UnderLine < f2->UnderLine)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+}
+
+// Initialize the font
+void InitFont()
+{
+ if (font_list != NULL)
+ {
+ return;
+ }
+ font_list = NewList(CompareFont);
+}
+
+// Release the font
+void FreeFont()
+{
+ UINT i;
+ if (font_list == NULL)
+ {
+ return;
+ }
+ for (i = 0;i < LIST_NUM(font_list);i++)
+ {
+ FONT *f = LIST_DATA(font_list, i);
+ Free(f->Name);
+ DeleteObject((HGDIOBJ)f->hFont);
+ Free(f);
+ }
+ ReleaseList(font_list);
+ font_list = NULL;
+}
+
+// Show a button to close the window
+void EnableClose(HWND hWnd)
+{
+ HMENU h;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ h = GetSystemMenu(hWnd, false);
+ EnableMenuItem(h, SC_CLOSE, MF_ENABLED);
+ DrawMenuBar(hWnd);
+}
+
+// Hide the button to close the window
+void DisableClose(HWND hWnd)
+{
+ HMENU h;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ h = GetSystemMenu(hWnd, false);
+ EnableMenuItem(h, SC_CLOSE, MF_GRAYED);
+ DrawMenuBar(hWnd);
+}
+
+// Move to the center of the parent window
+void CenterParent(HWND hWnd)
+{
+ RECT rp;
+ RECT r;
+ HWND hWndParent = GetParent(hWnd);
+ int win_x, win_y;
+ int x, y;
+
+ if (hWndParent == NULL || IsHide(hWndParent, 0) || IsIconic(hWndParent))
+ {
+ Center(hWnd);
+ return;
+ }
+
+ if (GetWindowRect(hWndParent, &rp) == false)
+ {
+ Center(hWnd);
+ return;
+ }
+
+ GetWindowRect(hWnd, &r);
+
+ win_x = r.right - r.left;
+ win_y = r.bottom - r.top;
+
+ x = (rp.right - rp.left - win_x) / 2 + rp.left;
+ y = (rp.bottom - rp.top - win_y) / 2 + rp.top;
+
+ x = MAX(x, 0);
+ y = MAX(y, 0);
+
+ SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
+}
+
+// Get the coordinates of the client region of the window
+void GetWindowClientRect(HWND hWnd, struct tagRECT *rect)
+{
+ RECT r1, r2;
+ HWND hParent;
+ WINDOWINFO info;
+ Zero(rect, sizeof(RECT));
+ // Validate arguments
+ if (hWnd == NULL || rect == NULL)
+ {
+ return;
+ }
+
+ hParent = GetParent(hWnd);
+ if (hParent == NULL)
+ {
+ return;
+ }
+
+ Zero(&info, sizeof(info));
+ info.cbSize = sizeof(WINDOWINFO);
+
+ if (GetWindowInfo(hParent, &info) == false)
+ {
+ return;
+ }
+
+ if (GetWindowRect(hWnd, &r1) == false ||
+ GetWindowRect(hParent, &r2) == false)
+ {
+ return;
+ }
+
+ rect->left = r1.left - r2.left - (info.rcClient.left - info.rcWindow.left);
+ rect->right = r1.right - r2.left - (info.rcClient.left - info.rcWindow.left);
+ rect->top = r1.top - r2.top - (info.rcClient.top - info.rcWindow.top);
+ rect->bottom = r1.bottom - r2.top - (info.rcClient.top - info.rcWindow.top);
+}
+
+// Move the window to the center
+void Center(HWND hWnd)
+{
+ RECT screen;
+ RECT win;
+ UINT x, y;
+ UINT win_x, win_y;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (SystemParametersInfo(SPI_GETWORKAREA, 0, &screen, 0) == false)
+ {
+ return;
+ }
+
+ GetWindowRect(hWnd, &win);
+ win_x = win.right - win.left;
+ win_y = win.bottom - win.top;
+
+ if (win_x < (UINT)(screen.right - screen.left))
+ {
+ x = (screen.right - screen.left - win_x) / 2;
+ }
+ else
+ {
+ x = 0;
+ }
+
+ if (win_y < (UINT)(screen.bottom - screen.top))
+ {
+ y = (screen.bottom - screen.top - win_y) / 2;
+ }
+ else
+ {
+ y = 0;
+ }
+
+ SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
+}
+
+// Move the window to the center 2
+void Center2(HWND hWnd)
+{
+ RECT screen;
+ RECT win;
+ UINT x, y;
+ UINT win_x, win_y;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (SystemParametersInfo(SPI_GETWORKAREA, 0, &screen, 0) == false)
+ {
+ return;
+ }
+
+ GetWindowRect(hWnd, &win);
+ win_x = win.right - win.left;
+ win_y = win.bottom - win.top;
+
+ if (win_x < (UINT)(screen.right - screen.left))
+ {
+ x = (screen.right - screen.left - win_x) / 2;
+ }
+ else
+ {
+ x = 0;
+ }
+
+ if (win_y < (UINT)(screen.bottom - screen.top))
+ {
+ y = (screen.bottom - screen.top - win_y) / 4;
+ }
+ else
+ {
+ y = 0;
+ }
+
+ SetWindowPos(hWnd, NULL, x, y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
+}
+
+// Get the size of the monitor
+void GetMonitorSize(UINT *width, UINT *height)
+{
+ // Validate arguments
+ if (width == NULL || height == NULL)
+ {
+ return;
+ }
+
+ *width = GetSystemMetrics(SM_CXSCREEN);
+ *height = GetSystemMetrics(SM_CYSCREEN);
+}
+
+// Format the string in the window
+void FormatText(HWND hWnd, UINT id, ...)
+{
+ va_list args;
+ wchar_t *buf;
+ UINT size;
+ wchar_t *str;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ str = GetText(hWnd, id);
+ if (str == NULL)
+ {
+ return;
+ }
+
+ size = MAX(UniStrSize(str) * 10, MAX_SIZE * 10);
+ buf = MallocEx(size, true);
+
+ va_start(args, id);
+ UniFormatArgs(buf, size, str, args);
+
+ SetText(hWnd, id, buf);
+
+ Free(buf);
+
+ Free(str);
+ va_end(args);
+}
+void FormatTextA(HWND hWnd, UINT id, ...)
+{
+ va_list args;
+ char *buf;
+ UINT size;
+ char *str;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ str = GetTextA(hWnd, id);
+ if (str == NULL)
+ {
+ return;
+ }
+
+ size = MAX(StrSize(str) * 10, MAX_SIZE * 10);
+ buf = MallocEx(size, true);
+
+ va_start(args, id);
+ FormatArgs(buf, size, str, args);
+
+ SetTextA(hWnd, id, buf);
+
+ Free(buf);
+
+ Free(str);
+ va_end(args);
+}
+
+// Set a variable-length argument string to the window
+void SetTextEx(HWND hWnd, UINT id, wchar_t *str, ...)
+{
+ va_list args;
+ wchar_t *buf;
+ UINT size;
+ // Validate arguments
+ if (str == NULL || hWnd == NULL)
+ {
+ return;
+ }
+
+ size = MAX(UniStrSize(str) * 10, MAX_SIZE * 10);
+ buf = MallocEx(size, true);
+
+ va_start(args, str);
+ UniFormatArgs(buf, size, str, args);
+
+ SetText(hWnd, id, buf);
+
+ Free(buf);
+ va_end(args);
+}
+void SetTextExA(HWND hWnd, UINT id, char *str, ...)
+{
+ va_list args;
+ char *buf;
+ UINT size;
+ // Validate arguments
+ if (str == NULL || hWnd == NULL)
+ {
+ return;
+ }
+
+ size = MAX(StrSize(str) * 10, MAX_SIZE * 10);
+ buf = MallocEx(size, true);
+
+ va_start(args, str);
+ FormatArgs(buf, size, str, args);
+
+ SetTextA(hWnd, id, buf);
+
+ Free(buf);
+ va_end(args);
+}
+
+// Show the variable-length message box
+UINT MsgBoxEx(HWND hWnd, UINT flag, wchar_t *msg, ...)
+{
+ va_list args;
+ wchar_t *buf;
+ UINT size;
+ UINT ret;
+ // Validate arguments
+ if (msg == NULL)
+ {
+ msg = L"MessageBox";
+ }
+
+ size = MAX(UniStrSize(msg) * 10, MAX_SIZE * 10);
+ buf = MallocEx(size, true);
+
+ va_start(args, msg);
+ UniFormatArgs(buf, size, msg, args);
+
+ ret = MsgBox(hWnd, flag, buf);
+ Free(buf);
+ va_end(args);
+
+ return ret;
+}
+
+// Show the message box
+UINT MsgBox(HWND hWnd, UINT flag, wchar_t *msg)
+{
+ UINT ret;
+ wchar_t *title;
+ // Validate arguments
+ if (msg == NULL)
+ {
+ msg = L"MessageBox";
+ }
+
+ if (title_bar != NULL)
+ {
+ title = CopyUniStr(title_bar);
+ }
+ else
+ {
+ title = CopyStrToUni(CEDAR_PRODUCT_STR);
+ }
+
+ if (hWnd)
+ {
+ // Raise the message box to top-level if the parent window is the top-level window
+ if (GetExStyle(hWnd, 0) & WS_EX_TOPMOST)
+ {
+ flag |= MB_SYSTEMMODAL;
+ }
+ }
+
+ ret = MessageBoxW(hWnd, msg, title, flag);
+
+ Free(title);
+
+ return ret;
+}
+
+// Create a dialog (internal)
+UINT DialogInternal(HWND hWnd, UINT id, DIALOG_PROC *proc, void *param)
+{
+ // Validate arguments
+ if (proc == NULL)
+ {
+ return 0;
+ }
+
+ if (MsIsNt() == false)
+ {
+ // Win9x
+ return (UINT)DialogBoxParam(hDll, MAKEINTRESOURCE(id), hWnd, (DLGPROC)proc, (LPARAM)param);
+ }
+ else
+ {
+ // WinNT
+ return (UINT)DialogBoxParamW(hDll, MAKEINTRESOURCEW(id), hWnd, (DLGPROC)proc, (LPARAM)param);
+ }
+}
+
+// Notice that the system configuration has been updated
+void NoticeSettingChange()
+{
+ PostMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0);
+ DoEvents(NULL);
+}
+
+// Dialog box procedure managed by WinUi
+UINT DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, bool white_color)
+{
+ void *param;
+ HWND hWndParent;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ param = (void *)lParam;
+ SetParam(hWnd, param);
+
+ // Examine whether the parent window exists
+ hWndParent = GetParent(hWnd);
+ if (hWndParent == NULL || IsShow(hWndParent, 0) == false)
+ {
+ // Place in the center if parent does not exist
+ Center(hWnd);
+ }
+
+ if (UseAlpha)
+ {
+ UINT os_type = GetOsInfo()->OsType;
+ if (OS_IS_WINDOWS_NT(os_type) && GET_KETA(os_type, 100) >= 2)
+ {
+ bool (WINAPI *_SetLayeredWindowAttributes)(HWND, COLORREF, BYTE, DWORD);
+ HINSTANCE hInst;
+
+ hInst = LoadLibrary("user32.dll");
+ _SetLayeredWindowAttributes =
+ (bool (__stdcall *)(HWND,COLORREF,BYTE,DWORD))
+ GetProcAddress(hInst, "SetLayeredWindowAttributes");
+
+ if (_SetLayeredWindowAttributes != NULL)
+ {
+ // Only available on Windows 2000 or later
+ SetExStyle(hWnd, 0, WS_EX_LAYERED);
+ _SetLayeredWindowAttributes(hWnd, 0, AlphaValue * 255 / 100, LWA_ALPHA);
+ }
+ }
+ }
+
+ break;
+
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORDLG:
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORLISTBOX:
+ case WM_CTLCOLORMSGBOX:
+ case WM_CTLCOLORSCROLLBAR:
+ case WM_CTLCOLORSTATIC:
+ if (white_color)
+ {
+ return (UINT)GetStockObject(WHITE_BRUSH);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+// Set the parameters of the dialog box
+void SetParam(HWND hWnd, void *param)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR)param);
+}
+
+// Get the parameters of the dialog box
+void *GetParam(HWND hWnd)
+{
+ void *ret;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return NULL;
+ }
+
+ ret = (void *)GetWindowLongPtr(hWnd, DWLP_USER);
+ return ret;
+}
+
+// Relieve the window from foreground
+void NoTop(HWND hWnd)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+}
+
+// Show the windows as foreground
+void Top(HWND hWnd)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+}
+
+// Hide the window
+void Hide(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (IsShow(hWnd, id))
+ {
+ ShowWindow(DlgItem(hWnd, id), SW_HIDE);
+ }
+}
+
+// Show the window
+void Show(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (IsHide(hWnd, id))
+ {
+ ShowWindow(DlgItem(hWnd, id), SW_SHOW);
+ }
+}
+
+// Change the display settings
+void SetShow(HWND hWnd, UINT id, bool b)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (b)
+ {
+ Show(hWnd, id);
+ }
+ else
+ {
+ Hide(hWnd, id);
+ }
+}
+
+// Get whether the window is shown
+bool IsShow(HWND hWnd, UINT id)
+{
+ return IsHide(hWnd, id) ? false : true;
+}
+
+// Get whether the window is hidden
+bool IsHide(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return true;
+ }
+
+ if (GetStyle(hWnd, id) & WS_VISIBLE)
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+// Remove the window style
+void RemoveExStyle(HWND hWnd, UINT id, UINT style)
+{
+ UINT old;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ old = GetExStyle(hWnd, id);
+ if ((old & style) == 0)
+ {
+ return;
+ }
+
+ SetWindowLong(DlgItem(hWnd, id), GWL_EXSTYLE, old & ~style);
+ Refresh(DlgItem(hWnd, id));
+}
+
+// Set the window style
+void SetExStyle(HWND hWnd, UINT id, UINT style)
+{
+ UINT old;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ old = GetExStyle(hWnd, id);
+ if (old & style)
+ {
+ return;
+ }
+
+ SetWindowLong(DlgItem(hWnd, id), GWL_EXSTYLE, old | style);
+ Refresh(DlgItem(hWnd, id));
+}
+
+// Get the window style
+UINT GetExStyle(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ return GetWindowLong(DlgItem(hWnd, id), GWL_EXSTYLE);
+}
+
+// Remove the window style
+void RemoveStyle(HWND hWnd, UINT id, UINT style)
+{
+ UINT old;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ old = GetStyle(hWnd, id);
+ if ((old & style) == 0)
+ {
+ return;
+ }
+
+ SetWindowLong(DlgItem(hWnd, id), GWL_STYLE, old & ~style);
+ Refresh(DlgItem(hWnd, id));
+}
+
+// Set the window style
+void SetStyle(HWND hWnd, UINT id, UINT style)
+{
+ UINT old;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ old = GetStyle(hWnd, id);
+ if (old & style)
+ {
+ return;
+ }
+
+ SetWindowLong(DlgItem(hWnd, id), GWL_STYLE, old | style);
+ Refresh(DlgItem(hWnd, id));
+}
+
+// Get the window style
+UINT GetStyle(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ return GetWindowLong(DlgItem(hWnd, id), GWL_STYLE);
+}
+
+// Get the number of bytes of the text
+UINT GetTextSize(HWND hWnd, UINT id, bool unicode)
+{
+ UINT len;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ len = GetTextLen(hWnd, id, unicode);
+
+ return len + (unicode ? 2 : 1);
+}
+
+// Get the number of characters in the text
+UINT GetTextLen(HWND hWnd, UINT id, bool unicode)
+{
+ wchar_t *s;
+ UINT ret;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ s = GetText(hWnd, id);
+ if (s == NULL)
+ {
+ return 0;
+ }
+
+ if (unicode)
+ {
+ ret = UniStrLen(s);
+ }
+ else
+ {
+ char *tmp = CopyUniToStr(s);
+ ret = StrLen(tmp);
+ Free(tmp);
+ }
+
+ Free(s);
+
+ return ret;
+}
+
+// Check whether the text is blank
+bool IsEmpty(HWND hWnd, UINT id)
+{
+ bool ret;
+ wchar_t *s;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return true;
+ }
+
+ s = GetText(hWnd, id);
+
+ UniTrim(s);
+ if (UniStrLen(s) == 0)
+ {
+ ret = true;
+ }
+ else
+ {
+ ret = false;
+ }
+
+ Free(s);
+
+ return ret;
+}
+
+// Get the window class
+wchar_t *GetClass(HWND hWnd, UINT id)
+{
+ wchar_t tmp[MAX_SIZE];
+
+ if (MsIsNt() == false)
+ {
+ wchar_t *ret;
+ char *s;
+ s = GetClassA(hWnd, id);
+ ret = CopyStrToUni(s);
+ Free(s);
+ return ret;
+ }
+
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return CopyUniStr(L"");
+ }
+
+ GetClassNameW(DlgItem(hWnd, id), tmp, sizeof(tmp));
+
+ return UniCopyStr(tmp);
+}
+char *GetClassA(HWND hWnd, UINT id)
+{
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return CopyStr("");
+ }
+
+ GetClassName(DlgItem(hWnd, id), tmp, sizeof(tmp));
+
+ return CopyStr(tmp);
+}
+
+// Transmit a message to the control
+UINT SendMsg(HWND hWnd, UINT id, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ if (MsIsNt())
+ {
+ return (UINT)SendMessageW(DlgItem(hWnd, id), msg, wParam, lParam);
+ }
+ else
+ {
+ return (UINT)SendMessageA(DlgItem(hWnd, id), msg, wParam, lParam);
+ }
+}
+
+// Move the cursor to the right edge of the text in the EDIT
+void SetCursorOnRight(HWND hWnd, UINT id)
+{
+ wchar_t *class_name;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ class_name = GetClass(hWnd, id);
+
+ if (class_name != NULL)
+ {
+ if (UniStrCmpi(class_name, L"edit") == 0)
+ {
+ wchar_t *str = GetText(hWnd, id);
+
+ if (str != NULL)
+ {
+ UINT len = UniStrLen(str);
+
+ SendMsg(hWnd, id, EM_SETSEL, len, len);
+
+ Free(str);
+ }
+ }
+ Free(class_name);
+ }
+}
+
+// Select entire the text in the EDIT
+void SelectEdit(HWND hWnd, UINT id)
+{
+ wchar_t *class_name;
+
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ class_name = GetClass(hWnd, id);
+
+ if (class_name != NULL)
+ {
+ if (UniStrCmpi(class_name, L"edit") == 0)
+ {
+ SendMsg(hWnd, id, EM_SETSEL, 0, -1);
+ }
+ Free(class_name);
+ }
+}
+
+// Deselect the text of EDIT
+void UnselectEdit(HWND hWnd, UINT id)
+{
+ wchar_t *class_name;
+
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ class_name = GetClass(hWnd, id);
+
+ if (class_name != NULL)
+ {
+ if (UniStrCmpi(class_name, L"edit") == 0)
+ {
+ SendMsg(hWnd, id, EM_SETSEL, -1, 0);
+ }
+ Free(class_name);
+ }
+}
+
+// Select all by setting the focus to the EDIT
+void FocusEx(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (IsEnable(hWnd, id) == false || IsShow(hWnd, id) == false)
+ {
+ return;
+ }
+
+ SelectEdit(hWnd, id);
+
+ Focus(hWnd, id);
+}
+
+// Get whether the specified window has focus
+bool IsFocus(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return false;
+ }
+
+ if (GetFocus() == DlgItem(hWnd, id))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Set the focus
+void Focus(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (IsEnable(hWnd, id) == false || IsShow(hWnd, id) == false)
+ {
+ return;
+ }
+
+ SetFocus(DlgItem(hWnd, id));
+}
+
+// Set the value of the int type
+void SetInt(HWND hWnd, UINT id, UINT value)
+{
+ wchar_t tmp[MAX_SIZE];
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ UniToStru(tmp, value);
+ SetText(hWnd, id, tmp);
+}
+void SetIntEx(HWND hWnd, UINT id, UINT value)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (value == 0)
+ {
+ // Leave blank in the case of 0
+ SetText(hWnd, id, L"");
+ }
+ else
+ {
+ SetInt(hWnd, id, value);
+ }
+}
+
+// Get the value of the int type
+UINT GetInt(HWND hWnd, UINT id)
+{
+ wchar_t *s;
+ UINT ret;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return 0;
+ }
+
+ s = GetText(hWnd, id);
+ if (s == NULL)
+ {
+ return 0;
+ }
+
+ ret = UniToInt(s);
+ Free(s);
+
+ return ret;
+}
+
+// Update the window appearance
+void Refresh(HWND hWnd)
+{
+ HWND parent;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ DoEvents(hWnd);
+ UpdateWindow(hWnd);
+ DoEvents(hWnd);
+
+ parent = GetParent(hWnd);
+ if (parent != NULL)
+ {
+ Refresh(parent);
+ }
+}
+
+// Handle the event
+void DoEvents(HWND hWnd)
+{
+ MSG msg;
+
+ if (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ UpdateWindow(hWnd);
+
+ if (hWnd)
+ {
+ DoEvents(NULL);
+ }
+}
+
+// Close the window
+void Close(HWND hWnd)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ SendMessage(hWnd, WM_CLOSE, 0, 0);
+}
+
+// Disable the window
+void Disable(HWND hWnd, UINT id)
+{
+ SetEnable(hWnd, id, false);
+}
+
+// Enable the window
+void Enable(HWND hWnd, UINT id)
+{
+ SetEnable(hWnd, id, true);
+}
+
+// Set the enabled state of a window
+void SetEnable(HWND hWnd, UINT id, bool b)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ if (b == false)
+ {
+ if (IsEnable(hWnd, id))
+ {
+ if (id != 0 && IsFocus(hWnd, id))
+ {
+ Focus(hWnd, IDCANCEL);
+ Focus(hWnd, IDOK);
+ }
+ EnableWindow(DlgItem(hWnd, id), false);
+ Refresh(DlgItem(hWnd, id));
+ }
+ }
+ else
+ {
+ if (IsDisable(hWnd, id))
+ {
+ EnableWindow(DlgItem(hWnd, id), true);
+ Refresh(DlgItem(hWnd, id));
+ }
+ }
+}
+
+// Examine whether the window is disabled
+bool IsDisable(HWND hWnd, UINT id)
+{
+ return IsEnable(hWnd, id) ? false : true;
+}
+
+// Examine whether the window is enabled
+bool IsEnable(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return false;
+ }
+
+ return IsWindowEnabled(DlgItem(hWnd, id));
+}
+
+static LOCK *winui_debug_lock = NULL;
+
+// Initialize the debug function
+void WinUiDebugInit()
+{
+ winui_debug_lock = NewLock();
+}
+
+// Release the debug function
+void WinUiDebugFree()
+{
+ DeleteLock(winui_debug_lock);
+}
+
+// Write a string to the debug file
+void WinUiDebug(wchar_t *str)
+{
+ wchar_t tmp[1024];
+ char dtstr[256];
+ char *buf;
+ wchar_t exename[MAX_PATH];
+ UINT tid;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return;
+ }
+
+ tid = GetCurrentThreadId();
+
+ GetExeNameW(exename, sizeof(exename));
+ GetFileNameFromFilePathW(exename, sizeof(exename), exename);
+
+ GetDateTimeStrMilli64(dtstr, sizeof(dtstr), LocalTime64());
+
+ UniFormat(tmp, sizeof(tmp), L"[%S] (%s:%u) %s\r\n", dtstr, exename, tid, str);
+
+ buf = CopyUniToUtf(tmp);
+
+ Lock(winui_debug_lock);
+ {
+ IO *o = FileOpenEx(WINUI_DEBUG_TEXT, true, true);
+ if (o == NULL)
+ {
+ o = FileCreate(WINUI_DEBUG_TEXT);
+ }
+
+ if (o != NULL)
+ {
+ UINT size = FileSize(o);
+
+ FileSeek(o, FILE_BEGIN, size);
+
+ FileWrite(o, buf, StrLen(buf));
+ FileFlush(o);
+
+ FileClose(o);
+ }
+ }
+ Unlock(winui_debug_lock);
+
+ Free(buf);
+}
+
+// If the control protrude by large font size, adjust into appropriate size
+void AdjustFontSize(HWND hWnd, UINT id)
+{
+ char class_name[MAX_PATH];
+ UINT style;
+ UINT format = 0;
+ HFONT current_font;
+ FONT font;
+ wchar_t *text;
+ RECT rect;
+ UINT width, height;
+ HFONT new_font = NULL;
+ UINT old_font_size;
+ UINT style1;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return;
+ }
+
+ hWnd = DlgItem(hWnd, id);
+
+ if (GetClassNameA(hWnd, class_name, sizeof(class_name)) == 0)
+ {
+ return;
+ }
+
+ if (StrCmpi(class_name, "static") != 0)
+ {
+ return;
+ }
+
+ style = GetStyle(hWnd, 0);
+
+ if ((style & SS_ENDELLIPSIS) || (style & SS_PATHELLIPSIS))
+ {
+ return;
+ }
+
+ style1 = style & 0x0F;
+
+ // Create a format for DrawText
+ if (style1 == SS_RIGHT)
+ {
+ // Right justification
+ format |= DT_RIGHT;
+ }
+ else if (style1 == SS_CENTER)
+ {
+ // Center justification
+ format |= DT_CENTER;
+ }
+ else if (style1 == SS_LEFT)
+ {
+ // Left justification
+ format |= DT_LEFT;
+ }
+ else
+ {
+ // Others
+ return;
+ }
+
+ if (style & DT_NOPREFIX)
+ {
+ // Without prefix
+ format |= DT_NOPREFIX;
+ }
+
+ // Get the font parameters currently set
+ current_font = (HFONT)SendMessageA(hWnd, WM_GETFONT, 0, 0);
+ if (current_font == NULL)
+ {
+ return;
+ }
+
+ Zero(&font, sizeof(font));
+ if (GetFontParam(current_font, &font) == false)
+ {
+ return;
+ }
+
+ // Get the size of the static area
+ Zero(&rect, sizeof(rect));
+ if (GetWindowRect(hWnd, &rect) == false)
+ {
+ return;
+ }
+
+ // Get the text that is currently set
+ text = GetText(hWnd, 0);
+ if (text == NULL)
+ {
+ return;
+ }
+
+ if (IsEmptyUniStr(text))
+ {
+ Free(text);
+ return;
+ }
+
+ width = GET_ABS(rect.right - rect.left);
+ height = GET_ABS(rect.bottom - rect.top);
+
+ new_font = NULL;
+ old_font_size = font.Size;
+
+ // Try to gradually reduce the font size until drawing succeeds
+ while (font.Size != 0)
+ {
+ // Drawing test
+ bool aborted = false;
+
+ if (IsFontFitInRect(&font, width, height, text, format, &aborted))
+ {
+ // Drawing success
+ if (old_font_size != font.Size)
+ {
+ // Font size is changed
+ new_font = GetFont(font.Name, font.Size, font.Bold, font.Italic, font.UnderLine, font.StrikeOut);
+ }
+ break;
+ }
+ else
+ {
+ if (aborted)
+ {
+ // Fatal error
+ break;
+ }
+ }
+
+ font.Size--;
+
+ if (font.Size == 1)
+ {
+ // Not supposed to become a font size like this. Fatal error
+ break;
+ }
+ }
+
+ Free(text);
+
+ if (new_font != NULL)
+ {
+ // Change the font size
+ SetFontEx(hWnd, 0, new_font, true);
+ }
+}
+
+// Check whether the specified string can be drawn in the specified area with the specified font
+bool IsFontFitInRect(struct FONT *f, UINT width, UINT height, wchar_t *text, UINT format, bool *aborted)
+{
+ RECT r;
+ int i;
+ bool dummy_bool;
+ UINT new_height;
+ HFONT hCreatedFont, hOldFont;
+ // Validate arguments
+ if (f == NULL || text == NULL)
+ {
+ return false;
+ }
+ if (aborted == NULL)
+ {
+ aborted = &dummy_bool;
+ }
+
+ format |= DT_CALCRECT | DT_WORDBREAK;
+
+ *aborted = false;
+
+ // Create a font
+ hCreatedFont = GetFont(f->Name, f->Size, f->Bold, f->Italic, f->UnderLine, f->StrikeOut);
+ if (hCreatedFont == NULL)
+ {
+ *aborted = true;
+ return false;
+ }
+
+ Lock(lock_common_dc);
+ {
+ hOldFont = SelectObject(hCommonDC, hCreatedFont);
+
+ Zero(&r, sizeof(r));
+ r.left = r.top = 0;
+ r.right = width;
+ r.bottom = height;
+
+ if (MsIsNt())
+ {
+ i = DrawTextW(hCommonDC, text, -1, &r, format);
+ }
+ else
+ {
+ char *a = CopyUniToStr(text);
+
+ i = DrawTextA(hCommonDC, a, -1, &r, format);
+
+ Free(a);
+ }
+
+ SelectObject(hCommonDC, hOldFont);
+ }
+ Unlock(lock_common_dc);
+
+ if (i == 0)
+ {
+ *aborted = true;
+ return false;
+ }
+
+ new_height = GET_ABS(r.bottom - r.top);
+
+ if (new_height > height)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+// Set a text string
+void SetText(HWND hWnd, UINT id, wchar_t *str)
+{
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return;
+ }
+
+ SetTextInner(hWnd, id, str);
+}
+void SetTextInner(HWND hWnd, UINT id, wchar_t *str)
+{
+ wchar_t *old;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return;
+ }
+
+ // Get the old string
+ old = GetText(hWnd, id);
+ if (UniStrCmp(str, old) == 0)
+ {
+ // Identity
+ Free(old);
+ return;
+ }
+
+ Free(old);
+
+ if (MsIsNt())
+ {
+ SetWindowTextW(DlgItem(hWnd, id), str);
+ }
+ else
+ {
+ char *tmp = CopyUniToStr(str);
+
+ if (MsIsNt() == false && StrLen(tmp) >= 32000)
+ {
+ // Truncate to less than 32k
+ tmp[32000] = 0;
+ }
+
+ SetWindowTextA(DlgItem(hWnd, id), tmp);
+ Free(tmp);
+ }
+
+ AdjustFontSize(hWnd, id);
+
+ if (id != 0)
+ {
+ Refresh(DlgItem(hWnd, id));
+ }
+}
+void SetTextA(HWND hWnd, UINT id, char *str)
+{
+ wchar_t *s;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return;
+ }
+
+ s = CopyStrToUni(str);
+ if (s == NULL)
+ {
+ return;
+ }
+
+ SetText(hWnd, id, s);
+
+ Free(s);
+}
+
+// Get the text string to the buffer
+bool GetTxt(HWND hWnd, UINT id, wchar_t *str, UINT size)
+{
+ wchar_t *s;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ s = GetText(hWnd, id);
+ if (s == NULL)
+ {
+ UniStrCpy(str, size, L"");
+ return false;
+ }
+
+ UniStrCpy(str, size, s);
+ Free(s);
+
+ return true;
+}
+bool GetTxtA(HWND hWnd, UINT id, char *str, UINT size)
+{
+ char *s;
+ // Validate arguments
+ if (hWnd == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ s = GetTextA(hWnd, id);
+ if (s == NULL)
+ {
+ StrCpy(str, size, "");
+ return false;
+ }
+
+ StrCpy(str, size, s);
+ Free(s);
+
+ return true;
+}
+
+// Get the text string
+wchar_t *GetText(HWND hWnd, UINT id)
+{
+ wchar_t *ret;
+ UINT size, len;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return NULL;
+ }
+
+ if (MsIsNt() == false)
+ {
+ char *s = GetTextA(hWnd, id);
+ ret = CopyStrToUni(s);
+ Free(s);
+
+ return ret;
+ }
+
+ len = GetWindowTextLengthW(DlgItem(hWnd, id));
+ if (len == 0)
+ {
+ return CopyUniStr(L"");
+ }
+
+ size = (len + 1) * 2;
+ ret = ZeroMallocEx(size, true);
+
+ GetWindowTextW(DlgItem(hWnd, id), ret, size);
+
+ return ret;
+}
+char *GetTextA(HWND hWnd, UINT id)
+{
+ char *ret;
+ UINT size, len;
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return NULL;
+ }
+
+ len = GetWindowTextLengthA(DlgItem(hWnd, id));
+ if (len == 0)
+ {
+ return CopyStr("");
+ }
+
+ size = len + 1;
+ ret = ZeroMallocEx(size, true);
+
+ GetWindowTextA(DlgItem(hWnd, id), ret, size);
+
+ return ret;
+}
+
+// Get the item in the dialog
+HWND DlgItem(HWND hWnd, UINT id)
+{
+ // Validate arguments
+ if (hWnd == NULL)
+ {
+ return NULL;
+ }
+
+ if (id == 0)
+ {
+ return hWnd;
+ }
+ else
+ {
+ return GetDlgItem(hWnd, id);
+ }
+}
+
+// Set the title
+void SetWinUiTitle(wchar_t *title)
+{
+ // Validate arguments
+ if (title == NULL)
+ {
+ return;
+ }
+
+ Free(title_bar);
+ title_bar = CopyUniStr(title);
+}
+
+// Initialize the WinUi
+void InitWinUi(wchar_t *software_name, char *font, UINT fontsize)
+{
+ if (tls_current_wizard == 0xffffffff)
+ {
+ tls_current_wizard = TlsAlloc();
+ }
+
+ if ((init_winui_counter++) != 0)
+ {
+ return;
+ }
+
+ if (hDll != NULL)
+ {
+ return;
+ }
+
+ WinUiDebugInit();
+
+ if (MayaquaIsMinimalMode() == false)
+ {
+ if (Is64())
+ {
+ hDll = MsLoadLibraryAsDataFile(MsGetPenCoreDllFileName());
+ }
+ else
+ {
+ hDll = MsLoadLibrary(MsGetPenCoreDllFileName());
+ }
+
+ if (hDll == NULL)
+ {
+ Alert(PENCORE_DLL_NAME " not found. "CEDAR_PRODUCT_STR " VPN couldn't start.\r\n\r\n"
+ "Please reinstall all files with "CEDAR_PRODUCT_STR " VPN Installer.",
+ NULL);
+ exit(0);
+ }
+ }
+ else
+ {
+ hDll = LoadLibrary(MsGetExeFileName());
+
+ if (hDll == NULL)
+ {
+ Alert("MsLoadLibrary() Error.",
+ NULL);
+ exit(0);
+ }
+ }
+
+ if (software_name != NULL)
+ {
+ title_bar = CopyUniStr(software_name);
+ }
+ else
+ {
+ title_bar = CopyUniStr(CEDAR_PRODUCT_STR_W L" VPN");
+ }
+
+ if (font != NULL)
+ {
+ font_name = CopyStr(font);
+ }
+ else
+ {
+ font_name = CopyStr(_SS("DEFAULT_FONT"));
+ }
+
+ if (MsIsWindows7())
+ {
+ char *win7_font = _SS("DEFAULT_FONT_WIN7");
+
+ if (IsEmptyStr(win7_font) == false)
+ {
+ Free(font_name);
+ font_name = CopyStr(win7_font);
+ }
+
+ if (GetTextScalingFactor() >= 1.44)
+ {
+ // Use a substitute font in the case of high-DPI in Windows 7 and later
+ char *alternative_font = _SS("DEFAULT_FONT_HIGHDPI");
+
+ if (IsEmptyStr(alternative_font) == false)
+ {
+ Free(font_name);
+ font_name = CopyStr(alternative_font);
+ }
+ }
+ }
+
+ if (fontsize != 0)
+ {
+ font_size = fontsize;
+ }
+ else
+ {
+ font_size = _II("DEFAULT_FONT_SIZE");
+ if (font_size == 0)
+ {
+ font_size = 9;
+ }
+ }
+
+ lock_common_dc = NewLock();
+
+ hCommonDC = CreateCompatibleDC(NULL);
+
+ InitIconCache();
+
+ InitFont();
+
+ InitImageList();
+}
+
+// Release the WinUi
+void FreeWinUi()
+{
+ if ((--init_winui_counter) != 0)
+ {
+ return;
+ }
+
+ if (hDll == NULL)
+ {
+ return;
+ }
+
+ FreeImageList();
+
+ FreeFont();
+
+ FreeIconCache();
+
+ FreeLibrary(hDll);
+ hDll = NULL;
+
+ Free(title_bar);
+ title_bar = NULL;
+
+ Free(font_name);
+ font_name = NULL;
+
+ WinUiDebugFree();
+
+ if (hCommonDC != NULL)
+ {
+ DeleteDC(hCommonDC);
+ hCommonDC = NULL;
+ }
+
+ DeleteLock(lock_common_dc);
+ lock_common_dc = NULL;
+}
+
+#endif // WIN32
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/WinUi.h b/src/Cedar/WinUi.h
new file mode 100644
index 00000000..06bd5f77
--- /dev/null
+++ b/src/Cedar/WinUi.h
@@ -0,0 +1,906 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// WinUi.h
+// User interface code for Win32
+
+#ifdef OS_WIN32
+
+#define WINUI_DEBUG_TEXT "@winui_debug.txt"
+
+#define LV_INSERT_RESET_ALL_ITEM_MIN 500
+
+#define WINUI_PASSWORD_NULL_USERNAME "NULL"
+
+#define WINUI_DEFAULT_DIALOG_UNIT_X 7
+#define WINUI_DEFAULT_DIALOG_UNIT_Y 12
+
+// Make available the types for Windows even if windows.h is not included
+#ifndef _WINDEF_
+
+typedef void *HWND;
+typedef void *HFONT;
+typedef void *HICON;
+typedef void *HMENU;
+typedef UINT_PTR WPARAM;
+typedef LONG_PTR LPARAM;
+typedef void *HINSTANCE;
+
+#endif // _WINDEF_
+
+
+// Constants
+#define FREE_REGKEY "Software\\" GC_REG_COMPANY_NAME "\\" CEDAR_PRODUCT_STR " VPN Client\\Free Edition Info"
+#define ONCE_MSG_REGKEY "Software\\" GC_REG_COMPANY_NAME "\\" CEDAR_PRODUCT_STR " VPN\\Common"
+#define ONCE_MSG_REGVALUE "HideMessage_%u"
+
+#define NICINFO_AUTOCLOSE_TIME_1 (20 * 1000)
+#define NICINFO_AUTOCLOSE_TIME_2 1800
+
+extern bool UseAlpha;
+extern UINT AlphaValue;
+
+
+// Minimum font size
+#define WINUI_MIN_FONTSIZE 5
+
+
+// Macro
+#define DIALOG DIALOGEX(false)
+#define DIALOG_WHITE DIALOGEX(true)
+#define DIALOGEX(white) \
+ void *param = GetParam(hWnd); \
+ { \
+ UINT ret; \
+ ret = DlgProc(hWnd, msg, wParam, lParam, white); \
+ if (ret != 0) return ret; \
+ }
+
+typedef UINT (__stdcall DIALOG_PROC)(HWND, UINT, WPARAM, LPARAM);
+
+typedef UINT (WINUI_DIALOG_PROC)(HWND, UINT, WPARAM, LPARAM, void *);
+
+typedef UINT (WINUI_WIZARD_PROC)(HWND, UINT, WPARAM, LPARAM, WIZARD *, WIZARD_PAGE *, void *);
+
+
+// Special message to be used for this wizard
+#define WM_WIZ_BASE (WM_APP + 201)
+#define WM_WIZ_NEXT (WM_WIZ_BASE + 0)
+#define WM_WIZ_BACK (WM_WIZ_BASE + 1)
+#define WM_WIZ_CLOSE (WM_WIZ_BASE + 2)
+#define WM_WIZ_SHOW (WM_WIZ_BASE + 3)
+#define WM_WIZ_HIDE (WM_WIZ_BASE + 4)
+
+
+// Secure operation contents
+#define WINUI_SECURE_ENUM_OBJECTS 1 // Enumerate objects
+#define WINUI_SECURE_WRITE_DATA 2 // Write the data
+#define WINUI_SECURE_READ_DATA 3 // Read the data
+#define WINUI_SECURE_WRITE_CERT 4 // Write the certificate
+#define WINUI_SECURE_READ_CERT 5 // Read the certificate
+#define WINUI_SECURE_WRITE_KEY 6 // Write the secret key
+#define WINUI_SECURE_SIGN_WITH_KEY 7 // Signature by the private key
+#define WINUI_SECURE_DELETE_OBJECT 8 // Delete the object
+#define WINUI_SECURE_DELETE_CERT 9 // Delete the certificate
+#define WINUI_SECURE_DELETE_KEY 10 // Delete the private key
+#define WINUI_SECURE_DELETE_DATA 11 // Delete the Data
+
+// Secure operation structure
+typedef struct WINUI_SECURE_BATCH
+{
+ UINT Type; // Type of operation
+ char *Name; // Name
+ bool Private; // Private mode
+ BUF *InputData; // Input data
+ BUF *OutputData; // Output data
+ X *InputX; // Input certificate
+ X *OutputX; // Output certificate
+ K *InputK; // Input secret key
+ LIST *EnumList; // Enumerated list
+ UCHAR OutputSign[128]; // Output signature
+ bool Succeed; // Success flag
+} WINUI_SECURE_BATCH;
+
+// Status window
+typedef struct STATUS_WINDOW
+{
+ HWND hWnd;
+ THREAD *Thread;
+} STATUS_WINDOW;
+
+// Batch processing items
+typedef struct LVB_ITEM
+{
+ UINT NumStrings; // The number of strings
+ wchar_t **Strings; // String buffer
+ UINT Image; // Image number
+ void *Param; // Parameters
+} LVB_ITEM;
+
+// LV insertion batch process
+typedef struct LVB
+{
+ LIST *ItemList; // Item list
+} LVB;
+
+
+#ifdef CreateWindow
+
+// Internal code
+
+// Font
+typedef struct FONT
+{
+ UINT Size; // Size
+ bool Bold; // Bold type
+ bool Italic; // Italic type
+ bool UnderLine; // Underline
+ bool StrikeOut; // Strike through
+ char *Name; // Font name
+ HFONT hFont; // Font
+ UINT x, y; // Font size
+} FONT;
+
+// Font cache list
+static LIST *font_list = NULL;
+
+// Dialog related
+typedef struct DIALOG_PARAM
+{
+ bool white;
+ void *param;
+ WINUI_DIALOG_PROC *proc;
+ bool meiryo;
+ LIST *BitmapList;
+
+ WIZARD *wizard;
+ WIZARD_PAGE *wizard_page;
+ WINUI_WIZARD_PROC *wizard_proc;
+} DIALOG_PARAM;
+
+// Secure device window related
+typedef struct SECURE_DEVICE_WINDOW
+{
+ WINUI_SECURE_BATCH *batch;
+ UINT num_batch;
+ UINT device_id;
+ struct SECURE_DEVICE_THREAD *p;
+ char *default_pin;
+ UINT BitmapId;
+} SECURE_DEVICE_WINDOW;
+
+// Thread
+typedef struct SECURE_DEVICE_THREAD
+{
+ SECURE_DEVICE_WINDOW *w;
+ HWND hWnd;
+ bool Succeed;
+ wchar_t *ErrorMessage;
+ char *pin;
+} SECURE_DEVICE_THREAD;
+
+void StartSecureDevice(HWND hWnd, SECURE_DEVICE_WINDOW *w);
+
+// Passphrase
+typedef struct PASSPHRASE_DLG
+{
+ char pass[MAX_SIZE];
+ BUF *buf;
+ bool p12;
+} PASSPHRASE_DLG;
+
+void PassphraseDlgProcCommand(HWND hWnd, PASSPHRASE_DLG *p);
+
+// Status window
+typedef struct STATUS_WINDOW_PARAM
+{
+ HWND hWnd;
+ SOCK *Sock;
+ THREAD *Thread;
+ wchar_t AccountName[MAX_ACCOUNT_NAME_LEN + 1];
+} STATUS_WINDOW_PARAM;
+
+// Certificate display dialog
+typedef struct CERT_DLG
+{
+ X *x, *issuer_x;
+ bool ManagerMode;
+} CERT_DLG;
+
+
+typedef struct IMAGELIST_ICON
+{
+ UINT id;
+ HICON hSmallImage;
+ HICON hLargeImage;
+ UINT Index;
+} IMAGELIST_ICON;
+
+typedef struct SEARCH_WINDOW_PARAM
+{
+ wchar_t *caption;
+ HWND hWndFound;
+} SEARCH_WINDOW_PARAM;
+
+// Remote connection screen setting
+typedef struct WINUI_REMOTE
+{
+ bool flag1;
+ char *RegKeyName; // Registry key name
+ UINT Icon; // Icon
+ wchar_t *Caption; // Caption
+ wchar_t *Title; // Title
+ char *Hostname; // Host name
+ char *DefaultHostname; // Default host name
+ LIST *CandidateList; // Candidate list
+} WINUI_REMOTE;
+
+void InitImageList();
+void FreeImageList();
+IMAGELIST_ICON *LoadIconForImageList(UINT id);
+int CompareImageListIcon(void *p1, void *p2);
+BOOL CALLBACK EnumResNameProc(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam);
+void PrintCertInfo(HWND hWnd, CERT_DLG *p);
+void CertDlgUpdate(HWND hWnd, CERT_DLG *p);
+bool CALLBACK SearchWindowEnumProc(HWND hWnd, LPARAM lParam);
+UINT RemoteDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void RemoteDlgInit(HWND hWnd, WINUI_REMOTE *r);
+void RemoteDlgRefresh(HWND hWnd, WINUI_REMOTE *r);
+void RemoteDlgOnOk(HWND hWnd, WINUI_REMOTE *r);
+int CALLBACK LvSortProc(LPARAM param1, LPARAM param2, LPARAM sort_param);
+
+// Icon cache
+typedef struct ICON_CACHE
+{
+ UINT id;
+ bool small_icon;
+ HICON hIcon;
+} ICON_CACHE;
+
+static LIST *icon_cache_list = NULL;
+
+// Sort related
+typedef struct WINUI_LV_SORT
+{
+ HWND hWnd;
+ UINT id;
+ UINT subitem;
+ bool desc;
+ bool numeric;
+} WINUI_LV_SORT;
+
+// Version information
+typedef struct WINUI_ABOUT
+{
+ CEDAR *Cedar;
+ wchar_t *ProductName;
+ UINT Bitmap;
+ WINUI_UPDATE *Update;
+} WINUI_ABOUT;
+
+UINT AboutDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void AboutDlgInit(HWND hWnd, WINUI_ABOUT *a);
+
+typedef struct WIN9X_REBOOT_DLG
+{
+ UINT64 StartTime;
+ UINT TotalTime;
+} WIN9X_REBOOT_DLG;
+
+#define LED_WIDTH 96
+#define LED_HEIGHT 16
+#define LED_FORCE_UPDATE 60000
+
+// LED
+struct LED
+{
+ HDC hDC;
+ HBITMAP hBM;
+ void *Buf;
+ UCHAR px[LED_WIDTH][LED_HEIGHT];
+ bool Updated;
+ UINT64 LastUpdated;
+};
+
+void LedDrawString(LED *d, char *str, HFONT f);
+void LedDrawRect(LED *d);
+void LedMainDraw(LED *d, HANDLE h);
+void LedSpecial(LED *d, HANDLE h, UINT n);
+
+
+// STRING
+typedef struct STRING_DLG
+{
+ wchar_t String[MAX_SIZE];
+ wchar_t *Title;
+ wchar_t *Info;
+ UINT Icon;
+ bool AllowEmpty;
+ bool AllowUnsafe;
+} STRING_DLG;
+
+void StringDlgInit(HWND hWnd, STRING_DLG *s);
+void StringDlgUpdate(HWND hWnd, STRING_DLG *s);
+
+// PIN code is cached for five minutes
+#define WINUI_SECUREDEVICE_PIN_CACHE_TIME (5 * 60 * 1000)
+extern char cached_pin_code[MAX_SIZE];
+extern UINT64 cached_pin_code_expires;
+
+// TCP connection dialog related
+typedef struct WINCONNECT_DLG_DATA
+{
+ wchar_t *caption;
+ wchar_t *info;
+ UINT icon_id;
+ UINT timeout;
+ char *hostname;
+ UINT port;
+ bool cancel;
+ SOCK *ret_sock;
+ THREAD *thread;
+ HWND hWnd;
+ char nat_t_svc_name[MAX_SIZE];
+ UINT nat_t_error_code;
+ bool try_start_ssl;
+ bool ssl_no_tls;
+} WINCONNECT_DLG_DATA;
+
+HBITMAP ResizeBitmap(HBITMAP hSrc, UINT src_x, UINT src_y, UINT dst_x, UINT dst_y);
+
+#endif // WINUI_C
+
+// Kakushi
+typedef struct KAKUSHI
+{
+ HWND hWnd;
+ THREAD *Thread;
+ volatile bool Halt;
+ UINT64 StartTick, Span;
+} KAKUSHI;
+
+// The information screen about the free version
+typedef struct FREEINFO
+{
+ char ServerName[MAX_SERVER_STR_LEN + 1];
+ HWND hWnd;
+ THREAD *Thread;
+ EVENT *Event;
+} FREEINFO;
+
+// Message
+typedef struct ONCEMSG_DLG
+{
+ UINT Icon;
+ wchar_t *Title;
+ wchar_t *Message;
+ bool ShowCheckbox;
+ bool Checked;
+ UINT MessageHash;
+ bool *halt;
+} ONCEMSG_DLG;
+
+// Definition of bad process
+typedef struct BAD_PROCESS
+{
+ char *ExeName;
+ char *Title;
+} BAD_PROCESS;
+
+#ifdef WINUI_C
+
+// Process name list of incompatible anti-virus software
+static BAD_PROCESS bad_processes[] =
+{
+ {"nod32krn.exe", "NOD32 Antivirus",},
+};
+
+static UINT num_bad_processes = sizeof(bad_processes) / sizeof(bad_processes[0]);
+
+#endif // WINUI_C
+
+// Page in the wizard
+struct WIZARD_PAGE
+{
+ UINT Id;
+ UINT Index;
+ WINUI_WIZARD_PROC *Proc;
+ wchar_t *Title;
+ WIZARD *Wizard;
+
+ struct DIALOG_PARAM *DialogParam;
+ HWND hWndPage;
+ bool EnableNext;
+ bool EnableBack;
+ bool EnableClose;
+ bool IsFinish;
+};
+
+// Wizard
+struct WIZARD
+{
+ UINT Icon;
+ HWND hWndParent;
+ LIST *Pages;
+ void *Param;
+ UINT Bitmap;
+ wchar_t *Caption;
+ wchar_t *CloseConfirmMsg;
+ bool IsAreoStyle;
+
+ HWND hWndWizard;
+ bool SetCenterFlag;
+ bool ReplaceWindowProcFlag;
+ void *OriginalWindowProc;
+};
+
+// Update notification
+struct WINUI_UPDATE
+{
+ wchar_t SoftwareTitle[MAX_SIZE];
+ char SoftwareName[MAX_SIZE];
+ UINT64 CurrentDate;
+ UINT CurrentBuild;
+ UINT CurrentVer;
+ char ClientId[128];
+ char RegKey[MAX_PATH];
+ UPDATE_CLIENT *UpdateClient;
+};
+
+// Update notification parameters
+struct WINUI_UPDATE_DLG_PARAM
+{
+ WINUI_UPDATE *Update;
+ UINT LatestBuild;
+ UINT64 LatestDate;
+ char *LatestVer;
+ char *Url;
+ volatile bool *halt_flag;
+ bool IsInConfigDialog;
+};
+
+// Registry key to save the update notification settings
+#define WINUI_UPDATE_REGKEY "Software\\" GC_REG_COMPANY_NAME "\\" CEDAR_PRODUCT_STR " VPN\\Check Update\\%s"
+
+
+// Function prototype
+void InitWinUi(wchar_t *software_name, char *font, UINT fontsize);
+void SetWinUiTitle(wchar_t *title);
+void FreeWinUi();
+
+WINUI_UPDATE *InitUpdateUi(wchar_t *title, char *name, char *family_name, UINT64 current_date, UINT current_build, UINT current_ver, char *client_id);
+void FreeUpdateUi(WINUI_UPDATE *u);
+void LoadUpdateUiSetting(WINUI_UPDATE *u, UPDATE_CLIENT_SETTING *s);
+void SaveUpdateUiSetting(WINUI_UPDATE *u, UPDATE_CLIENT_SETTING *s);
+void UpdateNotifyProcUi(UPDATE_CLIENT *c, UINT latest_build, UINT64 latest_date, char *latest_ver, char *url, volatile bool *halt_flag, void *param);
+UINT UpdateNoticeDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+bool ConfigUpdateUi(WINUI_UPDATE *u, HWND hWnd);
+UINT UpdateConfigDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+
+bool IsThisProcessForeground();
+HWND DlgItem(HWND hWnd, UINT id);
+void SetText(HWND hWnd, UINT id, wchar_t *str);
+void SetTextInner(HWND hWnd, UINT id, wchar_t *str);
+void SetTextA(HWND hWnd, UINT id, char *str);
+wchar_t *GetText(HWND hWnd, UINT id);
+char *GetTextA(HWND hWnd, UINT id);
+bool GetTxt(HWND hWnd, UINT id, wchar_t *str, UINT size);
+bool GetTxtA(HWND hWnd, UINT id, char *str, UINT size);
+bool IsEnable(HWND hWnd, UINT id);
+bool IsDisable(HWND hWnd, UINT id);
+void Enable(HWND hWnd, UINT id);
+void Disable(HWND hWnd, UINT id);
+void SetEnable(HWND hWnd, UINT id, bool b);
+void Close(HWND hWnd);
+void DoEvents(HWND hWnd);
+void Refresh(HWND hWnd);
+UINT GetInt(HWND hWnd, UINT id);
+void SetInt(HWND hWnd, UINT id, UINT value);
+void SetIntEx(HWND hWnd, UINT id, UINT value);
+void Focus(HWND hWnd, UINT id);
+void FocusEx(HWND hWnd, UINT id);
+bool IsFocus(HWND hWnd, UINT id);
+wchar_t *GetClass(HWND hWnd, UINT id);
+char *GetClassA(HWND hWnd, UINT id);
+void SelectEdit(HWND hWnd, UINT id);
+void SetCursorOnRight(HWND hWnd, UINT id);
+void UnselectEdit(HWND hWnd, UINT id);
+UINT SendMsg(HWND hWnd, UINT id, UINT msg, WPARAM wParam, LPARAM lParam);
+bool IsEmpty(HWND hWnd, UINT id);
+UINT GetTextLen(HWND hWnd, UINT id, bool unicode);
+UINT GetTextSize(HWND hWnd, UINT id, bool unicode);
+UINT GetStyle(HWND hWnd, UINT id);
+void SetStyle(HWND hWnd, UINT id, UINT style);
+void RemoveStyle(HWND hWnd, UINT id, UINT style);
+UINT GetExStyle(HWND hWnd, UINT id);
+void SetExStyle(HWND hWnd, UINT id, UINT style);
+void RemoveExStyle(HWND hWnd, UINT id, UINT style);
+void Hide(HWND hWnd, UINT id);
+void Show(HWND hWnd, UINT id);
+void SetShow(HWND hWnd, UINT id, bool b);
+bool IsHide(HWND hWnd, UINT id);
+bool IsShow(HWND hWnd, UINT id);
+void Top(HWND hWnd);
+void NoTop(HWND hWnd);
+void *GetParam(HWND hWnd);
+void SetParam(HWND hWnd, void *param);
+UINT DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, bool white_color);
+void NoticeSettingChange();
+void UiTest();
+UINT DialogInternal(HWND hWnd, UINT id, DIALOG_PROC *proc, void *param);
+UINT MsgBox(HWND hWnd, UINT flag, wchar_t *msg);
+UINT MsgBoxEx(HWND hWnd, UINT flag, wchar_t *msg, ...);
+void SetTextEx(HWND hWnd, UINT id, wchar_t *str, ...);
+void SetTextExA(HWND hWnd, UINT id, char *str, ...);
+void FormatText(HWND hWnd, UINT id, ...);
+void FormatTextA(HWND hWnd, UINT id, ...);
+void Center(HWND hWnd);
+void Center2(HWND hWnd);
+void GetWindowClientRect(HWND hWnd, struct tagRECT *rect);
+void CenterParent(HWND hWnd);
+void GetMonitorSize(UINT *width, UINT *height);
+void DisableClose(HWND hWnd);
+void EnableClose(HWND hWnd);
+void InitFont();
+void FreeFont();
+int CompareFont(void *p1, void *p2);
+HFONT GetFont(char *name, UINT size, bool bold, bool italic, bool underline, bool strikeout);
+double GetTextScalingFactor();
+bool CalcFontSize(HFONT hFont, UINT *x, UINT *y);
+bool GetFontSize(HFONT hFont, UINT *x, UINT *y);
+void SetFont(HWND hWnd, UINT id, HFONT hFont);
+void SetFontEx(HWND hWnd, UINT id, HFONT hFont, bool no_adjust_font_size);
+void LimitText(HWND hWnd, UINT id, UINT count);
+bool CheckTextLen(HWND hWnd, UINT id, UINT len, bool unicode);
+bool CheckTextSize(HWND hWnd, UINT id, UINT size, bool unicode);
+void Check(HWND hWnd, UINT id, bool b);
+bool IsChecked(HWND hWnd, UINT id);
+void SetIcon(HWND hWnd, UINT id, UINT icon_id);
+void SetBitmap(HWND hWnd, UINT id, UINT bmp_id);
+bool SecureDeviceWindow(HWND hWnd, WINUI_SECURE_BATCH *batch, UINT num_batch, UINT device_id, UINT bitmap_id);
+UINT Dialog(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param);
+UINT DialogEx(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param, bool white);
+UINT DialogEx2(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param, bool white, bool meiryo);
+HWND DialogCreateEx(HWND hWnd, UINT id, WINUI_DIALOG_PROC *proc, void *param, bool white);
+UINT __stdcall InternalDialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+UINT SecureDeviceWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+HFONT Font(UINT size, UINT bold);
+void DlgFont(HWND hWnd, UINT id, UINT size, UINT bold);
+void OpenAvi(HWND hWnd, UINT id, UINT avi_id);
+void CloseAvi(HWND hWnd, UINT id);
+void PlayAvi(HWND hWnd, UINT id, bool repeat);
+void StopAvi(HWND hWnd, UINT id);
+void EnableSecureDeviceWindowControls(HWND hWnd, bool enable);
+void SecureDeviceThread(THREAD *t, void *param);
+void Command(HWND hWnd, UINT id);
+wchar_t *OpenDlg(HWND hWnd, wchar_t *filter, wchar_t *title);
+char *OpenDlgA(HWND hWnd, char *filter, char *title);
+wchar_t *SaveDlg(HWND hWnd, wchar_t *filter, wchar_t *title, wchar_t *default_name, wchar_t *default_ext);
+char *SaveDlgA(HWND hWnd, char *filter, char *title, char *default_name, char *default_ext);
+wchar_t *MakeFilter(wchar_t *str);
+char *MakeFilterA(char *str);
+void PkcsUtil();
+UINT PkcsUtilProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void PkcsUtilWrite(HWND hWnd);
+void PkcsUtilErase(HWND hWnd);
+bool PassphraseDlg(HWND hWnd, char *pass, UINT pass_size, BUF *buf, bool p12);
+UINT PassphraseDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+bool PasswordDlg(HWND hWnd, UI_PASSWORD_DLG *p);
+void PasswordDlgOnOk(HWND hWnd, UI_PASSWORD_DLG *p);
+UINT PasswordDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void PasswordDlgProcChange(HWND hWnd, UI_PASSWORD_DLG *p);
+UINT CbAddStr(HWND hWnd, UINT id, wchar_t *str, UINT data);
+UINT CbAddStrA(HWND hWnd, UINT id, char *str, UINT data);
+UINT CbAddStr9xA(HWND hWnd, UINT id, char *str, UINT data);
+UINT CbInsertStr(HWND hWnd, UINT id, UINT index, wchar_t *str, UINT data);
+UINT CbInsertStrA(HWND hWnd, UINT id, UINT index, char *str, UINT data);
+UINT CbInsertStr9xA(HWND hWnd, UINT id, UINT index, char *str, UINT data);
+void CbSelectIndex(HWND hWnd, UINT id, UINT index);
+UINT CbNum(HWND hWnd, UINT id);
+UINT CbFindStr(HWND hWnd, UINT id, wchar_t *str);
+UINT CbFindStr9xA(HWND hWnd, UINT id, char *str);
+wchar_t *CbGetStr(HWND hWnd, UINT id);
+UINT CbFindData(HWND hWnd, UINT id, UINT data);
+UINT CbGetData(HWND hWnd, UINT id, UINT index);
+void CbSelect(HWND hWnd, UINT id, int data);
+void CbReset(HWND hWnd, UINT id);
+void CbSetHeight(HWND hWnd, UINT id, UINT value);
+UINT CbGetSelectIndex(HWND hWnd, UINT id);
+UINT CbGetSelect(HWND hWnd, UINT id);
+void SetRange(HWND hWnd, UINT id, UINT start, UINT end);
+void SetPos(HWND hWnd, UINT id, UINT pos);
+UINT LbAddStr(HWND hWnd, UINT id, wchar_t *str, UINT data);
+UINT LbAddStrA(HWND hWnd, UINT id, char *str, UINT data);
+UINT LbInsertStr(HWND hWnd, UINT id, UINT index, wchar_t *str, UINT data);
+UINT LbInsertStrA(HWND hWnd, UINT id, UINT index, char *str, UINT data);
+void LbSelectIndex(HWND hWnd, UINT id, UINT index);
+UINT LbNum(HWND hWnd, UINT id);
+UINT LbFindStr(HWND hWnd, UINT id, wchar_t *str);
+wchar_t *LbGetStr(HWND hWnd, UINT id);
+UINT LbFindData(HWND hWnd, UINT id, UINT data);
+UINT LbGetData(HWND hWnd, UINT id, UINT index);
+void LbSelect(HWND hWnd, UINT id, int data);
+void LbReset(HWND hWnd, UINT id);
+void LbSetHeight(HWND hWnd, UINT id, UINT value);
+UINT LbGetSelectIndex(HWND hWnd, UINT id);
+UINT LbGetSelect(HWND hWnd, UINT id);
+STATUS_WINDOW *StatusPrinterWindowStart(SOCK *s, wchar_t *account_name);
+void StatusPrinterWindowStop(STATUS_WINDOW *sw);
+void StatusPrinterWindowPrint(STATUS_WINDOW *sw, wchar_t *str);
+void StatusPrinterWindowThread(THREAD *thread, void *param);
+UINT StatusPrinterWindowDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void CertDlg(HWND hWnd, X *x, X *issuer_x, bool manager);
+UINT CertDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void LvInit(HWND hWnd, UINT id);
+void LvInitEx(HWND hWnd, UINT id, bool no_image);
+void LvInitEx2(HWND hWnd, UINT id, bool no_image, bool large_icon);
+void LvReset(HWND hWnd, UINT id);
+void LvInsertColumn(HWND hWnd, UINT id, UINT index, wchar_t *str, UINT width);
+UINT GetIcon(UINT icon_id);
+void LvInsert(HWND hWnd, UINT id, UINT icon, void *param, UINT num_str, ...);
+UINT LvInsertItem(HWND hWnd, UINT id, UINT icon, void *param, wchar_t *str);
+UINT LvInsertItemByImageListId(HWND hWnd, UINT id, UINT image, void *param, wchar_t *str);
+UINT LvInsertItemByImageListIdA(HWND hWnd, UINT id, UINT image, void *param, char *str);
+void LvSetItem(HWND hWnd, UINT id, UINT index, UINT pos, wchar_t *str);
+void LvSetItemA(HWND hWnd, UINT id, UINT index, UINT pos, char *str);
+void LvSetItemParam(HWND hWnd, UINT id, UINT index, void *param);
+void LvSetItemImage(HWND hWnd, UINT id, UINT index, UINT icon);
+void LvSetItemImageByImageListId(HWND hWnd, UINT id, UINT index, UINT image);
+void LvDeleteItem(HWND hWnd, UINT id, UINT index);
+UINT LvNum(HWND hWnd, UINT id);
+void *LvGetParam(HWND hWnd, UINT id, UINT index);
+wchar_t *LvGetStr(HWND hWnd, UINT id, UINT index, UINT pos);
+char *LvGetStrA(HWND hWnd, UINT id, UINT index, UINT pos);
+void LvShow(HWND hWnd, UINT id, UINT index);
+UINT LvSearchParam(HWND hWnd, UINT id, void *param);
+UINT LvSearchStr(HWND hWnd, UINT id, UINT pos, wchar_t *str);
+UINT LvSearchStrA(HWND hWnd, UINT id, UINT pos, char *str);
+UINT LvGetSelected(HWND hWnd, UINT id);
+void *LvGetSelectedParam(HWND hWnd, UINT id);
+UINT LvGetFocused(HWND hWnd, UINT id);
+wchar_t *LvGetFocusedStr(HWND hWnd, UINT id, UINT pos);
+wchar_t *LvGetSelectedStr(HWND hWnd, UINT id, UINT pos);
+char *LvGetSelectedStrA(HWND hWnd, UINT id, UINT pos);
+bool LvIsSelected(HWND hWnd, UINT id);
+UINT LvGetNextMasked(HWND hWnd, UINT id, UINT start);
+bool LvIsMasked(HWND hWnd, UINT id);
+bool LvIsSingleSelected(HWND hWnd, UINT id);
+bool LvIsMultiMasked(HWND hWnd, UINT id);
+UINT LvGetMaskedNum(HWND hWnd, UINT id);
+void LvAutoSize(HWND hWnd, UINT id);
+void LvSelect(HWND hWnd, UINT id, UINT index);
+void LvSelectByParam(HWND hWnd, UINT id, void *param);
+void LvSelectAll(HWND hWnd, UINT id);
+void LvSwitchSelect(HWND hWnd, UINT id);
+void LvSetView(HWND hWnd, UINT id, bool details);
+UINT LvGetColumnWidth(HWND hWnd, UINT id, UINT index);
+void CheckCertDlg(UI_CHECKCERT *p);
+UINT CheckCertDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void PrintCheckCertInfo(HWND hWnd, UI_CHECKCERT *p);
+void ShowDlgDiffWarning(HWND hWnd, UI_CHECKCERT *p);
+void CheckCertDialogOnOk(HWND hWnd, UI_CHECKCERT *p);
+bool ConnectErrorDlg(UI_CONNECTERROR_DLG *p);
+UINT ConnectErrorDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+HINSTANCE GetUiDll();
+HICON LoadLargeIconInner(UINT id);
+HICON LoadSmallIconInner(UINT id);
+HICON LoadLargeIcon(UINT id);
+HICON LoadSmallIcon(UINT id);
+HICON LoadIconEx(UINT id, bool small_icon);
+void InitIconCache();
+void FreeIconCache();
+LVB *LvInsertStart();
+void LvInsertAdd(LVB *b, UINT icon, void *param, UINT num_str, ...);
+void LvInsertEnd(LVB *b, HWND hWnd, UINT id);
+void LvInsertEndEx(LVB *b, HWND hWnd, UINT id, bool force_reset);
+void LvSetStyle(HWND hWnd, UINT id, UINT style);
+void LvRemoveStyle(HWND hWnd, UINT id, UINT style);
+HMENU LoadSubMenu(UINT menu_id, UINT pos, HMENU *parent_menu);
+UINT GetMenuItemPos(HMENU hMenu, UINT id);
+void DeleteMenuItem(HMENU hMenu, UINT pos);
+void SetMenuItemEnable(HMENU hMenu, UINT pos, bool enable);
+void SetMenuItemBold(HMENU hMenu, UINT pos, bool bold);
+wchar_t *GetMenuStr(HMENU hMenu, UINT pos);
+char *GetMenuStrA(HMENU hMenu, UINT pos);
+void SetMenuStr(HMENU hMenu, UINT pos, wchar_t *str);
+void SetMenuStrA(HMENU hMenu, UINT pos, char *str);
+void RemoveShortcutKeyStrFromMenu(HMENU hMenu);
+UINT GetMenuNum(HMENU hMenu);
+void PrintMenu(HWND hWnd, HMENU hMenu);
+void LvRename(HWND hWnd, UINT id, UINT pos);
+void AllowFGWindow(UINT process_id);
+HWND SearchWindow(wchar_t *caption);
+char *RemoteDlg(HWND hWnd, char *regkey, UINT icon, wchar_t *caption, wchar_t *title, char *default_host);
+LIST *ReadCandidateFromReg(UINT root, char *key, char *name);
+void WriteCandidateToReg(UINT root, char *key, LIST *o, char *name);
+UINT LvGetColumnNum(HWND hWnd, UINT id);
+void LvSetItemParamEx(HWND hWnd, UINT id, UINT index, UINT subitem, void *param);
+void LvSortEx(HWND hWnd, UINT id, UINT subitem, bool desc, bool numeric);
+void LvSort(HWND hWnd, UINT id, UINT subitem, bool desc);
+void *LvGetParamEx(HWND hWnd, UINT id, UINT index, UINT subitem);
+void LvSortHander(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT id);
+void LvStandardHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT id);
+void IpSet(HWND hWnd, UINT id, UINT ip);
+UINT IpGet(HWND hWnd, UINT id);
+void IpClear(HWND hWnd, UINT id);
+bool IpIsFilled(HWND hWnd, UINT id);
+UINT IpGetFilledNum(HWND hWnd, UINT id);
+void About(HWND hWnd, CEDAR *cedar, wchar_t *product_name);
+void AboutEx(HWND hWnd, CEDAR *cedar, wchar_t *product_name, WINUI_UPDATE *u);
+void Win9xReboot(HWND hWnd);
+void Win9xRebootThread(THREAD *t, void *p);
+UINT Win9xRebootDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+wchar_t *StringDlg(HWND hWnd, wchar_t *title, wchar_t *info, wchar_t *def, UINT icon, bool allow_empty, bool allow_unsafe);
+char *StringDlgA(HWND hWnd, wchar_t *title, wchar_t *info, char *def, UINT icon, bool allow_empty, bool allow_unsafe);
+UINT StringDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void InitDialogInternational(HWND hWnd, void *pparam);
+void AdjustWindowAndControlSize(HWND hWnd, bool *need_resize, double *factor_x, double *factor_y);
+void GetWindowAndControlSizeResizeScale(HWND hWnd, bool *need_resize, double *factor_x, double *factor_y);
+void AdjustDialogXY(UINT *x, UINT *y, UINT dlgfont_x, UINT dlgfont_y);
+HFONT GetDialogDefaultFont();
+HFONT GetDialogDefaultFontEx(bool meiryo);
+void InitMenuInternational(HMENU hMenu, char *prefix);
+void InitMenuInternationalUni(HMENU hMenu, char *prefix);
+void ShowTcpIpConfigUtil(HWND hWnd, bool util_mode);
+void ShowCpu64Warning();
+UINT Cpu64DlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+UINT TcpIpDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void TcpIpDlgInit(HWND hWnd);
+void TcpIpDlgUpdate(HWND hWnd);
+UINT TcpMsgDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+UINT KakushiDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void KakushiThread(THREAD *thread, void *param);
+KAKUSHI *InitKakushi();
+void FreeKakushi(KAKUSHI *k);
+void ShowEasterEgg(HWND hWnd);
+bool ExecuteHamcoreExe(char *name);
+bool IsRegistedToDontShowFreeEditionDialog(char *server_name);
+void RegistToDontShowFreeEditionDialog(char *server_name);
+void ShowFreeInfoDialog(HWND hWnd, FREEINFO *info);
+UINT FreeInfoDialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+FREEINFO *StartFreeInfoDlg(char *server_name);
+void FreeInfoThread(THREAD *thread, void *param);
+void EndFreeInfoDlg(FREEINFO *info);
+bool Win32CnCheckAlreadyExists(bool lock);
+void RegistWindowsFirewallAll();
+void RegistWindowsFirewallAllEx(char *dir);
+void InitVistaWindowTheme(HWND hWnd);
+void WinUiDebug(wchar_t *str);
+void WinUiDebugInit();
+void WinUiDebugFree();
+void OnceMsg(HWND hWnd, wchar_t *title, wchar_t *message, bool show_checkbox, UINT icon);
+void OnceMsgEx(HWND hWnd, wchar_t *title, wchar_t *message, bool show_checkbox, UINT icon, bool *halt);
+UINT GetOnceMsgHash(wchar_t *title, wchar_t *message);
+UINT OnceMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+bool CheckBadProcesses(HWND hWnd);
+BAD_PROCESS *IsBadProcess(char *exe);
+void ShowBadProcessWarning(HWND hWnd, BAD_PROCESS *bad);
+void SetFontMeiryo(HWND hWnd, UINT id, UINT font_size);
+char *GetMeiryoFontName();
+void SetFontDefault(HWND hWnd, UINT id);
+HFONT GetMeiryoFont();
+HFONT GetMeiryoFontEx(UINT font_size);
+HFONT GetMeiryoFontEx2(UINT font_size, bool bold);
+bool ShowWindowsNetworkConnectionDialog();
+SOCK *WinConnectEx2(HWND hWnd, char *server, UINT port, UINT timeout, UINT icon_id, wchar_t *caption, wchar_t *info, bool try_start_ssl, bool ssl_no_tls);
+SOCK *WinConnectEx3(HWND hWnd, char *server, UINT port, UINT timeout, UINT icon_id, wchar_t *caption, wchar_t *info, UINT *nat_t_error_code, char *nat_t_svc_name, bool try_start_ssl, bool ssl_no_tls);
+UINT WinConnectDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void WinConnectDlgThread(THREAD *thread, void *param);
+void NicInfo(UI_NICINFO *info);
+UINT NicInfoProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param);
+void NicInfoInit(HWND hWnd, UI_NICINFO *info);
+void NicInfoOnTimer(HWND hWnd, UI_NICINFO *info);
+void NicInfoRefresh(HWND hWnd, UI_NICINFO *info);
+void NicInfoShowStatus(HWND hWnd, UI_NICINFO *info, wchar_t *msg1, wchar_t *msg2, UINT icon, bool animate);
+void NicInfoCloseAfterTime(HWND hWnd, UI_NICINFO *info, UINT tick);
+
+WIZARD *NewWizard(UINT icon, UINT bitmap, wchar_t *caption, void *param);
+void FreeWizard(WIZARD *w);
+WIZARD_PAGE *NewWizardPage(UINT id, WINUI_WIZARD_PROC *proc, wchar_t *title);
+void FreeWizardPage(WIZARD_PAGE *p);
+void AddWizardPage(WIZARD *w, WIZARD_PAGE *p);
+WIZARD_PAGE *GetWizardPage(WIZARD *w, UINT id);
+UINT GetWizardPageIndex(WIZARD *w, UINT id);
+void *CreateWizardPageInstance(WIZARD *w, WIZARD_PAGE *p);
+void ShowWizard(HWND hWndParent, WIZARD *w, UINT start_id);
+void SetWizardButton(WIZARD_PAGE *p, bool enable_next, bool enable_back, bool enable_close, bool is_finish);
+void SetWizardButtonEx(WIZARD_PAGE *p, bool enable_next, bool enable_back, bool enable_close, bool is_finish, bool shield_icon);
+void JumpWizard(WIZARD_PAGE *p, UINT next_id);
+void CloseWizard(WIZARD_PAGE *p);
+void SetUacIcon(HWND hWnd, UINT id);
+
+LIST *NewBitmapList();
+void FreeBitmapList(LIST *o);
+
+bool GetBitmapSize(void *bmp, UINT *x, UINT *y);
+
+bool GetFontParam(HFONT hFont, struct FONT *f);
+void AdjustFontSize(HWND hWnd, UINT id);
+bool IsFontFitInRect(struct FONT *f, UINT width, UINT height, wchar_t *text, UINT format, bool *aborted);
+
+void ShowTextFile(HWND hWnd, char *filename, wchar_t *caption, UINT icon);
+
+#endif // OS_WIN32
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Wpc.c b/src/Cedar/Wpc.c
new file mode 100644
index 00000000..45a30222
--- /dev/null
+++ b/src/Cedar/Wpc.c
@@ -0,0 +1,1326 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Wpc.c
+// RPC over HTTP
+
+#include <GlobalConst.h>
+
+#include "CedarPch.h"
+
+// Get whether the proxy server is specified by a private IP
+bool IsProxyPrivateIp(INTERNET_SETTING *s)
+{
+ IP ip;
+ // Validate arguments
+ if (s == NULL)
+ {
+ return false;
+ }
+
+ if (s->ProxyType == PROXY_DIRECT)
+ {
+ return false;
+ }
+
+ if (GetIP(&ip, s->ProxyHostName) == false)
+ {
+ return false;
+ }
+
+ if (IsIPPrivate(&ip))
+ {
+ return true;
+ }
+
+ if (IsIPMyHost(&ip))
+ {
+ return true;
+ }
+
+ if (IsLocalHostIP(&ip))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+// Call
+PACK *WpcCall(char *url, INTERNET_SETTING *setting, UINT timeout_connect, UINT timeout_comm,
+ char *function_name, PACK *pack, X *cert, K *key, void *sha1_cert_hash)
+{
+ return WpcCallEx(url, setting, timeout_connect, timeout_comm, function_name, pack, cert, key,
+ sha1_cert_hash, NULL, 0);
+}
+PACK *WpcCallEx(char *url, INTERNET_SETTING *setting, UINT timeout_connect, UINT timeout_comm,
+ char *function_name, PACK *pack, X *cert, K *key, void *sha1_cert_hash, bool *cancel, UINT max_recv_size)
+{
+ URL_DATA data;
+ BUF *b, *recv;
+ UINT error;
+ WPC_PACKET packet;
+ // Validate arguments
+ if (function_name == NULL || pack == NULL)
+ {
+ return PackError(ERR_INTERNAL_ERROR);
+ }
+
+ if (ParseUrl(&data, url, true, NULL) == false)
+ {
+ return PackError(ERR_INTERNAL_ERROR);
+ }
+
+ PackAddStr(pack, "function", function_name);
+
+ b = WpcGeneratePacket(pack, cert, key);
+ if (b == NULL)
+ {
+ return PackError(ERR_INTERNAL_ERROR);
+ }
+
+ SeekBuf(b, b->Size, 0);
+ WriteBufInt(b, 0);
+ SeekBuf(b, 0, 0);
+
+ recv = HttpRequestEx(&data, setting, timeout_connect, timeout_comm, &error,
+ false, b->Buf, NULL, NULL, sha1_cert_hash, cancel, max_recv_size);
+
+ FreeBuf(b);
+
+ if (recv == NULL)
+ {
+ return PackError(error);
+ }
+
+ if (WpcParsePacket(&packet, recv) == false)
+ {
+ FreeBuf(recv);
+ return PackError(ERR_PROTOCOL_ERROR);
+ }
+
+ FreeBuf(recv);
+
+ FreeX(packet.Cert);
+
+ return packet.Pack;
+}
+
+// Release the packet
+void WpcFreePacket(WPC_PACKET *packet)
+{
+ // Validate arguments
+ if (packet == NULL)
+ {
+ return;
+ }
+
+ FreePack(packet->Pack);
+ FreeX(packet->Cert);
+}
+
+// Parse the packet
+bool WpcParsePacket(WPC_PACKET *packet, BUF *buf)
+{
+ LIST *o;
+ BUF *b;
+ bool ret = false;
+ UCHAR hash[SHA1_SIZE];
+ // Validate arguments
+ if (packet == NULL || buf == NULL)
+ {
+ return false;
+ }
+
+ Zero(packet, sizeof(WPC_PACKET));
+
+ o = WpcParseDataEntry(buf);
+
+ b = WpcDataEntryToBuf(WpcFindDataEntry(o, "PACK"));
+ if (b != NULL)
+ {
+ HashSha1(hash, b->Buf, b->Size);
+
+ packet->Pack = BufToPack(b);
+ FreeBuf(b);
+
+ if (packet->Pack != NULL)
+ {
+ BUF *b;
+
+ ret = true;
+
+ b = WpcDataEntryToBuf(WpcFindDataEntry(o, "HASH"));
+
+ if (b != NULL)
+ {
+ if (b->Size != SHA1_SIZE || Cmp(b->Buf, hash, SHA1_SIZE) != 0)
+ {
+ ret = false;
+ FreePack(packet->Pack);
+ }
+ else
+ {
+ BUF *b;
+
+ Copy(packet->Hash, hash, SHA1_SIZE);
+
+ b = WpcDataEntryToBuf(WpcFindDataEntry(o, "CERT"));
+
+ if (b != NULL)
+ {
+ X *cert = BufToX(b, false);
+ if (cert == NULL)
+ {
+ ret = false;
+ FreePack(packet->Pack);
+ }
+ else
+ {
+ BUF *b = WpcDataEntryToBuf(WpcFindDataEntry(o, "SIGN"));
+
+ if (b == NULL || (b->Size != 128))
+ {
+ ret = false;
+ FreeX(cert);
+ FreePack(packet->Pack);
+ }
+ else
+ {
+ K *k = GetKFromX(cert);
+
+ if (RsaVerify(hash, SHA1_SIZE, b->Buf, k) == false)
+ {
+ ret = false;
+ FreeX(cert);
+ FreePack(packet->Pack);
+ }
+ else
+ {
+ packet->Cert = cert;
+ Copy(packet->Sign, b->Buf, 128);
+ }
+
+ FreeK(k);
+ }
+
+ FreeBuf(b);
+ }
+ FreeBuf(b);
+ }
+ }
+ FreeBuf(b);
+ }
+ }
+ }
+
+ WpcFreeDataEntryList(o);
+
+ return ret;
+}
+
+// Generate the packet
+BUF *WpcGeneratePacket(PACK *pack, X *cert, K *key)
+{
+ UCHAR hash[SHA1_SIZE];
+ BUF *pack_data;
+ BUF *cert_data = NULL;
+ BUF *sign_data = NULL;
+ BUF *b;
+ // Validate arguments
+ if (pack == NULL)
+ {
+ return NULL;
+ }
+
+ pack_data = PackToBuf(pack);
+ HashSha1(hash, pack_data->Buf, pack_data->Size);
+
+ if (cert != NULL && key != NULL)
+ {
+ UCHAR sign[128];
+ cert_data = XToBuf(cert, false);
+
+ RsaSign(sign, hash, sizeof(hash), key);
+
+ sign_data = NewBuf();
+ WriteBuf(sign_data, sign, sizeof(sign));
+ SeekBuf(sign_data, 0, 0);
+ }
+
+ b = NewBuf();
+
+ WpcAddDataEntryBin(b, "PACK", pack_data->Buf, pack_data->Size);
+ WpcAddDataEntryBin(b, "HASH", hash, sizeof(hash));
+
+ if (cert_data != NULL)
+ {
+ WpcAddDataEntryBin(b, "CERT", cert_data->Buf, cert_data->Size);
+ WpcAddDataEntryBin(b, "SIGN", sign_data->Buf, sign_data->Size);
+ }
+
+ FreeBuf(pack_data);
+ FreeBuf(cert_data);
+ FreeBuf(sign_data);
+
+ SeekBuf(b, 0, 0);
+
+ return b;
+}
+
+// Decode the buffer from WPC_ENTRY
+BUF *WpcDataEntryToBuf(WPC_ENTRY *e)
+{
+ void *data;
+ UINT data_size;
+ UINT size;
+ BUF *b;
+ // Validate arguments
+ if (e == NULL)
+ {
+ return NULL;
+ }
+
+ data_size = e->Size + 4096;
+ data = Malloc(data_size);
+ size = DecodeSafe64(data, e->Data, e->Size);
+
+ b = NewBuf();
+ WriteBuf(b, data, size);
+ SeekBuf(b, 0, 0);
+
+ Free(data);
+
+ return b;
+}
+
+// Search for the data entry
+WPC_ENTRY *WpcFindDataEntry(LIST *o, char *name)
+{
+ UINT i;
+ char name_str[WPC_DATA_ENTRY_SIZE];
+ // Validate arguments
+ if (o == NULL || name == NULL)
+ {
+ return NULL;
+ }
+
+ WpcFillEntryName(name_str, name);
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ WPC_ENTRY *e = LIST_DATA(o, i);
+
+ if (Cmp(e->EntryName, name_str, WPC_DATA_ENTRY_SIZE) == 0)
+ {
+ return e;
+ }
+ }
+
+ return NULL;
+}
+
+// Release the data entry list
+void WpcFreeDataEntryList(LIST *o)
+{
+ UINT i;
+ // Validate arguments
+ if (o == NULL)
+ {
+ return;
+ }
+
+ for (i = 0;i < LIST_NUM(o);i++)
+ {
+ WPC_ENTRY *e = LIST_DATA(o, i);
+
+ Free(e);
+ }
+
+ ReleaseList(o);
+}
+
+// Parse the data entry
+LIST *WpcParseDataEntry(BUF *b)
+{
+ char entry_name[WPC_DATA_ENTRY_SIZE];
+ char size_str[11];
+ LIST *o;
+ // Validate arguments
+ if (b == NULL)
+ {
+ return NULL;
+ }
+
+ SeekBuf(b, 0, 0);
+
+ o = NewListFast(NULL);
+
+ while (true)
+ {
+ UINT size;
+ WPC_ENTRY *e;
+
+ if (ReadBuf(b, entry_name, WPC_DATA_ENTRY_SIZE) != WPC_DATA_ENTRY_SIZE)
+ {
+ break;
+ }
+
+ Zero(size_str, sizeof(size_str));
+ if (ReadBuf(b, size_str, 10) != 10)
+ {
+ break;
+ }
+
+ size = ToInt(size_str);
+ if ((b->Size - b->Current) < size)
+ {
+ break;
+ }
+
+ e = ZeroMalloc(sizeof(WPC_ENTRY));
+ e->Data = (UCHAR *)b->Buf + b->Current;
+ Copy(e->EntryName, entry_name, WPC_DATA_ENTRY_SIZE);
+ e->Size = size;
+
+ SeekBuf(b, size, 1);
+
+ Add(o, e);
+ }
+
+ return o;
+}
+
+// Generate a entry name
+void WpcFillEntryName(char *dst, char *name)
+{
+ UINT i, len;
+ char tmp[MAX_SIZE];
+ // Validate arguments
+ if (dst == NULL || name == NULL)
+ {
+ return;
+ }
+
+ StrCpy(tmp, sizeof(tmp), name);
+ StrUpper(tmp);
+ len = StrLen(tmp);
+
+ for (i = 0;i < WPC_DATA_ENTRY_SIZE;i++)
+ {
+ dst[i] = ' ';
+ }
+
+ if (len <= WPC_DATA_ENTRY_SIZE)
+ {
+ Copy(dst, tmp, len);
+ }
+ else
+ {
+ Copy(dst, tmp, WPC_DATA_ENTRY_SIZE);
+ }
+}
+
+// Add the data entry (binary)
+void WpcAddDataEntryBin(BUF *b, char *name, void *data, UINT size)
+{
+ char *str;
+ // Validate arguments
+ if (b == NULL || name == NULL || (data == NULL && size != 0))
+ {
+ return;
+ }
+
+ str = Malloc(size * 2 + 64);
+
+ EncodeSafe64(str, data, size);
+
+ WpcAddDataEntry(b, name, str, StrLen(str));
+
+ Free(str);
+}
+
+
+// Add the data entry
+void WpcAddDataEntry(BUF *b, char *name, void *data, UINT size)
+{
+ char entry_name[WPC_DATA_ENTRY_SIZE];
+ char size_str[11];
+ // Validate arguments
+ if (b == NULL || name == NULL || (data == NULL && size != 0))
+ {
+ return;
+ }
+
+ WpcFillEntryName(entry_name, name);
+ WriteBuf(b, entry_name, WPC_DATA_ENTRY_SIZE);
+
+ Format(size_str, sizeof(size_str), "%010u", size);
+ WriteBuf(b, size_str, 10);
+
+ WriteBuf(b, data, size);
+}
+
+// Get the empty INTERNET_SETTING
+INTERNET_SETTING *GetNullInternetSetting()
+{
+ static INTERNET_SETTING ret;
+
+ Zero(&ret, sizeof(ret));
+
+ return &ret;
+}
+
+// Socket connection
+SOCK *WpcSockConnect(WPC_CONNECT *param, UINT *error_code, UINT timeout)
+{
+ return WpcSockConnectEx(param, error_code, timeout, NULL);
+}
+SOCK *WpcSockConnectEx(WPC_CONNECT *param, UINT *error_code, UINT timeout, bool *cancel)
+{
+ CONNECTION c;
+ SOCK *sock;
+ UINT err = ERR_NO_ERROR;
+ // Validate arguments
+ if (param == NULL)
+ {
+ return NULL;
+ }
+
+ Zero(&c, sizeof(c));
+
+ sock = NULL;
+ err = ERR_INTERNAL_ERROR;
+
+ switch (param->ProxyType)
+ {
+ case PROXY_DIRECT:
+ sock = TcpConnectEx3(param->HostName, param->Port, timeout, cancel, NULL, true, NULL, false, false);
+ if (sock == NULL)
+ {
+ err = ERR_CONNECT_FAILED;
+ }
+ break;
+
+ case PROXY_HTTP:
+ sock = ProxyConnectEx2(&c, param->ProxyHostName, param->ProxyPort,
+ param->HostName, param->Port,
+ param->ProxyUsername, param->ProxyPassword, false, cancel, NULL, timeout);
+ if (sock == NULL)
+ {
+ err = c.Err;
+ }
+ break;
+
+ case PROXY_SOCKS:
+ sock = SocksConnectEx2(&c, param->ProxyHostName, param->ProxyPort,
+ param->HostName, param->Port,
+ param->ProxyUsername, false, cancel, NULL, timeout);
+ if (sock == NULL)
+ {
+ err = c.Err;
+ }
+ break;
+ }
+
+ if (error_code != NULL)
+ {
+ *error_code = err;
+ }
+
+ return sock;
+}
+SOCK *WpcSockConnect2(char *hostname, UINT port, INTERNET_SETTING *t, UINT *error_code, UINT timeout)
+{
+ // Validate arguments
+ INTERNET_SETTING t2;
+ WPC_CONNECT c;
+ if (t == NULL)
+ {
+ Zero(&t2, sizeof(t2));
+
+ t = &t2;
+ }
+
+ Zero(&c, sizeof(c));
+ StrCpy(c.HostName, sizeof(c.HostName), hostname);
+ c.Port = port;
+ c.ProxyType = t->ProxyType;
+ StrCpy(c.ProxyHostName, sizeof(c.HostName), t->ProxyHostName);
+ c.ProxyPort = t->ProxyPort;
+ StrCpy(c.ProxyUsername, sizeof(c.ProxyUsername), t->ProxyUsername);
+ StrCpy(c.ProxyPassword, sizeof(c.ProxyPassword), t->ProxyPassword);
+
+ return WpcSockConnect(&c, error_code, timeout);
+}
+
+// Handle the HTTP request
+BUF *HttpRequest(URL_DATA *data, INTERNET_SETTING *setting,
+ UINT timeout_connect, UINT timeout_comm,
+ UINT *error_code, bool check_ssl_trust, char *post_data,
+ WPC_RECV_CALLBACK *recv_callback, void *recv_callback_param, void *sha1_cert_hash)
+{
+ return HttpRequestEx(data, setting, timeout_connect, timeout_comm,
+ error_code, check_ssl_trust, post_data,
+ recv_callback, recv_callback_param, sha1_cert_hash, NULL, 0);
+}
+BUF *HttpRequestEx(URL_DATA *data, INTERNET_SETTING *setting,
+ UINT timeout_connect, UINT timeout_comm,
+ UINT *error_code, bool check_ssl_trust, char *post_data,
+ WPC_RECV_CALLBACK *recv_callback, void *recv_callback_param, void *sha1_cert_hash,
+ bool *cancel, UINT max_recv_size)
+{
+ return HttpRequestEx2(data, setting, timeout_connect, timeout_comm, error_code,
+ check_ssl_trust, post_data, recv_callback, recv_callback_param, sha1_cert_hash,
+ cancel, max_recv_size, NULL, NULL);
+}
+BUF *HttpRequestEx2(URL_DATA *data, INTERNET_SETTING *setting,
+ UINT timeout_connect, UINT timeout_comm,
+ UINT *error_code, bool check_ssl_trust, char *post_data,
+ WPC_RECV_CALLBACK *recv_callback, void *recv_callback_param, void *sha1_cert_hash,
+ bool *cancel, UINT max_recv_size, char *header_name, char *header_value)
+{
+ WPC_CONNECT con;
+ SOCK *s;
+ HTTP_HEADER *h;
+ bool use_http_proxy = false;
+ char target[MAX_SIZE * 4];
+ char *send_str;
+ BUF *send_buf;
+ BUF *recv_buf;
+ UINT http_error_code;
+ char len_str[100];
+ UINT content_len;
+ void *socket_buffer;
+ UINT socket_buffer_size = WPC_RECV_BUF_SIZE;
+ UINT num_continue = 0;
+ INTERNET_SETTING wt_setting;
+ // Validate arguments
+ if (data == NULL)
+ {
+ return NULL;
+ }
+ if (setting == NULL)
+ {
+ Zero(&wt_setting, sizeof(wt_setting));
+ setting = &wt_setting;
+ }
+ if (error_code == NULL)
+ {
+ static UINT ret = 0;
+ error_code = &ret;
+ }
+ if (timeout_comm == 0)
+ {
+ timeout_comm = WPC_TIMEOUT;
+ }
+
+ // Connection
+ Zero(&con, sizeof(con));
+ StrCpy(con.HostName, sizeof(con.HostName), data->HostName);
+ con.Port = data->Port;
+ con.ProxyType = setting->ProxyType;
+ StrCpy(con.ProxyHostName, sizeof(con.ProxyHostName), setting->ProxyHostName);
+ con.ProxyPort = setting->ProxyPort;
+ StrCpy(con.ProxyUsername, sizeof(con.ProxyUsername), setting->ProxyUsername);
+ StrCpy(con.ProxyPassword, sizeof(con.ProxyPassword), setting->ProxyPassword);
+
+ if (setting->ProxyType != PROXY_HTTP || data->Secure)
+ {
+ use_http_proxy = false;
+ StrCpy(target, sizeof(target), data->Target);
+ }
+ else
+ {
+ use_http_proxy = true;
+ CreateUrl(target, sizeof(target), data);
+ }
+
+ if (use_http_proxy == false)
+ {
+ // If the connection is not via HTTP Proxy, or is a SSL connection even via HTTP Proxy
+ s = WpcSockConnectEx(&con, error_code, timeout_connect, cancel);
+ }
+ else
+ {
+ // If the connection is not SSL via HTTP Proxy
+ s = TcpConnectEx3(con.ProxyHostName, con.ProxyPort, timeout_connect, cancel, NULL, true, NULL, false, false);
+ if (s == NULL)
+ {
+ *error_code = ERR_PROXY_CONNECT_FAILED;
+ }
+ }
+
+ if (s == NULL)
+ {
+ return NULL;
+ }
+
+ if (data->Secure)
+ {
+ // Start the SSL communication
+ if (StartSSLEx(s, NULL, NULL, true, 0, NULL) == false)
+ {
+ // SSL connection failed
+ *error_code = ERR_PROTOCOL_ERROR;
+ Disconnect(s);
+ ReleaseSock(s);
+ return NULL;
+ }
+
+ if (sha1_cert_hash != NULL)
+ {
+ UCHAR hash[SHA1_SIZE];
+ Zero(hash, sizeof(hash));
+ GetXDigest(s->RemoteX, hash, true);
+
+ if (Cmp(hash, sha1_cert_hash, SHA1_SIZE) != 0)
+ {
+ // Destination certificate hash mismatch
+ *error_code = ERR_CERT_NOT_TRUSTED;
+ Disconnect(s);
+ ReleaseSock(s);
+ return NULL;
+ }
+ }
+ }
+
+ // Timeout setting
+ SetTimeout(s, timeout_comm);
+
+ // Generate a request
+ h = NewHttpHeader(data->Method, target, use_http_proxy ? "HTTP/1.0" : "HTTP/1.1");
+ AddHttpValue(h, NewHttpValue("Keep-Alive", HTTP_KEEP_ALIVE));
+ AddHttpValue(h, NewHttpValue("Connection", "Keep-Alive"));
+ AddHttpValue(h, NewHttpValue("Accept-Language", "ja"));
+ AddHttpValue(h, NewHttpValue("User-Agent", WPC_USER_AGENT));
+ AddHttpValue(h, NewHttpValue("Pragma", "no-cache"));
+ AddHttpValue(h, NewHttpValue("Cache-Control", "no-cache"));
+ AddHttpValue(h, NewHttpValue("Host", data->HeaderHostName));
+
+ if (IsEmptyStr(header_name) == false && IsEmptyStr(header_value) == false)
+ {
+ AddHttpValue(h, NewHttpValue(header_name, header_value));
+ }
+
+ if (IsEmptyStr(data->Referer) == false)
+ {
+ AddHttpValue(h, NewHttpValue("Referer", data->Referer));
+ }
+
+ if (StrCmpi(data->Method, WPC_HTTP_POST_NAME) == 0)
+ {
+ ToStr(len_str, StrLen(post_data));
+ AddHttpValue(h, NewHttpValue("Content-Type", "application/x-www-form-urlencoded"));
+ AddHttpValue(h, NewHttpValue("Content-Length", len_str));
+ }
+
+ if (use_http_proxy)
+ {
+ AddHttpValue(h, NewHttpValue("Proxy-Connection", "Keep-Alive"));
+
+ if (IsEmptyStr(setting->ProxyUsername) == false || IsEmptyStr(setting->ProxyPassword) == false)
+ {
+ char auth_tmp_str[MAX_SIZE], auth_b64_str[MAX_SIZE * 2];
+ char basic_str[MAX_SIZE * 2];
+
+ // Generate the authentication string
+ Format(auth_tmp_str, sizeof(auth_tmp_str), "%s:%s",
+ setting->ProxyUsername, setting->ProxyPassword);
+
+ // Base64 encode
+ Zero(auth_b64_str, sizeof(auth_b64_str));
+ Encode64(auth_b64_str, auth_tmp_str);
+ Format(basic_str, sizeof(basic_str), "Basic %s", auth_b64_str);
+
+ AddHttpValue(h, NewHttpValue("Proxy-Authorization", basic_str));
+ }
+ }
+
+ send_str = HttpHeaderToStr(h);
+ FreeHttpHeader(h);
+
+ send_buf = NewBuf();
+ WriteBuf(send_buf, send_str, StrLen(send_str));
+ Free(send_str);
+
+ // Append to the sending data in the case of POST
+ if (StrCmpi(data->Method, WPC_HTTP_POST_NAME) == 0)
+ {
+ WriteBuf(send_buf, post_data, StrLen(post_data));
+ }
+
+ // Send
+ if (SendAll(s, send_buf->Buf, send_buf->Size, s->SecureMode) == false)
+ {
+ Disconnect(s);
+ ReleaseSock(s);
+ FreeBuf(send_buf);
+
+ *error_code = ERR_DISCONNECTED;
+
+ return NULL;
+ }
+
+ FreeBuf(send_buf);
+
+CONT:
+ // Receive
+ h = RecvHttpHeader(s);
+ if (h == NULL)
+ {
+ Disconnect(s);
+ ReleaseSock(s);
+
+ *error_code = ERR_DISCONNECTED;
+
+ return NULL;
+ }
+
+ http_error_code = 0;
+ if (StrLen(h->Method) == 8)
+ {
+ if (Cmp(h->Method, "HTTP/1.", 7) == 0)
+ {
+ http_error_code = ToInt(h->Target);
+ }
+ }
+
+ *error_code = ERR_NO_ERROR;
+
+ switch (http_error_code)
+ {
+ case 401:
+ case 407:
+ // Proxy authentication error
+ *error_code = ERR_PROXY_AUTH_FAILED;
+ break;
+
+ case 404:
+ // 404 File Not Found
+ *error_code = ERR_OBJECT_NOT_FOUND;
+ break;
+
+ case 100:
+ // Continue
+ num_continue++;
+ if (num_continue >= 10)
+ {
+ goto DEF;
+ }
+ FreeHttpHeader(h);
+ goto CONT;
+
+ case 200:
+ // Success
+ break;
+
+ default:
+ // Protocol error
+DEF:
+ *error_code = ERR_PROTOCOL_ERROR;
+ break;
+ }
+
+ if (*error_code != ERR_NO_ERROR)
+ {
+ // An error has occured
+ Disconnect(s);
+ ReleaseSock(s);
+ FreeHttpHeader(h);
+ return NULL;
+ }
+
+ // Get the length of the content
+ content_len = GetContentLength(h);
+ if (max_recv_size != 0)
+ {
+ content_len = MIN(content_len, max_recv_size);
+ }
+
+ FreeHttpHeader(h);
+
+ socket_buffer = Malloc(socket_buffer_size);
+
+ // Receive the content
+ recv_buf = NewBuf();
+
+ while (true)
+ {
+ UINT recvsize = MIN(socket_buffer_size, content_len - recv_buf->Size);
+ UINT size;
+
+ if (recv_callback != NULL)
+ {
+ if (recv_callback(recv_callback_param,
+ content_len, recv_buf->Size, recv_buf) == false)
+ {
+ // Cancel the reception
+ *error_code = ERR_USER_CANCEL;
+ goto RECV_CANCEL;
+ }
+ }
+
+ if (recvsize == 0)
+ {
+ break;
+ }
+
+ size = Recv(s, socket_buffer, recvsize, s->SecureMode);
+ if (size == 0)
+ {
+ // Disconnected
+ *error_code = ERR_DISCONNECTED;
+
+RECV_CANCEL:
+ FreeBuf(recv_buf);
+ Free(socket_buffer);
+ Disconnect(s);
+ ReleaseSock(s);
+
+ return NULL;
+ }
+
+ WriteBuf(recv_buf, socket_buffer, size);
+ }
+
+ SeekBuf(recv_buf, 0, 0);
+ Free(socket_buffer);
+
+ Disconnect(s);
+ ReleaseSock(s);
+
+ // Transmission
+ return recv_buf;
+}
+
+// Get the proxy server settings from the registry string of IE
+bool GetProxyServerNameAndPortFromIeProxyRegStr(char *name, UINT name_size, UINT *port, char *str, char *server_type)
+{
+#ifdef OS_WIN32
+ TOKEN_LIST *t;
+ UINT i;
+ bool ret = false;
+ // Validate arguments
+ if (name == NULL || port == NULL || str == NULL || server_type == NULL)
+ {
+ return false;
+ }
+
+ t = ParseToken(str, ";");
+
+ for (i = 0;i < t->NumTokens;i++)
+ {
+ char *s = t->Token[i];
+ UINT i;
+
+ Trim(s);
+
+ i = SearchStrEx(s, "=", 0, false);
+ if (i != INFINITE)
+ {
+ char tmp[MAX_PATH];
+
+ StrCpy(name, name_size, s);
+ name[i] = 0;
+
+ if (StrCmpi(name, server_type) == 0)
+ {
+ char *host;
+ StrCpy(tmp, sizeof(tmp), s + i + 1);
+
+ if (ParseHostPort(tmp, &host, port, 0))
+ {
+ StrCpy(name, name_size, host);
+ Free(host);
+
+ if (*port != 0)
+ {
+ ret = true;
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ FreeToken(t);
+
+ return ret;
+#else // OS_WIN32
+ return true;
+#endif // OS_WIN32
+}
+
+// Get the internet connection settings of the system
+void GetSystemInternetSetting(INTERNET_SETTING *setting)
+{
+#ifdef OS_WIN32
+ bool use_proxy;
+ // Validate arguments
+ if (setting == NULL)
+ {
+ return;
+ }
+
+ Zero(setting, sizeof(INTERNET_SETTING));
+
+ use_proxy = MsRegReadInt(REG_CURRENT_USER,
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
+ "ProxyEnable");
+
+ if (use_proxy)
+ {
+ char *str = MsRegReadStr(REG_CURRENT_USER,
+ "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings",
+ "ProxyServer");
+ if (str != NULL)
+ {
+ char name[MAX_HOST_NAME_LEN + 1];
+ UINT port;
+
+ if (GetProxyServerNameAndPortFromIeProxyRegStr(name, sizeof(name),
+ &port, str, "https"))
+ {
+ setting->ProxyType = PROXY_HTTP;
+ StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), name);
+ setting->ProxyPort = port;
+ }
+ else if (GetProxyServerNameAndPortFromIeProxyRegStr(name, sizeof(name),
+ &port, str, "http"))
+ {
+ setting->ProxyType = PROXY_HTTP;
+ StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), name);
+ setting->ProxyPort = port;
+ }
+ else if (GetProxyServerNameAndPortFromIeProxyRegStr(name, sizeof(name),
+ &port, str, "socks"))
+ {
+ setting->ProxyType = PROXY_SOCKS;
+ StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), name);
+ setting->ProxyPort = port;
+ }
+ else
+ {
+ if (SearchStrEx(str, "=", 0, false) == INFINITE)
+ {
+ char *host;
+ UINT port;
+ if (ParseHostPort(str, &host, &port, 0))
+ {
+ if (port != 0)
+ {
+ setting->ProxyType = PROXY_HTTP;
+ StrCpy(setting->ProxyHostName, sizeof(setting->ProxyHostName), host);
+ setting->ProxyPort = port;
+ }
+ Free(host);
+ }
+ }
+ }
+
+ Free(str);
+ }
+ }
+#else // OS_WIN32
+ Zero(setting, sizeof(INTERNET_SETTING));
+#endif // OS_WIN32
+}
+
+// Generate the URL
+void CreateUrl(char *url, UINT url_size, URL_DATA *data)
+{
+ char *protocol;
+ // Validate arguments
+ if (url == NULL || data == NULL)
+ {
+ return;
+ }
+
+ if (data->Secure == false)
+ {
+ protocol = "http://";
+ }
+ else
+ {
+ protocol = "https://";
+ }
+
+ Format(url, url_size, "%s%s%s", protocol, data->HeaderHostName, data->Target);
+}
+
+
+// Parse the URL
+bool ParseUrl(URL_DATA *data, char *str, bool is_post, char *referrer)
+{
+ char tmp[MAX_SIZE * 3];
+ char server_port[MAX_HOST_NAME_LEN + 16];
+ char *s = NULL;
+ char *host;
+ UINT port;
+ UINT i;
+ // Validate arguments
+ if (data == NULL || str == NULL)
+ {
+ return false;
+ }
+
+ Zero(data, sizeof(URL_DATA));
+
+ if (is_post)
+ {
+ StrCpy(data->Method, sizeof(data->Method), WPC_HTTP_POST_NAME);
+ }
+ else
+ {
+ StrCpy(data->Method, sizeof(data->Method), WPC_HTTP_GET_NAME);
+ }
+
+ if (referrer != NULL)
+ {
+ StrCpy(data->Referer, sizeof(data->Referer), referrer);
+ }
+
+ StrCpy(tmp, sizeof(tmp), str);
+ Trim(tmp);
+
+ // Determine the protocol
+ if (StartWith(tmp, "http://"))
+ {
+ data->Secure = false;
+ s = &tmp[7];
+ }
+ else if (StartWith(tmp, "https://"))
+ {
+ data->Secure = true;
+ s = &tmp[8];
+ }
+ else
+ {
+ if (SearchStrEx(tmp, "://", 0, false) != INFINITE)
+ {
+ return false;
+ }
+ data->Secure = false;
+ s = &tmp[0];
+ }
+
+ // Get the "server name:port number"
+ StrCpy(server_port, sizeof(server_port), s);
+ i = SearchStrEx(server_port, "/", 0, false);
+ if (i != INFINITE)
+ {
+ server_port[i] = 0;
+ s += StrLen(server_port);
+ StrCpy(data->Target, sizeof(data->Target), s);
+ }
+ else
+ {
+ StrCpy(data->Target, sizeof(data->Target), "/");
+ }
+
+ if (ParseHostPort(server_port, &host, &port, data->Secure ? 443 : 80) == false)
+ {
+ return false;
+ }
+
+ StrCpy(data->HostName, sizeof(data->HostName), host);
+ data->Port = port;
+
+ Free(host);
+
+ if ((data->Secure && data->Port == 443) || (data->Secure == false && data->Port == 80))
+ {
+ StrCpy(data->HeaderHostName, sizeof(data->HeaderHostName), data->HostName);
+ }
+ else
+ {
+ Format(data->HeaderHostName, sizeof(data->HeaderHostName),
+ "%s:%u", data->HostName, data->Port);
+ }
+
+ return true;
+}
+
+// String replacement
+void Base64ToSafe64(char *str)
+{
+ UINT i, len;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return;
+ }
+
+ len = StrLen(str);
+
+ for (i = 0;i < len;i++)
+ {
+ switch (str[i])
+ {
+ case '=':
+ str[i] = '(';
+ break;
+
+ case '+':
+ str[i] = ')';
+ break;
+
+ case '/':
+ str[i] = '_';
+ break;
+ }
+ }
+}
+void Safe64ToBase64(char *str)
+{
+ UINT i, len;
+ // Validate arguments
+ if (str == NULL)
+ {
+ return;
+ }
+
+ len = StrLen(str);
+
+ for (i = 0;i < len;i++)
+ {
+ switch (str[i])
+ {
+ case '(':
+ str[i] = '=';
+ break;
+
+ case ')':
+ str[i] = '+';
+ break;
+
+ case '_':
+ str[i] = '/';
+ break;
+ }
+ }
+}
+
+// Decode from Safe64
+UINT DecodeSafe64(void *dst, char *src, UINT src_strlen)
+{
+ char *tmp;
+ UINT ret;
+ if (dst == NULL || src == NULL)
+ {
+ return 0;
+ }
+
+ if (src_strlen == 0)
+ {
+ src_strlen = StrLen(src);
+ }
+
+ tmp = Malloc(src_strlen + 1);
+ Copy(tmp, src, src_strlen);
+ tmp[src_strlen] = 0;
+ Safe64ToBase64(tmp);
+
+ ret = B64_Decode(dst, tmp, src_strlen);
+ Free(tmp);
+
+ return ret;
+}
+
+// Encode to Safe64
+void EncodeSafe64(char *dst, void *src, UINT src_size)
+{
+ UINT size;
+ if (dst == NULL || src == NULL)
+ {
+ return;
+ }
+
+ size = B64_Encode(dst, src, src_size);
+ dst[size] = 0;
+
+ Base64ToSafe64(dst);
+}
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/Wpc.h b/src/Cedar/Wpc.h
new file mode 100644
index 00000000..f1a29866
--- /dev/null
+++ b/src/Cedar/Wpc.h
@@ -0,0 +1,201 @@
+// SoftEther VPN Source Code
+// Cedar Communication Module
+//
+// SoftEther VPN Server, Client and Bridge are free software under GPLv2.
+//
+// Copyright (c) 2012-2014 Daiyuu Nobori.
+// Copyright (c) 2012-2014 SoftEther VPN Project, University of Tsukuba, Japan.
+// Copyright (c) 2012-2014 SoftEther Corporation.
+//
+// All Rights Reserved.
+//
+// http://www.softether.org/
+//
+// Author: Daiyuu Nobori
+// Comments: Tetsuo Sugiyama, Ph.D.
+//
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// version 2 as published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License version 2
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+// THE LICENSE AGREEMENT IS ATTACHED ON THE SOURCE-CODE PACKAGE
+// AS "LICENSE.TXT" FILE. READ THE TEXT FILE IN ADVANCE TO USE THE SOFTWARE.
+//
+//
+// THIS SOFTWARE IS DEVELOPED IN JAPAN, AND DISTRIBUTED FROM JAPAN,
+// UNDER JAPANESE LAWS. YOU MUST AGREE IN ADVANCE TO USE, COPY, MODIFY,
+// MERGE, PUBLISH, DISTRIBUTE, SUBLICENSE, AND/OR SELL COPIES OF THIS
+// SOFTWARE, THAT ANY JURIDICAL DISPUTES WHICH ARE CONCERNED TO THIS
+// SOFTWARE OR ITS CONTENTS, AGAINST US (SOFTETHER PROJECT, SOFTETHER
+// CORPORATION, DAIYUU NOBORI OR OTHER SUPPLIERS), OR ANY JURIDICAL
+// DISPUTES AGAINST US WHICH ARE CAUSED BY ANY KIND OF USING, COPYING,
+// MODIFYING, MERGING, PUBLISHING, DISTRIBUTING, SUBLICENSING, AND/OR
+// SELLING COPIES OF THIS SOFTWARE SHALL BE REGARDED AS BE CONSTRUED AND
+// CONTROLLED BY JAPANESE LAWS, AND YOU MUST FURTHER CONSENT TO
+// EXCLUSIVE JURISDICTION AND VENUE IN THE COURTS SITTING IN TOKYO,
+// JAPAN. YOU MUST WAIVE ALL DEFENSES OF LACK OF PERSONAL JURISDICTION
+// AND FORUM NON CONVENIENS. PROCESS MAY BE SERVED ON EITHER PARTY IN
+// THE MANNER AUTHORIZED BY APPLICABLE LAW OR COURT RULE.
+//
+// USE ONLY IN JAPAN. DO NOT USE IT IN OTHER COUNTRIES. IMPORTING THIS
+// SOFTWARE INTO OTHER COUNTRIES IS AT YOUR OWN RISK. SOME COUNTRIES
+// PROHIBIT ENCRYPTED COMMUNICATIONS. USING THIS SOFTWARE IN OTHER
+// COUNTRIES MIGHT BE RESTRICTED.
+//
+//
+// DEAR SECURITY EXPERTS
+// ---------------------
+//
+// If you find a bug or a security vulnerability please kindly inform us
+// about the problem immediately so that we can fix the security problem
+// to protect a lot of users around the world as soon as possible.
+//
+// Our e-mail address for security reports is:
+// softether-vpn-security [at] softether.org
+//
+// Please note that the above e-mail address is not a technical support
+// inquiry address. If you need technical assistance, please visit
+// http://www.softether.org/ and ask your question on the users forum.
+//
+// Thank you for your cooperation.
+
+
+// Wpc.h
+// Header of Wpc.c
+
+#ifndef WPC_H
+#define WPC_H
+
+// Constant
+#define WPC_HTTP_POST_NAME "POST" // POST
+#define WPC_HTTP_GET_NAME "GET" // GET
+#define WPC_USER_AGENT DEFAULT_USER_AGENT // User Agent
+#define WPC_TIMEOUT (15 * 1000) // Time-out
+#define WPC_RECV_BUF_SIZE 64000 // Receive buffer size
+#define WPC_DATA_ENTRY_SIZE 4 // Data entry size
+#define WPC_MAX_HTTP_DATASIZE (134217728) // Maximum HTTP data size
+
+// Connection parameters
+struct WPC_CONNECT
+{
+ char HostName[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT Port; // Port number
+ UINT ProxyType; // Type of proxy server
+ char ProxyHostName[MAX_HOST_NAME_LEN + 1]; // Proxy server host name
+ UINT ProxyPort; // Proxy server port number
+ char ProxyUsername[MAX_USERNAME_LEN + 1]; // Proxy server user name
+ char ProxyPassword[MAX_USERNAME_LEN + 1]; // Proxy server password
+ bool UseCompress; // Use of compression
+ bool DontCheckCert; // Do not check the certificate
+};
+
+// Internet connection settings
+struct INTERNET_SETTING
+{
+ UINT ProxyType; // Type of proxy server
+ char ProxyHostName[MAX_HOST_NAME_LEN + 1]; // Proxy server host name
+ UINT ProxyPort; // Proxy server port number
+ char ProxyUsername[MAX_USERNAME_LEN + 1]; // Proxy server user name
+ char ProxyPassword[MAX_USERNAME_LEN + 1]; // Proxy server password
+};
+
+// URL
+struct URL_DATA
+{
+ bool Secure; // Whether HTTPS
+ char HostName[MAX_HOST_NAME_LEN + 1]; // Host name
+ UINT Port; // Port number
+ char HeaderHostName[MAX_HOST_NAME_LEN + 16]; // Host name on the header
+ char Method[32]; // Method
+ char Target[MAX_SIZE * 3]; // Target
+ char Referer[MAX_SIZE * 3]; // Referer
+};
+
+// WPC entry
+struct WPC_ENTRY
+{
+ char EntryName[WPC_DATA_ENTRY_SIZE]; // Entry name
+ void *Data; // Data
+ UINT Size; // Data size
+};
+
+// WPC packet
+struct WPC_PACKET
+{
+ PACK *Pack; // Pack (data body)
+ UCHAR Hash[SHA1_SIZE]; // Data hash
+ X *Cert; // Certificate
+ UCHAR Sign[128]; // Digital signature
+};
+
+// Reception callback
+typedef bool (WPC_RECV_CALLBACK)(void *param, UINT total_size, UINT current_size, BUF *recv_buf);
+
+// Function prototype
+void EncodeSafe64(char *dst, void *src, UINT src_size);
+UINT DecodeSafe64(void *dst, char *src, UINT src_strlen);
+void Base64ToSafe64(char *str);
+void Safe64ToBase64(char *str);
+bool ParseUrl(URL_DATA *data, char *str, bool is_post, char *referrer);
+void CreateUrl(char *url, UINT url_size, URL_DATA *data);
+void GetSystemInternetSetting(INTERNET_SETTING *setting);
+bool GetProxyServerNameAndPortFromIeProxyRegStr(char *name, UINT name_size, UINT *port, char *str, char *server_type);
+BUF *HttpRequest(URL_DATA *data, INTERNET_SETTING *setting,
+ UINT timeout_connect, UINT timeout_comm,
+ UINT *error_code, bool check_ssl_trust, char *post_data,
+ WPC_RECV_CALLBACK *recv_callback, void *recv_callback_param, void *sha1_cert_hash);
+BUF *HttpRequestEx(URL_DATA *data, INTERNET_SETTING *setting,
+ UINT timeout_connect, UINT timeout_comm,
+ UINT *error_code, bool check_ssl_trust, char *post_data,
+ WPC_RECV_CALLBACK *recv_callback, void *recv_callback_param, void *sha1_cert_hash,
+ bool *cancel, UINT max_recv_size);
+BUF *HttpRequestEx2(URL_DATA *data, INTERNET_SETTING *setting,
+ UINT timeout_connect, UINT timeout_comm,
+ UINT *error_code, bool check_ssl_trust, char *post_data,
+ WPC_RECV_CALLBACK *recv_callback, void *recv_callback_param, void *sha1_cert_hash,
+ bool *cancel, UINT max_recv_size, char *header_name, char *header_value);
+SOCK *WpcSockConnect(WPC_CONNECT *param, UINT *error_code, UINT timeout);
+SOCK *WpcSockConnectEx(WPC_CONNECT *param, UINT *error_code, UINT timeout, bool *cancel);
+SOCK *WpcSockConnect2(char *hostname, UINT port, INTERNET_SETTING *t, UINT *error_code, UINT timeout);
+INTERNET_SETTING *GetNullInternetSetting();
+void WpcAddDataEntry(BUF *b, char *name, void *data, UINT size);
+void WpcAddDataEntryBin(BUF *b, char *name, void *data, UINT size);
+void WpcFillEntryName(char *dst, char *name);
+LIST *WpcParseDataEntry(BUF *b);
+void WpcFreeDataEntryList(LIST *o);
+WPC_ENTRY *WpcFindDataEntry(LIST *o, char *name);
+BUF *WpcDataEntryToBuf(WPC_ENTRY *e);
+BUF *WpcGeneratePacket(PACK *pack, X *cert, K *key);
+bool WpcParsePacket(WPC_PACKET *packet, BUF *buf);
+void WpcFreePacket(WPC_PACKET *packet);
+PACK *WpcCall(char *url, INTERNET_SETTING *setting, UINT timeout_connect, UINT timeout_comm,
+ char *function_name, PACK *pack, X *cert, K *key, void *sha1_cert_hash);
+PACK *WpcCallEx(char *url, INTERNET_SETTING *setting, UINT timeout_connect, UINT timeout_comm,
+ char *function_name, PACK *pack, X *cert, K *key, void *sha1_cert_hash, bool *cancel, UINT max_recv_size);
+bool IsProxyPrivateIp(INTERNET_SETTING *s);
+
+#endif // WPC_H
+
+
+
+// Developed by SoftEther VPN Project at University of Tsukuba in Japan.
+// Department of Computer Science has dozens of overly-enthusiastic geeks.
+// Join us: http://www.tsukuba.ac.jp/english/admission/
diff --git a/src/Cedar/netcfgn.h b/src/Cedar/netcfgn.h
new file mode 100644
index 00000000..796f32be
--- /dev/null
+++ b/src/Cedar/netcfgn.h
@@ -0,0 +1,1335 @@
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 7.00.0555 */
+/* Compiler settings for netcfgn.idl:
+ Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555
+ protocol : dce , ms_ext, c_ext, robust
+ error checks: allocation ref bounds_check enum stub_data
+ VC __declspec() decoration level:
+ __declspec(uuid()), __declspec(selectany), __declspec(novtable)
+ DECLSPEC_UUID(), MIDL_INTERFACE()
+*/
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 500
+#endif
+
+/* verify that the <rpcsal.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCSAL_H_VERSION__
+#define __REQUIRED_RPCSAL_H_VERSION__ 100
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __netcfgn_h__
+#define __netcfgn_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __INetCfgPnpReconfigCallback_FWD_DEFINED__
+#define __INetCfgPnpReconfigCallback_FWD_DEFINED__
+typedef interface INetCfgPnpReconfigCallback INetCfgPnpReconfigCallback;
+#endif /* __INetCfgPnpReconfigCallback_FWD_DEFINED__ */
+
+
+#ifndef __INetCfgComponentControl_FWD_DEFINED__
+#define __INetCfgComponentControl_FWD_DEFINED__
+typedef interface INetCfgComponentControl INetCfgComponentControl;
+#endif /* __INetCfgComponentControl_FWD_DEFINED__ */
+
+
+#ifndef __INetCfgComponentSetup_FWD_DEFINED__
+#define __INetCfgComponentSetup_FWD_DEFINED__
+typedef interface INetCfgComponentSetup INetCfgComponentSetup;
+#endif /* __INetCfgComponentSetup_FWD_DEFINED__ */
+
+
+#ifndef __INetCfgComponentPropertyUi_FWD_DEFINED__
+#define __INetCfgComponentPropertyUi_FWD_DEFINED__
+typedef interface INetCfgComponentPropertyUi INetCfgComponentPropertyUi;
+#endif /* __INetCfgComponentPropertyUi_FWD_DEFINED__ */
+
+
+#ifndef __INetCfgComponentNotifyBinding_FWD_DEFINED__
+#define __INetCfgComponentNotifyBinding_FWD_DEFINED__
+typedef interface INetCfgComponentNotifyBinding INetCfgComponentNotifyBinding;
+#endif /* __INetCfgComponentNotifyBinding_FWD_DEFINED__ */
+
+
+#ifndef __INetCfgComponentNotifyGlobal_FWD_DEFINED__
+#define __INetCfgComponentNotifyGlobal_FWD_DEFINED__
+typedef interface INetCfgComponentNotifyGlobal INetCfgComponentNotifyGlobal;
+#endif /* __INetCfgComponentNotifyGlobal_FWD_DEFINED__ */
+
+
+#ifndef __INetCfgComponentUpperEdge_FWD_DEFINED__
+#define __INetCfgComponentUpperEdge_FWD_DEFINED__
+typedef interface INetCfgComponentUpperEdge INetCfgComponentUpperEdge;
+#endif /* __INetCfgComponentUpperEdge_FWD_DEFINED__ */
+
+
+#ifndef __INetLanConnectionUiInfo_FWD_DEFINED__
+#define __INetLanConnectionUiInfo_FWD_DEFINED__
+typedef interface INetLanConnectionUiInfo INetLanConnectionUiInfo;
+#endif /* __INetLanConnectionUiInfo_FWD_DEFINED__ */
+
+
+#ifndef __INetRasConnectionIpUiInfo_FWD_DEFINED__
+#define __INetRasConnectionIpUiInfo_FWD_DEFINED__
+typedef interface INetRasConnectionIpUiInfo INetRasConnectionIpUiInfo;
+#endif /* __INetRasConnectionIpUiInfo_FWD_DEFINED__ */
+
+
+#ifndef __INetCfgComponentSysPrep_FWD_DEFINED__
+#define __INetCfgComponentSysPrep_FWD_DEFINED__
+typedef interface INetCfgComponentSysPrep INetCfgComponentSysPrep;
+#endif /* __INetCfgComponentSysPrep_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "unknwn.h"
+#include "netcfgx.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_netcfgn_0000_0000 */
+/* [local] */
+
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+//--------------------------------------------------------------------------
+#if ( _MSC_VER >= 800 )
+#pragma warning(disable:4201)
+#endif
+
+
+extern RPC_IF_HANDLE __MIDL_itf_netcfgn_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_netcfgn_0000_0000_v0_0_s_ifspec;
+
+#ifndef __INetCfgPnpReconfigCallback_INTERFACE_DEFINED__
+#define __INetCfgPnpReconfigCallback_INTERFACE_DEFINED__
+
+/* interface INetCfgPnpReconfigCallback */
+/* [unique][uuid][object][local] */
+
+typedef /* [v1_enum] */
+enum tagNCPNP_RECONFIG_LAYER
+ { NCRL_NDIS = 1,
+ NCRL_TDI = 2
+ } NCPNP_RECONFIG_LAYER;
+
+
+EXTERN_C const IID IID_INetCfgPnpReconfigCallback;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("8d84bd35-e227-11d2-b700-00a0c98a6a85")
+ INetCfgPnpReconfigCallback : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SendPnpReconfig(
+ /* [annotation][in] */
+ __in NCPNP_RECONFIG_LAYER Layer,
+ /* [annotation][in] */
+ __in LPCWSTR pszwUpper,
+ /* [annotation][in] */
+ __in LPCWSTR pszwLower,
+ /* [annotation][in] */
+ __in_bcount(dwSizeOfData) PVOID pvData,
+ /* [annotation][in] */
+ __in DWORD dwSizeOfData) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct INetCfgPnpReconfigCallbackVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ INetCfgPnpReconfigCallback * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ INetCfgPnpReconfigCallback * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ INetCfgPnpReconfigCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SendPnpReconfig )(
+ INetCfgPnpReconfigCallback * This,
+ /* [annotation][in] */
+ __in NCPNP_RECONFIG_LAYER Layer,
+ /* [annotation][in] */
+ __in LPCWSTR pszwUpper,
+ /* [annotation][in] */
+ __in LPCWSTR pszwLower,
+ /* [annotation][in] */
+ __in_bcount(dwSizeOfData) PVOID pvData,
+ /* [annotation][in] */
+ __in DWORD dwSizeOfData);
+
+ END_INTERFACE
+ } INetCfgPnpReconfigCallbackVtbl;
+
+ interface INetCfgPnpReconfigCallback
+ {
+ CONST_VTBL struct INetCfgPnpReconfigCallbackVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define INetCfgPnpReconfigCallback_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define INetCfgPnpReconfigCallback_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define INetCfgPnpReconfigCallback_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define INetCfgPnpReconfigCallback_SendPnpReconfig(This,Layer,pszwUpper,pszwLower,pvData,dwSizeOfData) \
+ ( (This)->lpVtbl -> SendPnpReconfig(This,Layer,pszwUpper,pszwLower,pvData,dwSizeOfData) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __INetCfgPnpReconfigCallback_INTERFACE_DEFINED__ */
+
+
+#ifndef __INetCfgComponentControl_INTERFACE_DEFINED__
+#define __INetCfgComponentControl_INTERFACE_DEFINED__
+
+/* interface INetCfgComponentControl */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_INetCfgComponentControl;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("932238df-bea1-11d0-9298-00c04fc99dcf")
+ INetCfgComponentControl : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Initialize(
+ /* [annotation][in] */
+ __in INetCfgComponent *pIComp,
+ /* [annotation][in] */
+ __in INetCfg *pINetCfg,
+ /* [annotation][in] */
+ __in BOOL fInstalling) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ApplyRegistryChanges( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ApplyPnpChanges(
+ /* [annotation][in] */
+ __in INetCfgPnpReconfigCallback *pICallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CancelChanges( void) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct INetCfgComponentControlVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ INetCfgComponentControl * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ INetCfgComponentControl * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ INetCfgComponentControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ INetCfgComponentControl * This,
+ /* [annotation][in] */
+ __in INetCfgComponent *pIComp,
+ /* [annotation][in] */
+ __in INetCfg *pINetCfg,
+ /* [annotation][in] */
+ __in BOOL fInstalling);
+
+ HRESULT ( STDMETHODCALLTYPE *ApplyRegistryChanges )(
+ INetCfgComponentControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ApplyPnpChanges )(
+ INetCfgComponentControl * This,
+ /* [annotation][in] */
+ __in INetCfgPnpReconfigCallback *pICallback);
+
+ HRESULT ( STDMETHODCALLTYPE *CancelChanges )(
+ INetCfgComponentControl * This);
+
+ END_INTERFACE
+ } INetCfgComponentControlVtbl;
+
+ interface INetCfgComponentControl
+ {
+ CONST_VTBL struct INetCfgComponentControlVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define INetCfgComponentControl_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define INetCfgComponentControl_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define INetCfgComponentControl_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define INetCfgComponentControl_Initialize(This,pIComp,pINetCfg,fInstalling) \
+ ( (This)->lpVtbl -> Initialize(This,pIComp,pINetCfg,fInstalling) )
+
+#define INetCfgComponentControl_ApplyRegistryChanges(This) \
+ ( (This)->lpVtbl -> ApplyRegistryChanges(This) )
+
+#define INetCfgComponentControl_ApplyPnpChanges(This,pICallback) \
+ ( (This)->lpVtbl -> ApplyPnpChanges(This,pICallback) )
+
+#define INetCfgComponentControl_CancelChanges(This) \
+ ( (This)->lpVtbl -> CancelChanges(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __INetCfgComponentControl_INTERFACE_DEFINED__ */
+
+
+#ifndef __INetCfgComponentSetup_INTERFACE_DEFINED__
+#define __INetCfgComponentSetup_INTERFACE_DEFINED__
+
+/* interface INetCfgComponentSetup */
+/* [unique][uuid][object][local] */
+
+typedef /* [v1_enum] */
+enum tagNETWORK_INSTALL_TIME
+ { NSF_PRIMARYINSTALL = 0x1,
+ NSF_POSTSYSINSTALL = 0x2
+ } NETWORK_INSTALL_TIME;
+
+typedef /* [v1_enum] */
+enum tagNETWORK_UPGRADE_TYPE
+ { NSF_WIN16_UPGRADE = 0x10,
+ NSF_WIN95_UPGRADE = 0x20,
+ NSF_WINNT_WKS_UPGRADE = 0x40,
+ NSF_WINNT_SVR_UPGRADE = 0x80,
+ NSF_WINNT_SBS_UPGRADE = 0x100,
+ NSF_COMPONENT_UPDATE = 0x200
+ } NETWORK_UPGRADE_TYPE;
+
+
+EXTERN_C const IID IID_INetCfgComponentSetup;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("932238e3-bea1-11d0-9298-00c04fc99dcf")
+ INetCfgComponentSetup : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Install(
+ /* [annotation][in] */
+ __in DWORD dwSetupFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Upgrade(
+ /* [annotation][in] */
+ __in DWORD dwSetupFlags,
+ /* [annotation][in] */
+ __in DWORD dwUpgradeFomBuildNo) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ReadAnswerFile(
+ /* [annotation][in] */
+ __in LPCWSTR pszwAnswerFile,
+ /* [annotation][in] */
+ __in LPCWSTR pszwAnswerSections) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Removing( void) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct INetCfgComponentSetupVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ INetCfgComponentSetup * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ INetCfgComponentSetup * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ INetCfgComponentSetup * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Install )(
+ INetCfgComponentSetup * This,
+ /* [annotation][in] */
+ __in DWORD dwSetupFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *Upgrade )(
+ INetCfgComponentSetup * This,
+ /* [annotation][in] */
+ __in DWORD dwSetupFlags,
+ /* [annotation][in] */
+ __in DWORD dwUpgradeFomBuildNo);
+
+ HRESULT ( STDMETHODCALLTYPE *ReadAnswerFile )(
+ INetCfgComponentSetup * This,
+ /* [annotation][in] */
+ __in LPCWSTR pszwAnswerFile,
+ /* [annotation][in] */
+ __in LPCWSTR pszwAnswerSections);
+
+ HRESULT ( STDMETHODCALLTYPE *Removing )(
+ INetCfgComponentSetup * This);
+
+ END_INTERFACE
+ } INetCfgComponentSetupVtbl;
+
+ interface INetCfgComponentSetup
+ {
+ CONST_VTBL struct INetCfgComponentSetupVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define INetCfgComponentSetup_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define INetCfgComponentSetup_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define INetCfgComponentSetup_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define INetCfgComponentSetup_Install(This,dwSetupFlags) \
+ ( (This)->lpVtbl -> Install(This,dwSetupFlags) )
+
+#define INetCfgComponentSetup_Upgrade(This,dwSetupFlags,dwUpgradeFomBuildNo) \
+ ( (This)->lpVtbl -> Upgrade(This,dwSetupFlags,dwUpgradeFomBuildNo) )
+
+#define INetCfgComponentSetup_ReadAnswerFile(This,pszwAnswerFile,pszwAnswerSections) \
+ ( (This)->lpVtbl -> ReadAnswerFile(This,pszwAnswerFile,pszwAnswerSections) )
+
+#define INetCfgComponentSetup_Removing(This) \
+ ( (This)->lpVtbl -> Removing(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __INetCfgComponentSetup_INTERFACE_DEFINED__ */
+
+
+#ifndef __INetCfgComponentPropertyUi_INTERFACE_DEFINED__
+#define __INetCfgComponentPropertyUi_INTERFACE_DEFINED__
+
+/* interface INetCfgComponentPropertyUi */
+/* [unique][uuid][object][local] */
+
+typedef /* [v1_enum] */
+enum tagDEFAULT_PAGES
+ { DPP_ADVANCED = 1
+ } DEFAULT_PAGES;
+
+
+EXTERN_C const IID IID_INetCfgComponentPropertyUi;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("932238e0-bea1-11d0-9298-00c04fc99dcf")
+ INetCfgComponentPropertyUi : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE QueryPropertyUi(
+ /* [annotation][in] */
+ __in IUnknown *pUnkReserved) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetContext(
+ /* [annotation][in] */
+ __in IUnknown *pUnkReserved) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE MergePropPages(
+ /* [annotation][out][in] */
+ __inout DWORD *pdwDefPages,
+ /* [annotation][out] */
+ __out BYTE **pahpspPrivate,
+ /* [annotation][out] */
+ __out UINT *pcPages,
+ /* [annotation][in] */
+ __in HWND hwndParent,
+ /* [annotation][in] */
+ __in_opt LPCWSTR *pszStartPage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ValidateProperties(
+ /* [annotation][in] */
+ __in HWND hwndSheet) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ApplyProperties( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CancelProperties( void) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct INetCfgComponentPropertyUiVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ INetCfgComponentPropertyUi * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ INetCfgComponentPropertyUi * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ INetCfgComponentPropertyUi * This);
+
+ HRESULT ( STDMETHODCALLTYPE *QueryPropertyUi )(
+ INetCfgComponentPropertyUi * This,
+ /* [annotation][in] */
+ __in IUnknown *pUnkReserved);
+
+ HRESULT ( STDMETHODCALLTYPE *SetContext )(
+ INetCfgComponentPropertyUi * This,
+ /* [annotation][in] */
+ __in IUnknown *pUnkReserved);
+
+ HRESULT ( STDMETHODCALLTYPE *MergePropPages )(
+ INetCfgComponentPropertyUi * This,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwDefPages,
+ /* [annotation][out] */
+ __out BYTE **pahpspPrivate,
+ /* [annotation][out] */
+ __out UINT *pcPages,
+ /* [annotation][in] */
+ __in HWND hwndParent,
+ /* [annotation][in] */
+ __in_opt LPCWSTR *pszStartPage);
+
+ HRESULT ( STDMETHODCALLTYPE *ValidateProperties )(
+ INetCfgComponentPropertyUi * This,
+ /* [annotation][in] */
+ __in HWND hwndSheet);
+
+ HRESULT ( STDMETHODCALLTYPE *ApplyProperties )(
+ INetCfgComponentPropertyUi * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CancelProperties )(
+ INetCfgComponentPropertyUi * This);
+
+ END_INTERFACE
+ } INetCfgComponentPropertyUiVtbl;
+
+ interface INetCfgComponentPropertyUi
+ {
+ CONST_VTBL struct INetCfgComponentPropertyUiVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define INetCfgComponentPropertyUi_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define INetCfgComponentPropertyUi_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define INetCfgComponentPropertyUi_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define INetCfgComponentPropertyUi_QueryPropertyUi(This,pUnkReserved) \
+ ( (This)->lpVtbl -> QueryPropertyUi(This,pUnkReserved) )
+
+#define INetCfgComponentPropertyUi_SetContext(This,pUnkReserved) \
+ ( (This)->lpVtbl -> SetContext(This,pUnkReserved) )
+
+#define INetCfgComponentPropertyUi_MergePropPages(This,pdwDefPages,pahpspPrivate,pcPages,hwndParent,pszStartPage) \
+ ( (This)->lpVtbl -> MergePropPages(This,pdwDefPages,pahpspPrivate,pcPages,hwndParent,pszStartPage) )
+
+#define INetCfgComponentPropertyUi_ValidateProperties(This,hwndSheet) \
+ ( (This)->lpVtbl -> ValidateProperties(This,hwndSheet) )
+
+#define INetCfgComponentPropertyUi_ApplyProperties(This) \
+ ( (This)->lpVtbl -> ApplyProperties(This) )
+
+#define INetCfgComponentPropertyUi_CancelProperties(This) \
+ ( (This)->lpVtbl -> CancelProperties(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __INetCfgComponentPropertyUi_INTERFACE_DEFINED__ */
+
+
+#ifndef __INetCfgComponentNotifyBinding_INTERFACE_DEFINED__
+#define __INetCfgComponentNotifyBinding_INTERFACE_DEFINED__
+
+/* interface INetCfgComponentNotifyBinding */
+/* [unique][uuid][object][local] */
+
+typedef /* [v1_enum] */
+enum tagBIND_FLAGS1
+ { NCN_ADD = 0x1,
+ NCN_REMOVE = 0x2,
+ NCN_UPDATE = 0x4,
+ NCN_ENABLE = 0x10,
+ NCN_DISABLE = 0x20,
+ NCN_BINDING_PATH = 0x100,
+ NCN_PROPERTYCHANGE = 0x200,
+ NCN_NET = 0x10000,
+ NCN_NETTRANS = 0x20000,
+ NCN_NETCLIENT = 0x40000,
+ NCN_NETSERVICE = 0x80000
+ } BIND_FLAGS1;
+
+
+EXTERN_C const IID IID_INetCfgComponentNotifyBinding;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("932238e1-bea1-11d0-9298-00c04fc99dcf")
+ INetCfgComponentNotifyBinding : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE QueryBindingPath(
+ /* [annotation][in] */
+ __in DWORD dwChangeFlag,
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pIPath) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE NotifyBindingPath(
+ /* [annotation][in] */
+ __in DWORD dwChangeFlag,
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pIPath) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct INetCfgComponentNotifyBindingVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ INetCfgComponentNotifyBinding * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ INetCfgComponentNotifyBinding * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ INetCfgComponentNotifyBinding * This);
+
+ HRESULT ( STDMETHODCALLTYPE *QueryBindingPath )(
+ INetCfgComponentNotifyBinding * This,
+ /* [annotation][in] */
+ __in DWORD dwChangeFlag,
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pIPath);
+
+ HRESULT ( STDMETHODCALLTYPE *NotifyBindingPath )(
+ INetCfgComponentNotifyBinding * This,
+ /* [annotation][in] */
+ __in DWORD dwChangeFlag,
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pIPath);
+
+ END_INTERFACE
+ } INetCfgComponentNotifyBindingVtbl;
+
+ interface INetCfgComponentNotifyBinding
+ {
+ CONST_VTBL struct INetCfgComponentNotifyBindingVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define INetCfgComponentNotifyBinding_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define INetCfgComponentNotifyBinding_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define INetCfgComponentNotifyBinding_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define INetCfgComponentNotifyBinding_QueryBindingPath(This,dwChangeFlag,pIPath) \
+ ( (This)->lpVtbl -> QueryBindingPath(This,dwChangeFlag,pIPath) )
+
+#define INetCfgComponentNotifyBinding_NotifyBindingPath(This,dwChangeFlag,pIPath) \
+ ( (This)->lpVtbl -> NotifyBindingPath(This,dwChangeFlag,pIPath) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __INetCfgComponentNotifyBinding_INTERFACE_DEFINED__ */
+
+
+#ifndef __INetCfgComponentNotifyGlobal_INTERFACE_DEFINED__
+#define __INetCfgComponentNotifyGlobal_INTERFACE_DEFINED__
+
+/* interface INetCfgComponentNotifyGlobal */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_INetCfgComponentNotifyGlobal;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("932238e2-bea1-11d0-9298-00c04fc99dcf")
+ INetCfgComponentNotifyGlobal : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetSupportedNotifications(
+ /* [annotation][out] */
+ __out DWORD *dwNotifications) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SysQueryBindingPath(
+ /* [annotation][in] */
+ __in DWORD dwChangeFlag,
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pIPath) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SysNotifyBindingPath(
+ /* [annotation][in] */
+ __in DWORD dwChangeFlag,
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pIPath) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SysNotifyComponent(
+ /* [annotation][in] */
+ __in DWORD dwChangeFlag,
+ /* [annotation][in] */
+ __in INetCfgComponent *pIComp) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct INetCfgComponentNotifyGlobalVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ INetCfgComponentNotifyGlobal * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ INetCfgComponentNotifyGlobal * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ INetCfgComponentNotifyGlobal * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSupportedNotifications )(
+ INetCfgComponentNotifyGlobal * This,
+ /* [annotation][out] */
+ __out DWORD *dwNotifications);
+
+ HRESULT ( STDMETHODCALLTYPE *SysQueryBindingPath )(
+ INetCfgComponentNotifyGlobal * This,
+ /* [annotation][in] */
+ __in DWORD dwChangeFlag,
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pIPath);
+
+ HRESULT ( STDMETHODCALLTYPE *SysNotifyBindingPath )(
+ INetCfgComponentNotifyGlobal * This,
+ /* [annotation][in] */
+ __in DWORD dwChangeFlag,
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pIPath);
+
+ HRESULT ( STDMETHODCALLTYPE *SysNotifyComponent )(
+ INetCfgComponentNotifyGlobal * This,
+ /* [annotation][in] */
+ __in DWORD dwChangeFlag,
+ /* [annotation][in] */
+ __in INetCfgComponent *pIComp);
+
+ END_INTERFACE
+ } INetCfgComponentNotifyGlobalVtbl;
+
+ interface INetCfgComponentNotifyGlobal
+ {
+ CONST_VTBL struct INetCfgComponentNotifyGlobalVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define INetCfgComponentNotifyGlobal_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define INetCfgComponentNotifyGlobal_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define INetCfgComponentNotifyGlobal_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define INetCfgComponentNotifyGlobal_GetSupportedNotifications(This,dwNotifications) \
+ ( (This)->lpVtbl -> GetSupportedNotifications(This,dwNotifications) )
+
+#define INetCfgComponentNotifyGlobal_SysQueryBindingPath(This,dwChangeFlag,pIPath) \
+ ( (This)->lpVtbl -> SysQueryBindingPath(This,dwChangeFlag,pIPath) )
+
+#define INetCfgComponentNotifyGlobal_SysNotifyBindingPath(This,dwChangeFlag,pIPath) \
+ ( (This)->lpVtbl -> SysNotifyBindingPath(This,dwChangeFlag,pIPath) )
+
+#define INetCfgComponentNotifyGlobal_SysNotifyComponent(This,dwChangeFlag,pIComp) \
+ ( (This)->lpVtbl -> SysNotifyComponent(This,dwChangeFlag,pIComp) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __INetCfgComponentNotifyGlobal_INTERFACE_DEFINED__ */
+
+
+#ifndef __INetCfgComponentUpperEdge_INTERFACE_DEFINED__
+#define __INetCfgComponentUpperEdge_INTERFACE_DEFINED__
+
+/* interface INetCfgComponentUpperEdge */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_INetCfgComponentUpperEdge;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("932238e4-bea1-11d0-9298-00c04fc99dcf")
+ INetCfgComponentUpperEdge : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetInterfaceIdsForAdapter(
+ /* [annotation][in] */
+ __in INetCfgComponent *pAdapter,
+ /* [annotation][out] */
+ __out DWORD *pdwNumInterfaces,
+ /* [annotation][out] */
+ __deref_out_opt GUID **ppguidInterfaceIds) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AddInterfacesToAdapter(
+ /* [annotation][in] */
+ __in INetCfgComponent *pAdapter,
+ /* [annotation][in] */
+ __in DWORD dwNumInterfaces) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RemoveInterfacesFromAdapter(
+ /* [annotation][in] */
+ __in INetCfgComponent *pAdapter,
+ /* [annotation][in] */
+ __in DWORD dwNumInterfaces,
+ /* [annotation][in] */
+ __in const GUID *pguidInterfaceIds) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct INetCfgComponentUpperEdgeVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ INetCfgComponentUpperEdge * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ INetCfgComponentUpperEdge * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ INetCfgComponentUpperEdge * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInterfaceIdsForAdapter )(
+ INetCfgComponentUpperEdge * This,
+ /* [annotation][in] */
+ __in INetCfgComponent *pAdapter,
+ /* [annotation][out] */
+ __out DWORD *pdwNumInterfaces,
+ /* [annotation][out] */
+ __deref_out_opt GUID **ppguidInterfaceIds);
+
+ HRESULT ( STDMETHODCALLTYPE *AddInterfacesToAdapter )(
+ INetCfgComponentUpperEdge * This,
+ /* [annotation][in] */
+ __in INetCfgComponent *pAdapter,
+ /* [annotation][in] */
+ __in DWORD dwNumInterfaces);
+
+ HRESULT ( STDMETHODCALLTYPE *RemoveInterfacesFromAdapter )(
+ INetCfgComponentUpperEdge * This,
+ /* [annotation][in] */
+ __in INetCfgComponent *pAdapter,
+ /* [annotation][in] */
+ __in DWORD dwNumInterfaces,
+ /* [annotation][in] */
+ __in const GUID *pguidInterfaceIds);
+
+ END_INTERFACE
+ } INetCfgComponentUpperEdgeVtbl;
+
+ interface INetCfgComponentUpperEdge
+ {
+ CONST_VTBL struct INetCfgComponentUpperEdgeVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define INetCfgComponentUpperEdge_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define INetCfgComponentUpperEdge_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define INetCfgComponentUpperEdge_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define INetCfgComponentUpperEdge_GetInterfaceIdsForAdapter(This,pAdapter,pdwNumInterfaces,ppguidInterfaceIds) \
+ ( (This)->lpVtbl -> GetInterfaceIdsForAdapter(This,pAdapter,pdwNumInterfaces,ppguidInterfaceIds) )
+
+#define INetCfgComponentUpperEdge_AddInterfacesToAdapter(This,pAdapter,dwNumInterfaces) \
+ ( (This)->lpVtbl -> AddInterfacesToAdapter(This,pAdapter,dwNumInterfaces) )
+
+#define INetCfgComponentUpperEdge_RemoveInterfacesFromAdapter(This,pAdapter,dwNumInterfaces,pguidInterfaceIds) \
+ ( (This)->lpVtbl -> RemoveInterfacesFromAdapter(This,pAdapter,dwNumInterfaces,pguidInterfaceIds) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __INetCfgComponentUpperEdge_INTERFACE_DEFINED__ */
+
+
+#ifndef __INetLanConnectionUiInfo_INTERFACE_DEFINED__
+#define __INetLanConnectionUiInfo_INTERFACE_DEFINED__
+
+/* interface INetLanConnectionUiInfo */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_INetLanConnectionUiInfo;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C08956A6-1CD3-11D1-B1C5-00805FC1270E")
+ INetLanConnectionUiInfo : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetDeviceGuid(
+ /* [out] */ __RPC__out GUID *pguid) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct INetLanConnectionUiInfoVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in INetLanConnectionUiInfo * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in INetLanConnectionUiInfo * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in INetLanConnectionUiInfo * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceGuid )(
+ __RPC__in INetLanConnectionUiInfo * This,
+ /* [out] */ __RPC__out GUID *pguid);
+
+ END_INTERFACE
+ } INetLanConnectionUiInfoVtbl;
+
+ interface INetLanConnectionUiInfo
+ {
+ CONST_VTBL struct INetLanConnectionUiInfoVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define INetLanConnectionUiInfo_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define INetLanConnectionUiInfo_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define INetLanConnectionUiInfo_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define INetLanConnectionUiInfo_GetDeviceGuid(This,pguid) \
+ ( (This)->lpVtbl -> GetDeviceGuid(This,pguid) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __INetLanConnectionUiInfo_INTERFACE_DEFINED__ */
+
+
+#ifndef __INetRasConnectionIpUiInfo_INTERFACE_DEFINED__
+#define __INetRasConnectionIpUiInfo_INTERFACE_DEFINED__
+
+/* interface INetRasConnectionIpUiInfo */
+/* [unique][uuid][object] */
+
+typedef
+enum tagRASCON_IPUI_FLAGS
+ { RCUIF_VPN = 0x1,
+ RCUIF_DEMAND_DIAL = 0x2,
+ RCUIF_NOT_ADMIN = 0x4,
+ RCUIF_USE_IPv4_STATICADDRESS = 0x8,
+ RCUIF_USE_IPv4_NAME_SERVERS = 0x10,
+ RCUIF_USE_IPv4_REMOTE_GATEWAY = 0x20,
+ RCUIF_USE_IPv4_EXPLICIT_METRIC = 0x40,
+ RCUIF_USE_HEADER_COMPRESSION = 0x80,
+ RCUIF_USE_DISABLE_REGISTER_DNS = 0x100,
+ RCUIF_USE_PRIVATE_DNS_SUFFIX = 0x200,
+ RCUIF_ENABLE_NBT = 0x400,
+ RCUIF_USE_IPv6_STATICADDRESS = 0x800,
+ RCUIF_USE_IPv6_NAME_SERVERS = 0x1000,
+ RCUIF_USE_IPv6_REMOTE_GATEWAY = 0x2000,
+ RCUIF_USE_IPv6_EXPLICIT_METRIC = 0x4000,
+ RCUIF_DISABLE_CLASS_BASED_ROUTE = 0x8000
+ } RASCON_UIINFO_FLAGS;
+
+typedef struct tagRASCON_IPUI
+ {
+ GUID guidConnection;
+ BOOL fIPv6Cfg;
+ DWORD dwFlags;
+ WCHAR pszwIpAddr[ 16 ];
+ WCHAR pszwDnsAddr[ 16 ];
+ WCHAR pszwDns2Addr[ 16 ];
+ WCHAR pszwWinsAddr[ 16 ];
+ WCHAR pszwWins2Addr[ 16 ];
+ WCHAR pszwDnsSuffix[ 256 ];
+ WCHAR pszwIpv6Addr[ 65 ];
+ DWORD dwIpv6PrefixLength;
+ WCHAR pszwIpv6DnsAddr[ 65 ];
+ WCHAR pszwIpv6Dns2Addr[ 65 ];
+ DWORD dwIPv4InfMetric;
+ DWORD dwIPv6InfMetric;
+ } RASCON_IPUI;
+
+
+EXTERN_C const IID IID_INetRasConnectionIpUiInfo;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("FAEDCF58-31FE-11D1-AAD2-00805FC1270E")
+ INetRasConnectionIpUiInfo : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetUiInfo(
+ /* [out] */ __RPC__out RASCON_IPUI *pInfo) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct INetRasConnectionIpUiInfoVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in INetRasConnectionIpUiInfo * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in INetRasConnectionIpUiInfo * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in INetRasConnectionIpUiInfo * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetUiInfo )(
+ __RPC__in INetRasConnectionIpUiInfo * This,
+ /* [out] */ __RPC__out RASCON_IPUI *pInfo);
+
+ END_INTERFACE
+ } INetRasConnectionIpUiInfoVtbl;
+
+ interface INetRasConnectionIpUiInfo
+ {
+ CONST_VTBL struct INetRasConnectionIpUiInfoVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define INetRasConnectionIpUiInfo_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define INetRasConnectionIpUiInfo_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define INetRasConnectionIpUiInfo_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define INetRasConnectionIpUiInfo_GetUiInfo(This,pInfo) \
+ ( (This)->lpVtbl -> GetUiInfo(This,pInfo) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __INetRasConnectionIpUiInfo_INTERFACE_DEFINED__ */
+
+
+#ifndef __INetCfgComponentSysPrep_INTERFACE_DEFINED__
+#define __INetCfgComponentSysPrep_INTERFACE_DEFINED__
+
+/* interface INetCfgComponentSysPrep */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_INetCfgComponentSysPrep;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C0E8AE9A-306E-11D1-AACF-00805FC1270E")
+ INetCfgComponentSysPrep : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SaveAdapterParameters(
+ /* [annotation][in] */
+ __in INetCfgSysPrep *pncsp,
+ /* [annotation][in] */
+ __in LPCWSTR pszwAnswerSections,
+ /* [annotation][in] */
+ __in GUID *pAdapterInstanceGuid) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RestoreAdapterParameters(
+ /* [annotation][in] */
+ __in LPCWSTR pszwAnswerFile,
+ /* [annotation][in] */
+ __in LPCWSTR pszwAnswerSection,
+ /* [annotation][in] */
+ __in GUID *pAdapterInstanceGuid) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct INetCfgComponentSysPrepVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ INetCfgComponentSysPrep * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ INetCfgComponentSysPrep * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ INetCfgComponentSysPrep * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SaveAdapterParameters )(
+ INetCfgComponentSysPrep * This,
+ /* [annotation][in] */
+ __in INetCfgSysPrep *pncsp,
+ /* [annotation][in] */
+ __in LPCWSTR pszwAnswerSections,
+ /* [annotation][in] */
+ __in GUID *pAdapterInstanceGuid);
+
+ HRESULT ( STDMETHODCALLTYPE *RestoreAdapterParameters )(
+ INetCfgComponentSysPrep * This,
+ /* [annotation][in] */
+ __in LPCWSTR pszwAnswerFile,
+ /* [annotation][in] */
+ __in LPCWSTR pszwAnswerSection,
+ /* [annotation][in] */
+ __in GUID *pAdapterInstanceGuid);
+
+ END_INTERFACE
+ } INetCfgComponentSysPrepVtbl;
+
+ interface INetCfgComponentSysPrep
+ {
+ CONST_VTBL struct INetCfgComponentSysPrepVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define INetCfgComponentSysPrep_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define INetCfgComponentSysPrep_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define INetCfgComponentSysPrep_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define INetCfgComponentSysPrep_SaveAdapterParameters(This,pncsp,pszwAnswerSections,pAdapterInstanceGuid) \
+ ( (This)->lpVtbl -> SaveAdapterParameters(This,pncsp,pszwAnswerSections,pAdapterInstanceGuid) )
+
+#define INetCfgComponentSysPrep_RestoreAdapterParameters(This,pszwAnswerFile,pszwAnswerSection,pAdapterInstanceGuid) \
+ ( (This)->lpVtbl -> RestoreAdapterParameters(This,pszwAnswerFile,pszwAnswerSection,pAdapterInstanceGuid) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __INetCfgComponentSysPrep_INTERFACE_DEFINED__ */
+
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
+
diff --git a/src/Cedar/netcfgx.h b/src/Cedar/netcfgx.h
new file mode 100644
index 00000000..59c9f52c
--- /dev/null
+++ b/src/Cedar/netcfgx.h
@@ -0,0 +1,1941 @@
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 7.00.0555 */
+/* Compiler settings for netcfgx.idl:
+ Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 7.00.0555
+ protocol : dce , ms_ext, c_ext, robust
+ error checks: allocation ref bounds_check enum stub_data
+ VC __declspec() decoration level:
+ __declspec(uuid()), __declspec(selectany), __declspec(novtable)
+ DECLSPEC_UUID(), MIDL_INTERFACE()
+*/
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 500
+#endif
+
+/* verify that the <rpcsal.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCSAL_H_VERSION__
+#define __REQUIRED_RPCSAL_H_VERSION__ 100
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __netcfgx_h__
+#define __netcfgx_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __IEnumNetCfgBindingInterface_FWD_DEFINED__
+#define __IEnumNetCfgBindingInterface_FWD_DEFINED__
+typedef interface IEnumNetCfgBindingInterface IEnumNetCfgBindingInterface;
+#endif /* __IEnumNetCfgBindingInterface_FWD_DEFINED__ */
+
+
+#ifndef __IEnumNetCfgBindingPath_FWD_DEFINED__
+#define __IEnumNetCfgBindingPath_FWD_DEFINED__
+typedef interface IEnumNetCfgBindingPath IEnumNetCfgBindingPath;
+#endif /* __IEnumNetCfgBindingPath_FWD_DEFINED__ */
+
+
+#ifndef __IEnumNetCfgComponent_FWD_DEFINED__
+#define __IEnumNetCfgComponent_FWD_DEFINED__
+typedef interface IEnumNetCfgComponent IEnumNetCfgComponent;
+#endif /* __IEnumNetCfgComponent_FWD_DEFINED__ */
+
+
+#ifndef __INetCfg_FWD_DEFINED__
+#define __INetCfg_FWD_DEFINED__
+typedef interface INetCfg INetCfg;
+#endif /* __INetCfg_FWD_DEFINED__ */
+
+
+#ifndef __INetCfgLock_FWD_DEFINED__
+#define __INetCfgLock_FWD_DEFINED__
+typedef interface INetCfgLock INetCfgLock;
+#endif /* __INetCfgLock_FWD_DEFINED__ */
+
+
+#ifndef __INetCfgBindingInterface_FWD_DEFINED__
+#define __INetCfgBindingInterface_FWD_DEFINED__
+typedef interface INetCfgBindingInterface INetCfgBindingInterface;
+#endif /* __INetCfgBindingInterface_FWD_DEFINED__ */
+
+
+#ifndef __INetCfgBindingPath_FWD_DEFINED__
+#define __INetCfgBindingPath_FWD_DEFINED__
+typedef interface INetCfgBindingPath INetCfgBindingPath;
+#endif /* __INetCfgBindingPath_FWD_DEFINED__ */
+
+
+#ifndef __INetCfgClass_FWD_DEFINED__
+#define __INetCfgClass_FWD_DEFINED__
+typedef interface INetCfgClass INetCfgClass;
+#endif /* __INetCfgClass_FWD_DEFINED__ */
+
+
+#ifndef __INetCfgClassSetup_FWD_DEFINED__
+#define __INetCfgClassSetup_FWD_DEFINED__
+typedef interface INetCfgClassSetup INetCfgClassSetup;
+#endif /* __INetCfgClassSetup_FWD_DEFINED__ */
+
+
+#ifndef __INetCfgComponent_FWD_DEFINED__
+#define __INetCfgComponent_FWD_DEFINED__
+typedef interface INetCfgComponent INetCfgComponent;
+#endif /* __INetCfgComponent_FWD_DEFINED__ */
+
+
+#ifndef __INetCfgComponentBindings_FWD_DEFINED__
+#define __INetCfgComponentBindings_FWD_DEFINED__
+typedef interface INetCfgComponentBindings INetCfgComponentBindings;
+#endif /* __INetCfgComponentBindings_FWD_DEFINED__ */
+
+
+#ifndef __INetCfgSysPrep_FWD_DEFINED__
+#define __INetCfgSysPrep_FWD_DEFINED__
+typedef interface INetCfgSysPrep INetCfgSysPrep;
+#endif /* __INetCfgSysPrep_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "unknwn.h"
+#include "prsht.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_netcfgx_0000_0000 */
+/* [local] */
+
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+//--------------------------------------------------------------------------
+#if ( _MSC_VER >= 800 )
+#pragma warning(disable:4201)
+#endif
+
+EXTERN_C const CLSID CLSID_CNetCfg;
+
+#define NETCFG_E_ALREADY_INITIALIZED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xA020)
+#define NETCFG_E_NOT_INITIALIZED MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xA021)
+#define NETCFG_E_IN_USE MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xA022)
+#define NETCFG_E_NO_WRITE_LOCK MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xA024)
+#define NETCFG_E_NEED_REBOOT MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xA025)
+#define NETCFG_E_ACTIVE_RAS_CONNECTIONS MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xA026)
+#define NETCFG_E_ADAPTER_NOT_FOUND MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xA027)
+#define NETCFG_E_COMPONENT_REMOVED_PENDING_REBOOT MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xA028)
+#define NETCFG_E_MAX_FILTER_LIMIT MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, 0xA029)
+#define NETCFG_S_REBOOT MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_ITF, 0xA020)
+#define NETCFG_S_DISABLE_QUERY MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_ITF, 0xA022)
+#define NETCFG_S_STILL_REFERENCED MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_ITF, 0xA023)
+#define NETCFG_S_CAUSED_SETUP_CHANGE MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_ITF, 0xA024)
+#define NETCFG_S_COMMIT_NOW MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_ITF, 0xA025)
+
+#define NETCFG_CLIENT_CID_MS_MSClient TEXT("ms_msclient")
+#define NETCFG_SERVICE_CID_MS_SERVER TEXT("ms_server")
+#define NETCFG_SERVICE_CID_MS_NETBIOS TEXT("ms_netbios")
+#define NETCFG_SERVICE_CID_MS_PSCHED TEXT("ms_pschedpc")
+#define NETCFG_SERVICE_CID_MS_WLBS TEXT("ms_wlbs")
+#define NETCFG_TRANS_CID_MS_APPLETALK TEXT("ms_appletalk")
+#define NETCFG_TRANS_CID_MS_NETBEUI TEXT("ms_netbeui")
+#define NETCFG_TRANS_CID_MS_NETMON TEXT("ms_netmon")
+#define NETCFG_TRANS_CID_MS_NWIPX TEXT("ms_nwipx")
+#define NETCFG_TRANS_CID_MS_NWSPX TEXT("ms_nwspx")
+#define NETCFG_TRANS_CID_MS_TCPIP TEXT("ms_tcpip")
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_netcfgx_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_netcfgx_0000_0000_v0_0_s_ifspec;
+
+#ifndef __IEnumNetCfgBindingInterface_INTERFACE_DEFINED__
+#define __IEnumNetCfgBindingInterface_INTERFACE_DEFINED__
+
+/* interface IEnumNetCfgBindingInterface */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_IEnumNetCfgBindingInterface;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C0E8AE90-306E-11D1-AACF-00805FC1270E")
+ IEnumNetCfgBindingInterface : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [annotation][in] */
+ __in ULONG celt,
+ /* [annotation][length_is][size_is][out] */
+ __out_ecount(celt) INetCfgBindingInterface **rgelt,
+ /* [annotation][out] */
+ __out_opt ULONG *pceltFetched) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Skip(
+ /* [annotation][in] */
+ __in ULONG celt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ /* [annotation][out] */
+ __out IEnumNetCfgBindingInterface **ppenum) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IEnumNetCfgBindingInterfaceVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IEnumNetCfgBindingInterface * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IEnumNetCfgBindingInterface * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IEnumNetCfgBindingInterface * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ IEnumNetCfgBindingInterface * This,
+ /* [annotation][in] */
+ __in ULONG celt,
+ /* [annotation][length_is][size_is][out] */
+ __out_ecount(celt) INetCfgBindingInterface **rgelt,
+ /* [annotation][out] */
+ __out_opt ULONG *pceltFetched);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ IEnumNetCfgBindingInterface * This,
+ /* [annotation][in] */
+ __in ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ IEnumNetCfgBindingInterface * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ IEnumNetCfgBindingInterface * This,
+ /* [annotation][out] */
+ __out IEnumNetCfgBindingInterface **ppenum);
+
+ END_INTERFACE
+ } IEnumNetCfgBindingInterfaceVtbl;
+
+ interface IEnumNetCfgBindingInterface
+ {
+ CONST_VTBL struct IEnumNetCfgBindingInterfaceVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IEnumNetCfgBindingInterface_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IEnumNetCfgBindingInterface_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IEnumNetCfgBindingInterface_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IEnumNetCfgBindingInterface_Next(This,celt,rgelt,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,rgelt,pceltFetched) )
+
+#define IEnumNetCfgBindingInterface_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define IEnumNetCfgBindingInterface_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define IEnumNetCfgBindingInterface_Clone(This,ppenum) \
+ ( (This)->lpVtbl -> Clone(This,ppenum) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IEnumNetCfgBindingInterface_INTERFACE_DEFINED__ */
+
+
+#ifndef __IEnumNetCfgBindingPath_INTERFACE_DEFINED__
+#define __IEnumNetCfgBindingPath_INTERFACE_DEFINED__
+
+/* interface IEnumNetCfgBindingPath */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_IEnumNetCfgBindingPath;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C0E8AE91-306E-11D1-AACF-00805FC1270E")
+ IEnumNetCfgBindingPath : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [annotation][in] */
+ __in ULONG celt,
+ /* [annotation][length_is][size_is][out] */
+ __out_ecount(celt) INetCfgBindingPath **rgelt,
+ /* [annotation][out] */
+ __out ULONG *pceltFetched) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Skip(
+ /* [annotation][in] */
+ __in ULONG celt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ /* [annotation][out] */
+ __out IEnumNetCfgBindingPath **ppenum) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IEnumNetCfgBindingPathVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IEnumNetCfgBindingPath * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IEnumNetCfgBindingPath * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IEnumNetCfgBindingPath * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ IEnumNetCfgBindingPath * This,
+ /* [annotation][in] */
+ __in ULONG celt,
+ /* [annotation][length_is][size_is][out] */
+ __out_ecount(celt) INetCfgBindingPath **rgelt,
+ /* [annotation][out] */
+ __out ULONG *pceltFetched);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ IEnumNetCfgBindingPath * This,
+ /* [annotation][in] */
+ __in ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ IEnumNetCfgBindingPath * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ IEnumNetCfgBindingPath * This,
+ /* [annotation][out] */
+ __out IEnumNetCfgBindingPath **ppenum);
+
+ END_INTERFACE
+ } IEnumNetCfgBindingPathVtbl;
+
+ interface IEnumNetCfgBindingPath
+ {
+ CONST_VTBL struct IEnumNetCfgBindingPathVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IEnumNetCfgBindingPath_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IEnumNetCfgBindingPath_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IEnumNetCfgBindingPath_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IEnumNetCfgBindingPath_Next(This,celt,rgelt,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,rgelt,pceltFetched) )
+
+#define IEnumNetCfgBindingPath_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define IEnumNetCfgBindingPath_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define IEnumNetCfgBindingPath_Clone(This,ppenum) \
+ ( (This)->lpVtbl -> Clone(This,ppenum) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IEnumNetCfgBindingPath_INTERFACE_DEFINED__ */
+
+
+#ifndef __IEnumNetCfgComponent_INTERFACE_DEFINED__
+#define __IEnumNetCfgComponent_INTERFACE_DEFINED__
+
+/* interface IEnumNetCfgComponent */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_IEnumNetCfgComponent;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C0E8AE92-306E-11D1-AACF-00805FC1270E")
+ IEnumNetCfgComponent : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [annotation][in] */
+ __in ULONG celt,
+ /* [annotation][length_is][size_is][out] */
+ __out_ecount(celt) INetCfgComponent **rgelt,
+ /* [annotation][out] */
+ __out ULONG *pceltFetched) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Skip(
+ /* [annotation][in] */
+ __in ULONG celt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ /* [annotation][out] */
+ __out IEnumNetCfgComponent **ppenum) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct IEnumNetCfgComponentVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IEnumNetCfgComponent * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IEnumNetCfgComponent * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IEnumNetCfgComponent * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ IEnumNetCfgComponent * This,
+ /* [annotation][in] */
+ __in ULONG celt,
+ /* [annotation][length_is][size_is][out] */
+ __out_ecount(celt) INetCfgComponent **rgelt,
+ /* [annotation][out] */
+ __out ULONG *pceltFetched);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ IEnumNetCfgComponent * This,
+ /* [annotation][in] */
+ __in ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ IEnumNetCfgComponent * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ IEnumNetCfgComponent * This,
+ /* [annotation][out] */
+ __out IEnumNetCfgComponent **ppenum);
+
+ END_INTERFACE
+ } IEnumNetCfgComponentVtbl;
+
+ interface IEnumNetCfgComponent
+ {
+ CONST_VTBL struct IEnumNetCfgComponentVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IEnumNetCfgComponent_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IEnumNetCfgComponent_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IEnumNetCfgComponent_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IEnumNetCfgComponent_Next(This,celt,rgelt,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,rgelt,pceltFetched) )
+
+#define IEnumNetCfgComponent_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define IEnumNetCfgComponent_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define IEnumNetCfgComponent_Clone(This,ppenum) \
+ ( (This)->lpVtbl -> Clone(This,ppenum) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IEnumNetCfgComponent_INTERFACE_DEFINED__ */
+
+
+#ifndef __INetCfg_INTERFACE_DEFINED__
+#define __INetCfg_INTERFACE_DEFINED__
+
+/* interface INetCfg */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_INetCfg;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C0E8AE93-306E-11D1-AACF-00805FC1270E")
+ INetCfg : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Initialize(
+ /* [annotation][in] */
+ __in PVOID pvReserved) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Uninitialize( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Apply( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Cancel( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumComponents(
+ /* [annotation][in] */
+ __in const GUID *pguidClass,
+ /* [annotation][out] */
+ __deref_out_opt IEnumNetCfgComponent **ppenumComponent) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FindComponent(
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pszwInfId,
+ /* [annotation][out] */
+ __deref_out_opt INetCfgComponent **pComponent) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE QueryNetCfgClass(
+ /* [annotation][in] */
+ __in const GUID *pguidClass,
+ /* [annotation][in] */
+ __in REFIID riid,
+ /* [annotation][iid_is][out] */
+ __deref_out_opt void **ppvObject) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct INetCfgVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ INetCfg * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ INetCfg * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ INetCfg * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ INetCfg * This,
+ /* [annotation][in] */
+ __in PVOID pvReserved);
+
+ HRESULT ( STDMETHODCALLTYPE *Uninitialize )(
+ INetCfg * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Apply )(
+ INetCfg * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Cancel )(
+ INetCfg * This);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumComponents )(
+ INetCfg * This,
+ /* [annotation][in] */
+ __in const GUID *pguidClass,
+ /* [annotation][out] */
+ __deref_out_opt IEnumNetCfgComponent **ppenumComponent);
+
+ HRESULT ( STDMETHODCALLTYPE *FindComponent )(
+ INetCfg * This,
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pszwInfId,
+ /* [annotation][out] */
+ __deref_out_opt INetCfgComponent **pComponent);
+
+ HRESULT ( STDMETHODCALLTYPE *QueryNetCfgClass )(
+ INetCfg * This,
+ /* [annotation][in] */
+ __in const GUID *pguidClass,
+ /* [annotation][in] */
+ __in REFIID riid,
+ /* [annotation][iid_is][out] */
+ __deref_out_opt void **ppvObject);
+
+ END_INTERFACE
+ } INetCfgVtbl;
+
+ interface INetCfg
+ {
+ CONST_VTBL struct INetCfgVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define INetCfg_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define INetCfg_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define INetCfg_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define INetCfg_Initialize(This,pvReserved) \
+ ( (This)->lpVtbl -> Initialize(This,pvReserved) )
+
+#define INetCfg_Uninitialize(This) \
+ ( (This)->lpVtbl -> Uninitialize(This) )
+
+#define INetCfg_Apply(This) \
+ ( (This)->lpVtbl -> Apply(This) )
+
+#define INetCfg_Cancel(This) \
+ ( (This)->lpVtbl -> Cancel(This) )
+
+#define INetCfg_EnumComponents(This,pguidClass,ppenumComponent) \
+ ( (This)->lpVtbl -> EnumComponents(This,pguidClass,ppenumComponent) )
+
+#define INetCfg_FindComponent(This,pszwInfId,pComponent) \
+ ( (This)->lpVtbl -> FindComponent(This,pszwInfId,pComponent) )
+
+#define INetCfg_QueryNetCfgClass(This,pguidClass,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryNetCfgClass(This,pguidClass,riid,ppvObject) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __INetCfg_INTERFACE_DEFINED__ */
+
+
+#ifndef __INetCfgLock_INTERFACE_DEFINED__
+#define __INetCfgLock_INTERFACE_DEFINED__
+
+/* interface INetCfgLock */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_INetCfgLock;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C0E8AE9F-306E-11D1-AACF-00805FC1270E")
+ INetCfgLock : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE AcquireWriteLock(
+ /* [annotation][in] */
+ __in DWORD cmsTimeout,
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pszwClientDescription,
+ /* [annotation][string][out] */
+ __deref_out_opt LPWSTR *ppszwClientDescription) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ReleaseWriteLock( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsWriteLocked(
+ /* [annotation][string][out] */
+ __deref_out __nullterminated LPWSTR *ppszwClientDescription) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct INetCfgLockVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ INetCfgLock * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ INetCfgLock * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ INetCfgLock * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AcquireWriteLock )(
+ INetCfgLock * This,
+ /* [annotation][in] */
+ __in DWORD cmsTimeout,
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pszwClientDescription,
+ /* [annotation][string][out] */
+ __deref_out_opt LPWSTR *ppszwClientDescription);
+
+ HRESULT ( STDMETHODCALLTYPE *ReleaseWriteLock )(
+ INetCfgLock * This);
+
+ HRESULT ( STDMETHODCALLTYPE *IsWriteLocked )(
+ INetCfgLock * This,
+ /* [annotation][string][out] */
+ __deref_out __nullterminated LPWSTR *ppszwClientDescription);
+
+ END_INTERFACE
+ } INetCfgLockVtbl;
+
+ interface INetCfgLock
+ {
+ CONST_VTBL struct INetCfgLockVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define INetCfgLock_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define INetCfgLock_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define INetCfgLock_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define INetCfgLock_AcquireWriteLock(This,cmsTimeout,pszwClientDescription,ppszwClientDescription) \
+ ( (This)->lpVtbl -> AcquireWriteLock(This,cmsTimeout,pszwClientDescription,ppszwClientDescription) )
+
+#define INetCfgLock_ReleaseWriteLock(This) \
+ ( (This)->lpVtbl -> ReleaseWriteLock(This) )
+
+#define INetCfgLock_IsWriteLocked(This,ppszwClientDescription) \
+ ( (This)->lpVtbl -> IsWriteLocked(This,ppszwClientDescription) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __INetCfgLock_INTERFACE_DEFINED__ */
+
+
+#ifndef __INetCfgBindingInterface_INTERFACE_DEFINED__
+#define __INetCfgBindingInterface_INTERFACE_DEFINED__
+
+/* interface INetCfgBindingInterface */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_INetCfgBindingInterface;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C0E8AE94-306E-11D1-AACF-00805FC1270E")
+ INetCfgBindingInterface : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [annotation][string][out] */
+ __deref_out LPWSTR *ppszwInterfaceName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetUpperComponent(
+ /* [annotation][out] */
+ __deref_out_opt INetCfgComponent **ppnccItem) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLowerComponent(
+ /* [annotation][out] */
+ __deref_out_opt INetCfgComponent **ppnccItem) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct INetCfgBindingInterfaceVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ INetCfgBindingInterface * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ INetCfgBindingInterface * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ INetCfgBindingInterface * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ INetCfgBindingInterface * This,
+ /* [annotation][string][out] */
+ __deref_out LPWSTR *ppszwInterfaceName);
+
+ HRESULT ( STDMETHODCALLTYPE *GetUpperComponent )(
+ INetCfgBindingInterface * This,
+ /* [annotation][out] */
+ __deref_out_opt INetCfgComponent **ppnccItem);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLowerComponent )(
+ INetCfgBindingInterface * This,
+ /* [annotation][out] */
+ __deref_out_opt INetCfgComponent **ppnccItem);
+
+ END_INTERFACE
+ } INetCfgBindingInterfaceVtbl;
+
+ interface INetCfgBindingInterface
+ {
+ CONST_VTBL struct INetCfgBindingInterfaceVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define INetCfgBindingInterface_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define INetCfgBindingInterface_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define INetCfgBindingInterface_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define INetCfgBindingInterface_GetName(This,ppszwInterfaceName) \
+ ( (This)->lpVtbl -> GetName(This,ppszwInterfaceName) )
+
+#define INetCfgBindingInterface_GetUpperComponent(This,ppnccItem) \
+ ( (This)->lpVtbl -> GetUpperComponent(This,ppnccItem) )
+
+#define INetCfgBindingInterface_GetLowerComponent(This,ppnccItem) \
+ ( (This)->lpVtbl -> GetLowerComponent(This,ppnccItem) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __INetCfgBindingInterface_INTERFACE_DEFINED__ */
+
+
+#ifndef __INetCfgBindingPath_INTERFACE_DEFINED__
+#define __INetCfgBindingPath_INTERFACE_DEFINED__
+
+/* interface INetCfgBindingPath */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_INetCfgBindingPath;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C0E8AE96-306E-11D1-AACF-00805FC1270E")
+ INetCfgBindingPath : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE IsSamePathAs(
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pPath) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsSubPathOf(
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pPath) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsEnabled( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Enable(
+ /* [annotation][in] */
+ __in BOOL fEnable) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPathToken(
+ /* [annotation][string][out] */
+ __deref_out __nullterminated LPWSTR *ppszwPathToken) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetOwner(
+ /* [annotation][out] */
+ __deref_out_opt INetCfgComponent **ppComponent) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDepth(
+ /* [annotation][out] */
+ __out ULONG *pcInterfaces) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumBindingInterfaces(
+ /* [annotation][out] */
+ __deref_out_opt IEnumNetCfgBindingInterface **ppenumInterface) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct INetCfgBindingPathVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ INetCfgBindingPath * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ INetCfgBindingPath * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ INetCfgBindingPath * This);
+
+ HRESULT ( STDMETHODCALLTYPE *IsSamePathAs )(
+ INetCfgBindingPath * This,
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pPath);
+
+ HRESULT ( STDMETHODCALLTYPE *IsSubPathOf )(
+ INetCfgBindingPath * This,
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pPath);
+
+ HRESULT ( STDMETHODCALLTYPE *IsEnabled )(
+ INetCfgBindingPath * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Enable )(
+ INetCfgBindingPath * This,
+ /* [annotation][in] */
+ __in BOOL fEnable);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPathToken )(
+ INetCfgBindingPath * This,
+ /* [annotation][string][out] */
+ __deref_out __nullterminated LPWSTR *ppszwPathToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetOwner )(
+ INetCfgBindingPath * This,
+ /* [annotation][out] */
+ __deref_out_opt INetCfgComponent **ppComponent);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDepth )(
+ INetCfgBindingPath * This,
+ /* [annotation][out] */
+ __out ULONG *pcInterfaces);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumBindingInterfaces )(
+ INetCfgBindingPath * This,
+ /* [annotation][out] */
+ __deref_out_opt IEnumNetCfgBindingInterface **ppenumInterface);
+
+ END_INTERFACE
+ } INetCfgBindingPathVtbl;
+
+ interface INetCfgBindingPath
+ {
+ CONST_VTBL struct INetCfgBindingPathVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define INetCfgBindingPath_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define INetCfgBindingPath_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define INetCfgBindingPath_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define INetCfgBindingPath_IsSamePathAs(This,pPath) \
+ ( (This)->lpVtbl -> IsSamePathAs(This,pPath) )
+
+#define INetCfgBindingPath_IsSubPathOf(This,pPath) \
+ ( (This)->lpVtbl -> IsSubPathOf(This,pPath) )
+
+#define INetCfgBindingPath_IsEnabled(This) \
+ ( (This)->lpVtbl -> IsEnabled(This) )
+
+#define INetCfgBindingPath_Enable(This,fEnable) \
+ ( (This)->lpVtbl -> Enable(This,fEnable) )
+
+#define INetCfgBindingPath_GetPathToken(This,ppszwPathToken) \
+ ( (This)->lpVtbl -> GetPathToken(This,ppszwPathToken) )
+
+#define INetCfgBindingPath_GetOwner(This,ppComponent) \
+ ( (This)->lpVtbl -> GetOwner(This,ppComponent) )
+
+#define INetCfgBindingPath_GetDepth(This,pcInterfaces) \
+ ( (This)->lpVtbl -> GetDepth(This,pcInterfaces) )
+
+#define INetCfgBindingPath_EnumBindingInterfaces(This,ppenumInterface) \
+ ( (This)->lpVtbl -> EnumBindingInterfaces(This,ppenumInterface) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __INetCfgBindingPath_INTERFACE_DEFINED__ */
+
+
+#ifndef __INetCfgClass_INTERFACE_DEFINED__
+#define __INetCfgClass_INTERFACE_DEFINED__
+
+/* interface INetCfgClass */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_INetCfgClass;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C0E8AE97-306E-11D1-AACF-00805FC1270E")
+ INetCfgClass : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE FindComponent(
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pszwInfId,
+ /* [annotation][out] */
+ __deref_out_opt INetCfgComponent **ppnccItem) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumComponents(
+ /* [annotation][out] */
+ __deref_out_opt IEnumNetCfgComponent **ppenumComponent) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct INetCfgClassVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ INetCfgClass * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ INetCfgClass * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ INetCfgClass * This);
+
+ HRESULT ( STDMETHODCALLTYPE *FindComponent )(
+ INetCfgClass * This,
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pszwInfId,
+ /* [annotation][out] */
+ __deref_out_opt INetCfgComponent **ppnccItem);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumComponents )(
+ INetCfgClass * This,
+ /* [annotation][out] */
+ __deref_out_opt IEnumNetCfgComponent **ppenumComponent);
+
+ END_INTERFACE
+ } INetCfgClassVtbl;
+
+ interface INetCfgClass
+ {
+ CONST_VTBL struct INetCfgClassVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define INetCfgClass_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define INetCfgClass_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define INetCfgClass_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define INetCfgClass_FindComponent(This,pszwInfId,ppnccItem) \
+ ( (This)->lpVtbl -> FindComponent(This,pszwInfId,ppnccItem) )
+
+#define INetCfgClass_EnumComponents(This,ppenumComponent) \
+ ( (This)->lpVtbl -> EnumComponents(This,ppenumComponent) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __INetCfgClass_INTERFACE_DEFINED__ */
+
+
+#ifndef __INetCfgClassSetup_INTERFACE_DEFINED__
+#define __INetCfgClassSetup_INTERFACE_DEFINED__
+
+/* interface INetCfgClassSetup */
+/* [unique][uuid][object][local] */
+
+typedef
+enum tagOBO_TOKEN_TYPE
+ { OBO_USER = 1,
+ OBO_COMPONENT = 2,
+ OBO_SOFTWARE = 3
+ } OBO_TOKEN_TYPE;
+
+typedef struct tagOBO_TOKEN
+ {
+ OBO_TOKEN_TYPE Type;
+ INetCfgComponent *pncc;
+ LPCWSTR pszwManufacturer;
+ LPCWSTR pszwProduct;
+ LPCWSTR pszwDisplayName;
+ BOOL fRegistered;
+ } OBO_TOKEN;
+
+
+EXTERN_C const IID IID_INetCfgClassSetup;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C0E8AE9D-306E-11D1-AACF-00805FC1270E")
+ INetCfgClassSetup : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SelectAndInstall(
+ /* [annotation][in] */
+ __in HWND hwndParent,
+ /* [annotation][in] */
+ __in_opt OBO_TOKEN *pOboToken,
+ /* [annotation][out] */
+ __deref_out_opt INetCfgComponent **ppnccItem) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Install(
+ /* [annotation][string][in] */
+ __in LPCWSTR pszwInfId,
+ /* [annotation][in] */
+ __in_opt OBO_TOKEN *pOboToken,
+ /* [annotation][in] */
+ __in_opt DWORD dwSetupFlags,
+ /* [annotation][in] */
+ __in_opt DWORD dwUpgradeFromBuildNo,
+ /* [annotation][string][in] */
+ __in_opt LPCWSTR pszwAnswerFile,
+ /* [annotation][string][in] */
+ __in_opt LPCWSTR pszwAnswerSections,
+ /* [annotation][out] */
+ __deref_out_opt INetCfgComponent **ppnccItem) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DeInstall(
+ /* [annotation][in] */
+ __in INetCfgComponent *pComponent,
+ /* [annotation][in] */
+ __in_opt OBO_TOKEN *pOboToken,
+ /* [annotation][out] */
+ __deref_out_opt LPWSTR *pmszwRefs) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct INetCfgClassSetupVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ INetCfgClassSetup * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ INetCfgClassSetup * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ INetCfgClassSetup * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SelectAndInstall )(
+ INetCfgClassSetup * This,
+ /* [annotation][in] */
+ __in HWND hwndParent,
+ /* [annotation][in] */
+ __in_opt OBO_TOKEN *pOboToken,
+ /* [annotation][out] */
+ __deref_out_opt INetCfgComponent **ppnccItem);
+
+ HRESULT ( STDMETHODCALLTYPE *Install )(
+ INetCfgClassSetup * This,
+ /* [annotation][string][in] */
+ __in LPCWSTR pszwInfId,
+ /* [annotation][in] */
+ __in_opt OBO_TOKEN *pOboToken,
+ /* [annotation][in] */
+ __in_opt DWORD dwSetupFlags,
+ /* [annotation][in] */
+ __in_opt DWORD dwUpgradeFromBuildNo,
+ /* [annotation][string][in] */
+ __in_opt LPCWSTR pszwAnswerFile,
+ /* [annotation][string][in] */
+ __in_opt LPCWSTR pszwAnswerSections,
+ /* [annotation][out] */
+ __deref_out_opt INetCfgComponent **ppnccItem);
+
+ HRESULT ( STDMETHODCALLTYPE *DeInstall )(
+ INetCfgClassSetup * This,
+ /* [annotation][in] */
+ __in INetCfgComponent *pComponent,
+ /* [annotation][in] */
+ __in_opt OBO_TOKEN *pOboToken,
+ /* [annotation][out] */
+ __deref_out_opt LPWSTR *pmszwRefs);
+
+ END_INTERFACE
+ } INetCfgClassSetupVtbl;
+
+ interface INetCfgClassSetup
+ {
+ CONST_VTBL struct INetCfgClassSetupVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define INetCfgClassSetup_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define INetCfgClassSetup_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define INetCfgClassSetup_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define INetCfgClassSetup_SelectAndInstall(This,hwndParent,pOboToken,ppnccItem) \
+ ( (This)->lpVtbl -> SelectAndInstall(This,hwndParent,pOboToken,ppnccItem) )
+
+#define INetCfgClassSetup_Install(This,pszwInfId,pOboToken,dwSetupFlags,dwUpgradeFromBuildNo,pszwAnswerFile,pszwAnswerSections,ppnccItem) \
+ ( (This)->lpVtbl -> Install(This,pszwInfId,pOboToken,dwSetupFlags,dwUpgradeFromBuildNo,pszwAnswerFile,pszwAnswerSections,ppnccItem) )
+
+#define INetCfgClassSetup_DeInstall(This,pComponent,pOboToken,pmszwRefs) \
+ ( (This)->lpVtbl -> DeInstall(This,pComponent,pOboToken,pmszwRefs) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __INetCfgClassSetup_INTERFACE_DEFINED__ */
+
+
+#ifndef __INetCfgComponent_INTERFACE_DEFINED__
+#define __INetCfgComponent_INTERFACE_DEFINED__
+
+/* interface INetCfgComponent */
+/* [unique][uuid][object][local] */
+
+typedef
+enum tagCOMPONENT_CHARACTERISTICS
+ { NCF_VIRTUAL = 0x1,
+ NCF_SOFTWARE_ENUMERATED = 0x2,
+ NCF_PHYSICAL = 0x4,
+ NCF_HIDDEN = 0x8,
+ NCF_NO_SERVICE = 0x10,
+ NCF_NOT_USER_REMOVABLE = 0x20,
+ NCF_MULTIPORT_INSTANCED_ADAPTER = 0x40,
+ NCF_HAS_UI = 0x80,
+ NCF_SINGLE_INSTANCE = 0x100,
+ NCF_FILTER = 0x400,
+ NCF_DONTEXPOSELOWER = 0x1000,
+ NCF_HIDE_BINDING = 0x2000,
+ NCF_NDIS_PROTOCOL = 0x4000,
+ NCF_FIXED_BINDING = 0x20000,
+ NCF_LW_FILTER = 0x40000
+ } COMPONENT_CHARACTERISTICS;
+
+typedef
+enum tagNCRP_FLAGS
+ { NCRP_QUERY_PROPERTY_UI = 0x1,
+ NCRP_SHOW_PROPERTY_UI = 0x2
+ } NCRP_FLAGS;
+
+
+EXTERN_C const IID IID_INetCfgComponent;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C0E8AE99-306E-11D1-AACF-00805FC1270E")
+ INetCfgComponent : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetDisplayName(
+ /* [annotation][string][out] */
+ __deref_out_opt LPWSTR *ppszwDisplayName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetDisplayName(
+ /* [annotation][string][in] */
+ __in LPCWSTR pszwDisplayName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHelpText(
+ /* [annotation][string][out] */
+ __deref_out_opt LPWSTR *pszwHelpText) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetId(
+ /* [annotation][string][out] */
+ __deref_out_opt LPWSTR *ppszwId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCharacteristics(
+ /* [annotation][out] */
+ __out LPDWORD pdwCharacteristics) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInstanceGuid(
+ /* [annotation][out] */
+ __out_opt GUID *pGuid) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPnpDevNodeId(
+ /* [annotation][string][out] */
+ __deref_out_opt LPWSTR *ppszwDevNodeId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetClassGuid(
+ /* [annotation][out] */
+ __out_opt GUID *pGuid) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBindName(
+ /* [annotation][string][out] */
+ __deref_out_opt LPWSTR *ppszwBindName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDeviceStatus(
+ /* [annotation][out] */
+ __out ULONG *pulStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE OpenParamKey(
+ /* [annotation][out] */
+ __deref_out_opt HKEY *phkey) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RaisePropertyUi(
+ /* [annotation][in] */
+ __in_opt HWND hwndParent,
+ /* [annotation][in] */
+ __in DWORD dwFlags,
+ /* [annotation][in] */
+ __in_opt IUnknown *punkContext) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct INetCfgComponentVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ INetCfgComponent * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ INetCfgComponent * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ INetCfgComponent * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDisplayName )(
+ INetCfgComponent * This,
+ /* [annotation][string][out] */
+ __deref_out_opt LPWSTR *ppszwDisplayName);
+
+ HRESULT ( STDMETHODCALLTYPE *SetDisplayName )(
+ INetCfgComponent * This,
+ /* [annotation][string][in] */
+ __in LPCWSTR pszwDisplayName);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHelpText )(
+ INetCfgComponent * This,
+ /* [annotation][string][out] */
+ __deref_out_opt LPWSTR *pszwHelpText);
+
+ HRESULT ( STDMETHODCALLTYPE *GetId )(
+ INetCfgComponent * This,
+ /* [annotation][string][out] */
+ __deref_out_opt LPWSTR *ppszwId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCharacteristics )(
+ INetCfgComponent * This,
+ /* [annotation][out] */
+ __out LPDWORD pdwCharacteristics);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInstanceGuid )(
+ INetCfgComponent * This,
+ /* [annotation][out] */
+ __out_opt GUID *pGuid);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPnpDevNodeId )(
+ INetCfgComponent * This,
+ /* [annotation][string][out] */
+ __deref_out_opt LPWSTR *ppszwDevNodeId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassGuid )(
+ INetCfgComponent * This,
+ /* [annotation][out] */
+ __out_opt GUID *pGuid);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBindName )(
+ INetCfgComponent * This,
+ /* [annotation][string][out] */
+ __deref_out_opt LPWSTR *ppszwBindName);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDeviceStatus )(
+ INetCfgComponent * This,
+ /* [annotation][out] */
+ __out ULONG *pulStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenParamKey )(
+ INetCfgComponent * This,
+ /* [annotation][out] */
+ __deref_out_opt HKEY *phkey);
+
+ HRESULT ( STDMETHODCALLTYPE *RaisePropertyUi )(
+ INetCfgComponent * This,
+ /* [annotation][in] */
+ __in_opt HWND hwndParent,
+ /* [annotation][in] */
+ __in DWORD dwFlags,
+ /* [annotation][in] */
+ __in_opt IUnknown *punkContext);
+
+ END_INTERFACE
+ } INetCfgComponentVtbl;
+
+ interface INetCfgComponent
+ {
+ CONST_VTBL struct INetCfgComponentVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define INetCfgComponent_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define INetCfgComponent_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define INetCfgComponent_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define INetCfgComponent_GetDisplayName(This,ppszwDisplayName) \
+ ( (This)->lpVtbl -> GetDisplayName(This,ppszwDisplayName) )
+
+#define INetCfgComponent_SetDisplayName(This,pszwDisplayName) \
+ ( (This)->lpVtbl -> SetDisplayName(This,pszwDisplayName) )
+
+#define INetCfgComponent_GetHelpText(This,pszwHelpText) \
+ ( (This)->lpVtbl -> GetHelpText(This,pszwHelpText) )
+
+#define INetCfgComponent_GetId(This,ppszwId) \
+ ( (This)->lpVtbl -> GetId(This,ppszwId) )
+
+#define INetCfgComponent_GetCharacteristics(This,pdwCharacteristics) \
+ ( (This)->lpVtbl -> GetCharacteristics(This,pdwCharacteristics) )
+
+#define INetCfgComponent_GetInstanceGuid(This,pGuid) \
+ ( (This)->lpVtbl -> GetInstanceGuid(This,pGuid) )
+
+#define INetCfgComponent_GetPnpDevNodeId(This,ppszwDevNodeId) \
+ ( (This)->lpVtbl -> GetPnpDevNodeId(This,ppszwDevNodeId) )
+
+#define INetCfgComponent_GetClassGuid(This,pGuid) \
+ ( (This)->lpVtbl -> GetClassGuid(This,pGuid) )
+
+#define INetCfgComponent_GetBindName(This,ppszwBindName) \
+ ( (This)->lpVtbl -> GetBindName(This,ppszwBindName) )
+
+#define INetCfgComponent_GetDeviceStatus(This,pulStatus) \
+ ( (This)->lpVtbl -> GetDeviceStatus(This,pulStatus) )
+
+#define INetCfgComponent_OpenParamKey(This,phkey) \
+ ( (This)->lpVtbl -> OpenParamKey(This,phkey) )
+
+#define INetCfgComponent_RaisePropertyUi(This,hwndParent,dwFlags,punkContext) \
+ ( (This)->lpVtbl -> RaisePropertyUi(This,hwndParent,dwFlags,punkContext) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __INetCfgComponent_INTERFACE_DEFINED__ */
+
+
+#ifndef __INetCfgComponentBindings_INTERFACE_DEFINED__
+#define __INetCfgComponentBindings_INTERFACE_DEFINED__
+
+/* interface INetCfgComponentBindings */
+/* [unique][uuid][object][local] */
+
+typedef
+enum tagSUPPORTS_BINDING_INTERFACE_FLAGS
+ { NCF_LOWER = 0x1,
+ NCF_UPPER = 0x2
+ } SUPPORTS_BINDING_INTERFACE_FLAGS;
+
+typedef
+enum tagENUM_BINDING_PATHS_FLAGS
+ { EBP_ABOVE = 0x1,
+ EBP_BELOW = 0x2
+ } ENUM_BINDING_PATHS_FLAGS;
+
+
+EXTERN_C const IID IID_INetCfgComponentBindings;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C0E8AE9E-306E-11D1-AACF-00805FC1270E")
+ INetCfgComponentBindings : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE BindTo(
+ /* [annotation][in] */
+ __in INetCfgComponent *pnccItem) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE UnbindFrom(
+ /* [annotation][in] */
+ __in INetCfgComponent *pnccItem) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SupportsBindingInterface(
+ /* [annotation][in] */
+ __in DWORD dwFlags,
+ /* [annotation][in] */
+ __in __nullterminated LPCWSTR pszwInterfaceName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsBoundTo(
+ /* [annotation][in] */
+ __in INetCfgComponent *pnccItem) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsBindableTo(
+ /* [annotation][in] */
+ __in INetCfgComponent *pnccItem) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumBindingPaths(
+ /* [annotation][in] */
+ __in DWORD dwFlags,
+ /* [annotation][out] */
+ __deref_out_opt IEnumNetCfgBindingPath **ppIEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE MoveBefore(
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pncbItemSrc,
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pncbItemDest) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE MoveAfter(
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pncbItemSrc,
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pncbItemDest) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct INetCfgComponentBindingsVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ INetCfgComponentBindings * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ INetCfgComponentBindings * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ INetCfgComponentBindings * This);
+
+ HRESULT ( STDMETHODCALLTYPE *BindTo )(
+ INetCfgComponentBindings * This,
+ /* [annotation][in] */
+ __in INetCfgComponent *pnccItem);
+
+ HRESULT ( STDMETHODCALLTYPE *UnbindFrom )(
+ INetCfgComponentBindings * This,
+ /* [annotation][in] */
+ __in INetCfgComponent *pnccItem);
+
+ HRESULT ( STDMETHODCALLTYPE *SupportsBindingInterface )(
+ INetCfgComponentBindings * This,
+ /* [annotation][in] */
+ __in DWORD dwFlags,
+ /* [annotation][in] */
+ __in __nullterminated LPCWSTR pszwInterfaceName);
+
+ HRESULT ( STDMETHODCALLTYPE *IsBoundTo )(
+ INetCfgComponentBindings * This,
+ /* [annotation][in] */
+ __in INetCfgComponent *pnccItem);
+
+ HRESULT ( STDMETHODCALLTYPE *IsBindableTo )(
+ INetCfgComponentBindings * This,
+ /* [annotation][in] */
+ __in INetCfgComponent *pnccItem);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumBindingPaths )(
+ INetCfgComponentBindings * This,
+ /* [annotation][in] */
+ __in DWORD dwFlags,
+ /* [annotation][out] */
+ __deref_out_opt IEnumNetCfgBindingPath **ppIEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *MoveBefore )(
+ INetCfgComponentBindings * This,
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pncbItemSrc,
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pncbItemDest);
+
+ HRESULT ( STDMETHODCALLTYPE *MoveAfter )(
+ INetCfgComponentBindings * This,
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pncbItemSrc,
+ /* [annotation][in] */
+ __in INetCfgBindingPath *pncbItemDest);
+
+ END_INTERFACE
+ } INetCfgComponentBindingsVtbl;
+
+ interface INetCfgComponentBindings
+ {
+ CONST_VTBL struct INetCfgComponentBindingsVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define INetCfgComponentBindings_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define INetCfgComponentBindings_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define INetCfgComponentBindings_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define INetCfgComponentBindings_BindTo(This,pnccItem) \
+ ( (This)->lpVtbl -> BindTo(This,pnccItem) )
+
+#define INetCfgComponentBindings_UnbindFrom(This,pnccItem) \
+ ( (This)->lpVtbl -> UnbindFrom(This,pnccItem) )
+
+#define INetCfgComponentBindings_SupportsBindingInterface(This,dwFlags,pszwInterfaceName) \
+ ( (This)->lpVtbl -> SupportsBindingInterface(This,dwFlags,pszwInterfaceName) )
+
+#define INetCfgComponentBindings_IsBoundTo(This,pnccItem) \
+ ( (This)->lpVtbl -> IsBoundTo(This,pnccItem) )
+
+#define INetCfgComponentBindings_IsBindableTo(This,pnccItem) \
+ ( (This)->lpVtbl -> IsBindableTo(This,pnccItem) )
+
+#define INetCfgComponentBindings_EnumBindingPaths(This,dwFlags,ppIEnum) \
+ ( (This)->lpVtbl -> EnumBindingPaths(This,dwFlags,ppIEnum) )
+
+#define INetCfgComponentBindings_MoveBefore(This,pncbItemSrc,pncbItemDest) \
+ ( (This)->lpVtbl -> MoveBefore(This,pncbItemSrc,pncbItemDest) )
+
+#define INetCfgComponentBindings_MoveAfter(This,pncbItemSrc,pncbItemDest) \
+ ( (This)->lpVtbl -> MoveAfter(This,pncbItemSrc,pncbItemDest) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __INetCfgComponentBindings_INTERFACE_DEFINED__ */
+
+
+#ifndef __INetCfgSysPrep_INTERFACE_DEFINED__
+#define __INetCfgSysPrep_INTERFACE_DEFINED__
+
+/* interface INetCfgSysPrep */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_INetCfgSysPrep;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C0E8AE98-306E-11D1-AACF-00805FC1270E")
+ INetCfgSysPrep : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE HrSetupSetFirstDword(
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pwszSection,
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pwszKey,
+ /* [in] */ DWORD dwValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE HrSetupSetFirstString(
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pwszSection,
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pwszKey,
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pwszValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE HrSetupSetFirstStringAsBool(
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pwszSection,
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pwszKey,
+ /* [in] */ BOOL fValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE HrSetupSetFirstMultiSzField(
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pwszSection,
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pwszKey,
+ /* [annotation][in] */
+ __in __nullterminated LPCWSTR pmszValue) = 0;
+
+ };
+
+#else /* C style interface */
+
+ typedef struct INetCfgSysPrepVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ INetCfgSysPrep * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ __RPC__deref_out void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ INetCfgSysPrep * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ INetCfgSysPrep * This);
+
+ HRESULT ( STDMETHODCALLTYPE *HrSetupSetFirstDword )(
+ INetCfgSysPrep * This,
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pwszSection,
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pwszKey,
+ /* [in] */ DWORD dwValue);
+
+ HRESULT ( STDMETHODCALLTYPE *HrSetupSetFirstString )(
+ INetCfgSysPrep * This,
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pwszSection,
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pwszKey,
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pwszValue);
+
+ HRESULT ( STDMETHODCALLTYPE *HrSetupSetFirstStringAsBool )(
+ INetCfgSysPrep * This,
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pwszSection,
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pwszKey,
+ /* [in] */ BOOL fValue);
+
+ HRESULT ( STDMETHODCALLTYPE *HrSetupSetFirstMultiSzField )(
+ INetCfgSysPrep * This,
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pwszSection,
+ /* [annotation][string][in] */
+ __in __nullterminated LPCWSTR pwszKey,
+ /* [annotation][in] */
+ __in __nullterminated LPCWSTR pmszValue);
+
+ END_INTERFACE
+ } INetCfgSysPrepVtbl;
+
+ interface INetCfgSysPrep
+ {
+ CONST_VTBL struct INetCfgSysPrepVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define INetCfgSysPrep_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define INetCfgSysPrep_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define INetCfgSysPrep_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define INetCfgSysPrep_HrSetupSetFirstDword(This,pwszSection,pwszKey,dwValue) \
+ ( (This)->lpVtbl -> HrSetupSetFirstDword(This,pwszSection,pwszKey,dwValue) )
+
+#define INetCfgSysPrep_HrSetupSetFirstString(This,pwszSection,pwszKey,pwszValue) \
+ ( (This)->lpVtbl -> HrSetupSetFirstString(This,pwszSection,pwszKey,pwszValue) )
+
+#define INetCfgSysPrep_HrSetupSetFirstStringAsBool(This,pwszSection,pwszKey,fValue) \
+ ( (This)->lpVtbl -> HrSetupSetFirstStringAsBool(This,pwszSection,pwszKey,fValue) )
+
+#define INetCfgSysPrep_HrSetupSetFirstMultiSzField(This,pwszSection,pwszKey,pmszValue) \
+ ( (This)->lpVtbl -> HrSetupSetFirstMultiSzField(This,pwszSection,pwszKey,pmszValue) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __INetCfgSysPrep_INTERFACE_DEFINED__ */
+
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
+
diff --git a/src/Cedar/winpcap/Devioctl.h b/src/Cedar/winpcap/Devioctl.h
new file mode 100644
index 00000000..af8784bf
--- /dev/null
+++ b/src/Cedar/winpcap/Devioctl.h
@@ -0,0 +1,90 @@
+/*++ BUILD Version: 0004 // Increment this if a change has global effects
+ Copyright (c) 1992-1993 Microsoft Corporation
+ Module Name:
+ devioctl.h
+ Revision History:
+ -- */
+// begin_winioctl
+#ifndef _DEVIOCTL_
+#define _DEVIOCTL_
+// begin_ntddk begin_nthal begin_ntifs
+//
+// Define the various device type values. Note that values used by Microsoft
+// Corporation are in the range 0-32767, and 32768-65535 are reserved for use
+// by customers.
+//
+#define DEVICE_TYPE ULONG
+#define FILE_DEVICE_BEEP 0x00000001
+#define FILE_DEVICE_CD_ROM 0x00000002
+#define FILE_DEVICE_CD_ROM_FILE_SYSTEM 0x00000003
+#define FILE_DEVICE_CONTROLLER 0x00000004
+#define FILE_DEVICE_DATALINK 0x00000005
+#define FILE_DEVICE_DFS 0x00000006
+#define FILE_DEVICE_DISK 0x00000007
+#define FILE_DEVICE_DISK_FILE_SYSTEM 0x00000008
+#define FILE_DEVICE_FILE_SYSTEM 0x00000009
+#define FILE_DEVICE_INPORT_PORT 0x0000000a
+#define FILE_DEVICE_KEYBOARD 0x0000000b
+#define FILE_DEVICE_MAILSLOT 0x0000000c
+#define FILE_DEVICE_MIDI_IN 0x0000000d
+#define FILE_DEVICE_MIDI_OUT 0x0000000e
+#define FILE_DEVICE_MOUSE 0x0000000f
+#define FILE_DEVICE_MULTI_UNC_PROVIDER 0x00000010
+#define FILE_DEVICE_NAMED_PIPE 0x00000011
+#define FILE_DEVICE_NETWORK 0x00000012
+#define FILE_DEVICE_NETWORK_BROWSER 0x00000013
+#define FILE_DEVICE_NETWORK_FILE_SYSTEM 0x00000014
+#define FILE_DEVICE_NULL 0x00000015
+#define FILE_DEVICE_PARALLEL_PORT 0x00000016
+#define FILE_DEVICE_PHYSICAL_NETCARD 0x00000017
+#define FILE_DEVICE_PRINTER 0x00000018
+#define FILE_DEVICE_SCANNER 0x00000019
+#define FILE_DEVICE_SERIAL_MOUSE_PORT 0x0000001a
+#define FILE_DEVICE_SERIAL_PORT 0x0000001b
+#define FILE_DEVICE_SCREEN 0x0000001c
+#define FILE_DEVICE_SOUND 0x0000001d
+#define FILE_DEVICE_STREAMS 0x0000001e
+#define FILE_DEVICE_TAPE 0x0000001f
+#define FILE_DEVICE_TAPE_FILE_SYSTEM 0x00000020
+#define FILE_DEVICE_TRANSPORT 0x00000021
+#define FILE_DEVICE_UNKNOWN 0x00000022
+#define FILE_DEVICE_VIDEO 0x00000023
+#define FILE_DEVICE_VIRTUAL_DISK 0x00000024
+#define FILE_DEVICE_WAVE_IN 0x00000025
+#define FILE_DEVICE_WAVE_OUT 0x00000026
+#define FILE_DEVICE_8042_PORT 0x00000027
+#define FILE_DEVICE_NETWORK_REDIRECTOR 0x00000028
+#define FILE_DEVICE_BATTERY 0x00000029
+#define FILE_DEVICE_BUS_EXTENDER 0x0000002a
+#define FILE_DEVICE_MODEM 0x0000002b
+#define FILE_DEVICE_VDM 0x0000002c
+#define FILE_DEVICE_MASS_STORAGE 0x0000002d
+//
+// Macro definition for defining IOCTL and FSCTL function control codes. Note
+// that function codes 0-2047 are reserved for Microsoft Corporation, and
+// 2048-4095 are reserved for customers.
+//
+#define CTL_CODE( DeviceType, Function, Method, Access ) ( \
+ ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \
+)
+//
+// Define the method codes for how buffers are passed for I/O and FS controls
+//
+#define METHOD_BUFFERED 0
+#define METHOD_IN_DIRECT 1
+#define METHOD_OUT_DIRECT 2
+#define METHOD_NEITHER 3
+//
+// Define the access check value for any access
+//
+//
+// The FILE_READ_ACCESS and FILE_WRITE_ACCESS constants are also defined in
+// ntioapi.h as FILE_READ_DATA and FILE_WRITE_DATA. The values for these
+// constants *MUST* always be in sync.
+//
+#define FILE_ANY_ACCESS 0
+#define FILE_READ_ACCESS ( 0x0001 ) // file & pipe
+#define FILE_WRITE_ACCESS ( 0x0002 ) // file & pipe
+// end_ntddk end_nthal end_ntifs
+#endif // _DEVIOCTL_
+// end_winioctl
diff --git a/src/Cedar/winpcap/Gnuc.h b/src/Cedar/winpcap/Gnuc.h
new file mode 100644
index 00000000..b7cfb59c
--- /dev/null
+++ b/src/Cedar/winpcap/Gnuc.h
@@ -0,0 +1,46 @@
+/* @(#) $Header: /tcpdump/master/libpcap/Win32/Include/Gnuc.h,v 1.1 2002/08/01 08:33:05 risso Exp $ (LBL) */
+
+/* Define __P() macro, if necessary */
+
+#ifndef __P
+#if __STDC__
+#define __P(protos) protos
+#else
+#define __P(protos) ()
+#endif
+#endif
+
+/* inline foo */
+#ifndef __cplusplus
+#ifdef __GNUC__
+#define inline __inline
+#else
+#define inline
+#endif
+#endif
+
+/*
+ * Handle new and old "dead" routine prototypes
+ *
+ * For example:
+ *
+ * __dead void foo(void) __attribute__((volatile));
+ *
+ */
+#ifdef __GNUC__
+#ifndef __dead
+#define __dead volatile
+#endif
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5)
+#ifndef __attribute__
+#define __attribute__(args)
+#endif
+#endif
+#else
+#ifndef __dead
+#define __dead
+#endif
+#ifndef __attribute__
+#define __attribute__(args)
+#endif
+#endif
diff --git a/src/Cedar/winpcap/Ntddndis.h b/src/Cedar/winpcap/Ntddndis.h
new file mode 100644
index 00000000..0b629806
--- /dev/null
+++ b/src/Cedar/winpcap/Ntddndis.h
@@ -0,0 +1,1400 @@
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+ Copyright (c) 1990-1993 Microsoft Corporation
+ Module Name:
+ ntddndis.h
+ Abstract:
+ This is the include file that defines all constants and types for
+ accessing the Network driver interface device.
+ Author:
+ Steve Wood (stevewo) 27-May-1990
+ Revision History:
+ Adam Barr (adamba) 04-Nov-1992 added the correct values for NDIS 3.0.
+ Jameel Hyder (jameelh) 01-Aug-95 added Pnp IoCTLs and structures
+ Kyle Brandon (kyleb) 09/24/96 added general co ndis oids.
+ -- */
+#ifndef _NTDDNDIS_
+#define _NTDDNDIS_
+//
+// Device Name - this string is the name of the device. It is the name
+// that should be passed to NtOpenFile when accessing the device.
+//
+// Note: For devices that support multiple units, it should be suffixed
+// with the Ascii representation of the unit number.
+//
+#define DD_NDIS_DEVICE_NAME "\\Device\\UNKNOWN"
+//
+// NtDeviceIoControlFile IoControlCode values for this device.
+//
+// Warning: Remember that the low two bits of the code specify how the
+// buffers are passed to the driver!
+//
+#define _NDIS_CONTROL_CODE(request,method) \
+ CTL_CODE(FILE_DEVICE_PHYSICAL_NETCARD, request, method, FILE_ANY_ACCESS)
+#define IOCTL_NDIS_QUERY_GLOBAL_STATS _NDIS_CONTROL_CODE( 0, METHOD_OUT_DIRECT )
+#define IOCTL_NDIS_QUERY_ALL_STATS _NDIS_CONTROL_CODE( 1, METHOD_OUT_DIRECT )
+#define IOCTL_NDIS_ADD_DEVICE _NDIS_CONTROL_CODE( 2, METHOD_BUFFERED )
+#define IOCTL_NDIS_DELETE_DEVICE _NDIS_CONTROL_CODE( 3, METHOD_BUFFERED )
+#define IOCTL_NDIS_TRANSLATE_NAME _NDIS_CONTROL_CODE( 4, METHOD_BUFFERED )
+#define IOCTL_NDIS_ADD_TDI_DEVICE _NDIS_CONTROL_CODE( 5, METHOD_BUFFERED )
+#define IOCTL_NDIS_NOTIFY_PROTOCOL _NDIS_CONTROL_CODE( 6, METHOD_BUFFERED )
+#define IOCTL_NDIS_GET_LOG_DATA _NDIS_CONTROL_CODE( 7, METHOD_OUT_DIRECT )
+//
+// NtDeviceIoControlFile InputBuffer/OutputBuffer record structures for
+// this device.
+//
+//
+// This is the type of an NDIS OID value.
+//
+typedef ULONG NDIS_OID, *PNDIS_OID;
+//
+// IOCTL_NDIS_QUERY_ALL_STATS returns a sequence of these, packed
+// together (no padding is required since statistics all have
+// four or eight bytes of data).
+//
+typedef struct _NDIS_STATISTICS_VALUE {
+ NDIS_OID Oid;
+ ULONG DataLength;
+ UCHAR Data[1]; // variable length
+
+} NDIS_STATISTICS_VALUE, *PNDIS_STATISTICS_VALUE;
+
+//
+// Structure used by TRANSLATE_NAME IOCTL
+//
+typedef struct _NET_PNP_ID {
+ ULONG ClassId;
+ ULONG Token;
+} NET_PNP_ID, *PNET_PNP_ID;
+
+typedef struct _NET_PNP_TRANSLATE_LIST {
+ ULONG BytesNeeded;
+ NET_PNP_ID IdArray[ANYSIZE_ARRAY];
+} NET_PNP_TRANSLATE_LIST, *PNET_PNP_TRANSLATE_LIST;
+
+//
+// Structure used to define a self-contained variable data structure
+//
+typedef struct _NDIS_VAR_DATA_DESC {
+ USHORT Length; // # of octects of data
+
+ USHORT MaximumLength; // # of octects available
+
+ LONG Offset; // Offset of data relative to the descriptor
+
+} NDIS_VAR_DATA_DESC, *PNDIS_VAR_DATA_DESC;
+
+//
+// Object Identifiers used by NdisRequest Query/Set Information
+//
+//
+// General Objects
+//
+#define OID_GEN_SUPPORTED_LIST 0x00010101
+#define OID_GEN_HARDWARE_STATUS 0x00010102
+#define OID_GEN_MEDIA_SUPPORTED 0x00010103
+#define OID_GEN_MEDIA_IN_USE 0x00010104
+#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105
+#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106
+#define OID_GEN_LINK_SPEED 0x00010107
+#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108
+#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109
+#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A
+#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B
+#define OID_GEN_VENDOR_ID 0x0001010C
+#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D
+#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E
+#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F
+#define OID_GEN_DRIVER_VERSION 0x00010110
+#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111
+#define OID_GEN_PROTOCOL_OPTIONS 0x00010112
+#define OID_GEN_MAC_OPTIONS 0x00010113
+#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114
+#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115
+#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116
+#define OID_GEN_XMIT_OK 0x00020101
+#define OID_GEN_RCV_OK 0x00020102
+#define OID_GEN_XMIT_ERROR 0x00020103
+#define OID_GEN_RCV_ERROR 0x00020104
+#define OID_GEN_RCV_NO_BUFFER 0x00020105
+#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201
+#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202
+#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203
+#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204
+#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205
+#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206
+#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207
+#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208
+#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209
+#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A
+#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B
+#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C
+#define OID_GEN_RCV_CRC_ERROR 0x0002020D
+#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E
+#define OID_GEN_GET_TIME_CAPS 0x0002020F
+#define OID_GEN_GET_NETCARD_TIME 0x00020210
+//
+// These are connection-oriented general OIDs.
+// These replace the above OIDs for connection-oriented media.
+//
+#define OID_GEN_CO_SUPPORTED_LIST 0x00010101
+#define OID_GEN_CO_HARDWARE_STATUS 0x00010102
+#define OID_GEN_CO_MEDIA_SUPPORTED 0x00010103
+#define OID_GEN_CO_MEDIA_IN_USE 0x00010104
+#define OID_GEN_CO_LINK_SPEED 0x00010105
+#define OID_GEN_CO_VENDOR_ID 0x00010106
+#define OID_GEN_CO_VENDOR_DESCRIPTION 0x00010107
+#define OID_GEN_CO_DRIVER_VERSION 0x00010108
+#define OID_GEN_CO_PROTOCOL_OPTIONS 0x00010109
+#define OID_GEN_CO_MAC_OPTIONS 0x0001010A
+#define OID_GEN_CO_MEDIA_CONNECT_STATUS 0x0001010B
+#define OID_GEN_CO_VENDOR_DRIVER_VERSION 0x0001010C
+#define OID_GEN_CO_MINIMUM_LINK_SPEED 0x0001010D
+#define OID_GEN_CO_GET_TIME_CAPS 0x00010201
+#define OID_GEN_CO_GET_NETCARD_TIME 0x00010202
+//
+// These are connection-oriented statistics OIDs.
+//
+#define OID_GEN_CO_XMIT_PDUS_OK 0x00020101
+#define OID_GEN_CO_RCV_PDUS_OK 0x00020102
+#define OID_GEN_CO_XMIT_PDUS_ERROR 0x00020103
+#define OID_GEN_CO_RCV_PDUS_ERROR 0x00020104
+#define OID_GEN_CO_RCV_PDUS_NO_BUFFER 0x00020105
+#define OID_GEN_CO_RCV_CRC_ERROR 0x00020201
+#define OID_GEN_CO_TRANSMIT_QUEUE_LENGTH 0x00020202
+#define OID_GEN_CO_BYTES_XMIT 0x00020203
+#define OID_GEN_CO_BYTES_RCV 0x00020204
+#define OID_GEN_CO_BYTES_XMIT_OUTSTANDING 0x00020205
+#define OID_GEN_CO_NETCARD_LOAD 0x00020206
+//
+// These are objects for Connection-oriented media call-managers and are not
+// valid for ndis drivers. Under construction.
+//
+#define OID_CO_ADD_PVC 0xFF000001
+#define OID_CO_DELETE_PVC 0xFF000002
+#define OID_CO_GET_CALL_INFORMATION 0xFF000003
+#define OID_CO_ADD_ADDRESS 0xFF000004
+#define OID_CO_DELETE_ADDRESS 0xFF000005
+#define OID_CO_GET_ADDRESSES 0xFF000006
+#define OID_CO_ADDRESS_CHANGE 0xFF000007
+#define OID_CO_SIGNALING_ENABLED 0xFF000008
+#define OID_CO_SIGNALING_DISABLED 0xFF000009
+//
+// 802.3 Objects (Ethernet)
+//
+#define OID_802_3_PERMANENT_ADDRESS 0x01010101
+#define OID_802_3_CURRENT_ADDRESS 0x01010102
+#define OID_802_3_MULTICAST_LIST 0x01010103
+#define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104
+#define OID_802_3_MAC_OPTIONS 0x01010105
+//
+//
+#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001
+#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101
+#define OID_802_3_XMIT_ONE_COLLISION 0x01020102
+#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103
+#define OID_802_3_XMIT_DEFERRED 0x01020201
+#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202
+#define OID_802_3_RCV_OVERRUN 0x01020203
+#define OID_802_3_XMIT_UNDERRUN 0x01020204
+#define OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205
+#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206
+#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207
+//
+// 802.5 Objects (Token-Ring)
+//
+#define OID_802_5_PERMANENT_ADDRESS 0x02010101
+#define OID_802_5_CURRENT_ADDRESS 0x02010102
+#define OID_802_5_CURRENT_FUNCTIONAL 0x02010103
+#define OID_802_5_CURRENT_GROUP 0x02010104
+#define OID_802_5_LAST_OPEN_STATUS 0x02010105
+#define OID_802_5_CURRENT_RING_STATUS 0x02010106
+#define OID_802_5_CURRENT_RING_STATE 0x02010107
+#define OID_802_5_LINE_ERRORS 0x02020101
+#define OID_802_5_LOST_FRAMES 0x02020102
+#define OID_802_5_BURST_ERRORS 0x02020201
+#define OID_802_5_AC_ERRORS 0x02020202
+#define OID_802_5_ABORT_DELIMETERS 0x02020203
+#define OID_802_5_FRAME_COPIED_ERRORS 0x02020204
+#define OID_802_5_FREQUENCY_ERRORS 0x02020205
+#define OID_802_5_TOKEN_ERRORS 0x02020206
+#define OID_802_5_INTERNAL_ERRORS 0x02020207
+//
+// FDDI Objects
+//
+#define OID_FDDI_LONG_PERMANENT_ADDR 0x03010101
+#define OID_FDDI_LONG_CURRENT_ADDR 0x03010102
+#define OID_FDDI_LONG_MULTICAST_LIST 0x03010103
+#define OID_FDDI_LONG_MAX_LIST_SIZE 0x03010104
+#define OID_FDDI_SHORT_PERMANENT_ADDR 0x03010105
+#define OID_FDDI_SHORT_CURRENT_ADDR 0x03010106
+#define OID_FDDI_SHORT_MULTICAST_LIST 0x03010107
+#define OID_FDDI_SHORT_MAX_LIST_SIZE 0x03010108
+#define OID_FDDI_ATTACHMENT_TYPE 0x03020101
+#define OID_FDDI_UPSTREAM_NODE_LONG 0x03020102
+#define OID_FDDI_DOWNSTREAM_NODE_LONG 0x03020103
+#define OID_FDDI_FRAME_ERRORS 0x03020104
+#define OID_FDDI_FRAMES_LOST 0x03020105
+#define OID_FDDI_RING_MGT_STATE 0x03020106
+#define OID_FDDI_LCT_FAILURES 0x03020107
+#define OID_FDDI_LEM_REJECTS 0x03020108
+#define OID_FDDI_LCONNECTION_STATE 0x03020109
+#define OID_FDDI_SMT_STATION_ID 0x03030201
+#define OID_FDDI_SMT_OP_VERSION_ID 0x03030202
+#define OID_FDDI_SMT_HI_VERSION_ID 0x03030203
+#define OID_FDDI_SMT_LO_VERSION_ID 0x03030204
+#define OID_FDDI_SMT_MANUFACTURER_DATA 0x03030205
+#define OID_FDDI_SMT_USER_DATA 0x03030206
+#define OID_FDDI_SMT_MIB_VERSION_ID 0x03030207
+#define OID_FDDI_SMT_MAC_CT 0x03030208
+#define OID_FDDI_SMT_NON_MASTER_CT 0x03030209
+#define OID_FDDI_SMT_MASTER_CT 0x0303020A
+#define OID_FDDI_SMT_AVAILABLE_PATHS 0x0303020B
+#define OID_FDDI_SMT_CONFIG_CAPABILITIES 0x0303020C
+#define OID_FDDI_SMT_CONFIG_POLICY 0x0303020D
+#define OID_FDDI_SMT_CONNECTION_POLICY 0x0303020E
+#define OID_FDDI_SMT_T_NOTIFY 0x0303020F
+#define OID_FDDI_SMT_STAT_RPT_POLICY 0x03030210
+#define OID_FDDI_SMT_TRACE_MAX_EXPIRATION 0x03030211
+#define OID_FDDI_SMT_PORT_INDEXES 0x03030212
+#define OID_FDDI_SMT_MAC_INDEXES 0x03030213
+#define OID_FDDI_SMT_BYPASS_PRESENT 0x03030214
+#define OID_FDDI_SMT_ECM_STATE 0x03030215
+#define OID_FDDI_SMT_CF_STATE 0x03030216
+#define OID_FDDI_SMT_HOLD_STATE 0x03030217
+#define OID_FDDI_SMT_REMOTE_DISCONNECT_FLAG 0x03030218
+#define OID_FDDI_SMT_STATION_STATUS 0x03030219
+#define OID_FDDI_SMT_PEER_WRAP_FLAG 0x0303021A
+#define OID_FDDI_SMT_MSG_TIME_STAMP 0x0303021B
+#define OID_FDDI_SMT_TRANSITION_TIME_STAMP 0x0303021C
+#define OID_FDDI_SMT_SET_COUNT 0x0303021D
+#define OID_FDDI_SMT_LAST_SET_STATION_ID 0x0303021E
+#define OID_FDDI_MAC_FRAME_STATUS_FUNCTIONS 0x0303021F
+#define OID_FDDI_MAC_BRIDGE_FUNCTIONS 0x03030220
+#define OID_FDDI_MAC_T_MAX_CAPABILITY 0x03030221
+#define OID_FDDI_MAC_TVX_CAPABILITY 0x03030222
+#define OID_FDDI_MAC_AVAILABLE_PATHS 0x03030223
+#define OID_FDDI_MAC_CURRENT_PATH 0x03030224
+#define OID_FDDI_MAC_UPSTREAM_NBR 0x03030225
+#define OID_FDDI_MAC_DOWNSTREAM_NBR 0x03030226
+#define OID_FDDI_MAC_OLD_UPSTREAM_NBR 0x03030227
+#define OID_FDDI_MAC_OLD_DOWNSTREAM_NBR 0x03030228
+#define OID_FDDI_MAC_DUP_ADDRESS_TEST 0x03030229
+#define OID_FDDI_MAC_REQUESTED_PATHS 0x0303022A
+#define OID_FDDI_MAC_DOWNSTREAM_PORT_TYPE 0x0303022B
+#define OID_FDDI_MAC_INDEX 0x0303022C
+#define OID_FDDI_MAC_SMT_ADDRESS 0x0303022D
+#define OID_FDDI_MAC_LONG_GRP_ADDRESS 0x0303022E
+#define OID_FDDI_MAC_SHORT_GRP_ADDRESS 0x0303022F
+#define OID_FDDI_MAC_T_REQ 0x03030230
+#define OID_FDDI_MAC_T_NEG 0x03030231
+#define OID_FDDI_MAC_T_MAX 0x03030232
+#define OID_FDDI_MAC_TVX_VALUE 0x03030233
+#define OID_FDDI_MAC_T_PRI0 0x03030234
+#define OID_FDDI_MAC_T_PRI1 0x03030235
+#define OID_FDDI_MAC_T_PRI2 0x03030236
+#define OID_FDDI_MAC_T_PRI3 0x03030237
+#define OID_FDDI_MAC_T_PRI4 0x03030238
+#define OID_FDDI_MAC_T_PRI5 0x03030239
+#define OID_FDDI_MAC_T_PRI6 0x0303023A
+#define OID_FDDI_MAC_FRAME_CT 0x0303023B
+#define OID_FDDI_MAC_COPIED_CT 0x0303023C
+#define OID_FDDI_MAC_TRANSMIT_CT 0x0303023D
+#define OID_FDDI_MAC_TOKEN_CT 0x0303023E
+#define OID_FDDI_MAC_ERROR_CT 0x0303023F
+#define OID_FDDI_MAC_LOST_CT 0x03030240
+#define OID_FDDI_MAC_TVX_EXPIRED_CT 0x03030241
+#define OID_FDDI_MAC_NOT_COPIED_CT 0x03030242
+#define OID_FDDI_MAC_LATE_CT 0x03030243
+#define OID_FDDI_MAC_RING_OP_CT 0x03030244
+#define OID_FDDI_MAC_FRAME_ERROR_THRESHOLD 0x03030245
+#define OID_FDDI_MAC_FRAME_ERROR_RATIO 0x03030246
+#define OID_FDDI_MAC_NOT_COPIED_THRESHOLD 0x03030247
+#define OID_FDDI_MAC_NOT_COPIED_RATIO 0x03030248
+#define OID_FDDI_MAC_RMT_STATE 0x03030249
+#define OID_FDDI_MAC_DA_FLAG 0x0303024A
+#define OID_FDDI_MAC_UNDA_FLAG 0x0303024B
+#define OID_FDDI_MAC_FRAME_ERROR_FLAG 0x0303024C
+#define OID_FDDI_MAC_NOT_COPIED_FLAG 0x0303024D
+#define OID_FDDI_MAC_MA_UNITDATA_AVAILABLE 0x0303024E
+#define OID_FDDI_MAC_HARDWARE_PRESENT 0x0303024F
+#define OID_FDDI_MAC_MA_UNITDATA_ENABLE 0x03030250
+#define OID_FDDI_PATH_INDEX 0x03030251
+#define OID_FDDI_PATH_RING_LATENCY 0x03030252
+#define OID_FDDI_PATH_TRACE_STATUS 0x03030253
+#define OID_FDDI_PATH_SBA_PAYLOAD 0x03030254
+#define OID_FDDI_PATH_SBA_OVERHEAD 0x03030255
+#define OID_FDDI_PATH_CONFIGURATION 0x03030256
+#define OID_FDDI_PATH_T_R_MODE 0x03030257
+#define OID_FDDI_PATH_SBA_AVAILABLE 0x03030258
+#define OID_FDDI_PATH_TVX_LOWER_BOUND 0x03030259
+#define OID_FDDI_PATH_T_MAX_LOWER_BOUND 0x0303025A
+#define OID_FDDI_PATH_MAX_T_REQ 0x0303025B
+#define OID_FDDI_PORT_MY_TYPE 0x0303025C
+#define OID_FDDI_PORT_NEIGHBOR_TYPE 0x0303025D
+#define OID_FDDI_PORT_CONNECTION_POLICIES 0x0303025E
+#define OID_FDDI_PORT_MAC_INDICATED 0x0303025F
+#define OID_FDDI_PORT_CURRENT_PATH 0x03030260
+#define OID_FDDI_PORT_REQUESTED_PATHS 0x03030261
+#define OID_FDDI_PORT_MAC_PLACEMENT 0x03030262
+#define OID_FDDI_PORT_AVAILABLE_PATHS 0x03030263
+#define OID_FDDI_PORT_MAC_LOOP_TIME 0x03030264
+#define OID_FDDI_PORT_PMD_CLASS 0x03030265
+#define OID_FDDI_PORT_CONNECTION_CAPABILITIES 0x03030266
+#define OID_FDDI_PORT_INDEX 0x03030267
+#define OID_FDDI_PORT_MAINT_LS 0x03030268
+#define OID_FDDI_PORT_BS_FLAG 0x03030269
+#define OID_FDDI_PORT_PC_LS 0x0303026A
+#define OID_FDDI_PORT_EB_ERROR_CT 0x0303026B
+#define OID_FDDI_PORT_LCT_FAIL_CT 0x0303026C
+#define OID_FDDI_PORT_LER_ESTIMATE 0x0303026D
+#define OID_FDDI_PORT_LEM_REJECT_CT 0x0303026E
+#define OID_FDDI_PORT_LEM_CT 0x0303026F
+#define OID_FDDI_PORT_LER_CUTOFF 0x03030270
+#define OID_FDDI_PORT_LER_ALARM 0x03030271
+#define OID_FDDI_PORT_CONNNECT_STATE 0x03030272
+#define OID_FDDI_PORT_PCM_STATE 0x03030273
+#define OID_FDDI_PORT_PC_WITHHOLD 0x03030274
+#define OID_FDDI_PORT_LER_FLAG 0x03030275
+#define OID_FDDI_PORT_HARDWARE_PRESENT 0x03030276
+#define OID_FDDI_SMT_STATION_ACTION 0x03030277
+#define OID_FDDI_PORT_ACTION 0x03030278
+#define OID_FDDI_IF_DESCR 0x03030279
+#define OID_FDDI_IF_TYPE 0x0303027A
+#define OID_FDDI_IF_MTU 0x0303027B
+#define OID_FDDI_IF_SPEED 0x0303027C
+#define OID_FDDI_IF_PHYS_ADDRESS 0x0303027D
+#define OID_FDDI_IF_ADMIN_STATUS 0x0303027E
+#define OID_FDDI_IF_OPER_STATUS 0x0303027F
+#define OID_FDDI_IF_LAST_CHANGE 0x03030280
+#define OID_FDDI_IF_IN_OCTETS 0x03030281
+#define OID_FDDI_IF_IN_UCAST_PKTS 0x03030282
+#define OID_FDDI_IF_IN_NUCAST_PKTS 0x03030283
+#define OID_FDDI_IF_IN_DISCARDS 0x03030284
+#define OID_FDDI_IF_IN_ERRORS 0x03030285
+#define OID_FDDI_IF_IN_UNKNOWN_PROTOS 0x03030286
+#define OID_FDDI_IF_OUT_OCTETS 0x03030287
+#define OID_FDDI_IF_OUT_UCAST_PKTS 0x03030288
+#define OID_FDDI_IF_OUT_NUCAST_PKTS 0x03030289
+#define OID_FDDI_IF_OUT_DISCARDS 0x0303028A
+#define OID_FDDI_IF_OUT_ERRORS 0x0303028B
+#define OID_FDDI_IF_OUT_QLEN 0x0303028C
+#define OID_FDDI_IF_SPECIFIC 0x0303028D
+//
+// WAN objects
+//
+#define OID_WAN_PERMANENT_ADDRESS 0x04010101
+#define OID_WAN_CURRENT_ADDRESS 0x04010102
+#define OID_WAN_QUALITY_OF_SERVICE 0x04010103
+#define OID_WAN_PROTOCOL_TYPE 0x04010104
+#define OID_WAN_MEDIUM_SUBTYPE 0x04010105
+#define OID_WAN_HEADER_FORMAT 0x04010106
+#define OID_WAN_GET_INFO 0x04010107
+#define OID_WAN_SET_LINK_INFO 0x04010108
+#define OID_WAN_GET_LINK_INFO 0x04010109
+#define OID_WAN_LINE_COUNT 0x0401010A
+#define OID_WAN_GET_BRIDGE_INFO 0x0401020A
+#define OID_WAN_SET_BRIDGE_INFO 0x0401020B
+#define OID_WAN_GET_COMP_INFO 0x0401020C
+#define OID_WAN_SET_COMP_INFO 0x0401020D
+#define OID_WAN_GET_STATS_INFO 0x0401020E
+//
+// LocalTalk objects
+//
+#define OID_LTALK_CURRENT_NODE_ID 0x05010102
+#define OID_LTALK_IN_BROADCASTS 0x05020101
+#define OID_LTALK_IN_LENGTH_ERRORS 0x05020102
+#define OID_LTALK_OUT_NO_HANDLERS 0x05020201
+#define OID_LTALK_COLLISIONS 0x05020202
+#define OID_LTALK_DEFERS 0x05020203
+#define OID_LTALK_NO_DATA_ERRORS 0x05020204
+#define OID_LTALK_RANDOM_CTS_ERRORS 0x05020205
+#define OID_LTALK_FCS_ERRORS 0x05020206
+//
+// Arcnet objects
+//
+#define OID_ARCNET_PERMANENT_ADDRESS 0x06010101
+#define OID_ARCNET_CURRENT_ADDRESS 0x06010102
+#define OID_ARCNET_RECONFIGURATIONS 0x06020201
+//
+// TAPI objects
+//
+#define OID_TAPI_ACCEPT 0x07030101
+#define OID_TAPI_ANSWER 0x07030102
+#define OID_TAPI_CLOSE 0x07030103
+#define OID_TAPI_CLOSE_CALL 0x07030104
+#define OID_TAPI_CONDITIONAL_MEDIA_DETECTION 0x07030105
+#define OID_TAPI_CONFIG_DIALOG 0x07030106
+#define OID_TAPI_DEV_SPECIFIC 0x07030107
+#define OID_TAPI_DIAL 0x07030108
+#define OID_TAPI_DROP 0x07030109
+#define OID_TAPI_GET_ADDRESS_CAPS 0x0703010A
+#define OID_TAPI_GET_ADDRESS_ID 0x0703010B
+#define OID_TAPI_GET_ADDRESS_STATUS 0x0703010C
+#define OID_TAPI_GET_CALL_ADDRESS_ID 0x0703010D
+#define OID_TAPI_GET_CALL_INFO 0x0703010E
+#define OID_TAPI_GET_CALL_STATUS 0x0703010F
+#define OID_TAPI_GET_DEV_CAPS 0x07030110
+#define OID_TAPI_GET_DEV_CONFIG 0x07030111
+#define OID_TAPI_GET_EXTENSION_ID 0x07030112
+#define OID_TAPI_GET_ID 0x07030113
+#define OID_TAPI_GET_LINE_DEV_STATUS 0x07030114
+#define OID_TAPI_MAKE_CALL 0x07030115
+#define OID_TAPI_NEGOTIATE_EXT_VERSION 0x07030116
+#define OID_TAPI_OPEN 0x07030117
+#define OID_TAPI_PROVIDER_INITIALIZE 0x07030118
+#define OID_TAPI_PROVIDER_SHUTDOWN 0x07030119
+#define OID_TAPI_SECURE_CALL 0x0703011A
+#define OID_TAPI_SELECT_EXT_VERSION 0x0703011B
+#define OID_TAPI_SEND_USER_USER_INFO 0x0703011C
+#define OID_TAPI_SET_APP_SPECIFIC 0x0703011D
+#define OID_TAPI_SET_CALL_PARAMS 0x0703011E
+#define OID_TAPI_SET_DEFAULT_MEDIA_DETECTION 0x0703011F
+#define OID_TAPI_SET_DEV_CONFIG 0x07030120
+#define OID_TAPI_SET_MEDIA_MODE 0x07030121
+#define OID_TAPI_SET_STATUS_MESSAGES 0x07030122
+//
+// ATM Connection Oriented Ndis
+//
+#define OID_ATM_SUPPORTED_VC_RATES 0x08010101
+#define OID_ATM_SUPPORTED_SERVICE_CATEGORY 0x08010102
+#define OID_ATM_SUPPORTED_AAL_TYPES 0x08010103
+#define OID_ATM_HW_CURRENT_ADDRESS 0x08010104
+#define OID_ATM_MAX_ACTIVE_VCS 0x08010105
+#define OID_ATM_MAX_ACTIVE_VCI_BITS 0x08010106
+#define OID_ATM_MAX_ACTIVE_VPI_BITS 0x08010107
+#define OID_ATM_MAX_AAL0_PACKET_SIZE 0x08010108
+#define OID_ATM_MAX_AAL1_PACKET_SIZE 0x08010109
+#define OID_ATM_MAX_AAL34_PACKET_SIZE 0x0801010A
+#define OID_ATM_MAX_AAL5_PACKET_SIZE 0x0801010B
+#define OID_ATM_SIGNALING_VPIVCI 0x08010201
+#define OID_ATM_ASSIGNED_VPI 0x08010202
+#define OID_ATM_ACQUIRE_ACCESS_NET_RESOURCES 0x08010203
+#define OID_ATM_RELEASE_ACCESS_NET_RESOURCES 0x08010204
+#define OID_ATM_ILMI_VPIVCI 0x08010205
+#define OID_ATM_DIGITAL_BROADCAST_VPIVCI 0x08010206
+#define OID_ATM_GET_NEAREST_FLOW 0x08010207
+#define OID_ATM_ALIGNMENT_REQUIRED 0x08010208
+//
+// ATM specific statistics OIDs.
+//
+#define OID_ATM_RCV_CELLS_OK 0x08020101
+#define OID_ATM_XMIT_CELLS_OK 0x08020102
+#define OID_ATM_RCV_CELLS_DROPPED 0x08020103
+#define OID_ATM_RCV_INVALID_VPI_VCI 0x08020201
+#define OID_ATM_CELLS_HEC_ERROR 0x08020202
+#define OID_ATM_RCV_REASSEMBLY_ERROR 0x08020203
+//
+// PCCA (Wireless) object
+//
+//
+// All WirelessWAN devices must support the following OIDs
+//
+#define OID_WW_GEN_NETWORK_TYPES_SUPPORTED 0x09010101
+#define OID_WW_GEN_NETWORK_TYPE_IN_USE 0x09010102
+#define OID_WW_GEN_HEADER_FORMATS_SUPPORTED 0x09010103
+#define OID_WW_GEN_HEADER_FORMAT_IN_USE 0x09010104
+#define OID_WW_GEN_INDICATION_REQUEST 0x09010105
+#define OID_WW_GEN_DEVICE_INFO 0x09010106
+#define OID_WW_GEN_OPERATION_MODE 0x09010107
+#define OID_WW_GEN_LOCK_STATUS 0x09010108
+#define OID_WW_GEN_DISABLE_TRANSMITTER 0x09010109
+#define OID_WW_GEN_NETWORK_ID 0x0901010A
+#define OID_WW_GEN_PERMANENT_ADDRESS 0x0901010B
+#define OID_WW_GEN_CURRENT_ADDRESS 0x0901010C
+#define OID_WW_GEN_SUSPEND_DRIVER 0x0901010D
+#define OID_WW_GEN_BASESTATION_ID 0x0901010E
+#define OID_WW_GEN_CHANNEL_ID 0x0901010F
+#define OID_WW_GEN_ENCRYPTION_SUPPORTED 0x09010110
+#define OID_WW_GEN_ENCRYPTION_IN_USE 0x09010111
+#define OID_WW_GEN_ENCRYPTION_STATE 0x09010112
+#define OID_WW_GEN_CHANNEL_QUALITY 0x09010113
+#define OID_WW_GEN_REGISTRATION_STATUS 0x09010114
+#define OID_WW_GEN_RADIO_LINK_SPEED 0x09010115
+#define OID_WW_GEN_LATENCY 0x09010116
+#define OID_WW_GEN_BATTERY_LEVEL 0x09010117
+#define OID_WW_GEN_EXTERNAL_POWER 0x09010118
+//
+// Network Dependent OIDs - Mobitex:
+//
+#define OID_WW_MBX_SUBADDR 0x09050101
+// OID 0x09050102 is reserved and may not be used
+#define OID_WW_MBX_FLEXLIST 0x09050103
+#define OID_WW_MBX_GROUPLIST 0x09050104
+#define OID_WW_MBX_TRAFFIC_AREA 0x09050105
+#define OID_WW_MBX_LIVE_DIE 0x09050106
+#define OID_WW_MBX_TEMP_DEFAULTLIST 0x09050107
+//
+// Network Dependent OIDs - Pinpoint:
+//
+#define OID_WW_PIN_LOC_AUTHORIZE 0x09090101
+#define OID_WW_PIN_LAST_LOCATION 0x09090102
+#define OID_WW_PIN_LOC_FIX 0x09090103
+//
+// Network Dependent - CDPD:
+//
+#define OID_WW_CDPD_SPNI 0x090D0101
+#define OID_WW_CDPD_WASI 0x090D0102
+#define OID_WW_CDPD_AREA_COLOR 0x090D0103
+#define OID_WW_CDPD_TX_POWER_LEVEL 0x090D0104
+#define OID_WW_CDPD_EID 0x090D0105
+#define OID_WW_CDPD_HEADER_COMPRESSION 0x090D0106
+#define OID_WW_CDPD_DATA_COMPRESSION 0x090D0107
+#define OID_WW_CDPD_CHANNEL_SELECT 0x090D0108
+#define OID_WW_CDPD_CHANNEL_STATE 0x090D0109
+#define OID_WW_CDPD_NEI 0x090D010A
+#define OID_WW_CDPD_NEI_STATE 0x090D010B
+#define OID_WW_CDPD_SERVICE_PROVIDER_IDENTIFIER 0x090D010C
+#define OID_WW_CDPD_SLEEP_MODE 0x090D010D
+#define OID_WW_CDPD_CIRCUIT_SWITCHED 0x090D010E
+#define OID_WW_CDPD_TEI 0x090D010F
+#define OID_WW_CDPD_RSSI 0x090D0110
+//
+// Network Dependent - Ardis:
+//
+#define OID_WW_ARD_SNDCP 0x09110101
+#define OID_WW_ARD_TMLY_MSG 0x09110102
+#define OID_WW_ARD_DATAGRAM 0x09110103
+//
+// Network Dependent - DataTac:
+//
+#define OID_WW_TAC_COMPRESSION 0x09150101
+#define OID_WW_TAC_SET_CONFIG 0x09150102
+#define OID_WW_TAC_GET_STATUS 0x09150103
+#define OID_WW_TAC_USER_HEADER 0x09150104
+//
+// Network Dependent - Metricom:
+//
+#define OID_WW_MET_FUNCTION 0x09190101
+//
+// IRDA objects
+//
+#define OID_IRDA_RECEIVING 0x0A010100
+#define OID_IRDA_TURNAROUND_TIME 0x0A010101
+#define OID_IRDA_SUPPORTED_SPEEDS 0x0A010102
+#define OID_IRDA_LINK_SPEED 0x0A010103
+#define OID_IRDA_MEDIA_BUSY 0x0A010104
+#define OID_IRDA_EXTRA_RCV_BOFS 0x0A010200
+#define OID_IRDA_RATE_SNIFF 0x0A010201
+#define OID_IRDA_UNICAST_LIST 0x0A010202
+#define OID_IRDA_MAX_UNICAST_LIST_SIZE 0x0A010203
+#define OID_IRDA_MAX_RECEIVE_WINDOW_SIZE 0x0A010204
+#define OID_IRDA_MAX_SEND_WINDOW_SIZE 0x0A010205
+//
+// Medium the Ndis Driver is running on (OID_GEN_MEDIA_SUPPORTED/
+// OID_GEN_MEDIA_IN_USE).
+//
+typedef enum _NDIS_MEDIUM {
+ NdisMedium802_3,
+ NdisMedium802_5,
+ NdisMediumFddi,
+ NdisMediumWan,
+ NdisMediumLocalTalk,
+ NdisMediumDix, // defined for convenience, not a real medium
+ NdisMediumArcnetRaw,
+ NdisMediumArcnet878_2,
+ NdisMediumAtm,
+ NdisMediumWirelessWan,
+ NdisMediumIrda,
+ NdisMediumMax // Not a real medium, defined as an upper-bound
+} NDIS_MEDIUM, *PNDIS_MEDIUM;
+
+//
+// Hardware status codes (OID_GEN_HARDWARE_STATUS).
+//
+typedef enum _NDIS_HARDWARE_STATUS {
+ NdisHardwareStatusReady,
+ NdisHardwareStatusInitializing,
+ NdisHardwareStatusReset,
+ NdisHardwareStatusClosing,
+ NdisHardwareStatusNotReady
+} NDIS_HARDWARE_STATUS, *PNDIS_HARDWARE_STATUS;
+
+//
+// this is the type passed in the OID_GEN_GET_TIME_CAPS request
+//
+typedef struct _GEN_GET_TIME_CAPS {
+ ULONG Flags; // Bits defined below
+
+ ULONG ClockPrecision;
+} GEN_GET_TIME_CAPS, *PGEN_GET_TIME_CAPS;
+
+#define READABLE_LOCAL_CLOCK 0x000000001
+#define CLOCK_NETWORK_DERIVED 0x000000002
+#define CLOCK_PRECISION 0x000000004
+#define RECEIVE_TIME_INDICATION_CAPABLE 0x000000008
+#define TIMED_SEND_CAPABLE 0x000000010
+#define TIME_STAMP_CAPABLE 0x000000020
+//
+//
+// this is the type passed in the OID_GEN_GET_NETCARD_TIME request
+//
+typedef struct _GEN_GET_NETCARD_TIME {
+ ULONG ReadTime;
+} GEN_GET_NETCARD_TIME, *PGEN_GET_NETCARD_TIME;
+
+//
+// Defines the attachment types for FDDI (OID_FDDI_ATTACHMENT_TYPE).
+//
+typedef enum _NDIS_FDDI_ATTACHMENT_TYPE {
+ NdisFddiTypeIsolated = 1,
+ NdisFddiTypeLocalA,
+ NdisFddiTypeLocalB,
+ NdisFddiTypeLocalAB,
+ NdisFddiTypeLocalS,
+ NdisFddiTypeWrapA,
+ NdisFddiTypeWrapB,
+ NdisFddiTypeWrapAB,
+ NdisFddiTypeWrapS,
+ NdisFddiTypeCWrapA,
+ NdisFddiTypeCWrapB,
+ NdisFddiTypeCWrapS,
+ NdisFddiTypeThrough
+} NDIS_FDDI_ATTACHMENT_TYPE, *PNDIS_FDDI_ATTACHMENT_TYPE;
+
+//
+// Defines the ring management states for FDDI (OID_FDDI_RING_MGT_STATE).
+//
+typedef enum _NDIS_FDDI_RING_MGT_STATE {
+ NdisFddiRingIsolated = 1,
+ NdisFddiRingNonOperational,
+ NdisFddiRingOperational,
+ NdisFddiRingDetect,
+ NdisFddiRingNonOperationalDup,
+ NdisFddiRingOperationalDup,
+ NdisFddiRingDirected,
+ NdisFddiRingTrace
+} NDIS_FDDI_RING_MGT_STATE, *PNDIS_FDDI_RING_MGT_STATE;
+
+//
+// Defines the Lconnection state for FDDI (OID_FDDI_LCONNECTION_STATE).
+//
+typedef enum _NDIS_FDDI_LCONNECTION_STATE {
+ NdisFddiStateOff = 1,
+ NdisFddiStateBreak,
+ NdisFddiStateTrace,
+ NdisFddiStateConnect,
+ NdisFddiStateNext,
+ NdisFddiStateSignal,
+ NdisFddiStateJoin,
+ NdisFddiStateVerify,
+ NdisFddiStateActive,
+ NdisFddiStateMaintenance
+} NDIS_FDDI_LCONNECTION_STATE, *PNDIS_FDDI_LCONNECTION_STATE;
+
+//
+// Defines the medium subtypes for WAN medium (OID_WAN_MEDIUM_SUBTYPE).
+//
+typedef enum _NDIS_WAN_MEDIUM_SUBTYPE {
+ NdisWanMediumHub,
+ NdisWanMediumX_25,
+ NdisWanMediumIsdn,
+ NdisWanMediumSerial,
+ NdisWanMediumFrameRelay,
+ NdisWanMediumAtm,
+ NdisWanMediumSonet,
+ NdisWanMediumSW56K
+} NDIS_WAN_MEDIUM_SUBTYPE, *PNDIS_WAN_MEDIUM_SUBTYPE;
+
+//
+// Defines the header format for WAN medium (OID_WAN_HEADER_FORMAT).
+//
+typedef enum _NDIS_WAN_HEADER_FORMAT {
+ NdisWanHeaderNative, // src/dest based on subtype, followed by NLPID
+ NdisWanHeaderEthernet // emulation of ethernet header
+} NDIS_WAN_HEADER_FORMAT, *PNDIS_WAN_HEADER_FORMAT;
+
+//
+// Defines the line quality on a WAN line (OID_WAN_QUALITY_OF_SERVICE).
+//
+typedef enum _NDIS_WAN_QUALITY {
+ NdisWanRaw,
+ NdisWanErrorControl,
+ NdisWanReliable
+} NDIS_WAN_QUALITY, *PNDIS_WAN_QUALITY;
+
+//
+// Defines the state of a token-ring adapter (OID_802_5_CURRENT_RING_STATE).
+//
+typedef enum _NDIS_802_5_RING_STATE {
+ NdisRingStateOpened = 1,
+ NdisRingStateClosed,
+ NdisRingStateOpening,
+ NdisRingStateClosing,
+ NdisRingStateOpenFailure,
+ NdisRingStateRingFailure
+} NDIS_802_5_RING_STATE, *PNDIS_802_5_RING_STATE;
+
+//
+// Defines the state of the LAN media
+//
+typedef enum _NDIS_MEDIA_STATE {
+ NdisMediaStateConnected,
+ NdisMediaStateDisconnected
+} NDIS_MEDIA_STATE, *PNDIS_MEDIA_STATE;
+
+//
+// The following is set on a per-packet basis as OOB data with NdisClass802_3Priority
+//
+typedef ULONG Priority_802_3; // 0-7 priority levels
+//
+// The following structure is used to query OID_GEN_CO_LINK_SPEED and
+// OID_GEN_CO_MINIMUM_LINK_SPEED. The first OID will return the current
+// link speed of the adapter. The second will return the minimum link speed
+// the adapter is capable of.
+//
+
+typedef struct _NDIS_CO_LINK_SPEED {
+ ULONG Outbound;
+ ULONG Inbound;
+} NDIS_CO_LINK_SPEED,
+
+*PNDIS_CO_LINK_SPEED;
+//
+// Ndis Packet Filter Bits (OID_GEN_CURRENT_PACKET_FILTER).
+//
+#define NDIS_PACKET_TYPE_DIRECTED 0x0001
+#define NDIS_PACKET_TYPE_MULTICAST 0x0002
+#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x0004
+#define NDIS_PACKET_TYPE_BROADCAST 0x0008
+#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x0010
+#define NDIS_PACKET_TYPE_PROMISCUOUS 0x0020
+#define NDIS_PACKET_TYPE_SMT 0x0040
+#define NDIS_PACKET_TYPE_ALL_LOCAL 0x0080
+#define NDIS_PACKET_TYPE_MAC_FRAME 0x8000
+#define NDIS_PACKET_TYPE_FUNCTIONAL 0x4000
+#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x2000
+#define NDIS_PACKET_TYPE_GROUP 0x1000
+//
+// Ndis Token-Ring Ring Status Codes (OID_802_5_CURRENT_RING_STATUS).
+//
+#define NDIS_RING_SIGNAL_LOSS 0x00008000
+#define NDIS_RING_HARD_ERROR 0x00004000
+#define NDIS_RING_SOFT_ERROR 0x00002000
+#define NDIS_RING_TRANSMIT_BEACON 0x00001000
+#define NDIS_RING_LOBE_WIRE_FAULT 0x00000800
+#define NDIS_RING_AUTO_REMOVAL_ERROR 0x00000400
+#define NDIS_RING_REMOVE_RECEIVED 0x00000200
+#define NDIS_RING_COUNTER_OVERFLOW 0x00000100
+#define NDIS_RING_SINGLE_STATION 0x00000080
+#define NDIS_RING_RING_RECOVERY 0x00000040
+//
+// Ndis protocol option bits (OID_GEN_PROTOCOL_OPTIONS).
+//
+#define NDIS_PROT_OPTION_ESTIMATED_LENGTH 0x00000001
+#define NDIS_PROT_OPTION_NO_LOOPBACK 0x00000002
+#define NDIS_PROT_OPTION_NO_RSVD_ON_RCVPKT 0x00000004
+//
+// Ndis MAC option bits (OID_GEN_MAC_OPTIONS).
+//
+#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA 0x00000001
+#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED 0x00000002
+#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND 0x00000004
+#define NDIS_MAC_OPTION_NO_LOOPBACK 0x00000008
+#define NDIS_MAC_OPTION_FULL_DUPLEX 0x00000010
+#define NDIS_MAC_OPTION_EOTX_INDICATION 0x00000020
+#define NDIS_MAC_OPTION_RESERVED 0x80000000
+//
+// NDIS MAC option bits for OID_GEN_CO_MAC_OPTIONS.
+//
+#define NDIS_CO_MAC_OPTION_DYNAMIC_LINK_SPEED 0x00000001
+#ifdef IRDA
+//
+// The following is set on a per-packet basis as OOB data with NdisClassIrdaPacketInfo
+// This is the per-packet info specified on a per-packet basis
+//
+typedef struct _NDIS_IRDA_PACKET_INFO {
+ UINT ExtraBOFs;
+ UINT MinTurnAroundTime;
+} NDIS_IRDA_PACKET_INFO, *PNDIS_IRDA_PACKET_INFO;
+
+#endif
+#ifdef WIRELESS_WAN
+//
+// Wireless WAN structure definitions
+//
+//
+// currently defined Wireless network subtypes
+//
+typedef enum _NDIS_WW_NETWORK_TYPE {
+ NdisWWGeneric,
+ NdisWWMobitex,
+ NdisWWPinpoint,
+ NdisWWCDPD,
+ NdisWWArdis,
+ NdisWWDataTAC,
+ NdisWWMetricom,
+ NdisWWGSM,
+ NdisWWCDMA,
+ NdisWWTDMA,
+ NdisWWAMPS,
+ NdisWWInmarsat,
+ NdisWWpACT
+} NDIS_WW_NETWORK_TYPE;
+
+//
+// currently defined header formats
+//
+typedef enum _NDIS_WW_HEADER_FORMAT {
+ NdisWWDIXEthernetFrames,
+ NdisWWMPAKFrames,
+ NdisWWRDLAPFrames,
+ NdisWWMDC4800Frames
+} NDIS_WW_HEADER_FORMAT;
+
+//
+// currently defined encryption types
+//
+typedef enum _NDIS_WW_ENCRYPTION_TYPE {
+ NdisWWUnknownEncryption = -1,
+ NdisWWNoEncryption,
+ NdisWWDefaultEncryption
+} NDIS_WW_ENCRYPTION_TYPE, *PNDIS_WW_ENCRYPTION_TYPE;
+
+//
+// OID_WW_GEN_INDICATION_REQUEST
+//
+typedef struct _NDIS_WW_INDICATION_REQUEST {
+ NDIS_OID Oid; // IN
+
+ UINT uIndicationFlag; // IN
+
+ UINT uApplicationToken; // IN OUT
+
+ HANDLE hIndicationHandle; // IN OUT
+
+ INT iPollingInterval; // IN OUT
+
+ NDIS_VAR_DATA_DESC InitialValue; // IN OUT
+
+ NDIS_VAR_DATA_DESC OIDIndicationValue; // OUT - only valid after indication
+
+ NDIS_VAR_DATA_DESC TriggerValue; // IN
+
+} NDIS_WW_INDICATION_REQUEST, *PNDIS_WW_INDICATION_REQUEST;
+
+#define OID_INDICATION_REQUEST_ENABLE 0x0000
+#define OID_INDICATION_REQUEST_CANCEL 0x0001
+//
+// OID_WW_GEN_DEVICE_INFO
+//
+typedef struct _WW_DEVICE_INFO {
+ NDIS_VAR_DATA_DESC Manufacturer;
+ NDIS_VAR_DATA_DESC ModelNum;
+ NDIS_VAR_DATA_DESC SWVersionNum;
+ NDIS_VAR_DATA_DESC SerialNum;
+} WW_DEVICE_INFO, *PWW_DEVICE_INFO;
+
+//
+// OID_WW_GEN_OPERATION_MODE
+//
+typedef INT WW_OPERATION_MODE; // 0 = Normal mode
+ // 1 = Power saving mode
+ // -1 = mode unknown
+//
+// OID_WW_GEN_LOCK_STATUS
+//
+
+typedef INT WW_LOCK_STATUS; // 0 = unlocked
+ // 1 = locked
+ // -1 = unknown lock status
+//
+// OID_WW_GEN_DISABLE_TRANSMITTER
+//
+
+typedef INT WW_DISABLE_TRANSMITTER; // 0 = transmitter enabled
+ // 1 = transmitter disabled
+ // -1 = unknown value
+//
+// OID_WW_GEN_NETWORK_ID
+//
+
+typedef NDIS_VAR_DATA_DESC WW_NETWORK_ID;
+//
+// OID_WW_GEN_PERMANENT_ADDRESS
+//
+typedef NDIS_VAR_DATA_DESC WW_PERMANENT_ADDRESS;
+//
+// OID_WW_GEN_CURRENT_ADDRESS
+//
+typedef struct _WW_CURRENT_ADDRESS {
+ NDIS_WW_HEADER_FORMAT Format;
+ NDIS_VAR_DATA_DESC Address;
+} WW_CURRENT_ADDRESS, *PWW_CURRENT_ADDRESS;
+
+//
+// OID_WW_GEN_SUSPEND_DRIVER
+//
+typedef BOOLEAN WW_SUSPEND_DRIVER; // 0 = driver operational
+ // 1 = driver suspended
+//
+// OID_WW_GEN_BASESTATION_ID
+//
+
+typedef NDIS_VAR_DATA_DESC WW_BASESTATION_ID;
+//
+// OID_WW_GEN_CHANNEL_ID
+//
+typedef NDIS_VAR_DATA_DESC WW_CHANNEL_ID;
+//
+// OID_WW_GEN_ENCRYPTION_STATE
+//
+typedef BOOLEAN WW_ENCRYPTION_STATE; // 0 = if encryption is disabled
+ // 1 = if encryption is enabled
+//
+// OID_WW_GEN_CHANNEL_QUALITY
+//
+
+typedef INT WW_CHANNEL_QUALITY; // 0 = Not in network contact,
+ // 1-100 = Quality of Channel (100 is highest quality).
+ // -1 = channel quality is unknown
+//
+// OID_WW_GEN_REGISTRATION_STATUS
+//
+
+typedef INT WW_REGISTRATION_STATUS; // 0 = Registration denied
+ // 1 = Registration pending
+ // 2 = Registered
+ // -1 = unknown registration status
+//
+// OID_WW_GEN_RADIO_LINK_SPEED
+//
+
+typedef UINT WW_RADIO_LINK_SPEED; // Bits per second.
+//
+// OID_WW_GEN_LATENCY
+//
+
+typedef UINT WW_LATENCY; // milliseconds
+//
+// OID_WW_GEN_BATTERY_LEVEL
+//
+
+typedef INT WW_BATTERY_LEVEL; // 0-100 = battery level in percentage
+ // (100=fully charged)
+ // -1 = unknown battery level.
+//
+// OID_WW_GEN_EXTERNAL_POWER
+//
+
+typedef INT WW_EXTERNAL_POWER; // 0 = no external power connected
+ // 1 = external power connected
+ // -1 = unknown
+//
+// OID_WW_MET_FUNCTION
+//
+
+typedef NDIS_VAR_DATA_DESC WW_MET_FUNCTION;
+//
+// OID_WW_TAC_COMPRESSION
+//
+typedef BOOLEAN WW_TAC_COMPRESSION; // Determines whether or not network level compression
+ // is being used.
+//
+// OID_WW_TAC_SET_CONFIG
+//
+
+typedef struct _WW_TAC_SETCONFIG {
+ NDIS_VAR_DATA_DESC RCV_MODE;
+ NDIS_VAR_DATA_DESC TX_CONTROL;
+ NDIS_VAR_DATA_DESC RX_CONTROL;
+ NDIS_VAR_DATA_DESC FLOW_CONTROL;
+ NDIS_VAR_DATA_DESC RESET_CNF;
+ NDIS_VAR_DATA_DESC READ_CNF;
+} WW_TAC_SETCONFIG, *PWW_TAC_SETCONFIG;
+
+//
+// OID_WW_TAC_GET_STATUS
+//
+typedef struct _WW_TAC_GETSTATUS {
+ BOOLEAN Action; // Set = Execute command.
+
+ NDIS_VAR_DATA_DESC Command;
+ NDIS_VAR_DATA_DESC Option;
+ NDIS_VAR_DATA_DESC Response; // The response to the requested command
+ // - max. length of string is 256 octets.
+
+} WW_TAC_GETSTATUS, *PWW_TAC_GETSTATUS;
+
+//
+// OID_WW_TAC_USER_HEADER
+//
+typedef NDIS_VAR_DATA_DESC WW_TAC_USERHEADER; // This will hold the user header - Max. 64 octets.
+//
+// OID_WW_ARD_SNDCP
+//
+
+typedef struct _WW_ARD_SNDCP {
+ NDIS_VAR_DATA_DESC Version; // The version of SNDCP protocol supported.
+
+ INT BlockSize; // The block size used for SNDCP
+
+ INT Window; // The window size used in SNDCP
+
+} WW_ARD_SNDCP, *PWW_ARD_SNDCP;
+
+//
+// OID_WW_ARD_TMLY_MSG
+//
+typedef BOOLEAN WW_ARD_CHANNEL_STATUS; // The current status of the inbound RF Channel.
+//
+// OID_WW_ARD_DATAGRAM
+//
+
+typedef struct _WW_ARD_DATAGRAM {
+ BOOLEAN LoadLevel; // Byte that contains the load level info.
+
+ INT SessionTime; // Datagram session time remaining.
+
+ NDIS_VAR_DATA_DESC HostAddr; // Host address.
+
+ NDIS_VAR_DATA_DESC THostAddr; // Test host address.
+
+} WW_ARD_DATAGRAM, *PWW_ARD_DATAGRAM;
+
+//
+// OID_WW_CDPD_SPNI
+//
+typedef struct _WW_CDPD_SPNI {
+ UINT SPNI[10]; //10 16-bit service provider network IDs
+
+ INT OperatingMode; // 0 = ignore SPNI,
+ // 1 = require SPNI from list,
+ // 2 = prefer SPNI from list.
+ // 3 = exclude SPNI from list.
+
+} WW_CDPD_SPNI, *PWW_CDPD_SPNI;
+
+//
+// OID_WW_CDPD_WASI
+//
+typedef struct _WW_CDPD_WIDE_AREA_SERVICE_ID {
+ UINT WASI[10]; //10 16-bit wide area service IDs
+
+ INT OperatingMode; // 0 = ignore WASI,
+ // 1 = Require WASI from list,
+ // 2 = prefer WASI from list
+ // 3 = exclude WASI from list.
+
+} WW_CDPD_WIDE_AREA_SERVICE_ID, *PWW_CDPD_WIDE_AREA_SERVICE_ID;
+
+//
+// OID_WW_CDPD_AREA_COLOR
+//
+typedef INT WW_CDPD_AREA_COLOR;
+//
+// OID_WW_CDPD_TX_POWER_LEVEL
+//
+typedef UINT WW_CDPD_TX_POWER_LEVEL;
+//
+// OID_WW_CDPD_EID
+//
+typedef NDIS_VAR_DATA_DESC WW_CDPD_EID;
+//
+// OID_WW_CDPD_HEADER_COMPRESSION
+//
+typedef INT WW_CDPD_HEADER_COMPRESSION; // 0 = no header compression,
+ // 1 = always compress headers,
+ // 2 = compress headers if MD-IS does
+ // -1 = unknown
+//
+// OID_WW_CDPD_DATA_COMPRESSION
+//
+
+typedef INT WW_CDPD_DATA_COMPRESSION; // 0 = no data compression,
+ // 1 = data compression enabled
+ // -1 = unknown
+//
+// OID_WW_CDPD_CHANNEL_SELECT
+//
+
+typedef struct _WW_CDPD_CHANNEL_SELECT {
+ UINT ChannelID; // channel number
+
+ UINT fixedDuration; // duration in seconds
+
+} WW_CDPD_CHANNEL_SELECT, *PWW_CDPD_CHANNEL_SELECT;
+
+//
+// OID_WW_CDPD_CHANNEL_STATE
+//
+typedef enum _WW_CDPD_CHANNEL_STATE {
+ CDPDChannelNotAvail,
+ CDPDChannelScanning,
+ CDPDChannelInitAcquired,
+ CDPDChannelAcquired,
+ CDPDChannelSleeping,
+ CDPDChannelWaking,
+ CDPDChannelCSDialing,
+ CDPDChannelCSRedial,
+ CDPDChannelCSAnswering,
+ CDPDChannelCSConnected,
+ CDPDChannelCSSuspended
+} WW_CDPD_CHANNEL_STATE, *PWW_CDPD_CHANNEL_STATE;
+
+//
+// OID_WW_CDPD_NEI
+//
+typedef enum _WW_CDPD_NEI_FORMAT {
+ CDPDNeiIPv4,
+ CDPDNeiCLNP,
+ CDPDNeiIPv6
+} WW_CDPD_NEI_FORMAT, *PWW_CDPD_NEI_FORMAT;
+typedef enum _WW_CDPD_NEI_TYPE {
+ CDPDNeiIndividual,
+ CDPDNeiMulticast,
+ CDPDNeiBroadcast
+} WW_CDPD_NEI_TYPE;
+typedef struct _WW_CDPD_NEI {
+ UINT uNeiIndex;
+ WW_CDPD_NEI_FORMAT NeiFormat;
+ WW_CDPD_NEI_TYPE NeiType;
+ WORD NeiGmid; // group member identifier, only
+ // meaningful if NeiType ==
+ // CDPDNeiMulticast
+
+ NDIS_VAR_DATA_DESC NeiAddress;
+} WW_CDPD_NEI;
+
+//
+// OID_WW_CDPD_NEI_STATE
+//
+typedef enum _WW_CDPD_NEI_STATE {
+ CDPDUnknown,
+ CDPDRegistered,
+ CDPDDeregistered
+} WW_CDPD_NEI_STATE, *PWW_CDPD_NEI_STATE;
+typedef enum _WW_CDPD_NEI_SUB_STATE {
+ CDPDPending, // Registration pending
+ CDPDNoReason, // Registration denied - no reason given
+ CDPDMDISNotCapable, // Registration denied - MD-IS not capable of
+ // handling M-ES at this time
+ CDPDNEINotAuthorized, // Registration denied - NEI is not authorized to
+ // use this subnetwork
+ CDPDInsufficientAuth, // Registration denied - M-ES gave insufficient
+ // authentication credentials
+ CDPDUnsupportedAuth, // Registration denied - M-ES gave unsupported
+ // authentication credentials
+ CDPDUsageExceeded, // Registration denied - NEI has exceeded usage
+ // limitations
+ CDPDDeniedThisNetwork // Registration denied on this network, service
+ // may be obtained on alternate Service Provider
+ // network
+} WW_CDPD_NEI_SUB_STATE;
+typedef struct _WW_CDPD_NEI_REG_STATE {
+ UINT uNeiIndex;
+ WW_CDPD_NEI_STATE NeiState;
+ WW_CDPD_NEI_SUB_STATE NeiSubState;
+} WW_CDPD_NEI_REG_STATE, *PWW_CDPD_NEI_REG_STATE;
+
+//
+// OID_WW_CDPD_SERVICE_PROVIDER_IDENTIFIER
+//
+typedef struct _WW_CDPD_SERVICE_PROVIDER_ID {
+ UINT SPI[10]; //10 16-bit service provider IDs
+
+ INT OperatingMode; // 0 = ignore SPI,
+ // 1 = require SPI from list,
+ // 2 = prefer SPI from list.
+ // 3 = exclude SPI from list.
+
+} WW_CDPD_SERVICE_PROVIDER_ID, *PWW_CDPD_SERVICE_PROVIDER_ID;
+
+//
+// OID_WW_CDPD_SLEEP_MODE
+//
+typedef INT WW_CDPD_SLEEP_MODE;
+//
+// OID_WW_CDPD_TEI
+//
+typedef ULONG WW_CDPD_TEI;
+//
+// OID_WW_CDPD_CIRCUIT_SWITCHED
+//
+typedef struct _WW_CDPD_CIRCUIT_SWITCHED {
+ INT service_preference; // -1 = unknown,
+ // 0 = always use packet switched CDPD,
+ // 1 = always use CS CDPD via AMPS,
+ // 2 = always use CS CDPD via PSTN,
+ // 3 = use circuit switched via AMPS only
+ // when packet switched is not available.
+ // 4 = use packet switched only when circuit
+ // switched via AMPS is not available.
+ // 5 = device manuf. defined service
+ // preference.
+ // 6 = device manuf. defined service
+ // preference.
+
+ INT service_status; // -1 = unknown,
+ // 0 = packet switched CDPD,
+ // 1 = circuit switched CDPD via AMPS,
+ // 2 = circuit switched CDPD via PSTN.
+
+ INT connect_rate; // CS connection bit rate (bits per second).
+ // 0 = no active connection,
+ // -1 = unknown
+ // Dial code last used to dial.
+
+ NDIS_VAR_DATA_DESC dial_code[20];
+
+ UINT sid; // Current AMPS system ID
+
+ INT a_b_side_selection; // -1 = unknown,
+ // 0 = no AMPS service
+ // 1 = AMPS "A" side channels selected
+ // 2 = AMPS "B" side channels selected
+
+ INT AMPS_channel; // -1= unknown
+ // 0 = no AMPS service.
+ // 1-1023 = AMPS channel number in use
+
+ UINT action; // 0 = no action
+ // 1 = suspend (hangup)
+ // 2 = dial
+
+ // Default dial code for CS CDPD service
+ // encoded as specified in the CS CDPD
+ // implementor guidelines.
+ NDIS_VAR_DATA_DESC default_dial[20];
+
+ // Number for the CS CDPD network to call
+ // back the mobile, encoded as specified in
+ // the CS CDPD implementor guidelines.
+ NDIS_VAR_DATA_DESC call_back[20];
+
+ UINT sid_list[10]; // List of 10 16-bit preferred AMPS
+ // system IDs for CS CDPD.
+
+ UINT inactivity_timer; // Wait time after last data before dropping
+ // call.
+ // 0-65535 = inactivity time limit (seconds).
+
+ UINT receive_timer; // secs. per CS-CDPD Implementor Guidelines.
+
+ UINT conn_resp_timer; // secs. per CS-CDPD Implementor Guidelines.
+
+ UINT reconn_resp_timer; // secs. per CS-CDPD Implementor Guidelines.
+
+ UINT disconn_timer; // secs. per CS-CDPD Implementor Guidelines.
+
+ UINT NEI_reg_timer; // secs. per CS-CDPD Implementor Guidelines.
+
+ UINT reconn_retry_timer; // secs. per CS-CDPD Implementor Guidelines.
+
+ UINT link_reset_timer; // secs. per CS-CDPD Implementor Guidelines.
+
+ UINT link_reset_ack_timer; // secs. per CS-CDPD Implementor Guidelines.
+
+ UINT n401_retry_limit; // per CS-CDPD Implementor Guidelines.
+
+ UINT n402_retry_limit; // per CS-CDPD Implementor Guidelines.
+
+ UINT n404_retry_limit; // per CS-CDPD Implementor Guidelines.
+
+ UINT n405_retry_limit; // per CS-CDPD Implementor Guidelines.
+
+} WW_CDPD_CIRCUIT_SWITCHED, *WW_PCDPD_CIRCUIT_SWITCHED;
+typedef UINT WW_CDPD_RSSI;
+//
+// OID_WW_PIN_LOC_AUTHORIZE
+//
+typedef INT WW_PIN_AUTHORIZED; // 0 = unauthorized
+ // 1 = authorized
+ // -1 = unknown
+//
+// OID_WW_PIN_LAST_LOCATION
+// OID_WW_PIN_LOC_FIX
+//
+
+typedef struct _WW_PIN_LOCATION {
+ INT Latitude; // Latitude in hundredths of a second
+
+ INT Longitude; // Longitude in hundredths of a second
+
+ INT Altitude; // Altitude in feet
+
+ INT FixTime; // Time of the location fix, since midnight, local time (of the
+ // current day), in tenths of a second
+
+ INT NetTime; // Current local network time of the current day, since midnight,
+ // in tenths of a second
+
+ INT LocQuality; // 0-100 = location quality
+
+ INT LatReg; // Latitude registration offset, in hundredths of a second
+
+ INT LongReg; // Longitude registration offset, in hundredths of a second
+
+ INT GMTOffset; // Offset in minutes of the local time zone from GMT
+
+} WW_PIN_LOCATION, *PWW_PIN_LOCATION;
+
+//
+// The following is set on a per-packet basis as OOB data with NdisClassWirelessWanMbxMailbox
+//
+typedef ULONG WW_MBX_MAILBOX_FLAG; // 1 = set mailbox flag, 0 = do not set mailbox flag
+//
+// OID_WW_MBX_SUBADDR
+//
+
+typedef struct _WW_MBX_PMAN {
+ BOOLEAN ACTION; // 0 = Login PMAN, 1 = Logout PMAN
+
+ UINT MAN;
+ UCHAR PASSWORD[8]; // Password should be null for Logout and indications.
+ // Maximum length of password is 8 chars.
+
+} WW_MBX_PMAN, *PWW_MBX_PMAN;
+
+//
+// OID_WW_MBX_FLEXLIST
+//
+typedef struct _WW_MBX_FLEXLIST {
+ INT count; // Number of MAN entries used.
+ // -1=unknown.
+
+ UINT MAN[7]; // List of MANs.
+
+} WW_MBX_FLEXLIST;
+
+//
+// OID_WW_MBX_GROUPLIST
+//
+typedef struct _WW_MBX_GROUPLIST {
+ INT count; // Number of MAN entries used.
+ // -1=unknown.
+
+ UINT MAN[15]; // List of MANs.
+
+} WW_MBX_GROUPLIST;
+
+//
+// OID_WW_MBX_TRAFFIC_AREA
+//
+typedef enum _WW_MBX_TRAFFIC_AREA {
+ unknown_traffic_area, // The driver has no information about the current traffic area.
+ in_traffic_area, // Mobile unit has entered a subscribed traffic area.
+ in_auth_traffic_area, // Mobile unit is outside traffic area but is authorized.
+ unauth_traffic_area // Mobile unit is outside traffic area but is un-authorized.
+} WW_MBX_TRAFFIC_AREA;
+
+//
+// OID_WW_MBX_LIVE_DIE
+//
+typedef INT WW_MBX_LIVE_DIE; // 0 = DIE last received
+ // 1 = LIVE last received
+ // -1 = unknown
+//
+// OID_WW_MBX_TEMP_DEFAULTLIST
+//
+
+typedef struct _WW_MBX_CHANNEL_PAIR {
+ UINT Mobile_Tx;
+ UINT Mobile_Rx;
+} WW_MBX_CHANNEL_PAIR, *PWW_MBX_CHANNEL_PAIR;
+typedef struct _WW_MBX_TEMPDEFAULTLIST {
+ UINT Length;
+ WW_MBX_CHANNEL_PAIR ChannelPair[1];
+} WW_MBX_TEMPDEFAULTLIST, *WW_PMBX_TEMPDEFAULTLIST;
+
+#endif // WIRELESS_WAN
+#endif // _NTDDNDIS_
diff --git a/src/Cedar/winpcap/Ntddpack.h b/src/Cedar/winpcap/Ntddpack.h
new file mode 100644
index 00000000..30945c1e
--- /dev/null
+++ b/src/Cedar/winpcap/Ntddpack.h
@@ -0,0 +1,26 @@
+
+#ifndef __NTDDPACKET
+#define __NTDDPACKET 1
+#include "devioctl.h"
+/*#include <packon.h> */
+struct _PACKET_OID_DATA {
+ ULONG Oid;
+ ULONG Length;
+ UCHAR Data[1];
+};
+
+typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA;
+
+/*#include <packoff.h> */
+#define FILE_DEVICE_PROTOCOL 0x8000
+#define IOCTL_PROTOCOL_QUERY_OID CTL_CODE(FILE_DEVICE_PROTOCOL, 0 , METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_PROTOCOL_SET_OID CTL_CODE(FILE_DEVICE_PROTOCOL, 1 , METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_PROTOCOL_STATISTICS CTL_CODE(FILE_DEVICE_PROTOCOL, 2 , METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_PROTOCOL_RESET CTL_CODE(FILE_DEVICE_PROTOCOL, 3 , METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_PROTOCOL_READ CTL_CODE(FILE_DEVICE_PROTOCOL, 4 , METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_PROTOCOL_WRITE CTL_CODE(FILE_DEVICE_PROTOCOL, 5 , METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_PROTOCOL_MACNAME CTL_CODE(FILE_DEVICE_PROTOCOL, 6 , METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_OPEN CTL_CODE(FILE_DEVICE_PROTOCOL, 7 , METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_CLOSE CTL_CODE(FILE_DEVICE_PROTOCOL, 8 , METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#endif
diff --git a/src/Cedar/winpcap/Packet32.h b/src/Cedar/winpcap/Packet32.h
new file mode 100644
index 00000000..8c2c8c4a
--- /dev/null
+++ b/src/Cedar/winpcap/Packet32.h
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 1999 - 2003
+ * NetGroup, Politecnico di Torino (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/** @ingroup packetapi
+ * @{
+ */
+
+/** @defgroup packet32h Packet.dll definitions and data structures
+ * Packet32.h contains the data structures and the definitions used by packet.dll.
+ * The file is used both by the Win9x and the WinNTx versions of packet.dll, and can be included
+ * by the applications that use the functions of this library
+ * @{
+ */
+
+#ifndef __PACKET32
+#define __PACKET32
+
+#include <winsock2.h>
+#include "devioctl.h"
+#ifdef HAVE_DAG_API
+#include <dagc.h>
+#endif /* HAVE_DAG_API */
+
+// Working modes
+#define PACKET_MODE_CAPT 0x0 ///< Capture mode
+#define PACKET_MODE_STAT 0x1 ///< Statistical mode
+#define PACKET_MODE_MON 0x2 ///< Monitoring mode
+#define PACKET_MODE_DUMP 0x10 ///< Dump mode
+#define PACKET_MODE_STAT_DUMP MODE_DUMP | MODE_STAT ///< Statistical dump Mode
+
+// ioctls
+#define FILE_DEVICE_PROTOCOL 0x8000
+
+#define IOCTL_PROTOCOL_STATISTICS CTL_CODE(FILE_DEVICE_PROTOCOL, 2 , METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_PROTOCOL_RESET CTL_CODE(FILE_DEVICE_PROTOCOL, 3 , METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_PROTOCOL_READ CTL_CODE(FILE_DEVICE_PROTOCOL, 4 , METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_PROTOCOL_WRITE CTL_CODE(FILE_DEVICE_PROTOCOL, 5 , METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_PROTOCOL_MACNAME CTL_CODE(FILE_DEVICE_PROTOCOL, 6 , METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_OPEN CTL_CODE(FILE_DEVICE_PROTOCOL, 7 , METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_CLOSE CTL_CODE(FILE_DEVICE_PROTOCOL, 8 , METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+#define pBIOCSETBUFFERSIZE 9592 ///< IOCTL code: set kernel buffer size.
+#define pBIOCSETF 9030 ///< IOCTL code: set packet filtering program.
+#define pBIOCGSTATS 9031 ///< IOCTL code: get the capture stats.
+#define pBIOCSRTIMEOUT 7416 ///< IOCTL code: set the read timeout.
+#define pBIOCSMODE 7412 ///< IOCTL code: set working mode.
+#define pBIOCSWRITEREP 7413 ///< IOCTL code: set number of physical repetions of every packet written by the app.
+#define pBIOCSMINTOCOPY 7414 ///< IOCTL code: set minimum amount of data in the kernel buffer that unlocks a read call.
+#define pBIOCSETOID 2147483648 ///< IOCTL code: set an OID value.
+#define pBIOCQUERYOID 2147483652 ///< IOCTL code: get an OID value.
+#define pATTACHPROCESS 7117 ///< IOCTL code: attach a process to the driver. Used in Win9x only.
+#define pDETACHPROCESS 7118 ///< IOCTL code: detach a process from the driver. Used in Win9x only.
+#define pBIOCSETDUMPFILENAME 9029 ///< IOCTL code: set the name of a the file used by kernel dump mode.
+#define pBIOCEVNAME 7415 ///< IOCTL code: get the name of the event that the driver signals when some data is present in the buffer.
+#define pBIOCSENDPACKETSNOSYNC 9032 ///< IOCTL code: Send a buffer containing multiple packets to the network, ignoring the timestamps associated with the packets.
+#define pBIOCSENDPACKETSSYNC 9033 ///< IOCTL code: Send a buffer containing multiple packets to the network, respecting the timestamps associated with the packets.
+#define pBIOCSETDUMPLIMITS 9034 ///< IOCTL code: Set the dump file limits. See the PacketSetDumpLimits() function.
+#define pBIOCISDUMPENDED 7411 ///< IOCTL code: Get the status of the kernel dump process. See the PacketIsDumpEnded() function.
+
+#define pBIOCSTIMEZONE 7471 ///< IOCTL code: set time zone. Used in Win9x only.
+
+
+/// Alignment macro. Defines the alignment size.
+#define Packet_ALIGNMENT sizeof(int)
+/// Alignment macro. Rounds up to the next even multiple of Packet_ALIGNMENT.
+#define Packet_WORDALIGN(x) (((x)+(Packet_ALIGNMENT-1))&~(Packet_ALIGNMENT-1))
+
+
+#define NdisMediumNull -1 // Custom linktype: NDIS doesn't provide an equivalent
+#define NdisMediumCHDLC -2 // Custom linktype: NDIS doesn't provide an equivalent
+#define NdisMediumPPPSerial -3 // Custom linktype: NDIS doesn't provide an equivalent
+
+/*!
+ \brief Network type structure.
+
+ This structure is used by the PacketGetNetType() function to return information on the current adapter's type and speed.
+*/
+typedef struct NetType
+{
+ UINT LinkType; ///< The MAC of the current network adapter (see function PacketGetNetType() for more information)
+ ULONGLONG LinkSpeed; ///< The speed of the network in bits per second
+}NetType;
+
+
+//some definitions stolen from libpcap
+
+#ifndef BPF_MAJOR_VERSION
+
+/*!
+ \brief A BPF pseudo-assembly program.
+
+ The program will be injected in the kernel by the PacketSetBPF() function and applied to every incoming packet.
+*/
+struct bpf_program
+{
+ UINT bf_len; ///< Indicates the number of instructions of the program, i.e. the number of struct bpf_insn that will follow.
+ struct bpf_insn *bf_insns; ///< A pointer to the first instruction of the program.
+};
+
+/*!
+ \brief A single BPF pseudo-instruction.
+
+ bpf_insn contains a single instruction for the BPF register-machine. It is used to send a filter program to the driver.
+*/
+struct bpf_insn
+{
+ USHORT code; ///< Instruction type and addressing mode.
+ UCHAR jt; ///< Jump if true
+ UCHAR jf; ///< Jump if false
+ int k; ///< Generic field used for various purposes.
+};
+
+/*!
+ \brief Structure that contains a couple of statistics values on the current capture.
+
+ It is used by packet.dll to return statistics about a capture session.
+*/
+struct bpf_stat
+{
+ UINT bs_recv; ///< Number of packets that the driver received from the network adapter
+ ///< from the beginning of the current capture. This value includes the packets
+ ///< lost by the driver.
+ UINT bs_drop; ///< number of packets that the driver lost from the beginning of a capture.
+ ///< Basically, a packet is lost when the the buffer of the driver is full.
+ ///< In this situation the packet cannot be stored and the driver rejects it.
+ UINT ps_ifdrop; ///< drops by interface. XXX not yet supported
+ UINT bs_capt; ///< number of packets that pass the filter, find place in the kernel buffer and
+ ///< thus reach the application.
+};
+
+/*!
+ \brief Packet header.
+
+ This structure defines the header associated with every packet delivered to the application.
+*/
+struct bpf_hdr
+{
+ struct timeval bh_tstamp; ///< The timestamp associated with the captured packet.
+ ///< It is stored in a TimeVal structure.
+ UINT bh_caplen; ///< Length of captured portion. The captured portion <b>can be different</b>
+ ///< from the original packet, because it is possible (with a proper filter)
+ ///< to instruct the driver to capture only a portion of the packets.
+ UINT bh_datalen; ///< Original length of packet
+ USHORT bh_hdrlen; ///< Length of bpf header (this struct plus alignment padding). In some cases,
+ ///< a padding could be added between the end of this structure and the packet
+ ///< data for performance reasons. This filed can be used to retrieve the actual data
+ ///< of the packet.
+};
+
+/*!
+ \brief Dump packet header.
+
+ This structure defines the header associated with the packets in a buffer to be used with PacketSendPackets().
+ It is simpler than the bpf_hdr, because it corresponds to the header associated by WinPcap and libpcap to a
+ packet in a dump file. This makes straightforward sending WinPcap dump files to the network.
+*/
+struct dump_bpf_hdr{
+ struct timeval ts; ///< Time stamp of the packet
+ UINT caplen; ///< Length of captured portion. The captured portion can smaller than the
+ ///< the original packet, because it is possible (with a proper filter) to
+ ///< instruct the driver to capture only a portion of the packets.
+ UINT len; ///< Length of the original packet (off wire).
+};
+
+
+#endif
+
+#define DOSNAMEPREFIX TEXT("Packet_") ///< Prefix added to the adapters device names to create the WinPcap devices
+#define MAX_LINK_NAME_LENGTH 64 //< Maximum length of the devices symbolic links
+#define NMAX_PACKET 65535
+
+/*!
+ \brief Addresses of a network adapter.
+
+ This structure is used by the PacketGetNetInfoEx() function to return the IP addresses associated with
+ an adapter.
+*/
+typedef struct npf_if_addr {
+ struct sockaddr_storage IPAddress; ///< IP address.
+ struct sockaddr_storage SubnetMask; ///< Netmask for that address.
+ struct sockaddr_storage Broadcast; ///< Broadcast address.
+}npf_if_addr;
+
+
+#define ADAPTER_NAME_LENGTH 256 + 12 ///< Maximum length for the name of an adapter. The value is the same used by the IP Helper API.
+#define ADAPTER_DESC_LENGTH 128 ///< Maximum length for the description of an adapter. The value is the same used by the IP Helper API.
+#define MAX_MAC_ADDR_LENGTH 8 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API.
+#define MAX_NETWORK_ADDRESSES 16 ///< Maximum length for the link layer address of an adapter. The value is the same used by the IP Helper API.
+
+
+typedef struct WAN_ADAPTER_INT WAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API
+typedef WAN_ADAPTER *PWAN_ADAPTER; ///< Describes an opened wan (dialup, VPN...) network adapter using the NetMon API
+
+#define INFO_FLAG_NDIS_ADAPTER 0 ///< Flag for ADAPTER_INFO: this is a traditional ndis adapter
+#define INFO_FLAG_NDISWAN_ADAPTER 1 ///< Flag for ADAPTER_INFO: this is a NdisWan adapter
+#define INFO_FLAG_DAG_CARD 2 ///< Flag for ADAPTER_INFO: this is a DAG card
+#define INFO_FLAG_DAG_FILE 6 ///< Flag for ADAPTER_INFO: this is a DAG file
+#define INFO_FLAG_DONT_EXPORT 8 ///< Flag for ADAPTER_INFO: when this flag is set, the adapter will not be listed or openend by winpcap. This allows to prevent exporting broken network adapters, like for example FireWire ones.
+
+/*!
+ \brief Contains comprehensive information about a network adapter.
+
+ This structure is filled with all the accessory information that the user can need about an adapter installed
+ on his system.
+*/
+typedef struct _ADAPTER_INFO
+{
+ struct _ADAPTER_INFO *Next; ///< Pointer to the next adapter in the list.
+ CHAR Name[ADAPTER_NAME_LENGTH + 1]; ///< Name of the device representing the adapter.
+ CHAR Description[ADAPTER_DESC_LENGTH + 1]; ///< Human understandable description of the adapter
+ UINT MacAddressLen; ///< Length of the link layer address.
+ UCHAR MacAddress[MAX_MAC_ADDR_LENGTH]; ///< Link layer address.
+ NetType LinkLayer; ///< Physical characteristics of this adapter. This NetType structure contains the link type and the speed of the adapter.
+ INT NNetworkAddresses; ///< Number of network layer addresses of this adapter.
+ npf_if_addr *NetworkAddresses; ///< Pointer to an array of npf_if_addr, each of which specifies a network address of this adapter.
+ UINT Flags; ///< Adapter's flags. Tell if this adapter must be treated in a different way, using the Netmon API or the dagc API.
+}
+ADAPTER_INFO, *PADAPTER_INFO;
+
+/*!
+ \brief Describes an opened network adapter.
+
+ This structure is the most important for the functioning of packet.dll, but the great part of its fields
+ should be ignored by the user, since the library offers functions that avoid to cope with low-level parameters
+*/
+typedef struct _ADAPTER {
+ HANDLE hFile; ///< \internal Handle to an open instance of the NPF driver.
+ CHAR SymbolicLink[MAX_LINK_NAME_LENGTH]; ///< \internal A string containing the name of the network adapter currently opened.
+ int NumWrites; ///< \internal Number of times a packets written on this adapter will be repeated
+ ///< on the wire.
+ HANDLE ReadEvent; ///< A notification event associated with the read calls on the adapter.
+ ///< It can be passed to standard Win32 functions (like WaitForSingleObject
+ ///< or WaitForMultipleObjects) to wait until the driver's buffer contains some
+ ///< data. It is particularly useful in GUI applications that need to wait
+ ///< concurrently on several events. In Windows NT/2000 the PacketSetMinToCopy()
+ ///< function can be used to define the minimum amount of data in the kernel buffer
+ ///< that will cause the event to be signalled.
+
+ UINT ReadTimeOut; ///< \internal The amount of time after which a read on the driver will be released and
+ ///< ReadEvent will be signaled, also if no packets were captured
+ CHAR Name[ADAPTER_NAME_LENGTH];
+ PWAN_ADAPTER pWanAdapter;
+ UINT Flags; ///< Adapter's flags. Tell if this adapter must be treated in a different way, using the Netmon API or the dagc API.
+#ifdef HAVE_DAG_API
+ dagc_t *pDagCard; ///< Pointer to the dagc API adapter descriptor for this adapter
+ PCHAR DagBuffer; ///< Pointer to the buffer with the packets that is received from the DAG card
+ struct timeval DagReadTimeout; ///< Read timeout. The dagc API requires a timeval structure
+ unsigned DagFcsLen; ///< Length of the frame check sequence attached to any packet by the card. Obtained from the registry
+ DWORD DagFastProcess; ///< True if the user requests fast capture processing on this card. Higher level applications can use this value to provide a faster but possibly unprecise capture (for example, libpcap doesn't convert the timestamps).
+#endif // HAVE_DAG_API
+} ADAPTER, *LPADAPTER;
+
+/*!
+ \brief Structure that contains a group of packets coming from the driver.
+
+ This structure defines the header associated with every packet delivered to the application.
+*/
+typedef struct _PACKET {
+ HANDLE hEvent; ///< \deprecated Still present for compatibility with old applications.
+ OVERLAPPED OverLapped; ///< \deprecated Still present for compatibility with old applications.
+ PVOID Buffer; ///< Buffer with containing the packets. See the PacketReceivePacket() for
+ ///< details about the organization of the data in this buffer
+ UINT Length; ///< Length of the buffer
+ DWORD ulBytesReceived; ///< Number of valid bytes present in the buffer, i.e. amount of data
+ ///< received by the last call to PacketReceivePacket()
+ BOOLEAN bIoComplete; ///< \deprecated Still present for compatibility with old applications.
+} PACKET, *LPPACKET;
+
+/*!
+ \brief Structure containing an OID request.
+
+ It is used by the PacketRequest() function to send an OID to the interface card driver.
+ It can be used, for example, to retrieve the status of the error counters on the adapter, its MAC address,
+ the list of the multicast groups defined on it, and so on.
+*/
+struct _PACKET_OID_DATA {
+ ULONG Oid; ///< OID code. See the Microsoft DDK documentation or the file ntddndis.h
+ ///< for a complete list of valid codes.
+ ULONG Length; ///< Length of the data field
+ UCHAR Data[1]; ///< variable-lenght field that contains the information passed to or received
+ ///< from the adapter.
+};
+typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA;
+
+
+#if _DBG
+#define ODS(_x) OutputDebugString(TEXT(_x))
+#define ODSEx(_x, _y)
+#else
+#ifdef _DEBUG_TO_FILE
+/*!
+ \brief Macro to print a debug string. The behavior differs depending on the debug level
+*/
+#define ODS(_x) { \
+ FILE *f; \
+ f = fopen("winpcap_debug.txt", "a"); \
+ fprintf(f, "%s", _x); \
+ fclose(f); \
+}
+/*!
+ \brief Macro to print debug data with the printf convention. The behavior differs depending on
+ the debug level
+*/
+#define ODSEx(_x, _y) { \
+ FILE *f; \
+ f = fopen("winpcap_debug.txt", "a"); \
+ fprintf(f, _x, _y); \
+ fclose(f); \
+}
+
+
+
+LONG PacketDumpRegistryKey(PCHAR KeyName, PCHAR FileName);
+#else
+#define ODS(_x)
+#define ODSEx(_x, _y)
+#endif
+#endif
+
+/* We load dinamically the dag library in order link it only when it's present on the system */
+#ifdef HAVE_DAG_API
+typedef dagc_t* (*dagc_open_handler)(const char *source, unsigned flags, char *ebuf); ///< prototype used to dynamically load the dag dll
+typedef void (*dagc_close_handler)(dagc_t *dagcfd); ///< prototype used to dynamically load the dag dll
+typedef int (*dagc_getlinktype_handler)(dagc_t *dagcfd); ///< prototype used to dynamically load the dag dll
+typedef int (*dagc_getlinkspeed_handler)(dagc_t *dagcfd); ///< prototype used to dynamically load the dag dll
+typedef int (*dagc_setsnaplen_handler)(dagc_t *dagcfd, unsigned snaplen); ///< prototype used to dynamically load the dag dll
+typedef unsigned (*dagc_getfcslen_handler)(dagc_t *dagcfd); ///< prototype used to dynamically load the dag dll
+typedef int (*dagc_receive_handler)(dagc_t *dagcfd, u_char **buffer, u_int *bufsize); ///< prototype used to dynamically load the dag dll
+typedef int (*dagc_stats_handler)(dagc_t *dagcfd, dagc_stats_t *ps); ///< prototype used to dynamically load the dag dll
+typedef int (*dagc_wait_handler)(dagc_t *dagcfd, struct timeval *timeout); ///< prototype used to dynamically load the dag dll
+typedef int (*dagc_finddevs_handler)(dagc_if_t **alldevsp, char *ebuf); ///< prototype used to dynamically load the dag dll
+typedef int (*dagc_freedevs_handler)(dagc_if_t *alldevsp); ///< prototype used to dynamically load the dag dll
+#endif // HAVE_DAG_API
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @}
+ */
+
+// The following is used to check the adapter name in PacketOpenAdapterNPF and prevent
+// opening of firewire adapters
+#define FIREWIRE_SUBSTR L"1394"
+
+void PacketPopulateAdaptersInfoList();
+PWCHAR SChar2WChar(PCHAR string);
+PCHAR WChar2SChar(PWCHAR string);
+BOOL PacketGetFileVersion(LPTSTR FileName, PCHAR VersionBuff, UINT VersionBuffLen);
+PADAPTER_INFO PacketFindAdInfo(PCHAR AdapterName);
+BOOLEAN PacketUpdateAdInfo(PCHAR AdapterName);
+BOOLEAN IsFireWire(TCHAR *AdapterDesc);
+
+
+//---------------------------------------------------------------------------
+// EXPORTED FUNCTIONS
+//---------------------------------------------------------------------------
+
+PCHAR PacketGetVersion();
+PCHAR PacketGetDriverVersion();
+BOOLEAN PacketSetMinToCopy(LPADAPTER AdapterObject,int nbytes);
+BOOLEAN PacketSetNumWrites(LPADAPTER AdapterObject,int nwrites);
+BOOLEAN PacketSetMode(LPADAPTER AdapterObject,int mode);
+BOOLEAN PacketSetReadTimeout(LPADAPTER AdapterObject,int timeout);
+BOOLEAN PacketSetBpf(LPADAPTER AdapterObject,struct bpf_program *fp);
+INT PacketSetSnapLen(LPADAPTER AdapterObject,int snaplen);
+BOOLEAN PacketGetStats(LPADAPTER AdapterObject,struct bpf_stat *s);
+BOOLEAN PacketGetStatsEx(LPADAPTER AdapterObject,struct bpf_stat *s);
+BOOLEAN PacketSetBuff(LPADAPTER AdapterObject,int dim);
+BOOLEAN PacketGetNetType (LPADAPTER AdapterObject,NetType *type);
+LPADAPTER PacketOpenAdapter(PCHAR AdapterName);
+BOOLEAN PacketSendPacket(LPADAPTER AdapterObject,LPPACKET pPacket,BOOLEAN Sync);
+INT PacketSendPackets(LPADAPTER AdapterObject,PVOID PacketBuff,ULONG Size, BOOLEAN Sync);
+LPPACKET PacketAllocatePacket(void);
+VOID PacketInitPacket(LPPACKET lpPacket,PVOID Buffer,UINT Length);
+VOID PacketFreePacket(LPPACKET lpPacket);
+BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,LPPACKET lpPacket,BOOLEAN Sync);
+BOOLEAN PacketSetHwFilter(LPADAPTER AdapterObject,ULONG Filter);
+BOOLEAN PacketGetAdapterNames(PTSTR pStr,PULONG BufferSize);
+BOOLEAN PacketGetNetInfoEx(PCHAR AdapterName, npf_if_addr* buffer, PLONG NEntries);
+BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData);
+HANDLE PacketGetReadEvent(LPADAPTER AdapterObject);
+BOOLEAN PacketSetDumpName(LPADAPTER AdapterObject, void *name, int len);
+BOOLEAN PacketSetDumpLimits(LPADAPTER AdapterObject, UINT maxfilesize, UINT maxnpacks);
+BOOLEAN PacketIsDumpEnded(LPADAPTER AdapterObject, BOOLEAN sync);
+BOOL PacketStopDriver();
+VOID PacketCloseAdapter(LPADAPTER lpAdapter);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__PACKET32
diff --git a/src/Cedar/winpcap/Win32-Extensions.h b/src/Cedar/winpcap/Win32-Extensions.h
new file mode 100644
index 00000000..8466e0c2
--- /dev/null
+++ b/src/Cedar/winpcap/Win32-Extensions.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1999 - 2003
+ * NetGroup, Politecnico di Torino (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* Definitions */
+
+/*!
+ \brief A queue of raw packets that will be sent to the network with pcap_sendqueue_transmit().
+*/
+struct pcap_send_queue{
+ u_int maxlen; ///< Maximum size of the the queue, in bytes. This variable contains the size of the buffer field.
+ u_int len; ///< Current size of the queue, in bytes.
+ char *buffer; ///< Buffer containing the packets to be sent.
+};
+
+typedef struct pcap_send_queue pcap_send_queue;
+
+#define BPF_MEM_EX_IMM 0xc0
+#define BPF_MEM_EX_IND 0xe0
+
+/*used for ST*/
+#define BPF_MEM_EX 0xc0
+#define BPF_TME 0x08
+
+#define BPF_LOOKUP 0x90
+#define BPF_EXECUTE 0xa0
+#define BPF_INIT 0xb0
+#define BPF_VALIDATE 0xc0
+#define BPF_SET_ACTIVE 0xd0
+#define BPF_RESET 0xe0
+#define BPF_SET_MEMORY 0x80
+#define BPF_GET_REGISTER_VALUE 0x70
+#define BPF_SET_REGISTER_VALUE 0x60
+#define BPF_SET_WORKING 0x50
+#define BPF_SET_ACTIVE_READ 0x40
+#define BPF_SET_AUTODELETION 0x30
+#define BPF_SEPARATION 0xff
+
+/* Prototypes */
+pcap_send_queue* pcap_sendqueue_alloc(u_int memsize);
+
+void pcap_sendqueue_destroy(pcap_send_queue* queue);
+
+int pcap_sendqueue_queue(pcap_send_queue* queue, const struct pcap_pkthdr *pkt_header, const u_char *pkt_data);
+
+u_int pcap_sendqueue_transmit(pcap_t *p, pcap_send_queue* queue, int sync);
+
+HANDLE pcap_getevent(pcap_t *p);
+
+struct pcap_stat *pcap_stats_ex(pcap_t *p, int *pcap_stat_size);
+
+int pcap_setuserbuffer(pcap_t *p, int size);
+
+int pcap_live_dump(pcap_t *p, char *filename, int maxsize, int maxpacks);
+
+int pcap_live_dump_ended(pcap_t *p, int sync);
+
+int pcap_offline_filter(struct bpf_program *prog, const struct pcap_pkthdr *header, const u_char *pkt_data);
diff --git a/src/Cedar/winpcap/bittypes.h b/src/Cedar/winpcap/bittypes.h
new file mode 100644
index 00000000..1a2611d8
--- /dev/null
+++ b/src/Cedar/winpcap/bittypes.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 1999 WIDE Project.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#ifndef _BITTYPES_H
+#define _BITTYPES_H
+
+#ifndef HAVE_U_INT8_T
+
+#if SIZEOF_CHAR == 1
+typedef unsigned char u_int8_t;
+typedef signed char int8_t;
+#elif SIZEOF_INT == 1
+typedef unsigned int u_int8_t;
+typedef signed int int8_t;
+#else /* XXX */
+#error "there's no appropriate type for u_int8_t"
+#endif
+#define HAVE_U_INT8_T 1
+#define HAVE_INT8_T 1
+
+#endif /* HAVE_U_INT8_T */
+
+#ifndef HAVE_U_INT16_T
+
+#if SIZEOF_SHORT == 2
+typedef unsigned short u_int16_t;
+typedef signed short int16_t;
+#elif SIZEOF_INT == 2
+typedef unsigned int u_int16_t;
+typedef signed int int16_t;
+#elif SIZEOF_CHAR == 2
+typedef unsigned char u_int16_t;
+typedef signed char int16_t;
+#else /* XXX */
+#error "there's no appropriate type for u_int16_t"
+#endif
+#define HAVE_U_INT16_T 1
+#define HAVE_INT16_T 1
+
+#endif /* HAVE_U_INT16_T */
+
+#ifndef HAVE_U_INT32_T
+
+#if SIZEOF_INT == 4
+typedef unsigned int u_int32_t;
+typedef signed int int32_t;
+#elif SIZEOF_LONG == 4
+typedef unsigned long u_int32_t;
+typedef signed long int32_t;
+#elif SIZEOF_SHORT == 4
+typedef unsigned short u_int32_t;
+typedef signed short int32_t;
+#else /* XXX */
+#error "there's no appropriate type for u_int32_t"
+#endif
+#define HAVE_U_INT32_T 1
+#define HAVE_INT32_T 1
+
+#endif /* HAVE_U_INT32_T */
+
+#ifndef HAVE_U_INT64_T
+#if SIZEOF_LONG_LONG == 8
+typedef unsigned long long u_int64_t;
+#elif defined(_MSC_EXTENSIONS)
+typedef unsigned _int64 u_int64_t;
+#elif SIZEOF_INT == 8
+typedef unsigned int u_int64_t;
+#elif SIZEOF_LONG == 8
+typedef unsigned long u_int64_t;
+#elif SIZEOF_SHORT == 8
+typedef unsigned short u_int64_t;
+#else /* XXX */
+#error "there's no appropriate type for u_int64_t"
+#endif
+
+#endif /* HAVE_U_INT64_T */
+
+#ifndef PRId64
+#ifdef _MSC_EXTENSIONS
+#define PRId64 "I64d"
+#else /* _MSC_EXTENSIONS */
+#define PRId64 "lld"
+#endif /* _MSC_EXTENSIONS */
+#endif /* PRId64 */
+
+#ifndef PRIo64
+#ifdef _MSC_EXTENSIONS
+#define PRIo64 "I64o"
+#else /* _MSC_EXTENSIONS */
+#define PRIo64 "llo"
+#endif /* _MSC_EXTENSIONS */
+#endif /* PRIo64 */
+
+#ifndef PRIx64
+#ifdef _MSC_EXTENSIONS
+#define PRIx64 "I64x"
+#else /* _MSC_EXTENSIONS */
+#define PRIx64 "llx"
+#endif /* _MSC_EXTENSIONS */
+#endif /* PRIx64 */
+
+#ifndef PRIu64
+#ifdef _MSC_EXTENSIONS
+#define PRIu64 "I64u"
+#else /* _MSC_EXTENSIONS */
+#define PRIu64 "llu"
+#endif /* _MSC_EXTENSIONS */
+#endif /* PRIu64 */
+
+#endif /* _BITTYPES_H */
diff --git a/src/Cedar/winpcap/bucket_lookup.h b/src/Cedar/winpcap/bucket_lookup.h
new file mode 100644
index 00000000..d8700b54
--- /dev/null
+++ b/src/Cedar/winpcap/bucket_lookup.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2001 - 2003
+ * NetGroup, Politecnico di Torino (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __bucket_lookup
+#define __bucket_lookup
+#ifdef WIN32
+#include "tme.h"
+#endif
+
+#ifdef __FreeBSD__
+
+#ifdef _KERNEL
+#include <net/tme/tme.h>
+#else
+#include <tme/tme.h>
+#endif
+
+#endif
+
+#define BUCKET_LOOKUP_INSERT 0x00000011
+uint32 bucket_lookup_insert(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref);
+#define BUCKET_LOOKUP 0x00000010
+uint32 bucket_lookup(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref);
+
+#endif
diff --git a/src/Cedar/winpcap/count_packets.h b/src/Cedar/winpcap/count_packets.h
new file mode 100644
index 00000000..9853bda3
--- /dev/null
+++ b/src/Cedar/winpcap/count_packets.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2001 - 2003
+ * NetGroup, Politecnico di Torino (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __count_packets
+#define __count_packets
+
+#ifdef WIN32
+#include "tme.h"
+#endif
+
+#ifdef __FreeBSD__
+
+#ifdef _KERNEL
+#include <net/tme/tme.h>
+#else
+#include <tme/tme.h>
+#endif
+
+#endif
+
+typedef struct __c_p_data
+{
+ struct timeval timestamp;
+ uint64 packets;
+ uint64 bytes;
+}
+ c_p_data;
+
+#define COUNT_PACKETS 0x00000000
+uint32 count_packets(uint8 *block, uint32 pkt_size, TME_DATA *data, MEM_TYPE *mem_ex, uint8 *mem_data);
+
+#endif
+
diff --git a/src/Cedar/winpcap/ip6_misc.h b/src/Cedar/winpcap/ip6_misc.h
new file mode 100644
index 00000000..1965ecab
--- /dev/null
+++ b/src/Cedar/winpcap/ip6_misc.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 1993, 1994, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the University of California,
+ * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/Win32/Include/ip6_misc.h,v 1.4 2004/07/06 23:45:29 risso Exp $ (LBL)
+ */
+
+/*
+ * This file contains a collage of declarations for IPv6 from FreeBSD not present in Windows
+ */
+
+#include <winsock2.h>
+
+#ifndef __MINGW32__
+#include <ws2tcpip.h>
+#endif /* __MINGW32__ */
+
+#define IN_MULTICAST(a) IN_CLASSD(a)
+
+#define IN_EXPERIMENTAL(a) ((((u_int32_t) (a)) & 0xf0000000) == 0xf0000000)
+
+#define IN_LOOPBACKNET 127
+
+#ifdef __MINGW32__
+/* IPv6 address */
+struct in6_addr
+ {
+ union
+ {
+ u_int8_t u6_addr8[16];
+ u_int16_t u6_addr16[8];
+ u_int32_t u6_addr32[4];
+ } in6_u;
+#define s6_addr in6_u.u6_addr8
+#define s6_addr16 in6_u.u6_addr16
+#define s6_addr32 in6_u.u6_addr32
+#define s6_addr64 in6_u.u6_addr64
+ };
+
+#define IN6ADDR_ANY_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }
+#define IN6ADDR_LOOPBACK_INIT { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }
+#endif /* __MINGW32__ */
+
+
+#if (defined WIN32) || (defined __MINGW32__)
+typedef unsigned short sa_family_t;
+#endif
+
+
+#ifdef __MINGW32__
+
+#define __SOCKADDR_COMMON(sa_prefix) \
+ sa_family_t sa_prefix##family
+
+/* Ditto, for IPv6. */
+struct sockaddr_in6
+ {
+ __SOCKADDR_COMMON (sin6_);
+ u_int16_t sin6_port; /* Transport layer port # */
+ u_int32_t sin6_flowinfo; /* IPv6 flow information */
+ struct in6_addr sin6_addr; /* IPv6 address */
+ };
+
+#define IN6_IS_ADDR_V4MAPPED(a) \
+ ((((u_int32_t *) (a))[0] == 0) && (((u_int32_t *) (a))[1] == 0) && \
+ (((u_int32_t *) (a))[2] == htonl (0xffff)))
+
+#define IN6_IS_ADDR_MULTICAST(a) (((u_int8_t *) (a))[0] == 0xff)
+
+#define IN6_IS_ADDR_LINKLOCAL(a) \
+ ((((u_int32_t *) (a))[0] & htonl (0xffc00000)) == htonl (0xfe800000))
+
+#define IN6_IS_ADDR_LOOPBACK(a) \
+ (((u_int32_t *) (a))[0] == 0 && ((u_int32_t *) (a))[1] == 0 && \
+ ((u_int32_t *) (a))[2] == 0 && ((u_int32_t *) (a))[3] == htonl (1))
+#endif /* __MINGW32__ */
+
+#define ip6_vfc ip6_ctlun.ip6_un2_vfc
+#define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
+#define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
+#define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt
+#define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim
+#define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim
+
+#define nd_rd_type nd_rd_hdr.icmp6_type
+#define nd_rd_code nd_rd_hdr.icmp6_code
+#define nd_rd_cksum nd_rd_hdr.icmp6_cksum
+#define nd_rd_reserved nd_rd_hdr.icmp6_data32[0]
+
+/*
+ * IPV6 extension headers
+ */
+#define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */
+#define IPPROTO_IPV6 41 /* IPv6 header. */
+#define IPPROTO_ROUTING 43 /* IPv6 routing header */
+#define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */
+#define IPPROTO_ESP 50 /* encapsulating security payload */
+#define IPPROTO_AH 51 /* authentication header */
+#define IPPROTO_ICMPV6 58 /* ICMPv6 */
+#define IPPROTO_NONE 59 /* IPv6 no next header */
+#define IPPROTO_DSTOPTS 60 /* IPv6 destination options */
+#define IPPROTO_PIM 103 /* Protocol Independent Multicast. */
+
+#define IPV6_RTHDR_TYPE_0 0
+
+/* Option types and related macros */
+#define IP6OPT_PAD1 0x00 /* 00 0 00000 */
+#define IP6OPT_PADN 0x01 /* 00 0 00001 */
+#define IP6OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */
+#define IP6OPT_JUMBO_LEN 6
+#define IP6OPT_ROUTER_ALERT 0x05 /* 00 0 00101 */
+
+#define IP6OPT_RTALERT_LEN 4
+#define IP6OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */
+#define IP6OPT_RTALERT_RSVP 1 /* Datagram contains an RSVP message */
+#define IP6OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */
+#define IP6OPT_MINLEN 2
+
+#define IP6OPT_BINDING_UPDATE 0xc6 /* 11 0 00110 */
+#define IP6OPT_BINDING_ACK 0x07 /* 00 0 00111 */
+#define IP6OPT_BINDING_REQ 0x08 /* 00 0 01000 */
+#define IP6OPT_HOME_ADDRESS 0xc9 /* 11 0 01001 */
+#define IP6OPT_EID 0x8a /* 10 0 01010 */
+
+#define IP6OPT_TYPE(o) ((o) & 0xC0)
+#define IP6OPT_TYPE_SKIP 0x00
+#define IP6OPT_TYPE_DISCARD 0x40
+#define IP6OPT_TYPE_FORCEICMP 0x80
+#define IP6OPT_TYPE_ICMP 0xC0
+
+#define IP6OPT_MUTABLE 0x20
+
+
+#ifdef __MINGW32__
+#ifndef EAI_ADDRFAMILY
+struct addrinfo {
+ int ai_flags; /* AI_PASSIVE, AI_CANONNAME */
+ int ai_family; /* PF_xxx */
+ int ai_socktype; /* SOCK_xxx */
+ int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+ size_t ai_addrlen; /* length of ai_addr */
+ char *ai_canonname; /* canonical name for hostname */
+ struct sockaddr *ai_addr; /* binary address */
+ struct addrinfo *ai_next; /* next structure in linked list */
+};
+#endif
+#endif /* __MINGW32__ */
diff --git a/src/Cedar/winpcap/memory_t.h b/src/Cedar/winpcap/memory_t.h
new file mode 100644
index 00000000..ab3c85db
--- /dev/null
+++ b/src/Cedar/winpcap/memory_t.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2001 - 2003
+ * NetGroup, Politecnico di Torino (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __memory_t
+#define __memory_t
+
+#define uint8 UCHAR
+#define int8 CHAR
+#define uint16 USHORT
+#define int16 SHORT
+#define uint32 ULONG
+#define int32 LONG
+#define uint64 ULONGLONG
+#define int64 LONGLONG
+
+/*memory type*/
+typedef struct __MEM_TYPE
+{
+ uint8 *buffer;
+ uint32 size;
+} MEM_TYPE, *PMEM_TYPE;
+
+#define LONG_AT(base,offset) (*(int32*)((uint8*)base+(uint32)offset))
+
+#define ULONG_AT(base,offset) (*(uint32*)((uint8*)base+(uint32)offset))
+
+#define SHORT_AT(base,offset) (*(int16*)((uint8*)base+(uint32)offset))
+
+#define USHORT_AT(base,offset) (*(uint16*)((uint8*)base+(uint32)offset))
+
+__inline int32 SW_LONG_AT(void *b, uint32 c)
+{
+ return ((int32)*((uint8 *)b+c)<<24|
+ (int32)*((uint8 *)b+c+1)<<16|
+ (int32)*((uint8 *)b+c+2)<<8|
+ (int32)*((uint8 *)b+c+3)<<0);
+}
+
+
+__inline uint32 SW_ULONG_AT(void *b, uint32 c)
+{
+ return ((uint32)*((uint8 *)b+c)<<24|
+ (uint32)*((uint8 *)b+c+1)<<16|
+ (uint32)*((uint8 *)b+c+2)<<8|
+ (uint32)*((uint8 *)b+c+3)<<0);
+}
+
+__inline int16 SW_SHORT_AT(void *b, uint32 os)
+{
+ return ((int16)
+ ((int16)*((uint8 *)b+os+0)<<8|
+ (int16)*((uint8 *)b+os+1)<<0));
+}
+
+__inline uint16 SW_USHORT_AT(void *b, uint32 os)
+{
+ return ((uint16)
+ ((uint16)*((uint8 *)b+os+0)<<8|
+ (uint16)*((uint8 *)b+os+1)<<0));
+}
+
+__inline VOID SW_ULONG_ASSIGN(void *dst, uint32 src)
+{
+ *((uint8*)dst+0)=*((uint8*)&src+3);
+ *((uint8*)dst+1)=*((uint8*)&src+2);
+ *((uint8*)dst+2)=*((uint8*)&src+1);
+ *((uint8*)dst+3)=*((uint8*)&src+0);
+
+}
+
+#ifdef WIN_NT_DRIVER
+
+#define ALLOCATE_MEMORY(dest,type,amount) \
+ (dest)=ExAllocatePool(NonPagedPool,sizeof(type)*(amount));
+#define ALLOCATE_ZERO_MEMORY(dest,type,amount) \
+ { \
+ (dest)=ExAllocatePool(NonPagedPool,sizeof(type)*(amount)); \
+ if ((dest)!=NULL) \
+ RtlZeroMemory((dest),sizeof(type)*(amount)); \
+ }
+
+#define FREE_MEMORY(dest) ExFreePool(dest);
+#define ZERO_MEMORY(dest,amount) RtlZeroMemory(dest,amount);
+#define COPY_MEMORY(dest,src,amount) RtlCopyMemory(dest,src,amount);
+
+#else
+
+#define ALLOCATE_MEMORY(dest,type,amount) \
+ (dest)=(type*)GlobalAlloc(GPTR, sizeof(type)*(amount));
+#define ALLOCATE_ZERO_MEMORY(dest,type,amount) \
+ (dest)=(type*)GlobalAlloc(GPTR, sizeof(type)*(amount));
+
+#define FREE_MEMORY(dest) GlobalFree(dest);
+#define ZERO_MEMORY(dest,amount) RtlZeroMemory(dest,amount);
+#define COPY_MEMORY(dest,src,amount) RtlCopyMemory(dest,src,amount);
+
+
+#endif /*WIN_NT_DRIVER*/
+
+
+
+#endif
+
diff --git a/src/Cedar/winpcap/normal_lookup.h b/src/Cedar/winpcap/normal_lookup.h
new file mode 100644
index 00000000..45ac4fd1
--- /dev/null
+++ b/src/Cedar/winpcap/normal_lookup.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2001 - 2003
+ * NetGroup, Politecnico di Torino (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __normal_lookup
+#define __normal_lookup
+
+#ifdef WIN32
+#include "tme.h"
+#endif
+
+#ifdef __FreeBSD__
+
+#ifdef _KERNEL
+#include <net/tme/tme.h>
+#else
+#include <tme/tme.h>
+#endif
+
+#endif
+
+#define NORMAL_LUT_W_INSERT 0x00000000
+uint32 normal_lut_w_insert(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref);
+#define NORMAL_LUT_WO_INSERT 0x00000001
+uint32 normal_lut_wo_insert(uint8 *key, TME_DATA *data, MEM_TYPE *mem_ex, struct time_conv *time_ref);
+#define DUMMY_INSERT 1234
+
+#endif
diff --git a/src/Cedar/winpcap/pcap-bpf.h b/src/Cedar/winpcap/pcap-bpf.h
new file mode 100644
index 00000000..6e5d64af
--- /dev/null
+++ b/src/Cedar/winpcap/pcap-bpf.h
@@ -0,0 +1,685 @@
+/*-
+ * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from the Stanford/CMU enet packet filter,
+ * (net/enet.c) distributed as part of 4.3BSD, and code contributed
+ * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
+ * Berkeley Laboratory.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)bpf.h 7.1 (Berkeley) 5/7/91
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/pcap-bpf.h,v 1.34.2.5 2005/05/27 23:33:00 guy Exp $ (LBL)
+ */
+
+/*
+ * This is libpcap's cut-down version of bpf.h; it includes only
+ * the stuff needed for the code generator and the userland BPF
+ * interpreter, and the libpcap APIs for setting filters, etc..
+ *
+ * "pcap-bpf.c" will include the native OS version, as it deals with
+ * the OS's BPF implementation.
+ *
+ * XXX - should this all just be moved to "pcap.h"?
+ */
+
+#ifndef BPF_MAJOR_VERSION
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* BSD style release date */
+#define BPF_RELEASE 199606
+
+#ifdef MSDOS /* must be 32-bit */
+typedef long bpf_int32;
+typedef unsigned long bpf_u_int32;
+#else
+typedef int bpf_int32;
+typedef u_int bpf_u_int32;
+#endif
+
+/*
+ * Alignment macros. BPF_WORDALIGN rounds up to the next
+ * even multiple of BPF_ALIGNMENT.
+ */
+#ifndef __NetBSD__
+#define BPF_ALIGNMENT sizeof(bpf_int32)
+#else
+#define BPF_ALIGNMENT sizeof(long)
+#endif
+#define BPF_WORDALIGN(x) (((x)+(BPF_ALIGNMENT-1))&~(BPF_ALIGNMENT-1))
+
+#define BPF_MAXINSNS 512
+#define BPF_MAXBUFSIZE 0x8000
+#define BPF_MINBUFSIZE 32
+
+/*
+ * Structure for "pcap_compile()", "pcap_setfilter()", etc..
+ */
+struct bpf_program {
+ u_int bf_len;
+ struct bpf_insn *bf_insns;
+};
+
+/*
+ * Struct return by BIOCVERSION. This represents the version number of
+ * the filter language described by the instruction encodings below.
+ * bpf understands a program iff kernel_major == filter_major &&
+ * kernel_minor >= filter_minor, that is, if the value returned by the
+ * running kernel has the same major number and a minor number equal
+ * equal to or less than the filter being downloaded. Otherwise, the
+ * results are undefined, meaning an error may be returned or packets
+ * may be accepted haphazardly.
+ * It has nothing to do with the source code version.
+ */
+struct bpf_version {
+ u_short bv_major;
+ u_short bv_minor;
+};
+/* Current version number of filter architecture. */
+#define BPF_MAJOR_VERSION 1
+#define BPF_MINOR_VERSION 1
+
+/*
+ * Data-link level type codes.
+ *
+ * Do *NOT* add new values to this list without asking
+ * "tcpdump-workers@tcpdump.org" for a value. Otherwise, you run the
+ * risk of using a value that's already being used for some other purpose,
+ * and of having tools that read libpcap-format captures not being able
+ * to handle captures with your new DLT_ value, with no hope that they
+ * will ever be changed to do so (as that would destroy their ability
+ * to read captures using that value for that other purpose).
+ */
+
+/*
+ * These are the types that are the same on all platforms, and that
+ * have been defined by <net/bpf.h> for ages.
+ */
+#define DLT_NULL 0 /* BSD loopback encapsulation */
+#define DLT_EN10MB 1 /* Ethernet (10Mb) */
+#define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */
+#define DLT_AX25 3 /* Amateur Radio AX.25 */
+#define DLT_PRONET 4 /* Proteon ProNET Token Ring */
+#define DLT_CHAOS 5 /* Chaos */
+#define DLT_IEEE802 6 /* IEEE 802 Networks */
+#define DLT_ARCNET 7 /* ARCNET, with BSD-style header */
+#define DLT_SLIP 8 /* Serial Line IP */
+#define DLT_PPP 9 /* Point-to-point Protocol */
+#define DLT_FDDI 10 /* FDDI */
+
+/*
+ * These are types that are different on some platforms, and that
+ * have been defined by <net/bpf.h> for ages. We use #ifdefs to
+ * detect the BSDs that define them differently from the traditional
+ * libpcap <net/bpf.h>
+ *
+ * XXX - DLT_ATM_RFC1483 is 13 in BSD/OS, and DLT_RAW is 14 in BSD/OS,
+ * but I don't know what the right #define is for BSD/OS.
+ */
+#define DLT_ATM_RFC1483 11 /* LLC-encapsulated ATM */
+
+#ifdef __OpenBSD__
+#define DLT_RAW 14 /* raw IP */
+#else
+#define DLT_RAW 12 /* raw IP */
+#endif
+
+/*
+ * Given that the only OS that currently generates BSD/OS SLIP or PPP
+ * is, well, BSD/OS, arguably everybody should have chosen its values
+ * for DLT_SLIP_BSDOS and DLT_PPP_BSDOS, which are 15 and 16, but they
+ * didn't. So it goes.
+ */
+#if defined(__NetBSD__) || defined(__FreeBSD__)
+#ifndef DLT_SLIP_BSDOS
+#define DLT_SLIP_BSDOS 13 /* BSD/OS Serial Line IP */
+#define DLT_PPP_BSDOS 14 /* BSD/OS Point-to-point Protocol */
+#endif
+#else
+#define DLT_SLIP_BSDOS 15 /* BSD/OS Serial Line IP */
+#define DLT_PPP_BSDOS 16 /* BSD/OS Point-to-point Protocol */
+#endif
+
+/*
+ * 17 is used for DLT_OLD_PFLOG in OpenBSD;
+ * OBSOLETE: DLT_PFLOG is 117 in OpenBSD now as well. See below.
+ * 18 is used for DLT_PFSYNC in OpenBSD; don't use it for anything else.
+ */
+
+#define DLT_ATM_CLIP 19 /* Linux Classical-IP over ATM */
+
+/*
+ * Apparently Redback uses this for its SmartEdge 400/800. I hope
+ * nobody else decided to use it, too.
+ */
+#define DLT_REDBACK_SMARTEDGE 32
+
+/*
+ * These values are defined by NetBSD; other platforms should refrain from
+ * using them for other purposes, so that NetBSD savefiles with link
+ * types of 50 or 51 can be read as this type on all platforms.
+ */
+#define DLT_PPP_SERIAL 50 /* PPP over serial with HDLC encapsulation */
+#define DLT_PPP_ETHER 51 /* PPP over Ethernet */
+
+/*
+ * The Axent Raptor firewall - now the Symantec Enterprise Firewall - uses
+ * a link-layer type of 99 for the tcpdump it supplies. The link-layer
+ * header has 6 bytes of unknown data, something that appears to be an
+ * Ethernet type, and 36 bytes that appear to be 0 in at least one capture
+ * I've seen.
+ */
+#define DLT_SYMANTEC_FIREWALL 99
+
+/*
+ * Values between 100 and 103 are used in capture file headers as
+ * link-layer types corresponding to DLT_ types that differ
+ * between platforms; don't use those values for new DLT_ new types.
+ */
+
+/*
+ * This value was defined by libpcap 0.5; platforms that have defined
+ * it with a different value should define it here with that value -
+ * a link type of 104 in a save file will be mapped to DLT_C_HDLC,
+ * whatever value that happens to be, so programs will correctly
+ * handle files with that link type regardless of the value of
+ * DLT_C_HDLC.
+ *
+ * The name DLT_C_HDLC was used by BSD/OS; we use that name for source
+ * compatibility with programs written for BSD/OS.
+ *
+ * libpcap 0.5 defined it as DLT_CHDLC; we define DLT_CHDLC as well,
+ * for source compatibility with programs written for libpcap 0.5.
+ */
+#define DLT_C_HDLC 104 /* Cisco HDLC */
+#define DLT_CHDLC DLT_C_HDLC
+
+#define DLT_IEEE802_11 105 /* IEEE 802.11 wireless */
+
+/*
+ * 106 is reserved for Linux Classical IP over ATM; it's like DLT_RAW,
+ * except when it isn't. (I.e., sometimes it's just raw IP, and
+ * sometimes it isn't.) We currently handle it as DLT_LINUX_SLL,
+ * so that we don't have to worry about the link-layer header.)
+ */
+
+/*
+ * Frame Relay; BSD/OS has a DLT_FR with a value of 11, but that collides
+ * with other values.
+ * DLT_FR and DLT_FRELAY packets start with the Q.922 Frame Relay header
+ * (DLCI, etc.).
+ */
+#define DLT_FRELAY 107
+
+/*
+ * OpenBSD DLT_LOOP, for loopback devices; it's like DLT_NULL, except
+ * that the AF_ type in the link-layer header is in network byte order.
+ *
+ * OpenBSD defines it as 12, but that collides with DLT_RAW, so we
+ * define it as 108 here. If OpenBSD picks up this file, it should
+ * define DLT_LOOP as 12 in its version, as per the comment above -
+ * and should not use 108 as a DLT_ value.
+ */
+#define DLT_LOOP 108
+
+/*
+ * Encapsulated packets for IPsec; DLT_ENC is 13 in OpenBSD, but that's
+ * DLT_SLIP_BSDOS in NetBSD, so we don't use 13 for it in OSes other
+ * than OpenBSD.
+ */
+#ifdef __OpenBSD__
+#define DLT_ENC 13
+#else
+#define DLT_ENC 109
+#endif
+
+/*
+ * Values between 110 and 112 are reserved for use in capture file headers
+ * as link-layer types corresponding to DLT_ types that might differ
+ * between platforms; don't use those values for new DLT_ types
+ * other than the corresponding DLT_ types.
+ */
+
+/*
+ * This is for Linux cooked sockets.
+ */
+#define DLT_LINUX_SLL 113
+
+/*
+ * Apple LocalTalk hardware.
+ */
+#define DLT_LTALK 114
+
+/*
+ * Acorn Econet.
+ */
+#define DLT_ECONET 115
+
+/*
+ * Reserved for use with OpenBSD ipfilter.
+ */
+#define DLT_IPFILTER 116
+
+/*
+ * OpenBSD DLT_PFLOG; DLT_PFLOG is 17 in OpenBSD, but that's DLT_LANE8023
+ * in SuSE 6.3, so we can't use 17 for it in capture-file headers.
+ *
+ * XXX: is there a conflict with DLT_PFSYNC 18 as well?
+ */
+#ifdef __OpenBSD__
+#define DLT_OLD_PFLOG 17
+#define DLT_PFSYNC 18
+#endif
+#define DLT_PFLOG 117
+
+/*
+ * Registered for Cisco-internal use.
+ */
+#define DLT_CISCO_IOS 118
+
+/*
+ * For 802.11 cards using the Prism II chips, with a link-layer
+ * header including Prism monitor mode information plus an 802.11
+ * header.
+ */
+#define DLT_PRISM_HEADER 119
+
+/*
+ * Reserved for Aironet 802.11 cards, with an Aironet link-layer header
+ * (see Doug Ambrisko's FreeBSD patches).
+ */
+#define DLT_AIRONET_HEADER 120
+
+/*
+ * Reserved for Siemens HiPath HDLC.
+ */
+#define DLT_HHDLC 121
+
+/*
+ * This is for RFC 2625 IP-over-Fibre Channel.
+ *
+ * This is not for use with raw Fibre Channel, where the link-layer
+ * header starts with a Fibre Channel frame header; it's for IP-over-FC,
+ * where the link-layer header starts with an RFC 2625 Network_Header
+ * field.
+ */
+#define DLT_IP_OVER_FC 122
+
+/*
+ * This is for Full Frontal ATM on Solaris with SunATM, with a
+ * pseudo-header followed by an AALn PDU.
+ *
+ * There may be other forms of Full Frontal ATM on other OSes,
+ * with different pseudo-headers.
+ *
+ * If ATM software returns a pseudo-header with VPI/VCI information
+ * (and, ideally, packet type information, e.g. signalling, ILMI,
+ * LANE, LLC-multiplexed traffic, etc.), it should not use
+ * DLT_ATM_RFC1483, but should get a new DLT_ value, so tcpdump
+ * and the like don't have to infer the presence or absence of a
+ * pseudo-header and the form of the pseudo-header.
+ */
+#define DLT_SUNATM 123 /* Solaris+SunATM */
+
+/*
+ * Reserved as per request from Kent Dahlgren <kent@praesum.com>
+ * for private use.
+ */
+#define DLT_RIO 124 /* RapidIO */
+#define DLT_PCI_EXP 125 /* PCI Express */
+#define DLT_AURORA 126 /* Xilinx Aurora link layer */
+
+/*
+ * Header for 802.11 plus a number of bits of link-layer information
+ * including radio information, used by some recent BSD drivers as
+ * well as the madwifi Atheros driver for Linux.
+ */
+#define DLT_IEEE802_11_RADIO 127 /* 802.11 plus radiotap radio header */
+
+/*
+ * Reserved for the TZSP encapsulation, as per request from
+ * Chris Waters <chris.waters@networkchemistry.com>
+ * TZSP is a generic encapsulation for any other link type,
+ * which includes a means to include meta-information
+ * with the packet, e.g. signal strength and channel
+ * for 802.11 packets.
+ */
+#define DLT_TZSP 128 /* Tazmen Sniffer Protocol */
+
+/*
+ * BSD's ARCNET headers have the source host, destination host,
+ * and type at the beginning of the packet; that's what's handed
+ * up to userland via BPF.
+ *
+ * Linux's ARCNET headers, however, have a 2-byte offset field
+ * between the host IDs and the type; that's what's handed up
+ * to userland via PF_PACKET sockets.
+ *
+ * We therefore have to have separate DLT_ values for them.
+ */
+#define DLT_ARCNET_LINUX 129 /* ARCNET */
+
+/*
+ * Juniper-private data link types, as per request from
+ * Hannes Gredler <hannes@juniper.net>. The DLT_s are used
+ * for passing on chassis-internal metainformation such as
+ * QOS profiles, etc..
+ */
+#define DLT_JUNIPER_MLPPP 130
+#define DLT_JUNIPER_MLFR 131
+#define DLT_JUNIPER_ES 132
+#define DLT_JUNIPER_GGSN 133
+#define DLT_JUNIPER_MFR 134
+#define DLT_JUNIPER_ATM2 135
+#define DLT_JUNIPER_SERVICES 136
+#define DLT_JUNIPER_ATM1 137
+
+/*
+ * Apple IP-over-IEEE 1394, as per a request from Dieter Siegmund
+ * <dieter@apple.com>. The header that's presented is an Ethernet-like
+ * header:
+ *
+ * #define FIREWIRE_EUI64_LEN 8
+ * struct firewire_header {
+ * u_char firewire_dhost[FIREWIRE_EUI64_LEN];
+ * u_char firewire_shost[FIREWIRE_EUI64_LEN];
+ * u_short firewire_type;
+ * };
+ *
+ * with "firewire_type" being an Ethernet type value, rather than,
+ * for example, raw GASP frames being handed up.
+ */
+#define DLT_APPLE_IP_OVER_IEEE1394 138
+
+/*
+ * Various SS7 encapsulations, as per a request from Jeff Morriss
+ * <jeff.morriss[AT]ulticom.com> and subsequent discussions.
+ */
+#define DLT_MTP2_WITH_PHDR 139 /* pseudo-header with various info, followed by MTP2 */
+#define DLT_MTP2 140 /* MTP2, without pseudo-header */
+#define DLT_MTP3 141 /* MTP3, without pseudo-header or MTP2 */
+#define DLT_SCCP 142 /* SCCP, without pseudo-header or MTP2 or MTP3 */
+
+/*
+ * DOCSIS MAC frames.
+ */
+#define DLT_DOCSIS 143
+
+/*
+ * Linux-IrDA packets. Protocol defined at http://www.irda.org.
+ * Those packets include IrLAP headers and above (IrLMP...), but
+ * don't include Phy framing (SOF/EOF/CRC & byte stuffing), because Phy
+ * framing can be handled by the hardware and depend on the bitrate.
+ * This is exactly the format you would get capturing on a Linux-IrDA
+ * interface (irdaX), but not on a raw serial port.
+ * Note the capture is done in "Linux-cooked" mode, so each packet include
+ * a fake packet header (struct sll_header). This is because IrDA packet
+ * decoding is dependant on the direction of the packet (incomming or
+ * outgoing).
+ * When/if other platform implement IrDA capture, we may revisit the
+ * issue and define a real DLT_IRDA...
+ * Jean II
+ */
+#define DLT_LINUX_IRDA 144
+
+/*
+ * Reserved for IBM SP switch and IBM Next Federation switch.
+ */
+#define DLT_IBM_SP 145
+#define DLT_IBM_SN 146
+
+/*
+ * Reserved for private use. If you have some link-layer header type
+ * that you want to use within your organization, with the capture files
+ * using that link-layer header type not ever be sent outside your
+ * organization, you can use these values.
+ *
+ * No libpcap release will use these for any purpose, nor will any
+ * tcpdump release use them, either.
+ *
+ * Do *NOT* use these in capture files that you expect anybody not using
+ * your private versions of capture-file-reading tools to read; in
+ * particular, do *NOT* use them in products, otherwise you may find that
+ * people won't be able to use tcpdump, or snort, or Ethereal, or... to
+ * read capture files from your firewall/intrusion detection/traffic
+ * monitoring/etc. appliance, or whatever product uses that DLT_ value,
+ * and you may also find that the developers of those applications will
+ * not accept patches to let them read those files.
+ *
+ * Also, do not use them if somebody might send you a capture using them
+ * for *their* private type and tools using them for *your* private type
+ * would have to read them.
+ *
+ * Instead, ask "tcpdump-workers@tcpdump.org" for a new DLT_ value,
+ * as per the comment above, and use the type you're given.
+ */
+#define DLT_USER0 147
+#define DLT_USER1 148
+#define DLT_USER2 149
+#define DLT_USER3 150
+#define DLT_USER4 151
+#define DLT_USER5 152
+#define DLT_USER6 153
+#define DLT_USER7 154
+#define DLT_USER8 155
+#define DLT_USER9 156
+#define DLT_USER10 157
+#define DLT_USER11 158
+#define DLT_USER12 159
+#define DLT_USER13 160
+#define DLT_USER14 161
+#define DLT_USER15 162
+
+/*
+ * For future use with 802.11 captures - defined by AbsoluteValue
+ * Systems to store a number of bits of link-layer information
+ * including radio information:
+ *
+ * http://www.shaftnet.org/~pizza/software/capturefrm.txt
+ *
+ * but it might be used by some non-AVS drivers now or in the
+ * future.
+ */
+#define DLT_IEEE802_11_RADIO_AVS 163 /* 802.11 plus AVS radio header */
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>. The DLT_s are used
+ * for passing on chassis-internal metainformation such as
+ * QOS profiles, etc..
+ */
+#define DLT_JUNIPER_MONITOR 164
+
+/*
+ * Reserved for BACnet MS/TP.
+ */
+#define DLT_BACNET_MS_TP 165
+
+/*
+ * Another PPP variant as per request from Karsten Keil <kkeil@suse.de>.
+ *
+ * This is used in some OSes to allow a kernel socket filter to distinguish
+ * between incoming and outgoing packets, on a socket intended to
+ * supply pppd with outgoing packets so it can do dial-on-demand and
+ * hangup-on-lack-of-demand; incoming packets are filtered out so they
+ * don't cause pppd to hold the connection up (you don't want random
+ * input packets such as port scans, packets from old lost connections,
+ * etc. to force the connection to stay up).
+ *
+ * The first byte of the PPP header (0xff03) is modified to accomodate
+ * the direction - 0x00 = IN, 0x01 = OUT.
+ */
+#define DLT_PPP_PPPD 166
+
+/*
+ * Names for backwards compatibility with older versions of some PPP
+ * software; new software should use DLT_PPP_PPPD.
+ */
+#define DLT_PPP_WITH_DIRECTION DLT_PPP_PPPD
+#define DLT_LINUX_PPP_WITHDIRECTION DLT_PPP_PPPD
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>. The DLT_s are used
+ * for passing on chassis-internal metainformation such as
+ * QOS profiles, cookies, etc..
+ */
+#define DLT_JUNIPER_PPPOE 167
+#define DLT_JUNIPER_PPPOE_ATM 168
+
+#define DLT_GPRS_LLC 169 /* GPRS LLC */
+#define DLT_GPF_T 170 /* GPF-T (ITU-T G.7041/Y.1303) */
+#define DLT_GPF_F 171 /* GPF-F (ITU-T G.7041/Y.1303) */
+
+/*
+ * Requested by Oolan Zimmer <oz@gcom.com> for use in Gcom's T1/E1 line
+ * monitoring equipment.
+ */
+#define DLT_GCOM_T1E1 172
+#define DLT_GCOM_SERIAL 173
+
+/*
+ * Juniper-private data link type, as per request from
+ * Hannes Gredler <hannes@juniper.net>. The DLT_ is used
+ * for internal communication to Physical Interface Cards (PIC)
+ */
+#define DLT_JUNIPER_PIC_PEER 174
+
+/*
+ * Link types requested by Gregor Maier <gregor@endace.com> of Endace
+ * Measurement Systems. They add an ERF header (see
+ * http://www.endace.com/support/EndaceRecordFormat.pdf) in front of
+ * the link-layer header.
+ */
+#define DLT_ERF_ETH 175 /* Ethernet */
+#define DLT_ERF_POS 176 /* Packet-over-SONET */
+
+/*
+ * Requested by Daniele Orlandi <daniele@orlandi.com> for raw LAPD
+ * for vISDN (http://www.orlandi.com/visdn/). Its link-layer header
+ * includes additional information before the LAPD header, so it's
+ * not necessarily a generic LAPD header.
+ */
+#define DLT_LINUX_LAPD 177
+
+/*
+ * The instruction encodings.
+ */
+/* instruction classes */
+#define BPF_CLASS(code) ((code) & 0x07)
+#define BPF_LD 0x00
+#define BPF_LDX 0x01
+#define BPF_ST 0x02
+#define BPF_STX 0x03
+#define BPF_ALU 0x04
+#define BPF_JMP 0x05
+#define BPF_RET 0x06
+#define BPF_MISC 0x07
+
+/* ld/ldx fields */
+#define BPF_SIZE(code) ((code) & 0x18)
+#define BPF_W 0x00
+#define BPF_H 0x08
+#define BPF_B 0x10
+#define BPF_MODE(code) ((code) & 0xe0)
+#define BPF_IMM 0x00
+#define BPF_ABS 0x20
+#define BPF_IND 0x40
+#define BPF_MEM 0x60
+#define BPF_LEN 0x80
+#define BPF_MSH 0xa0
+
+/* alu/jmp fields */
+#define BPF_OP(code) ((code) & 0xf0)
+#define BPF_ADD 0x00
+#define BPF_SUB 0x10
+#define BPF_MUL 0x20
+#define BPF_DIV 0x30
+#define BPF_OR 0x40
+#define BPF_AND 0x50
+#define BPF_LSH 0x60
+#define BPF_RSH 0x70
+#define BPF_NEG 0x80
+#define BPF_JA 0x00
+#define BPF_JEQ 0x10
+#define BPF_JGT 0x20
+#define BPF_JGE 0x30
+#define BPF_JSET 0x40
+#define BPF_SRC(code) ((code) & 0x08)
+#define BPF_K 0x00
+#define BPF_X 0x08
+
+/* ret - BPF_K and BPF_X also apply */
+#define BPF_RVAL(code) ((code) & 0x18)
+#define BPF_A 0x10
+
+/* misc */
+#define BPF_MISCOP(code) ((code) & 0xf8)
+#define BPF_TAX 0x00
+#define BPF_TXA 0x80
+
+/*
+ * The instruction data structure.
+ */
+struct bpf_insn {
+ u_short code;
+ u_char jt;
+ u_char jf;
+ bpf_int32 k;
+};
+
+/*
+ * Macros for insn array initializers.
+ */
+#define BPF_STMT(code, k) { (u_short)(code), 0, 0, k }
+#define BPF_JUMP(code, k, jt, jf) { (u_short)(code), jt, jf, k }
+
+#if __STDC__ || defined(__cplusplus)
+extern int bpf_validate(struct bpf_insn *, int);
+extern u_int bpf_filter(struct bpf_insn *, u_char *, u_int, u_int);
+#else
+extern int bpf_validate();
+extern u_int bpf_filter();
+#endif
+
+/*
+ * Number of scratch memory words (for BPF_LD|BPF_MEM and BPF_ST).
+ */
+#define BPF_MEMWORDS 16
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/Cedar/winpcap/pcap-int.h b/src/Cedar/winpcap/pcap-int.h
new file mode 100644
index 00000000..1ffcd03f
--- /dev/null
+++ b/src/Cedar/winpcap/pcap-int.h
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 1994, 1995, 1996
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/pcap-int.h,v 1.68.2.6 2005/07/07 06:56:04 guy Exp $ (LBL)
+ */
+
+#ifndef pcap_int_h
+#define pcap_int_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <pcap.h>
+
+#ifdef WIN32
+#include <packet32.h>
+#endif /* WIN32 */
+
+#ifdef MSDOS
+#include <fcntl.h>
+#include <io.h>
+#endif
+
+/*
+ * Savefile
+ */
+typedef enum {
+ NOT_SWAPPED,
+ SWAPPED,
+ MAYBE_SWAPPED
+} swapped_type_t;
+
+struct pcap_sf {
+ FILE *rfile;
+ int swapped;
+ int hdrsize;
+ swapped_type_t lengths_swapped;
+ int version_major;
+ int version_minor;
+ u_char *base;
+};
+
+struct pcap_md {
+ struct pcap_stat stat;
+ /*XXX*/
+ int use_bpf; /* using kernel filter */
+ u_long TotPkts; /* can't oflow for 79 hrs on ether */
+ u_long TotAccepted; /* count accepted by filter */
+ u_long TotDrops; /* count of dropped packets */
+ long TotMissed; /* missed by i/f during this run */
+ long OrigMissed; /* missed by i/f before this run */
+ char *device; /* device name */
+#ifdef linux
+ int sock_packet; /* using Linux 2.0 compatible interface */
+ int timeout; /* timeout specified to pcap_open_live */
+ int clear_promisc; /* must clear promiscuous mode when we close */
+ int cooked; /* using SOCK_DGRAM rather than SOCK_RAW */
+ int ifindex; /* interface index of device we're bound to */
+ int lo_ifindex; /* interface index of the loopback device */
+ struct pcap *next; /* list of open promiscuous sock_packet pcaps */
+#endif
+
+#ifdef HAVE_DAG_API
+#ifdef HAVE_DAG_STREAMS_API
+ u_char *dag_mem_bottom; /* DAG card current memory bottom pointer */
+ u_char *dag_mem_top; /* DAG card current memory top pointer */
+#else
+ void *dag_mem_base; /* DAG card memory base address */
+ u_int dag_mem_bottom; /* DAG card current memory bottom offset */
+ u_int dag_mem_top; /* DAG card current memory top offset */
+#endif /* HAVE_DAG_STREAMS_API */
+ int dag_fcs_bits; /* Number of checksum bits from link layer */
+ int dag_offset_flags; /* Flags to pass to dag_offset(). */
+ int dag_stream; /* DAG stream number */
+ int dag_timeout; /* timeout specified to pcap_open_live.
+ * Same as in linux above, introduce
+ * generally? */
+#endif /* HAVE_DAG_API */
+
+#ifdef HAVE_REMOTE
+/*!
+ There is really a mess with previous variables, and it seems to me that they are not used
+ (they are used in pcap_pf.c only). I think we have to start using them.
+ The meaning is the following:
+
+ - TotPkts: the amount of packets received by the bpf filter, *before* applying the filter
+ - TotAccepted: the amount of packets that satisfies the filter
+ - TotDrops: the amount of packet that were dropped into the kernel buffer because of lack of space
+ - TotMissed: the amount of packets that were dropped by the physical interface; it is basically
+ the value of the hardware counter into the card. This number is never put to zero, so this number
+ takes into account the *total* number of interface drops starting from the interface power-on.
+ - OrigMissed: the amount of packets that were dropped by the interface *when the capture begins*.
+ This value is used to detect the number of packets dropped by the interface *during the present
+ capture*, so that (ps_ifdrops= TotMissed - OrigMissed).
+*/
+ unsigned int TotNetDrops; //!< keeps the number of packets that have been dropped by the network
+/*!
+ \brief It keeps the number of packets that have been received by the application.
+
+ Packets dropped by the kernel buffer are not counted in this variable. The variable is always
+ equal to (TotAccepted - TotDrops), exept for the case of remote capture, in which we have also
+ packets in fligh, i.e. that have been transmitted by the remote host, but that have not been
+ received (yet) from the client. In this case, (TotAccepted - TotDrops - TotNetDrops) gives a
+ wrong result, since this number does not corresponds always to the number of packet received by
+ the application. For this reason, in the remote capture we need another variable that takes
+ into account of the number of packets actually received by the application.
+*/
+ unsigned int TotCapt;
+#endif /* HAVE_REMOTE */
+};
+
+/*
+ * Ultrix, DEC OSF/1^H^H^H^H^H^H^H^H^HDigital UNIX^H^H^H^H^H^H^H^H^H^H^H^H
+ * Tru64 UNIX, and NetBSD pad to make everything line up on a nice boundary.
+ */
+#if defined(ultrix) || defined(__osf__) || (defined(__NetBSD__) && __NetBSD_Version__ > 106000000)
+#define PCAP_FDDIPAD 3
+#endif
+
+struct pcap {
+#ifdef WIN32
+ ADAPTER *adapter;
+ LPPACKET Packet;
+ int timeout;
+ int nonblock;
+#else
+ int fd;
+ int selectable_fd;
+ int send_fd;
+#endif /* WIN32 */
+ int snapshot;
+ int linktype;
+ int tzoff; /* timezone offset */
+ int offset; /* offset for proper alignment */
+
+ int break_loop; /* flag set to force break from packet-reading loop */
+
+#ifdef PCAP_FDDIPAD
+ int fddipad;
+#endif
+
+#ifdef MSDOS
+ int inter_packet_wait; /* offline: wait between packets */
+ void (*wait_proc)(void); /* call proc while waiting */
+#endif
+
+ struct pcap_sf sf;
+ struct pcap_md md;
+
+ /*
+ * Read buffer.
+ */
+ int bufsize;
+ u_char *buffer;
+ u_char *bp;
+ int cc;
+
+ /*
+ * Place holder for pcap_next().
+ */
+ u_char *pkt;
+
+ /* We're accepting only packets in this direction/these directions. */
+ pcap_direction_t direction;
+
+ /*
+ * Methods.
+ */
+ int (*read_op)(pcap_t *, int cnt, pcap_handler, u_char *);
+ int (*inject_op)(pcap_t *, const void *, size_t);
+ int (*setfilter_op)(pcap_t *, struct bpf_program *);
+ int (*setdirection_op)(pcap_t *, pcap_direction_t);
+ int (*set_datalink_op)(pcap_t *, int);
+ int (*getnonblock_op)(pcap_t *, char *);
+ int (*setnonblock_op)(pcap_t *, int, char *);
+ int (*stats_op)(pcap_t *, struct pcap_stat *);
+ void (*close_op)(pcap_t *);
+
+ /*
+ * Placeholder for filter code if bpf not in kernel.
+ */
+ struct bpf_program fcode;
+
+ char errbuf[PCAP_ERRBUF_SIZE + 1];
+ int dlt_count;
+ u_int *dlt_list;
+
+ struct pcap_pkthdr pcap_header; /* This is needed for the pcap_next_ex() to work */
+
+#ifdef HAVE_REMOTE
+#ifndef WIN32 // Win32 already defines 'timeout'
+ int timeout; //!< timeout to be used in the pcap_open()
+#endif
+ /*! \brief '1' if we're the network client; needed by several functions (like pcap_setfilter() ) to know if
+ they have to use the socket or they have to open the local adapter. */
+ int rmt_clientside;
+
+ SOCKET rmt_sockctrl; //!< socket ID of the socket used for the control connection
+ SOCKET rmt_sockdata; //!< socket ID of the socket used for the data connection
+ int rmt_flags; //!< we have to save flags, since they are passed by the pcap_open_live(), but they are used by the pcap_startcapture()
+ int rmt_capstarted; //!< 'true' if the capture is already started (needed to knoe if we have to call the pcap_startcapture()
+ struct pcap_samp rmt_samp; //!< Keeps the parameters related to the sampling process.
+ char *currentfilter; //!< Pointer to a buffer (allocated at run-time) that stores the current filter. Needed when flag PCAP_OPENFLAG_NOCAPTURE_RPCAP is turned on.
+#endif /* HAVE_REMOTE */
+};
+
+/*
+ * This is a timeval as stored in disk in a dumpfile.
+ * It has to use the same types everywhere, independent of the actual
+ * `struct timeval'
+ */
+
+struct pcap_timeval {
+ bpf_int32 tv_sec; /* seconds */
+ bpf_int32 tv_usec; /* microseconds */
+};
+
+/*
+ * How a `pcap_pkthdr' is actually stored in the dumpfile.
+ *
+ * Do not change the format of this structure, in any way (this includes
+ * changes that only affect the length of fields in this structure),
+ * and do not make the time stamp anything other than seconds and
+ * microseconds (e.g., seconds and nanoseconds). Instead:
+ *
+ * introduce a new structure for the new format;
+ *
+ * send mail to "tcpdump-workers@tcpdump.org", requesting a new
+ * magic number for your new capture file format, and, when
+ * you get the new magic number, put it in "savefile.c";
+ *
+ * use that magic number for save files with the changed record
+ * header;
+ *
+ * make the code in "savefile.c" capable of reading files with
+ * the old record header as well as files with the new record header
+ * (using the magic number to determine the header format).
+ *
+ * Then supply the changes to "patches@tcpdump.org", so that future
+ * versions of libpcap and programs that use it (such as tcpdump) will
+ * be able to read your new capture file format.
+ */
+
+struct pcap_sf_pkthdr {
+ struct pcap_timeval ts; /* time stamp */
+ bpf_u_int32 caplen; /* length of portion present */
+ bpf_u_int32 len; /* length this packet (off wire) */
+};
+
+/*
+ * How a `pcap_pkthdr' is actually stored in dumpfiles written
+ * by some patched versions of libpcap (e.g. the ones in Red
+ * Hat Linux 6.1 and 6.2).
+ *
+ * Do not change the format of this structure, in any way (this includes
+ * changes that only affect the length of fields in this structure).
+ * Instead, introduce a new structure, as per the above.
+ */
+
+struct pcap_sf_patched_pkthdr {
+ struct pcap_timeval ts; /* time stamp */
+ bpf_u_int32 caplen; /* length of portion present */
+ bpf_u_int32 len; /* length this packet (off wire) */
+ int index;
+ unsigned short protocol;
+ unsigned char pkt_type;
+};
+
+int yylex(void);
+
+#ifndef min
+#define min(a, b) ((a) > (b) ? (b) : (a))
+#endif
+
+/* XXX should these be in pcap.h? */
+int pcap_offline_read(pcap_t *, int, pcap_handler, u_char *);
+int pcap_read(pcap_t *, int cnt, pcap_handler, u_char *);
+
+#ifndef HAVE_STRLCPY
+#define strlcpy(x, y, z) \
+ (strncpy((x), (y), (z)), \
+ ((z) <= 0 ? 0 : ((x)[(z) - 1] = '\0')), \
+ strlen((y)))
+#endif
+
+#include <stdarg.h>
+
+#if !defined(HAVE_SNPRINTF)
+#define snprintf pcap_snprintf
+extern int snprintf (char *, size_t, const char *, ...);
+#endif
+
+#if !defined(HAVE_VSNPRINTF)
+#define vsnprintf pcap_vsnprintf
+extern int vsnprintf (char *, size_t, const char *, va_list ap);
+#endif
+
+/*
+ * Routines that most pcap implementations can use for non-blocking mode.
+ */
+#if !defined(WIN32) && !defined(MSDOS)
+int pcap_getnonblock_fd(pcap_t *, char *);
+int pcap_setnonblock_fd(pcap_t *p, int, char *);
+#endif
+
+void pcap_close_common(pcap_t *);
+
+/*
+ * Internal interfaces for "pcap_findalldevs()".
+ *
+ * "pcap_platform_finddevs()" is a platform-dependent routine to
+ * add devices not found by the "standard" mechanisms (SIOCGIFCONF,
+ * "getifaddrs()", etc..
+ *
+ * "pcap_add_if()" adds an interface to the list of interfaces.
+ */
+int pcap_platform_finddevs(pcap_if_t **, char *);
+int add_addr_to_iflist(pcap_if_t **, const char *, u_int, struct sockaddr *,
+ size_t, struct sockaddr *, size_t, struct sockaddr *, size_t,
+ struct sockaddr *, size_t, char *);
+int pcap_add_if(pcap_if_t **, const char *, u_int, const char *, char *);
+struct sockaddr *dup_sockaddr(struct sockaddr *, size_t);
+int add_or_find_if(pcap_if_t **, pcap_if_t **, const char *, u_int,
+ const char *, char *);
+
+#ifdef WIN32
+char *pcap_win32strerror(void);
+#endif
+
+int install_bpf_program(pcap_t *, struct bpf_program *);
+
+int pcap_strcasecmp(const char *, const char *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/Cedar/winpcap/pcap-stdinc.h b/src/Cedar/winpcap/pcap-stdinc.h
new file mode 100644
index 00000000..b04f9be7
--- /dev/null
+++ b/src/Cedar/winpcap/pcap-stdinc.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2002 - 2003
+ * NetGroup, Politecnico di Torino (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#define SIZEOF_CHAR 1
+#define SIZEOF_SHORT 2
+#define SIZEOF_INT 4
+#ifndef _MSC_EXTENSIONS
+#define SIZEOF_LONG_LONG 8
+#endif
+
+
+/*
+ * Avoids a compiler warning in case this was already defined
+ * (someone defined _WINSOCKAPI_ when including 'windows.h', in order
+ * to prevent it from including 'winsock.h')
+ */
+#ifdef _WINSOCKAPI_
+#undef _WINSOCKAPI_
+#endif
+#include <winsock2.h>
+
+#include <fcntl.h>
+
+#include "bittypes.h"
+#include <time.h>
+#include <io.h>
+
+#ifndef __MINGW32__
+#include "IP6_misc.h"
+#endif
+
+#define caddr_t char*
+
+#define snprintf _snprintf
+#define vsnprintf _vsnprintf
+#define inline __inline
diff --git a/src/Cedar/winpcap/pcap.h b/src/Cedar/winpcap/pcap.h
new file mode 100644
index 00000000..7e5a773f
--- /dev/null
+++ b/src/Cedar/winpcap/pcap.h
@@ -0,0 +1,337 @@
+/* -*- Mode: c; tab-width: 8; indent-tabs-mode: 1; c-basic-offset: 8; -*- */
+/*
+ * Copyright (c) 1993, 1994, 1995, 1996, 1997
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the Computer Systems
+ * Engineering Group at Lawrence Berkeley Laboratory.
+ * 4. Neither the name of the University nor of the Laboratory may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#) $Header: /tcpdump/master/libpcap/pcap.h,v 1.52.2.5 2005/07/07 02:04:36 guy Exp $ (LBL)
+ */
+
+#ifndef lib_pcap_h
+#define lib_pcap_h
+
+#if defined(WIN32)
+ #include <pcap-stdinc.h>
+#elif defined(MSDOS)
+ #include <sys/types.h>
+ #include <sys/socket.h> /* u_int, u_char etc. */
+#else /* UN*X */
+ #include <sys/types.h>
+ #include <sys/time.h>
+#endif /* WIN32/MSDOS/UN*X */
+
+#ifndef PCAP_DONT_INCLUDE_PCAP_BPF_H
+#include <pcap-bpf.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_REMOTE
+ // We have to define the SOCKET here, although it has been defined in sockutils.h
+ // This is to avoid the distribution of the 'sockutils.h' file around
+ // (for example in the WinPcap developer's pack)
+ #ifndef SOCKET
+ #ifdef WIN32
+ #define SOCKET unsigned int
+ #else
+ #define SOCKET int
+ #endif
+ #endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PCAP_VERSION_MAJOR 2
+#define PCAP_VERSION_MINOR 4
+
+#define PCAP_ERRBUF_SIZE 256
+
+/*
+ * Compatibility for systems that have a bpf.h that
+ * predates the bpf typedefs for 64-bit support.
+ */
+#if BPF_RELEASE - 0 < 199406
+typedef int bpf_int32;
+typedef u_int bpf_u_int32;
+#endif
+
+typedef struct pcap pcap_t;
+typedef struct pcap_dumper pcap_dumper_t;
+typedef struct pcap_if pcap_if_t;
+typedef struct pcap_addr pcap_addr_t;
+
+/*
+ * The first record in the file contains saved values for some
+ * of the flags used in the printout phases of tcpdump.
+ * Many fields here are 32 bit ints so compilers won't insert unwanted
+ * padding; these files need to be interchangeable across architectures.
+ *
+ * Do not change the layout of this structure, in any way (this includes
+ * changes that only affect the length of fields in this structure).
+ *
+ * Also, do not change the interpretation of any of the members of this
+ * structure, in any way (this includes using values other than
+ * LINKTYPE_ values, as defined in "savefile.c", in the "linktype"
+ * field).
+ *
+ * Instead:
+ *
+ * introduce a new structure for the new format, if the layout
+ * of the structure changed;
+ *
+ * send mail to "tcpdump-workers@tcpdump.org", requesting a new
+ * magic number for your new capture file format, and, when
+ * you get the new magic number, put it in "savefile.c";
+ *
+ * use that magic number for save files with the changed file
+ * header;
+ *
+ * make the code in "savefile.c" capable of reading files with
+ * the old file header as well as files with the new file header
+ * (using the magic number to determine the header format).
+ *
+ * Then supply the changes to "patches@tcpdump.org", so that future
+ * versions of libpcap and programs that use it (such as tcpdump) will
+ * be able to read your new capture file format.
+ */
+struct pcap_file_header {
+ bpf_u_int32 magic;
+ u_short version_major;
+ u_short version_minor;
+ bpf_int32 thiszone; /* gmt to local correction */
+ bpf_u_int32 sigfigs; /* accuracy of timestamps */
+ bpf_u_int32 snaplen; /* max length saved portion of each pkt */
+ bpf_u_int32 linktype; /* data link type (LINKTYPE_*) */
+};
+
+typedef enum {
+ PCAP_D_INOUT = 0,
+ PCAP_D_IN,
+ PCAP_D_OUT
+} pcap_direction_t;
+
+/*
+ * Each packet in the dump file is prepended with this generic header.
+ * This gets around the problem of different headers for different
+ * packet interfaces.
+ */
+struct pcap_pkthdr {
+ struct timeval ts; /* time stamp */
+ bpf_u_int32 caplen; /* length of portion present */
+ bpf_u_int32 len; /* length this packet (off wire) */
+};
+
+/*
+ * As returned by the pcap_stats()
+ */
+struct pcap_stat {
+ u_int ps_recv; /* number of packets received */
+ u_int ps_drop; /* number of packets dropped */
+ u_int ps_ifdrop; /* drops by interface XXX not yet supported */
+#ifdef HAVE_REMOTE
+ u_int ps_capt; /* number of packets that are received by the application; please get rid off the Win32 ifdef */
+ u_int ps_sent; /* number of packets sent by the server on the network */
+ u_int ps_netdrop; /* number of packets lost on the network */
+#endif /* HAVE_REMOTE */
+};
+
+#ifdef MSDOS
+/*
+ * As returned by the pcap_stats_ex()
+ */
+struct pcap_stat_ex {
+ u_long rx_packets; /* total packets received */
+ u_long tx_packets; /* total packets transmitted */
+ u_long rx_bytes; /* total bytes received */
+ u_long tx_bytes; /* total bytes transmitted */
+ u_long rx_errors; /* bad packets received */
+ u_long tx_errors; /* packet transmit problems */
+ u_long rx_dropped; /* no space in Rx buffers */
+ u_long tx_dropped; /* no space available for Tx */
+ u_long multicast; /* multicast packets received */
+ u_long collisions;
+
+ /* detailed rx_errors: */
+ u_long rx_length_errors;
+ u_long rx_over_errors; /* receiver ring buff overflow */
+ u_long rx_crc_errors; /* recv'd pkt with crc error */
+ u_long rx_frame_errors; /* recv'd frame alignment error */
+ u_long rx_fifo_errors; /* recv'r fifo overrun */
+ u_long rx_missed_errors; /* recv'r missed packet */
+
+ /* detailed tx_errors */
+ u_long tx_aborted_errors;
+ u_long tx_carrier_errors;
+ u_long tx_fifo_errors;
+ u_long tx_heartbeat_errors;
+ u_long tx_window_errors;
+ };
+#endif
+
+/*
+ * Item in a list of interfaces.
+ */
+struct pcap_if {
+ struct pcap_if *next;
+ char *name; /* name to hand to "pcap_open_live()" */
+ char *description; /* textual description of interface, or NULL */
+ struct pcap_addr *addresses;
+ bpf_u_int32 flags; /* PCAP_IF_ interface flags */
+};
+
+#define PCAP_IF_LOOPBACK 0x00000001 /* interface is loopback */
+
+/*
+ * Representation of an interface address.
+ */
+struct pcap_addr {
+ struct pcap_addr *next;
+ struct sockaddr *addr; /* address */
+ struct sockaddr *netmask; /* netmask for that address */
+ struct sockaddr *broadaddr; /* broadcast address for that address */
+ struct sockaddr *dstaddr; /* P2P destination address for that address */
+};
+
+typedef void (*pcap_handler)(u_char *, const struct pcap_pkthdr *,
+ const u_char *);
+
+char *pcap_lookupdev(char *);
+int pcap_lookupnet(const char *, bpf_u_int32 *, bpf_u_int32 *, char *);
+pcap_t *pcap_open_live(const char *, int, int, int, char *);
+pcap_t *pcap_open_dead(int, int);
+pcap_t *pcap_open_offline(const char *, char *);
+pcap_t *pcap_fopen_offline(FILE *, char *);
+void pcap_close(pcap_t *);
+int pcap_loop(pcap_t *, int, pcap_handler, u_char *);
+int pcap_dispatch(pcap_t *, int, pcap_handler, u_char *);
+const u_char*
+ pcap_next(pcap_t *, struct pcap_pkthdr *);
+int pcap_next_ex(pcap_t *, struct pcap_pkthdr **, const u_char **);
+void pcap_breakloop(pcap_t *);
+int pcap_stats(pcap_t *, struct pcap_stat *);
+int pcap_setfilter(pcap_t *, struct bpf_program *);
+int pcap_setdirection(pcap_t *, pcap_direction_t);
+int pcap_getnonblock(pcap_t *, char *);
+int pcap_setnonblock(pcap_t *, int, char *);
+void pcap_perror(pcap_t *, char *);
+int pcap_inject(pcap_t *, const void *, size_t);
+int pcap_sendpacket(pcap_t *, const u_char *, int);
+char *pcap_strerror(int);
+char *pcap_geterr(pcap_t *);
+int pcap_compile(pcap_t *, struct bpf_program *, char *, int,
+ bpf_u_int32);
+int pcap_compile_nopcap(int, int, struct bpf_program *,
+ char *, int, bpf_u_int32);
+void pcap_freecode(struct bpf_program *);
+int pcap_datalink(pcap_t *);
+int pcap_list_datalinks(pcap_t *, int **);
+int pcap_set_datalink(pcap_t *, int);
+int pcap_datalink_name_to_val(const char *);
+const char *pcap_datalink_val_to_name(int);
+const char *pcap_datalink_val_to_description(int);
+int pcap_snapshot(pcap_t *);
+int pcap_is_swapped(pcap_t *);
+int pcap_major_version(pcap_t *);
+int pcap_minor_version(pcap_t *);
+
+/* XXX */
+FILE *pcap_file(pcap_t *);
+int pcap_fileno(pcap_t *);
+
+pcap_dumper_t *pcap_dump_open(pcap_t *, const char *);
+pcap_dumper_t *pcap_dump_fopen(pcap_t *, FILE *fp);
+FILE *pcap_dump_file(pcap_dumper_t *);
+long pcap_dump_ftell(pcap_dumper_t *);
+int pcap_dump_flush(pcap_dumper_t *);
+void pcap_dump_close(pcap_dumper_t *);
+void pcap_dump(u_char *, const struct pcap_pkthdr *, const u_char *);
+
+int pcap_findalldevs(pcap_if_t **, char *);
+void pcap_freealldevs(pcap_if_t *);
+
+const char *pcap_lib_version(void);
+
+/* XXX this guy lives in the bpf tree */
+u_int bpf_filter(struct bpf_insn *, u_char *, u_int, u_int);
+int bpf_validate(struct bpf_insn *f, int len);
+char *bpf_image(struct bpf_insn *, int);
+void bpf_dump(struct bpf_program *, int);
+
+#if defined(WIN32)
+
+/*
+ * Win32 definitions
+ */
+
+int pcap_setbuff(pcap_t *p, int dim);
+int pcap_setmode(pcap_t *p, int mode);
+int pcap_setmintocopy(pcap_t *p, int size);
+
+#ifdef WPCAP
+/* Include file with the wpcap-specific extensions */
+#include <Win32-Extensions.h>
+#endif /* WPCAP */
+
+#define MODE_CAPT 0
+#define MODE_STAT 1
+#define MODE_MON 2
+
+#elif defined(MSDOS)
+
+/*
+ * MS-DOS definitions
+ */
+
+int pcap_stats_ex (pcap_t *, struct pcap_stat_ex *);
+void pcap_set_wait (pcap_t *p, void (*yield)(void), int wait);
+u_long pcap_mac_packets (void);
+
+#else /* UN*X */
+
+/*
+ * UN*X definitions
+ */
+
+int pcap_get_selectable_fd(pcap_t *);
+
+#endif /* WIN32/MSDOS/UN*X */
+
+#ifdef HAVE_REMOTE
+/* Includes most of the public stuff that is needed for the remote capture */
+#include "remote-ext.h"
+#endif /* HAVE_REMOTE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/Cedar/winpcap/pthread.h b/src/Cedar/winpcap/pthread.h
new file mode 100644
index 00000000..25c3cb5a
--- /dev/null
+++ b/src/Cedar/winpcap/pthread.h
@@ -0,0 +1,1300 @@
+/* This is an implementation of the threads API of POSIX 1003.1-2001.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2003 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@callisto.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#if !defined( PTHREAD_H )
+#define PTHREAD_H
+
+#undef PTW32_LEVEL
+
+#if defined(_POSIX_SOURCE)
+#define PTW32_LEVEL 0
+/* Early POSIX */
+#endif
+
+#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309
+#undef PTW32_LEVEL
+#define PTW32_LEVEL 1
+/* Include 1b, 1c and 1d */
+#endif
+
+#if defined(INCLUDE_NP)
+#undef PTW32_LEVEL
+#define PTW32_LEVEL 2
+/* Include Non-Portable extensions */
+#endif
+
+#define PTW32_LEVEL_MAX 3
+
+#if !defined(PTW32_LEVEL)
+#define PTW32_LEVEL PTW32_LEVEL_MAX
+/* Include everything */
+#endif
+
+#ifdef _UWIN
+# define HAVE_STRUCT_TIMESPEC 1
+# define HAVE_SIGNAL_H 1
+# undef HAVE_CONFIG_H
+# pragma comment(lib, "pthread")
+#endif
+
+/*
+ * -------------------------------------------------------------
+ *
+ *
+ * Module: pthread.h
+ *
+ * Purpose:
+ * Provides an implementation of PThreads based upon the
+ * standard:
+ *
+ * POSIX 1003.1-2001
+ * and
+ * The Single Unix Specification version 3
+ *
+ * (these two are equivalent)
+ *
+ * in order to enhance code portability between Windows,
+ * various commercial Unix implementations, and Linux.
+ *
+ * See the ANNOUNCE file for a full list of conforming
+ * routines and defined constants, and a list of missing
+ * routines and constants not defined in this implementation.
+ *
+ * Authors:
+ * There have been many contributors to this library.
+ * The initial implementation was contributed by
+ * John Bossom, and several others have provided major
+ * sections or revisions of parts of the implementation.
+ * Often significant effort has been contributed to
+ * find and fix important bugs and other problems to
+ * improve the reliability of the library, which sometimes
+ * is not reflected in the amount of code which changed as
+ * result.
+ * As much as possible, the contributors are acknowledged
+ * in the ChangeLog file in the source code distribution
+ * where their changes are noted in detail.
+ *
+ * Contributors are listed in the CONTRIBUTORS file.
+ *
+ * As usual, all bouquets go to the contributors, and all
+ * brickbats go to the project maintainer.
+ *
+ * Maintainer:
+ * The code base for this project is coordinated and
+ * eventually pre-tested, packaged, and made available by
+ *
+ * Ross Johnson <rpj@ise.canberra.edu.au>
+ *
+ * QA Testers:
+ * Ultimately, the library is tested in the real world by
+ * a host of competent and demanding scientists and
+ * engineers who report bugs and/or provide solutions
+ * which are then fixed or incorporated into subsequent
+ * versions of the library. Each time a bug is fixed, a
+ * test case is written to prove the fix and ensure
+ * that later changes to the code don't reintroduce the
+ * same error. The number of test cases is slowly growing
+ * and therefore so is the code reliability.
+ *
+ * Compliance:
+ * See the file ANNOUNCE for the list of implemented
+ * and not-implemented routines and defined options.
+ * Of course, these are all defined is this file as well.
+ *
+ * Web site:
+ * The source code and other information about this library
+ * are available from
+ *
+ * http://sources.redhat.com/pthreads-win32/
+ *
+ * -------------------------------------------------------------
+ */
+
+/* Try to avoid including windows.h */
+#if defined(__MINGW32__) && defined(__cplusplus)
+/*
+ * FIXME: The pthreadGCE.dll build gets linker unresolved errors
+ * on pthread_key_create() unless windows.h is included here.
+ * It appears to have something to do with an argument type mismatch.
+ * Looking at tsd.o with 'nm' shows this line:
+ * 00000000 T _pthread_key_create__FPP14pthread_key_t_PFPv_v
+ * instead of
+ * 00000000 T _pthread_key_create
+ */
+#define PTW32_INCLUDE_WINDOWS_H
+#endif
+
+#ifdef PTW32_INCLUDE_WINDOWS_H
+#include <windows.h>
+#endif
+
+/*
+ * -----------------
+ * autoconf switches
+ * -----------------
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#if PTW32_LEVEL >= PTW32_LEVEL_MAX
+
+/* Try to avoid including windows.h */
+#if defined(__MINGW32__) && defined(__cplusplus)
+/*
+ * FIXME: The pthreadGCE.dll build gets linker unresolved errors
+ * on pthread_key_create() unless windows.h is included here.
+ * It appears to have something to do with an argument type mismatch.
+ * Looking at tsd.o with 'nm' shows this line:
+ * 00000000 T _pthread_key_create__FPP14pthread_key_t_PFPv_v
+ * instead of
+ * 00000000 T _pthread_key_create
+ */
+#define PTW32_INCLUDE_WINDOWS_H
+#endif
+
+#ifdef PTW32_INCLUDE_WINDOWS_H
+#include <windows.h>
+#endif
+
+#ifndef NEED_FTIME
+#include <time.h>
+#else /* NEED_FTIME */
+/* use native WIN32 time API */
+#endif /* NEED_FTIME */
+
+#if HAVE_SIGNAL_H
+#include <signal.h>
+#endif /* HAVE_SIGNAL_H */
+
+#include <setjmp.h>
+#include <limits.h>
+
+/*
+ * Boolean values to make us independent of system includes.
+ */
+enum {
+ PTW32_FALSE = 0,
+ PTW32_TRUE = (! PTW32_FALSE)
+};
+
+/*
+ * This is a duplicate of what is in the autoconf config.h,
+ * which is only used when building the pthread-win32 libraries.
+ */
+
+#ifndef PTW32_CONFIG_H
+# if defined(WINCE)
+# define NEED_ERRNO
+# define NEED_SEM
+# endif
+# if defined(_UWIN) || defined(__MINGW32__)
+# define HAVE_MODE_T
+# endif
+#endif
+
+/*
+ *
+ */
+
+#if PTW32_LEVEL >= PTW32_LEVEL_MAX
+#ifdef NEED_ERRNO
+#include "need_errno.h"
+#else
+#include <errno.h>
+#endif
+#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
+
+/*
+ * Several systems don't define ENOTSUP. If not, we use
+ * the same value as Solaris.
+ */
+#ifndef ENOTSUP
+# define ENOTSUP 48
+#endif
+
+#ifndef ETIMEDOUT
+# define ETIMEDOUT 10060 /* This is the value in winsock.h. */
+#endif
+
+#include <sched.h>
+
+/*
+ * To avoid including windows.h we define only those things that we
+ * actually need from it. I don't like the potential incompatibility that
+ * this creates with future versions of windows.
+ */
+#ifndef PTW32_INCLUDE_WINDOWS_H
+#ifndef HANDLE
+# define PTW32__HANDLE_DEF
+# define HANDLE void *
+#endif
+#ifndef DWORD
+# define PTW32__DWORD_DEF
+# define DWORD unsigned long
+#endif
+#endif
+
+#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
+
+#ifndef HAVE_STRUCT_TIMESPEC
+struct timespec {
+ long tv_sec;
+ long tv_nsec;
+};
+#endif /* HAVE_STRUCT_TIMESPEC */
+
+#ifndef SIG_BLOCK
+#define SIG_BLOCK 0
+#endif /* SIG_BLOCK */
+
+#ifndef SIG_UNBLOCK
+#define SIG_UNBLOCK 1
+#endif /* SIG_UNBLOCK */
+
+#ifndef SIG_SETMASK
+#define SIG_SETMASK 2
+#endif /* SIG_SETMASK */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * -------------------------------------------------------------
+ *
+ * POSIX 1003.1-2001 Options
+ * =========================
+ *
+ * _POSIX_THREADS (set)
+ * If set, you can use threads
+ *
+ * _POSIX_THREAD_ATTR_STACKSIZE (set)
+ * If set, you can control the size of a thread's
+ * stack
+ * pthread_attr_getstacksize
+ * pthread_attr_setstacksize
+ *
+ * _POSIX_THREAD_ATTR_STACKADDR (not set)
+ * If set, you can allocate and control a thread's
+ * stack. If not supported, the following functions
+ * will return ENOSYS, indicating they are not
+ * supported:
+ * pthread_attr_getstackaddr
+ * pthread_attr_setstackaddr
+ *
+ * _POSIX_THREAD_PRIORITY_SCHEDULING (set)
+ * If set, you can use realtime scheduling.
+ * Indicates the availability of:
+ * pthread_attr_getinheritsched
+ * pthread_attr_getschedparam
+ * pthread_attr_getschedpolicy
+ * pthread_attr_getscope
+ * pthread_attr_setinheritsched
+ * pthread_attr_setschedparam
+ * pthread_attr_setschedpolicy
+ * pthread_attr_setscope
+ * pthread_getschedparam
+ * pthread_setschedparam
+ * sched_get_priority_max
+ * sched_get_priority_min
+ * sched_rr_set_interval
+ *
+ * _POSIX_THREAD_PRIO_INHERIT (not set)
+ * If set, you can create priority inheritance
+ * mutexes.
+ * pthread_mutexattr_getprotocol +
+ * pthread_mutexattr_setprotocol +
+ *
+ * _POSIX_THREAD_PRIO_PROTECT (not set)
+ * If set, you can create priority ceiling mutexes
+ * Indicates the availability of:
+ * pthread_mutex_getprioceiling
+ * pthread_mutex_setprioceiling
+ * pthread_mutexattr_getprioceiling
+ * pthread_mutexattr_getprotocol +
+ * pthread_mutexattr_setprioceiling
+ * pthread_mutexattr_setprotocol +
+ *
+ * _POSIX_THREAD_PROCESS_SHARED (not set)
+ * If set, you can create mutexes and condition
+ * variables that can be shared with another
+ * process.If set, indicates the availability
+ * of:
+ * pthread_mutexattr_getpshared
+ * pthread_mutexattr_setpshared
+ * pthread_condattr_getpshared
+ * pthread_condattr_setpshared
+ *
+ * _POSIX_THREAD_SAFE_FUNCTIONS (set)
+ * If set you can use the special *_r library
+ * functions that provide thread-safe behaviour
+ *
+ * _POSIX_READER_WRITER_LOCKS (set)
+ * If set, you can use read/write locks
+ *
+ * _POSIX_SPIN_LOCKS (set)
+ * If set, you can use spin locks
+ *
+ * _POSIX_BARRIERS (set)
+ * If set, you can use barriers
+ *
+ * + These functions provide both 'inherit' and/or
+ * 'protect' protocol, based upon these macro
+ * settings.
+ *
+ * POSIX 1003.1-2001 Limits
+ * ===========================
+ *
+ * PTHREAD_DESTRUCTOR_ITERATIONS
+ * Maximum number of attempts to destroy
+ * a thread's thread-specific data on
+ * termination (must be at least 4)
+ *
+ * PTHREAD_KEYS_MAX
+ * Maximum number of thread-specific data keys
+ * available per process (must be at least 128)
+ *
+ * PTHREAD_STACK_MIN
+ * Minimum supported stack size for a thread
+ *
+ * PTHREAD_THREADS_MAX
+ * Maximum number of threads supported per
+ * process (must be at least 64).
+ *
+ * _POSIX_SEM_NSEMS_MAX
+ * The maximum number of semaphores a process can have.
+ * (only defined if not already defined)
+ *
+ * _POSIX_SEM_VALUE_MAX
+ * The maximum value a semaphore can have.
+ * (only defined if not already defined)
+ *
+ * -------------------------------------------------------------
+ */
+
+/*
+ * POSIX Options
+ */
+#ifndef _POSIX_THREADS
+#define _POSIX_THREADS
+#endif
+
+#ifndef _POSIX_READER_WRITER_LOCKS
+#define _POSIX_READER_WRITER_LOCKS
+#endif
+
+#ifndef _POSIX_SPIN_LOCKS
+#define _POSIX_SPIN_LOCKS
+#endif
+
+#ifndef _POSIX_BARRIERS
+#define _POSIX_BARRIERS
+#endif
+
+#define _POSIX_THREAD_SAFE_FUNCTIONS
+#define _POSIX_THREAD_ATTR_STACKSIZE
+#define _POSIX_THREAD_PRIORITY_SCHEDULING
+
+#if defined( KLUDGE )
+/*
+ * The following are not supported
+ */
+#define _POSIX_THREAD_ATTR_STACKADDR
+#define _POSIX_THREAD_PRIO_INHERIT
+#define _POSIX_THREAD_PRIO_PROTECT
+#define _POSIX_THREAD_PROCESS_SHARED
+
+#endif /* KLUDGE */
+
+/*
+ * POSIX Limits
+ *
+ * PTHREAD_DESTRUCTOR_ITERATIONS
+ * Standard states this must be at least
+ * 4.
+ *
+ * PTHREAD_KEYS_MAX
+ * WIN32 permits only 64 TLS keys per process.
+ * This limitation could be worked around by
+ * simply simulating keys.
+ *
+ * PTHREADS_STACK_MIN
+ * POSIX specifies 0 which is also the value WIN32
+ * interprets as allowing the system to
+ * set the size to that of the main thread. The
+ * maximum stack size in Win32 is 1Meg. WIN32
+ * allocates more stack as required up to the 1Meg
+ * limit.
+ *
+ * PTHREAD_THREADS_MAX
+ * Not documented by WIN32. Wrote a test program
+ * that kept creating threads until it failed
+ * revealed this approximate number (Windows NT).
+ * This number is somewhat less for Windows 9x
+ * and is effectively less than 64. Perhaps this
+ * constant should be set at DLL load time.
+ *
+ */
+#define PTHREAD_DESTRUCTOR_ITERATIONS 4
+#define PTHREAD_KEYS_MAX 64
+#define PTHREAD_STACK_MIN 0
+#define PTHREAD_THREADS_MAX 2019
+#ifndef _POSIX_SEM_NSEMS_MAX
+/* Not used and only an arbitrary value. */
+# define _POSIX_SEM_NSEMS_MAX 1024
+#endif
+#ifndef _POSIX_SEM_VALUE_MAX
+# define _POSIX_SEM_VALUE_MAX (INT_MAX/2)
+#endif
+
+#if __GNUC__ && ! defined (__declspec)
+# error Please upgrade your GNU compiler to one that supports __declspec.
+#endif
+
+/*
+ * When building the DLL code, you should define PTW32_BUILD so that
+ * the variables/functions are exported correctly. When using the DLL,
+ * do NOT define PTW32_BUILD, and then the variables/functions will
+ * be imported correctly.
+ */
+#ifdef _DLL
+# ifdef PTW32_BUILD
+# define PTW32_DLLPORT __declspec (dllexport)
+# else
+# define PTW32_DLLPORT __declspec (dllimport)
+# endif
+#endif
+
+#if defined(_UWIN) && PTW32_LEVEL >= PTW32_LEVEL_MAX
+# include <sys/types.h>
+#else
+typedef struct pthread_t_ *pthread_t;
+typedef struct pthread_attr_t_ *pthread_attr_t;
+typedef struct pthread_once_t_ pthread_once_t;
+typedef struct pthread_key_t_ *pthread_key_t;
+typedef struct pthread_mutex_t_ *pthread_mutex_t;
+typedef struct pthread_mutexattr_t_ *pthread_mutexattr_t;
+typedef struct pthread_cond_t_ *pthread_cond_t;
+typedef struct pthread_condattr_t_ *pthread_condattr_t;
+#endif
+typedef struct pthread_rwlock_t_ *pthread_rwlock_t;
+typedef struct pthread_rwlockattr_t_ *pthread_rwlockattr_t;
+typedef struct pthread_spinlock_t_ *pthread_spinlock_t;
+typedef struct pthread_barrier_t_ *pthread_barrier_t;
+typedef struct pthread_barrierattr_t_ *pthread_barrierattr_t;
+
+/*
+ * ====================
+ * ====================
+ * POSIX Threads
+ * ====================
+ * ====================
+ */
+
+enum {
+/*
+ * pthread_attr_{get,set}detachstate
+ */
+ PTHREAD_CREATE_JOINABLE = 0, /* Default */
+ PTHREAD_CREATE_DETACHED = 1,
+
+/*
+ * pthread_attr_{get,set}inheritsched
+ */
+ PTHREAD_INHERIT_SCHED = 0,
+ PTHREAD_EXPLICIT_SCHED = 1, /* Default */
+
+/*
+ * pthread_{get,set}scope
+ */
+ PTHREAD_SCOPE_PROCESS = 0,
+ PTHREAD_SCOPE_SYSTEM = 1, /* Default */
+
+/*
+ * pthread_setcancelstate paramters
+ */
+ PTHREAD_CANCEL_ENABLE = 0, /* Default */
+ PTHREAD_CANCEL_DISABLE = 1,
+
+/*
+ * pthread_setcanceltype parameters
+ */
+ PTHREAD_CANCEL_ASYNCHRONOUS = 0,
+ PTHREAD_CANCEL_DEFERRED = 1, /* Default */
+
+/*
+ * pthread_mutexattr_{get,set}pshared
+ * pthread_condattr_{get,set}pshared
+ */
+ PTHREAD_PROCESS_PRIVATE = 0,
+ PTHREAD_PROCESS_SHARED = 1,
+
+/*
+ * pthread_barrier_wait
+ */
+ PTHREAD_BARRIER_SERIAL_THREAD = -1
+};
+
+/*
+ * ====================
+ * ====================
+ * Cancelation
+ * ====================
+ * ====================
+ */
+#define PTHREAD_CANCELED ((void *) -1)
+
+
+/*
+ * ====================
+ * ====================
+ * Once Key
+ * ====================
+ * ====================
+ */
+#define PTHREAD_ONCE_INIT { PTW32_FALSE, -1 }
+
+struct pthread_once_t_
+{
+ int done; /* indicates if user function executed */
+ long started; /* First thread to increment this value */
+ /* to zero executes the user function */
+};
+
+
+/*
+ * ====================
+ * ====================
+ * Object initialisers
+ * ====================
+ * ====================
+ */
+#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t) -1)
+
+#define PTHREAD_COND_INITIALIZER ((pthread_cond_t) -1)
+
+#define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t) -1)
+
+#define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t) -1)
+
+
+/*
+ * Mutex types.
+ */
+enum
+{
+ /* Compatibility with LinuxThreads */
+ PTHREAD_MUTEX_FAST_NP,
+ PTHREAD_MUTEX_RECURSIVE_NP,
+ PTHREAD_MUTEX_ERRORCHECK_NP,
+ PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP,
+ PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP,
+ /* For compatibility with POSIX */
+ PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP,
+ PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
+ PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
+ PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
+};
+
+
+/* There are three implementations of cancel cleanup.
+ * Note that pthread.h is included in both application
+ * compilation units and also internally for the library.
+ * The code here and within the library aims to work
+ * for all reasonable combinations of environments.
+ *
+ * The three implementations are:
+ *
+ * WIN32 SEH
+ * C
+ * C++
+ *
+ * Please note that exiting a push/pop block via
+ * "return", "exit", "break", or "continue" will
+ * lead to different behaviour amongst applications
+ * depending upon whether the library was built
+ * using SEH, C++, or C. For example, a library built
+ * with SEH will call the cleanup routine, while both
+ * C++ and C built versions will not.
+ */
+
+/*
+ * Define defaults for cleanup code.
+ * Note: Unless the build explicitly defines one of the following, then
+ * we default to standard C style cleanup. This style uses setjmp/longjmp
+ * in the cancelation and thread exit implementations and therefore won't
+ * do stack unwinding if linked to applications that have it (e.g.
+ * C++ apps). This is currently consistent with most/all commercial Unix
+ * POSIX threads implementations.
+ */
+#if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C )
+# define __CLEANUP_C
+#endif
+
+#if defined( __CLEANUP_SEH ) && defined(__GNUC__)
+#error ERROR [__FILE__, line __LINE__]: GNUC does not support SEH.
+#endif
+
+typedef struct ptw32_cleanup_t ptw32_cleanup_t;
+typedef void (__cdecl *ptw32_cleanup_callback_t)(void *);
+
+struct ptw32_cleanup_t
+{
+ ptw32_cleanup_callback_t routine;
+ void *arg;
+ struct ptw32_cleanup_t *prev;
+};
+
+#ifdef __CLEANUP_SEH
+ /*
+ * WIN32 SEH version of cancel cleanup.
+ */
+
+#define pthread_cleanup_push( _rout, _arg ) \
+ { \
+ ptw32_cleanup_t _cleanup; \
+ \
+ _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \
+ _cleanup.arg = (_arg); \
+ __try \
+ { \
+
+#define pthread_cleanup_pop( _execute ) \
+ } \
+ __finally \
+ { \
+ if( _execute || AbnormalTermination()) \
+ { \
+ (*(_cleanup.routine))( _cleanup.arg ); \
+ } \
+ } \
+ }
+
+#else /* __CLEANUP_SEH */
+
+#ifdef __CLEANUP_C
+
+ /*
+ * C implementation of PThreads cancel cleanup
+ */
+
+#define pthread_cleanup_push( _rout, _arg ) \
+ { \
+ ptw32_cleanup_t _cleanup; \
+ \
+ ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \
+
+#define pthread_cleanup_pop( _execute ) \
+ (void) ptw32_pop_cleanup( _execute ); \
+ }
+
+#else /* __CLEANUP_C */
+
+#ifdef __CLEANUP_CXX
+
+ /*
+ * C++ version of cancel cleanup.
+ * - John E. Bossom.
+ */
+
+ class PThreadCleanup {
+ /*
+ * PThreadCleanup
+ *
+ * Purpose
+ * This class is a C++ helper class that is
+ * used to implement pthread_cleanup_push/
+ * pthread_cleanup_pop.
+ * The destructor of this class automatically
+ * pops the pushed cleanup routine regardless
+ * of how the code exits the scope
+ * (i.e. such as by an exception)
+ */
+ ptw32_cleanup_callback_t cleanUpRout;
+ void * obj;
+ int executeIt;
+
+ public:
+ PThreadCleanup() :
+ cleanUpRout( 0 ),
+ obj( 0 ),
+ executeIt( 0 )
+ /*
+ * No cleanup performed
+ */
+ {
+ }
+
+ PThreadCleanup(
+ ptw32_cleanup_callback_t routine,
+ void * arg ) :
+ cleanUpRout( routine ),
+ obj( arg ),
+ executeIt( 1 )
+ /*
+ * Registers a cleanup routine for 'arg'
+ */
+ {
+ }
+
+ ~PThreadCleanup()
+ {
+ if ( executeIt && ((void *) cleanUpRout != (void *) 0) )
+ {
+ (void) (*cleanUpRout)( obj );
+ }
+ }
+
+ void execute( int exec )
+ {
+ executeIt = exec;
+ }
+ };
+
+ /*
+ * C++ implementation of PThreads cancel cleanup;
+ * This implementation takes advantage of a helper
+ * class who's destructor automatically calls the
+ * cleanup routine if we exit our scope weirdly
+ */
+#define pthread_cleanup_push( _rout, _arg ) \
+ { \
+ PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \
+ (void *) (_arg) );
+
+#define pthread_cleanup_pop( _execute ) \
+ cleanup.execute( _execute ); \
+ }
+
+#else
+
+#error ERROR [__FILE__, line __LINE__]: Cleanup type undefined.
+
+#endif /* __CLEANUP_CXX */
+
+#endif /* __CLEANUP_C */
+
+#endif /* __CLEANUP_SEH */
+
+/*
+ * ===============
+ * ===============
+ * Methods
+ * ===============
+ * ===============
+ */
+
+/*
+ * PThread Attribute Functions
+ */
+PTW32_DLLPORT int pthread_attr_init (pthread_attr_t * attr);
+
+PTW32_DLLPORT int pthread_attr_destroy (pthread_attr_t * attr);
+
+PTW32_DLLPORT int pthread_attr_getdetachstate (const pthread_attr_t * attr,
+ int *detachstate);
+
+PTW32_DLLPORT int pthread_attr_getstackaddr (const pthread_attr_t * attr,
+ void **stackaddr);
+
+PTW32_DLLPORT int pthread_attr_getstacksize (const pthread_attr_t * attr,
+ size_t * stacksize);
+
+PTW32_DLLPORT int pthread_attr_setdetachstate (pthread_attr_t * attr,
+ int detachstate);
+
+PTW32_DLLPORT int pthread_attr_setstackaddr (pthread_attr_t * attr,
+ void *stackaddr);
+
+PTW32_DLLPORT int pthread_attr_setstacksize (pthread_attr_t * attr,
+ size_t stacksize);
+
+PTW32_DLLPORT int pthread_attr_getschedparam (const pthread_attr_t *attr,
+ struct sched_param *param);
+
+PTW32_DLLPORT int pthread_attr_setschedparam (pthread_attr_t *attr,
+ const struct sched_param *param);
+
+PTW32_DLLPORT int pthread_attr_setschedpolicy (pthread_attr_t *,
+ int);
+
+PTW32_DLLPORT int pthread_attr_getschedpolicy (pthread_attr_t *,
+ int *);
+
+PTW32_DLLPORT int pthread_attr_setinheritsched(pthread_attr_t * attr,
+ int inheritsched);
+
+PTW32_DLLPORT int pthread_attr_getinheritsched(pthread_attr_t * attr,
+ int * inheritsched);
+
+PTW32_DLLPORT int pthread_attr_setscope (pthread_attr_t *,
+ int);
+
+PTW32_DLLPORT int pthread_attr_getscope (const pthread_attr_t *,
+ int *);
+
+/*
+ * PThread Functions
+ */
+PTW32_DLLPORT int pthread_create (pthread_t * tid,
+ const pthread_attr_t * attr,
+ void *(*start) (void *),
+ void *arg);
+
+PTW32_DLLPORT int pthread_detach (pthread_t tid);
+
+PTW32_DLLPORT int pthread_equal (pthread_t t1,
+ pthread_t t2);
+
+PTW32_DLLPORT void pthread_exit (void *value_ptr);
+
+PTW32_DLLPORT int pthread_join (pthread_t thread,
+ void **value_ptr);
+
+PTW32_DLLPORT pthread_t pthread_self (void);
+
+PTW32_DLLPORT int pthread_cancel (pthread_t thread);
+
+PTW32_DLLPORT int pthread_setcancelstate (int state,
+ int *oldstate);
+
+PTW32_DLLPORT int pthread_setcanceltype (int type,
+ int *oldtype);
+
+PTW32_DLLPORT void pthread_testcancel (void);
+
+PTW32_DLLPORT int pthread_once (pthread_once_t * once_control,
+ void (*init_routine) (void));
+
+#if PTW32_LEVEL >= PTW32_LEVEL_MAX
+PTW32_DLLPORT ptw32_cleanup_t *ptw32_pop_cleanup (int execute);
+
+PTW32_DLLPORT void ptw32_push_cleanup (ptw32_cleanup_t * cleanup,
+ void (*routine) (void *),
+ void *arg);
+#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
+
+/*
+ * Thread Specific Data Functions
+ */
+PTW32_DLLPORT int pthread_key_create (pthread_key_t * key,
+ void (*destructor) (void *));
+
+PTW32_DLLPORT int pthread_key_delete (pthread_key_t key);
+
+PTW32_DLLPORT int pthread_setspecific (pthread_key_t key,
+ const void *value);
+
+PTW32_DLLPORT void *pthread_getspecific (pthread_key_t key);
+
+
+/*
+ * Mutex Attribute Functions
+ */
+PTW32_DLLPORT int pthread_mutexattr_init (pthread_mutexattr_t * attr);
+
+PTW32_DLLPORT int pthread_mutexattr_destroy (pthread_mutexattr_t * attr);
+
+PTW32_DLLPORT int pthread_mutexattr_getpshared (const pthread_mutexattr_t
+ * attr,
+ int *pshared);
+
+PTW32_DLLPORT int pthread_mutexattr_setpshared (pthread_mutexattr_t * attr,
+ int pshared);
+
+PTW32_DLLPORT int pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind);
+PTW32_DLLPORT int pthread_mutexattr_gettype (pthread_mutexattr_t * attr, int *kind);
+
+/*
+ * Barrier Attribute Functions
+ */
+PTW32_DLLPORT int pthread_barrierattr_init (pthread_barrierattr_t * attr);
+
+PTW32_DLLPORT int pthread_barrierattr_destroy (pthread_barrierattr_t * attr);
+
+PTW32_DLLPORT int pthread_barrierattr_getpshared (const pthread_barrierattr_t
+ * attr,
+ int *pshared);
+
+PTW32_DLLPORT int pthread_barrierattr_setpshared (pthread_barrierattr_t * attr,
+ int pshared);
+
+/*
+ * Mutex Functions
+ */
+PTW32_DLLPORT int pthread_mutex_init (pthread_mutex_t * mutex,
+ const pthread_mutexattr_t * attr);
+
+PTW32_DLLPORT int pthread_mutex_destroy (pthread_mutex_t * mutex);
+
+PTW32_DLLPORT int pthread_mutex_lock (pthread_mutex_t * mutex);
+
+PTW32_DLLPORT int pthread_mutex_timedlock(pthread_mutex_t *mutex,
+ const struct timespec *abstime);
+
+PTW32_DLLPORT int pthread_mutex_trylock (pthread_mutex_t * mutex);
+
+PTW32_DLLPORT int pthread_mutex_unlock (pthread_mutex_t * mutex);
+
+/*
+ * Spinlock Functions
+ */
+PTW32_DLLPORT int pthread_spin_init (pthread_spinlock_t * lock, int pshared);
+
+PTW32_DLLPORT int pthread_spin_destroy (pthread_spinlock_t * lock);
+
+PTW32_DLLPORT int pthread_spin_lock (pthread_spinlock_t * lock);
+
+PTW32_DLLPORT int pthread_spin_trylock (pthread_spinlock_t * lock);
+
+PTW32_DLLPORT int pthread_spin_unlock (pthread_spinlock_t * lock);
+
+/*
+ * Barrier Functions
+ */
+PTW32_DLLPORT int pthread_barrier_init (pthread_barrier_t * barrier,
+ const pthread_barrierattr_t * attr,
+ unsigned int count);
+
+PTW32_DLLPORT int pthread_barrier_destroy (pthread_barrier_t * barrier);
+
+PTW32_DLLPORT int pthread_barrier_wait (pthread_barrier_t * barrier);
+
+/*
+ * Condition Variable Attribute Functions
+ */
+PTW32_DLLPORT int pthread_condattr_init (pthread_condattr_t * attr);
+
+PTW32_DLLPORT int pthread_condattr_destroy (pthread_condattr_t * attr);
+
+PTW32_DLLPORT int pthread_condattr_getpshared (const pthread_condattr_t * attr,
+ int *pshared);
+
+PTW32_DLLPORT int pthread_condattr_setpshared (pthread_condattr_t * attr,
+ int pshared);
+
+/*
+ * Condition Variable Functions
+ */
+PTW32_DLLPORT int pthread_cond_init (pthread_cond_t * cond,
+ const pthread_condattr_t * attr);
+
+PTW32_DLLPORT int pthread_cond_destroy (pthread_cond_t * cond);
+
+PTW32_DLLPORT int pthread_cond_wait (pthread_cond_t * cond,
+ pthread_mutex_t * mutex);
+
+PTW32_DLLPORT int pthread_cond_timedwait (pthread_cond_t * cond,
+ pthread_mutex_t * mutex,
+ const struct timespec *abstime);
+
+PTW32_DLLPORT int pthread_cond_signal (pthread_cond_t * cond);
+
+PTW32_DLLPORT int pthread_cond_broadcast (pthread_cond_t * cond);
+
+/*
+ * Scheduling
+ */
+PTW32_DLLPORT int pthread_setschedparam (pthread_t thread,
+ int policy,
+ const struct sched_param *param);
+
+PTW32_DLLPORT int pthread_getschedparam (pthread_t thread,
+ int *policy,
+ struct sched_param *param);
+
+PTW32_DLLPORT int pthread_setconcurrency (int);
+
+PTW32_DLLPORT int pthread_getconcurrency (void);
+
+/*
+ * Read-Write Lock Functions
+ */
+PTW32_DLLPORT int pthread_rwlock_init(pthread_rwlock_t *lock,
+ const pthread_rwlockattr_t *attr);
+
+PTW32_DLLPORT int pthread_rwlock_destroy(pthread_rwlock_t *lock);
+
+PTW32_DLLPORT int pthread_rwlock_tryrdlock(pthread_rwlock_t *);
+
+PTW32_DLLPORT int pthread_rwlock_trywrlock(pthread_rwlock_t *);
+
+PTW32_DLLPORT int pthread_rwlock_rdlock(pthread_rwlock_t *lock);
+
+PTW32_DLLPORT int pthread_rwlock_timedrdlock(pthread_rwlock_t *lock,
+ const struct timespec *abstime);
+
+PTW32_DLLPORT int pthread_rwlock_wrlock(pthread_rwlock_t *lock);
+
+PTW32_DLLPORT int pthread_rwlock_timedwrlock(pthread_rwlock_t *lock,
+ const struct timespec *abstime);
+
+PTW32_DLLPORT int pthread_rwlock_unlock(pthread_rwlock_t *lock);
+
+PTW32_DLLPORT int pthread_rwlockattr_init (pthread_rwlockattr_t * attr);
+
+PTW32_DLLPORT int pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr);
+
+PTW32_DLLPORT int pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr,
+ int *pshared);
+
+PTW32_DLLPORT int pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr,
+ int pshared);
+
+#if PTW32_LEVEL >= PTW32_LEVEL_MAX - 1
+
+/*
+ * Signal Functions. Should be defined in <signal.h> but MSVC and MinGW32
+ * already have signal.h that don't define these.
+ */
+PTW32_DLLPORT int pthread_kill(pthread_t thread, int sig);
+
+/*
+ * Non-portable functions
+ */
+
+/*
+ * Compatibility with Linux.
+ */
+PTW32_DLLPORT int pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr,
+ int kind);
+PTW32_DLLPORT int pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr,
+ int *kind);
+
+/*
+ * Possibly supported by other POSIX threads implementations
+ */
+PTW32_DLLPORT int pthread_delay_np (struct timespec * interval);
+PTW32_DLLPORT int pthread_num_processors_np(void);
+
+/*
+ * Useful if an application wants to statically link
+ * the lib rather than load the DLL at run-time.
+ */
+PTW32_DLLPORT int pthread_win32_process_attach_np(void);
+PTW32_DLLPORT int pthread_win32_process_detach_np(void);
+PTW32_DLLPORT int pthread_win32_thread_attach_np(void);
+PTW32_DLLPORT int pthread_win32_thread_detach_np(void);
+
+/*
+ * Register a system time change with the library.
+ * Causes the library to perform various functions
+ * in response to the change. Should be called whenever
+ * the application's top level window receives a
+ * WM_TIMECHANGE message. It can be passed directly to
+ * pthread_create() as a new thread if desired.
+ */
+PTW32_DLLPORT void * pthread_timechange_handler_np(void *);
+
+#endif /*PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 */
+
+#if PTW32_LEVEL >= PTW32_LEVEL_MAX
+
+/*
+ * Returns the Win32 HANDLE for the POSIX thread.
+ */
+PTW32_DLLPORT HANDLE pthread_getw32threadhandle_np(pthread_t thread);
+
+
+/*
+ * Protected Methods
+ *
+ * This function blocks until the given WIN32 handle
+ * is signaled or pthread_cancel had been called.
+ * This function allows the caller to hook into the
+ * PThreads cancel mechanism. It is implemented using
+ *
+ * WaitForMultipleObjects
+ *
+ * on 'waitHandle' and a manually reset WIN32 Event
+ * used to implement pthread_cancel. The 'timeout'
+ * argument to TimedWait is simply passed to
+ * WaitForMultipleObjects.
+ */
+PTW32_DLLPORT int pthreadCancelableWait (HANDLE waitHandle);
+PTW32_DLLPORT int pthreadCancelableTimedWait (HANDLE waitHandle,
+ DWORD timeout);
+
+#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
+
+/*
+ * Thread-Safe C Runtime Library Mappings.
+ */
+#ifndef _UWIN
+# if defined(NEED_ERRNO)
+ PTW32_DLLPORT int * _errno( void );
+# else
+# ifndef errno
+# if (defined(_MT) || defined(_DLL))
+ __declspec(dllimport) extern int * __cdecl _errno(void);
+# define errno (*_errno())
+# endif
+# endif
+# endif
+#endif
+
+/*
+ * WIN32 C runtime library had been made thread-safe
+ * without affecting the user interface. Provide
+ * mappings from the UNIX thread-safe versions to
+ * the standard C runtime library calls.
+ * Only provide function mappings for functions that
+ * actually exist on WIN32.
+ */
+
+#if !defined(__MINGW32__)
+#define strtok_r( _s, _sep, _lasts ) \
+ ( *(_lasts) = strtok( (_s), (_sep) ) )
+#endif /* !__MINGW32__ */
+
+#define asctime_r( _tm, _buf ) \
+ ( strcpy( (_buf), asctime( (_tm) ) ), \
+ (_buf) )
+
+#define ctime_r( _clock, _buf ) \
+ ( strcpy( (_buf), ctime( (_clock) ) ), \
+ (_buf) )
+
+#define gmtime_r( _clock, _result ) \
+ ( *(_result) = *gmtime( (_clock) ), \
+ (_result) )
+
+#define localtime_r( _clock, _result ) \
+ ( *(_result) = *localtime( (_clock) ), \
+ (_result) )
+
+#define rand_r( _seed ) \
+ ( _seed == _seed? rand() : rand() )
+
+
+#ifdef __cplusplus
+
+/*
+ * Internal exceptions
+ */
+class ptw32_exception {};
+class ptw32_exception_cancel : public ptw32_exception {};
+class ptw32_exception_exit : public ptw32_exception {};
+
+#endif
+
+#if PTW32_LEVEL >= PTW32_LEVEL_MAX
+
+/* FIXME: This is only required if the library was built using SEH */
+/*
+ * Get internal SEH tag
+ */
+PTW32_DLLPORT DWORD ptw32_get_exception_services_code(void);
+
+#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
+
+#ifndef PTW32_BUILD
+
+#ifdef __CLEANUP_SEH
+
+/*
+ * Redefine the SEH __except keyword to ensure that applications
+ * propagate our internal exceptions up to the library's internal handlers.
+ */
+#define __except( E ) \
+ __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \
+ ? EXCEPTION_CONTINUE_SEARCH : ( E ) )
+
+#endif /* __CLEANUP_SEH */
+
+#ifdef __CLEANUP_CXX
+
+/*
+ * Redefine the C++ catch keyword to ensure that applications
+ * propagate our internal exceptions up to the library's internal handlers.
+ */
+#ifdef _MSC_VER
+ /*
+ * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll'
+ * if you want Pthread-Win32 cancelation and pthread_exit to work.
+ */
+
+#ifndef PtW32NoCatchWarn
+
+#pragma message("Specify \"/DPtW32NoCatchWarn\" compiler flag to skip this message.")
+#pragma message("------------------------------------------------------------------")
+#pragma message("When compiling applications with MSVC++ and C++ exception handling:")
+#pragma message(" Replace any 'catch( ... )' in routines called from POSIX threads")
+#pragma message(" with 'PtW32CatchAll' or 'CATCHALL' if you want POSIX thread")
+#pragma message(" cancelation and pthread_exit to work. For example:")
+#pragma message("")
+#pragma message(" #ifdef PtW32CatchAll")
+#pragma message(" PtW32CatchAll")
+#pragma message(" #else")
+#pragma message(" catch(...)")
+#pragma message(" #endif")
+#pragma message(" {")
+#pragma message(" /* Catchall block processing */")
+#pragma message(" }")
+#pragma message("------------------------------------------------------------------")
+
+#endif
+
+#define PtW32CatchAll \
+ catch( ptw32_exception & ) { throw; } \
+ catch( ... )
+
+#else /* _MSC_VER */
+
+#define catch( E ) \
+ catch( ptw32_exception & ) { throw; } \
+ catch( E )
+
+#endif /* _MSC_VER */
+
+#endif /* __CLEANUP_CXX */
+
+#endif /* ! PTW32_BUILD */
+
+#ifdef __cplusplus
+} /* End of extern "C" */
+#endif /* __cplusplus */
+
+#ifdef PTW32__HANDLE_DEF
+# undef HANDLE
+#endif
+#ifdef PTW32__DWORD_DEF
+# undef DWORD
+#endif
+
+#undef PTW32_LEVEL
+#undef PTW32_LEVEL_MAX
+
+#endif /* PTHREAD_H */
diff --git a/src/Cedar/winpcap/remote-ext.h b/src/Cedar/winpcap/remote-ext.h
new file mode 100644
index 00000000..e8e675ec
--- /dev/null
+++ b/src/Cedar/winpcap/remote-ext.h
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2002 - 2003
+ * NetGroup, Politecnico di Torino (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+
+#ifndef __REMOTE_EXT_H__
+#define __REMOTE_EXT_H__
+
+
+
+// Definition for Microsoft Visual Studio
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*!
+ \file remote-ext.h
+
+ The goal of this file it to include most of the new definitions that should be
+ placed into the pcap.h file.
+
+ It includes all new definitions (structures and functions like pcap_open().
+ Some of the functions are not really a remote feature, but, right now,
+ they are placed here.
+*/
+
+
+
+// All this stuff is public
+/*! \addtogroup remote_struct
+ \{
+*/
+
+
+
+
+/*!
+ \brief Defines the maximum buffer size in which address, port, interface names are kept.
+
+ In case the adapter name or such is larger than this value, it is truncated.
+ This is not used by the user; however it must be aware that an hostname / interface
+ name longer than this value will be truncated.
+*/
+#define PCAP_BUF_SIZE 1024
+
+
+/*! \addtogroup remote_source_ID
+ \{
+*/
+
+
+/*!
+ \brief Internal representation of the type of source in use (file,
+ remote/local interface).
+
+ This indicates a file, i.e. the user want to open a capture from a local file.
+*/
+#define PCAP_SRC_FILE 2
+/*!
+ \brief Internal representation of the type of source in use (file,
+ remote/local interface).
+
+ This indicates a local interface, i.e. the user want to open a capture from
+ a local interface. This does not involve the RPCAP protocol.
+*/
+#define PCAP_SRC_IFLOCAL 3
+/*!
+ \brief Internal representation of the type of source in use (file,
+ remote/local interface).
+
+ This indicates a remote interface, i.e. the user want to open a capture from
+ an interface on a remote host. This does involve the RPCAP protocol.
+*/
+#define PCAP_SRC_IFREMOTE 4
+
+/*!
+ \}
+*/
+
+
+
+/*! \addtogroup remote_source_string
+
+ The formats allowed by the pcap_open() are the following:
+ - file://path_and_filename [opens a local file]
+ - rpcap://devicename [opens the selected device devices available on the local host, without using the RPCAP protocol]
+ - rpcap://host/devicename [opens the selected device available on a remote host]
+ - rpcap://host:port/devicename [opens the selected device available on a remote host, using a non-standard port for RPCAP]
+ - adaptername [to open a local adapter; kept for compability, but it is strongly discouraged]
+ - (NULL) [to open the first local adapter; kept for compability, but it is strongly discouraged]
+
+ The formats allowed by the pcap_findalldevs_ex() are the following:
+ - file://folder/ [lists all the files in the given folder]
+ - rpcap:// [lists all local adapters]
+ - rpcap://host:port/ [lists the devices available on a remote host]
+
+ Referring to the 'host' and 'port' paramters, they can be either numeric or literal. Since
+ IPv6 is fully supported, these are the allowed formats:
+
+ - host (literal): e.g. host.foo.bar
+ - host (numeric IPv4): e.g. 10.11.12.13
+ - host (numeric IPv4, IPv6 style): e.g. [10.11.12.13]
+ - host (numeric IPv6): e.g. [1:2:3::4]
+ - port: can be either numeric (e.g. '80') or literal (e.g. 'http')
+
+ Here you find some allowed examples:
+ - rpcap://host.foo.bar/devicename [everything literal, no port number]
+ - rpcap://host.foo.bar:1234/devicename [everything literal, with port number]
+ - rpcap://10.11.12.13/devicename [IPv4 numeric, no port number]
+ - rpcap://10.11.12.13:1234/devicename [IPv4 numeric, with port number]
+ - rpcap://[10.11.12.13]:1234/devicename [IPv4 numeric with IPv6 format, with port number]
+ - rpcap://[1:2:3::4]/devicename [IPv6 numeric, no port number]
+ - rpcap://[1:2:3::4]:1234/devicename [IPv6 numeric, with port number]
+ - rpcap://[1:2:3::4]:http/devicename [IPv6 numeric, with literal port number]
+
+ \{
+*/
+
+
+/*!
+ \brief String that will be used to determine the type of source in use (file,
+ remote/local interface).
+
+ This string will be prepended to the interface name in order to create a string
+ that contains all the information required to open the source.
+
+ This string indicates that the user wants to open a capture from a local file.
+*/
+#define PCAP_SRC_FILE_STRING "file://"
+/*!
+ \brief String that will be used to determine the type of source in use (file,
+ remote/local interface).
+
+ This string will be prepended to the interface name in order to create a string
+ that contains all the information required to open the source.
+
+ This string indicates that the user wants to open a capture from a network interface.
+ This string does not necessarily involve the use of the RPCAP protocol. If the
+ interface required resides on the local host, the RPCAP protocol is not involved
+ and the local functions are used.
+*/
+#define PCAP_SRC_IF_STRING "rpcap://"
+
+/*!
+ \}
+*/
+
+
+
+
+
+/*!
+ \addtogroup remote_open_flags
+ \{
+*/
+
+/*!
+ \brief It defines if the adapter has to go in promiscuous mode.
+
+ It is '1' if you have to open the adapter in promiscuous mode, '0' otherwise.
+ Note that even if this parameter is false, the interface could well be in promiscuous
+ mode for some other reason (for example because another capture process with
+ promiscuous mode enabled is currently using that interface).
+ On on Linux systems with 2.2 or later kernels (that have the "any" device), this
+ flag does not work on the "any" device; if an argument of "any" is supplied,
+ the 'promisc' flag is ignored.
+*/
+#define PCAP_OPENFLAG_PROMISCUOUS 1
+
+/*!
+ \brief It defines if the data trasfer (in case of a remote
+ capture) has to be done with UDP protocol.
+
+ If it is '1' if you want a UDP data connection, '0' if you want
+ a TCP data connection; control connection is always TCP-based.
+ A UDP connection is much lighter, but it does not guarantee that all
+ the captured packets arrive to the client workstation. Moreover,
+ it could be harmful in case of network congestion.
+ This flag is meaningless if the source is not a remote interface.
+ In that case, it is simply ignored.
+*/
+#define PCAP_OPENFLAG_DATATX_UDP 2
+
+
+/*!
+ \brief It defines if the remote probe has to capture its own generated traffic.
+
+ In case the remote probe uses the same interface to capture traffic and to send
+ data back to the caller, the captured traffic includes the RPCAP traffic as well.
+ If this flag is turned on, the RPCAP traffic is excluded from the capture, so that
+ the trace returned back to the collector is does not include this traffic.
+*/
+#define PCAP_OPENFLAG_NOCAPTURE_RPCAP 4
+/*!
+ \}
+*/
+
+
+/*!
+ \addtogroup remote_samp_methods
+ \{
+*/
+
+/*!
+ \brief No sampling has to be done on the current capture.
+
+ In this case, no sampling algorithms are applied to the current capture.
+*/
+#define PCAP_SAMP_NOSAMP 0
+
+/*!
+ \brief It defines that only 1 out of N packets must be returned to the user.
+
+ In this case, the 'value' field of the 'pcap_samp' structure indicates the
+ number of packets (minus 1) that must be discarded before one packet got accepted.
+ In other words, if 'value = 10', the first packet is returned to the caller, while
+ the following 9 are discarded.
+*/
+#define PCAP_SAMP_1_EVERY_N 1
+
+/*!
+ \brief It defines that we have to return 1 packet every N milliseconds.
+
+ In this case, the 'value' field of the 'pcap_samp' structure indicates the 'waiting
+ time' in milliseconds before one packet got accepted.
+ In other words, if 'value = 10', the first packet is returned to the caller; the next
+ returned one will be the first packet that arrives when 10ms have elapsed.
+*/
+#define PCAP_SAMP_FIRST_AFTER_N_MS 2
+
+/*!
+ \}
+*/
+
+
+/*!
+ \addtogroup remote_auth_methods
+ \{
+*/
+
+/*!
+ \brief It defines the NULL authentication.
+
+ This value has to be used within the 'type' member of the pcap_rmtauth structure.
+ The 'NULL' authentication has to be equal to 'zero', so that old applications
+ can just put every field of struct pcap_rmtauth to zero, and it does work.
+*/
+#define RPCAP_RMTAUTH_NULL 0
+/*!
+ \brief It defines the username/password authentication.
+
+ With this type of authentication, the RPCAP protocol will use the username/
+ password provided to authenticate the user on the remote machine. If the
+ authentication is successful (and the user has the right to open network devices)
+ the RPCAP connection will continue; otherwise it will be dropped.
+
+ This value has to be used within the 'type' member of the pcap_rmtauth structure.
+*/
+#define RPCAP_RMTAUTH_PWD 1
+
+/*!
+ \}
+*/
+
+
+
+
+/*!
+
+ \brief This structure keeps the information needed to autheticate
+ the user on a remote machine.
+
+ The remote machine can either grant or refuse the access according
+ to the information provided.
+ In case the NULL authentication is required, both 'username' and
+ 'password' can be NULL pointers.
+
+ This structure is meaningless if the source is not a remote interface;
+ in that case, the functions which requires such a structure can accept
+ a NULL pointer as well.
+*/
+struct pcap_rmtauth
+{
+ /*!
+ \brief Type of the authentication required.
+
+ In order to provide maximum flexibility, we can support different types
+ of authentication based on the value of this 'type' variable. The currently
+ supported authentication methods are defined into the
+ \link remote_auth_methods Remote Authentication Methods Section\endlink.
+
+ */
+ int type;
+ /*!
+ \brief Zero-terminated string containing the username that has to be
+ used on the remote machine for authentication.
+
+ This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication
+ and it can be NULL.
+ */
+ char *username;
+ /*!
+ \brief Zero-terminated string containing the password that has to be
+ used on the remote machine for authentication.
+
+ This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication
+ and it can be NULL.
+ */
+ char *password;
+};
+
+
+/*!
+ \brief This structure defines the information related to sampling.
+
+ In case the sampling is requested, the capturing device should read
+ only a subset of the packets coming from the source. The returned packets depend
+ on the sampling parameters.
+
+ \warning The sampling process is applied <strong>after</strong> the filtering process.
+ In other words, packets are filtered first, then the sampling process selects a
+ subset of the 'filtered' packets and it returns them to the caller.
+*/
+struct pcap_samp
+{
+ /*!
+ Method used for sampling. Currently, the supported methods are listed in the
+ \link remote_samp_methods Sampling Methods Section\endlink.
+ */
+ int method;
+
+ /*!
+ This value depends on the sampling method defined. For its meaning, please check
+ at the \link remote_samp_methods Sampling Methods Section\endlink.
+ */
+ int value;
+};
+
+
+
+
+//! Maximum lenght of an host name (needed for the RPCAP active mode)
+#define RPCAP_HOSTLIST_SIZE 1024
+
+
+/*!
+ \}
+*/ // end of public documentation
+
+
+// Exported functions
+
+
+
+/** \name New WinPcap functions
+
+ This section lists the new functions that are able to help considerably in writing
+ WinPcap programs because of their easiness of use.
+ */
+//\{
+pcap_t *pcap_open(const char *source, int snaplen, int flags, int read_timeout, struct pcap_rmtauth *auth, char *errbuf);
+int pcap_createsrcstr(char *source, int type, const char *host, const char *port, const char *name, char *errbuf);
+int pcap_parsesrcstr(const char *source, int *type, char *host, char *port, char *name, char *errbuf);
+int pcap_findalldevs_ex(char *source, struct pcap_rmtauth *auth, pcap_if_t **alldevs, char *errbuf);
+struct pcap_samp *pcap_setsampling(pcap_t *p);
+
+//\}
+// End of new winpcap functions
+
+
+
+/** \name Remote Capture functions
+ */
+//\{
+SOCKET pcap_remoteact_accept(const char *address, const char *port, const char *hostlist, char *connectinghost, struct pcap_rmtauth *auth, char *errbuf);
+int pcap_remoteact_list(char *hostlist, char sep, int size, char *errbuf);
+int pcap_remoteact_close(const char *host, char *errbuf);
+void pcap_remoteact_cleanup();
+//\}
+// End of remote capture functions
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/src/Cedar/winpcap/sched.h b/src/Cedar/winpcap/sched.h
new file mode 100644
index 00000000..8f4ddf4c
--- /dev/null
+++ b/src/Cedar/winpcap/sched.h
@@ -0,0 +1,174 @@
+/*
+ * Module: sched.h
+ *
+ * Purpose:
+ * Provides an implementation of POSIX realtime extensions
+ * as defined in
+ *
+ * POSIX 1003.1b-1993 (POSIX.1b)
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2003 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@callisto.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#ifndef _SCHED_H
+#define _SCHED_H
+
+#undef PTW32_LEVEL
+
+#if defined(_POSIX_SOURCE)
+#define PTW32_LEVEL 0
+/* Early POSIX */
+#endif
+
+#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309
+#undef PTW32_LEVEL
+#define PTW32_LEVEL 1
+/* Include 1b, 1c and 1d */
+#endif
+
+#if defined(INCLUDE_NP)
+#undef PTW32_LEVEL
+#define PTW32_LEVEL 2
+/* Include Non-Portable extensions */
+#endif
+
+#define PTW32_LEVEL_MAX 3
+
+#if !defined(PTW32_LEVEL)
+#define PTW32_LEVEL PTW32_LEVEL_MAX
+/* Include everything */
+#endif
+
+
+#if __GNUC__ && ! defined (__declspec)
+# error Please upgrade your GNU compiler to one that supports __declspec.
+#endif
+
+/*
+ * When building the DLL code, you should define PTW32_BUILD so that
+ * the variables/functions are exported correctly. When using the DLL,
+ * do NOT define PTW32_BUILD, and then the variables/functions will
+ * be imported correctly.
+ */
+#ifdef PTW32_BUILD
+# define PTW32_DLLPORT __declspec (dllexport)
+#else
+# define PTW32_DLLPORT __declspec (dllimport)
+#endif
+
+/*
+ * This is a duplicate of what is in the autoconf config.h,
+ * which is only used when building the pthread-win32 libraries.
+ */
+
+#ifndef PTW32_CONFIG_H
+# if defined(WINCE)
+# define NEED_ERRNO
+# define NEED_SEM
+# endif
+# if defined(_UWIN) || defined(__MINGW32__)
+# define HAVE_MODE_T
+# endif
+#endif
+
+/*
+ *
+ */
+
+#if PTW32_LEVEL >= PTW32_LEVEL_MAX
+#ifdef NEED_ERRNO
+#include "need_errno.h"
+#else
+#include <errno.h>
+#endif
+#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
+
+#if defined(__MINGW32__) || defined(_UWIN)
+#if PTW32_LEVEL >= PTW32_LEVEL_MAX
+/* For pid_t */
+# include <sys/types.h>
+/* Required by Unix 98 */
+# include <time.h>
+#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
+#else
+typedef int pid_t;
+#endif
+
+/* Thread scheduling policies */
+
+enum {
+ SCHED_OTHER = 0,
+ SCHED_FIFO,
+ SCHED_RR,
+ SCHED_MIN = SCHED_OTHER,
+ SCHED_MAX = SCHED_RR
+};
+
+struct sched_param {
+ int sched_priority;
+};
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+PTW32_DLLPORT int sched_yield (void);
+
+PTW32_DLLPORT int sched_get_priority_min (int policy);
+
+PTW32_DLLPORT int sched_get_priority_max (int policy);
+
+PTW32_DLLPORT int sched_setscheduler (pid_t pid, int policy);
+
+PTW32_DLLPORT int sched_getscheduler (pid_t pid);
+
+/*
+ * Note that this macro returns ENOTSUP rather than
+ * ENOSYS as might be expected. However, returning ENOSYS
+ * should mean that sched_get_priority_{min,max} are
+ * not implemented as well as sched_rr_get_interval.
+ * This is not the case, since we just don't support
+ * round-robin scheduling. Therefore I have chosen to
+ * return the same value as sched_setscheduler when
+ * SCHED_RR is passed to it.
+ */
+#define sched_rr_get_interval(_pid, _interval) \
+ ( errno = ENOTSUP, (int) -1 )
+
+
+#ifdef __cplusplus
+} /* End of extern "C" */
+#endif /* __cplusplus */
+
+#undef PTW32_LEVEL
+#undef PTW32_LEVEL_MAX
+
+#endif /* !_SCHED_H */
+
diff --git a/src/Cedar/winpcap/semaphore.h b/src/Cedar/winpcap/semaphore.h
new file mode 100644
index 00000000..733f0ae3
--- /dev/null
+++ b/src/Cedar/winpcap/semaphore.h
@@ -0,0 +1,163 @@
+/*
+ * Module: semaphore.h
+ *
+ * Purpose:
+ * Semaphores aren't actually part of the PThreads standard.
+ * They are defined by the POSIX Standard:
+ *
+ * POSIX 1003.1b-1993 (POSIX.1b)
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Pthreads-win32 - POSIX Threads Library for Win32
+ * Copyright(C) 1998 John E. Bossom
+ * Copyright(C) 1999,2003 Pthreads-win32 contributors
+ *
+ * Contact Email: rpj@callisto.canberra.edu.au
+ *
+ * The current list of contributors is contained
+ * in the file CONTRIBUTORS included with the source
+ * code distribution. The list can also be seen at the
+ * following World Wide Web location:
+ * http://sources.redhat.com/pthreads-win32/contributors.html
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library in the file COPYING.LIB;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+#if !defined( SEMAPHORE_H )
+#define SEMAPHORE_H
+
+#undef PTW32_LEVEL
+
+#if defined(_POSIX_SOURCE)
+#define PTW32_LEVEL 0
+/* Early POSIX */
+#endif
+
+#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309
+#undef PTW32_LEVEL
+#define PTW32_LEVEL 1
+/* Include 1b, 1c and 1d */
+#endif
+
+#if defined(INCLUDE_NP)
+#undef PTW32_LEVEL
+#define PTW32_LEVEL 2
+/* Include Non-Portable extensions */
+#endif
+
+#define PTW32_LEVEL_MAX 3
+
+#if !defined(PTW32_LEVEL)
+#define PTW32_LEVEL PTW32_LEVEL_MAX
+/* Include everything */
+#endif
+
+#if __GNUC__ && ! defined (__declspec)
+# error Please upgrade your GNU compiler to one that supports __declspec.
+#endif
+
+/*
+ * When building the DLL code, you should define PTW32_BUILD so that
+ * the variables/functions are exported correctly. When using the DLL,
+ * do NOT define PTW32_BUILD, and then the variables/functions will
+ * be imported correctly.
+ */
+#ifdef PTW32_BUILD
+# define PTW32_DLLPORT __declspec (dllexport)
+#else
+# define PTW32_DLLPORT __declspec (dllimport)
+#endif
+
+
+/*
+ * This is a duplicate of what is in the autoconf config.h,
+ * which is only used when building the pthread-win32 libraries.
+ */
+
+#ifndef PTW32_CONFIG_H
+# if defined(WINCE)
+# define NEED_ERRNO
+# define NEED_SEM
+# endif
+# if defined(_UWIN) || defined(__MINGW32__)
+# define HAVE_MODE_T
+# endif
+#endif
+
+/*
+ *
+ */
+
+#if PTW32_LEVEL >= PTW32_LEVEL_MAX
+#ifdef NEED_ERRNO
+#include "need_errno.h"
+#else
+#include <errno.h>
+#endif
+#endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */
+
+#define _POSIX_SEMAPHORES
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+#ifndef HAVE_MODE_T
+typedef unsigned int mode_t;
+#endif
+
+
+typedef struct sem_t_ * sem_t;
+
+PTW32_DLLPORT int sem_init (sem_t * sem,
+ int pshared,
+ unsigned int value);
+
+PTW32_DLLPORT int sem_destroy (sem_t * sem);
+
+PTW32_DLLPORT int sem_trywait (sem_t * sem);
+
+PTW32_DLLPORT int sem_wait (sem_t * sem);
+
+PTW32_DLLPORT int sem_timedwait (sem_t * sem,
+ const struct timespec * abstime);
+
+PTW32_DLLPORT int sem_post (sem_t * sem);
+
+PTW32_DLLPORT int sem_post_multiple (sem_t * sem,
+ int count);
+
+PTW32_DLLPORT int sem_open (const char * name,
+ int oflag,
+ mode_t mode,
+ unsigned int value);
+
+PTW32_DLLPORT int sem_close (sem_t * sem);
+
+PTW32_DLLPORT int sem_unlink (const char * name);
+
+PTW32_DLLPORT int sem_getvalue (sem_t * sem,
+ int * sval);
+
+#ifdef __cplusplus
+} /* End of extern "C" */
+#endif /* __cplusplus */
+
+#undef PTW32_LEVEL
+#undef PTW32_LEVEL_MAX
+
+#endif /* !SEMAPHORE_H */
diff --git a/src/Cedar/winpcap/tcp_session.h b/src/Cedar/winpcap/tcp_session.h
new file mode 100644
index 00000000..33aa99e1
--- /dev/null
+++ b/src/Cedar/winpcap/tcp_session.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2001 - 2003
+ * NetGroup, Politecnico di Torino (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __tcp_session
+#define __tcp_session
+
+#ifdef WIN32
+#include "tme.h"
+#endif
+
+#ifdef __FreeBSD__
+
+#ifdef _KERNEL
+#include <net/tme/tme.h>
+#else
+#include <tme/tme.h>
+#endif
+
+#endif
+
+#define UNKNOWN 0
+#define SYN_RCV 1
+#define SYN_ACK_RCV 2
+#define ESTABLISHED 3
+#define CLOSED_RST 4
+#define FIN_CLN_RCV 5
+#define FIN_SRV_RCV 6
+#define CLOSED_FIN 7
+#define ERROR_TCP 8
+#define FIRST_IS_CLN 0
+#define FIRST_IS_SRV 0xffffffff
+#define FIN_CLN 1
+#define FIN_SRV 2
+
+#define MAX_WINDOW 65536
+
+typedef struct __tcp_data
+{
+ struct timeval timestamp_block; /*DO NOT MOVE THIS VALUE*/
+ struct timeval syn_timestamp;
+ struct timeval last_timestamp;
+ struct timeval syn_ack_timestamp;
+ uint32 direction;
+ uint32 seq_n_0_srv;
+ uint32 seq_n_0_cln;
+ uint32 ack_srv; /* acknowledge of (data sent by server) */
+ uint32 ack_cln; /* acknowledge of (data sent by client) */
+ uint32 status;
+ uint32 pkts_cln_to_srv;
+ uint32 pkts_srv_to_cln;
+ uint32 bytes_srv_to_cln;
+ uint32 bytes_cln_to_srv;
+ uint32 close_state;
+}
+ tcp_data;
+
+#define FIN 1
+#define SYN 2
+#define RST 4
+#define PSH 8
+#define ACK 16
+#define URG 32
+
+#define TCP_SESSION 0x00000800
+uint32 tcp_session(uint8 *block, uint32 pkt_size, TME_DATA *data, MEM_TYPE *mem_ex, uint8 *mem_data);
+
+#endif
diff --git a/src/Cedar/winpcap/time_calls.h b/src/Cedar/winpcap/time_calls.h
new file mode 100644
index 00000000..6532162a
--- /dev/null
+++ b/src/Cedar/winpcap/time_calls.h
@@ -0,0 +1,438 @@
+/*
+ * Copyright (c) 2001
+ * Politecnico di Torino. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code distributions
+ * retain the above copyright notice and this paragraph in its entirety, (2)
+ * distributions including binary code include the above copyright notice and
+ * this paragraph in its entirety in the documentation or other materials
+ * provided with the distribution, and (3) all advertising materials mentioning
+ * features or use of this software display the following acknowledgement:
+ * ``This product includes software developed by the Politecnico
+ * di Torino, and its contributors.'' Neither the name of
+ * the University nor the names of its contributors may be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef _time_calls
+#define _time_calls
+
+#ifdef WIN_NT_DRIVER
+
+#include "debug.h"
+#include "ndis.h"
+
+#define DEFAULT_TIMESTAMPMODE 0
+
+#define TIMESTAMPMODE_SINGLE_SYNCHRONIZATION 0
+#define TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP 1
+#define TIMESTAMPMODE_QUERYSYSTEMTIME 2
+#define TIMESTAMPMODE_RDTSC 3
+
+#define TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_NO_FIXUP 99
+
+#define TIMESTAMPMODE_REGKEY L"TimestampMode"
+
+extern ULONG TimestampMode;
+
+/*!
+ \brief A microsecond precise timestamp.
+
+ included in the sf_pkthdr or the bpf_hdr that NPF associates with every packet.
+*/
+
+struct timeval {
+ long tv_sec; ///< seconds
+ long tv_usec; ///< microseconds
+};
+
+#endif /*WIN_NT_DRIVER*/
+
+struct time_conv
+{
+ ULONGLONG reference;
+ struct timeval start[32];
+};
+
+#ifdef WIN_NT_DRIVER
+
+__inline void TIME_DESYNCHRONIZE(struct time_conv *data)
+{
+ data->reference = 0;
+// data->start.tv_sec = 0;
+// data->start.tv_usec = 0;
+}
+
+
+__inline void ReadTimeStampModeFromRegistry(PUNICODE_STRING RegistryPath)
+{
+ ULONG NewLength;
+ PWSTR NullTerminatedString;
+ RTL_QUERY_REGISTRY_TABLE Queries[2];
+ ULONG DefaultTimestampMode = DEFAULT_TIMESTAMPMODE;
+
+ NewLength = RegistryPath->Length/2;
+
+ NullTerminatedString = ExAllocatePool(PagedPool, (NewLength+1) *sizeof(WCHAR));
+
+ if (NullTerminatedString != NULL)
+ {
+ RtlCopyMemory(NullTerminatedString, RegistryPath->Buffer, RegistryPath->Length);
+
+ NullTerminatedString[NewLength]=0;
+
+ RtlZeroMemory(Queries, sizeof(Queries));
+
+ Queries[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+ Queries[0].Name = TIMESTAMPMODE_REGKEY;
+ Queries[0].EntryContext = &TimestampMode;
+ Queries[0].DefaultType = REG_DWORD;
+ Queries[0].DefaultData = &DefaultTimestampMode;
+ Queries[0].DefaultLength = sizeof(ULONG);
+
+ if (RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, NullTerminatedString, Queries, NULL, NULL) != STATUS_SUCCESS)
+ {
+ TimestampMode = DEFAULT_TIMESTAMPMODE;
+ }
+
+ RtlWriteRegistryValue( RTL_REGISTRY_ABSOLUTE, NullTerminatedString, TIMESTAMPMODE_REGKEY, REG_DWORD, &TimestampMode,sizeof(ULONG));
+ ExFreePool(NullTerminatedString);
+ }
+ else
+ TimestampMode = DEFAULT_TIMESTAMPMODE;
+}
+
+#pragma optimize ("g",off) //Due to some weird behaviour of the optimizer of DDK build 2600
+
+/* KeQueryPerformanceCounter TimeStamps */
+__inline void SynchronizeOnCpu(struct timeval *start)
+{
+// struct timeval *start = (struct timeval*)Data;
+
+ struct timeval tmp;
+ LARGE_INTEGER SystemTime;
+ LARGE_INTEGER i;
+ ULONG tmp2;
+ LARGE_INTEGER TimeFreq,PTime;
+
+ // get the absolute value of the system boot time.
+
+ PTime = KeQueryPerformanceCounter(&TimeFreq);
+ KeQuerySystemTime(&SystemTime);
+
+ start->tv_sec = (LONG)(SystemTime.QuadPart/10000000-11644473600);
+
+ start->tv_usec = (LONG)((SystemTime.QuadPart%10000000)/10);
+
+ start->tv_sec -= (ULONG)(PTime.QuadPart/TimeFreq.QuadPart);
+
+ start->tv_usec -= (LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
+
+ if (start->tv_usec < 0)
+ {
+ start->tv_sec --;
+ start->tv_usec += 1000000;
+ }
+}
+
+/*RDTSC timestamps */
+/* callers must be at IRQL=PASSIVE_LEVEL*/
+__inline VOID TimeSynchronizeRDTSC(struct time_conv *data)
+{
+ struct timeval tmp;
+ LARGE_INTEGER system_time;
+ ULONGLONG curr_ticks;
+ KIRQL old;
+ LARGE_INTEGER start_kqpc,stop_kqpc,start_freq,stop_freq;
+ ULONGLONG start_ticks,stop_ticks;
+ ULONGLONG delta,delta2;
+ KEVENT event;
+ LARGE_INTEGER i;
+ ULONGLONG reference;
+
+ if (data->reference!=0)
+ return;
+
+ KeInitializeEvent(&event,NotificationEvent,FALSE);
+
+ i.QuadPart=-3500000;
+
+ KeRaiseIrql(HIGH_LEVEL,&old);
+ start_kqpc=KeQueryPerformanceCounter(&start_freq);
+ __asm
+ {
+ push eax
+ push edx
+ push ecx
+ rdtsc
+ lea ecx, start_ticks
+ mov [ecx+4], edx
+ mov [ecx], eax
+ pop ecx
+ pop edx
+ pop eax
+ }
+
+ KeLowerIrql(old);
+
+ KeWaitForSingleObject(&event,UserRequest,KernelMode,TRUE ,&i);
+
+ KeRaiseIrql(HIGH_LEVEL,&old);
+ stop_kqpc=KeQueryPerformanceCounter(&stop_freq);
+ __asm
+ {
+ push eax
+ push edx
+ push ecx
+ rdtsc
+ lea ecx, stop_ticks
+ mov [ecx+4], edx
+ mov [ecx], eax
+ pop ecx
+ pop edx
+ pop eax
+ }
+ KeLowerIrql(old);
+
+ delta=stop_ticks-start_ticks;
+ delta2=stop_kqpc.QuadPart-start_kqpc.QuadPart;
+ if (delta>10000000000)
+ {
+ delta/=16;
+ delta2/=16;
+ }
+
+ reference=delta*(start_freq.QuadPart)/delta2;
+
+ data->reference=reference/1000;
+
+ if (reference%1000>500)
+ data->reference++;
+
+ data->reference*=1000;
+
+ reference=data->reference;
+
+ KeQuerySystemTime(&system_time);
+
+ __asm
+ {
+ push eax
+ push edx
+ push ecx
+ rdtsc
+ lea ecx, curr_ticks
+ mov [ecx+4], edx
+ mov [ecx], eax
+ pop ecx
+ pop edx
+ pop eax
+ }
+
+ tmp.tv_sec=-(LONG)(curr_ticks/reference);
+
+ tmp.tv_usec=-(LONG)((curr_ticks%reference)*1000000/reference);
+
+ system_time.QuadPart-=116444736000000000;
+
+ tmp.tv_sec+=(LONG)(system_time.QuadPart/10000000);
+ tmp.tv_usec+=(LONG)((system_time.QuadPart%10000000)/10);
+
+ if (tmp.tv_usec<0)
+ {
+ tmp.tv_sec--;
+ tmp.tv_usec+=1000000;
+ }
+
+ data->start[0] = tmp;
+
+ IF_LOUD(DbgPrint("Frequency %I64u MHz\n",data->reference);)
+}
+
+#pragma optimize ("g",on) //Due to some weird behaviour of the optimizer of DDK build 2600
+
+__inline VOID TIME_SYNCHRONIZE(struct time_conv *data)
+{
+ ULONG NumberOfCpus, i;
+ KAFFINITY AffinityMask;
+
+ if (data->reference != 0)
+ return;
+
+ NumberOfCpus = NdisSystemProcessorCount();
+
+ if ( TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP || TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_NO_FIXUP)
+ {
+ for (i = 0 ; i < NumberOfCpus ; i++ )
+ {
+ AffinityMask = (1 << i);
+ ZwSetInformationThread(NtCurrentThread(), ThreadAffinityMask, &AffinityMask, sizeof(KAFFINITY));
+ SynchronizeOnCpu(&(data->start[i]));
+ }
+ AffinityMask = 0xFFFFFFFF;
+ ZwSetInformationThread(NtCurrentThread(), ThreadAffinityMask, &AffinityMask, sizeof(KAFFINITY));
+ data->reference = 1;
+ }
+ else
+ if ( TimestampMode == TIMESTAMPMODE_QUERYSYSTEMTIME )
+ {
+ //do nothing
+ data->reference = 1;
+ }
+ else
+ if ( TimestampMode == TIMESTAMPMODE_RDTSC )
+ {
+ TimeSynchronizeRDTSC(data);
+ }
+ else
+ { //it should be only the normal case i.e. TIMESTAMPMODE_SINGLESYNCHRONIZATION
+ SynchronizeOnCpu(data->start);
+ data->reference = 1;
+ }
+ return;
+}
+
+
+#pragma optimize ("g",off) //Due to some weird behaviour of the optimizer of DDK build 2600
+
+__inline void GetTimeKQPC(struct timeval *dst, struct time_conv *data)
+{
+ LARGE_INTEGER PTime, TimeFreq;
+ LONG tmp;
+ ULONG CurrentCpu;
+ static struct timeval old_ts={0,0};
+
+
+ PTime = KeQueryPerformanceCounter(&TimeFreq);
+ tmp = (LONG)(PTime.QuadPart/TimeFreq.QuadPart);
+
+ if (TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP || TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_NO_FIXUP)
+ {
+ //actually this code is ok only if we are guaranteed that no thread scheduling will take place.
+ CurrentCpu = KeGetCurrentProcessorNumber();
+
+ dst->tv_sec = data->start[CurrentCpu].tv_sec + tmp;
+ dst->tv_usec = data->start[CurrentCpu].tv_usec + (LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
+
+ if (dst->tv_usec >= 1000000)
+ {
+ dst->tv_sec ++;
+ dst->tv_usec -= 1000000;
+ }
+
+ if (TimestampMode == TIMESTAMPMODE_SYNCHRONIZATION_ON_CPU_WITH_FIXUP)
+ {
+ if (old_ts.tv_sec > dst->tv_sec || (old_ts.tv_sec == dst->tv_sec && old_ts.tv_usec > dst->tv_usec) )
+ *dst = old_ts;
+
+ else
+ old_ts = *dst;
+ }
+ }
+ else
+ { //it should be only the normal case i.e. TIMESTAMPMODE_SINGLESYNCHRONIZATION
+ dst->tv_sec = data->start[0].tv_sec + tmp;
+ dst->tv_usec = data->start[0].tv_usec + (LONG)((PTime.QuadPart%TimeFreq.QuadPart)*1000000/TimeFreq.QuadPart);
+
+ if (dst->tv_usec >= 1000000)
+ {
+ dst->tv_sec ++;
+ dst->tv_usec -= 1000000;
+ }
+ }
+}
+
+__inline void GetTimeRDTSC(struct timeval *dst, struct time_conv *data)
+{
+
+ ULONGLONG tmp;
+ __asm
+ {
+ push eax
+ push edx
+ push ecx
+ rdtsc
+ lea ecx, tmp
+ mov [ecx+4], edx
+ mov [ecx], eax
+ pop ecx
+ pop edx
+ pop eax
+ }
+
+ if (data->reference==0)
+ {
+ return;
+ }
+ dst->tv_sec=(LONG)(tmp/data->reference);
+
+ dst->tv_usec=(LONG)((tmp-dst->tv_sec*data->reference)*1000000/data->reference);
+
+ dst->tv_sec+=data->start[0].tv_sec;
+
+ dst->tv_usec+=data->start[0].tv_usec;
+
+ if (dst->tv_usec>=1000000)
+ {
+ dst->tv_sec++;
+ dst->tv_usec-=1000000;
+ }
+
+
+}
+
+__inline void GetTimeQST(struct timeval *dst, struct time_conv *data)
+{
+ LARGE_INTEGER SystemTime;
+
+ KeQuerySystemTime(&SystemTime);
+
+ dst->tv_sec = (LONG)(SystemTime.QuadPart/10000000-11644473600);
+ dst->tv_usec = (LONG)((SystemTime.QuadPart%10000000)/10);
+
+}
+
+#pragma optimize ("g",on) //Due to some weird behaviour of the optimizer of DDK build 2600
+
+
+__inline void GET_TIME(struct timeval *dst, struct time_conv *data)
+{
+ return;
+ if ( TimestampMode == TIMESTAMPMODE_RDTSC )
+ {
+ GetTimeRDTSC(dst,data);
+ }
+ else
+ if ( TimestampMode == TIMESTAMPMODE_QUERYSYSTEMTIME )
+ {
+ GetTimeQST(dst,data);
+ }
+ else
+ {
+ GetTimeKQPC(dst,data);
+ }
+}
+
+
+#else /*WIN_NT_DRIVER*/
+
+__inline void FORCE_TIME(struct timeval *src, struct time_conv *dest)
+{
+ dest->start[0]=*src;
+}
+
+__inline void GET_TIME(struct timeval *dst, struct time_conv *data)
+{
+ return;
+ *dst=data->start[0];
+}
+
+#endif /*WIN_NT_DRIVER*/
+
+
+#endif /*_time_calls*/
diff --git a/src/Cedar/winpcap/tme.h b/src/Cedar/winpcap/tme.h
new file mode 100644
index 00000000..eb8d4b12
--- /dev/null
+++ b/src/Cedar/winpcap/tme.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2001 - 2003
+ * NetGroup, Politecnico di Torino (Italy)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Politecnico di Torino nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __tme_include_
+#define __tme_include_
+
+#ifdef WIN_NT_DRIVER
+#include "ndis.h"
+#else
+#include <windows.h>
+#endif /*WIN_NT_DRIVER*/
+
+#include "memory_t.h"
+#include "time_calls.h"
+
+
+/* error codes */
+#define TME_ERROR 0
+#define TME_SUCCESS 1
+#define TME_TRUE 2
+#define TME_FALSE 3
+
+/* some constants */
+#define DEFAULT_MEM_EX_SIZE 65536
+#define MAX_TME_DATA_BLOCKS 4
+#define TME_NONE_ACTIVE 0xffffffff
+#define DELTA_READ 2 /* secs */
+
+#define TME_LUT_ENTRIES 0x00000000
+#define TME_MAX_FILL_STATE 0x00000001 /*potrebbe servire per un thread a passive level!?!?! */
+#define TME_REHASHING_VALUE 0x00000002
+#define TME_KEY_LEN 0x00000003
+#define TME_SHARED_MEMORY_BLOCKS 0x00000004
+#define TME_FILLED_ENTRIES 0x00000005
+#define TME_BLOCK_SIZE 0x00000006
+#define TME_EXTRA_SEGMENT_SIZE 0x00000007
+#define TME_LOOKUP_CODE 0x00000008
+#define TME_OUT_LUT_EXEC 0x00000009
+#define TME_FILLED_BLOCKS 0x0000000a
+#define TME_DEFAULT_EXEC 0x0000000b
+#define TME_LUT_BASE_ADDRESS 0x0000000c
+#define TME_SHARED_MEMORY_BASE_ADDRESS 0x0000000d
+#define TME_EXTRA_SEGMENT_BASE_ADDRESS 0x0000000e
+#define TME_LAST_FOUND 0x0000000f /* contains the offset of the last found entry */
+#define TME_LAST_FOUND_BLOCK 0x00000010
+/* TME default values */
+#define TME_LUT_ENTRIES_DEFAULT 32007
+#define TME_REHASHING_VALUE_DEFAULT 1
+#define TME_SHARED_MEMORY_BLOCKS_DEFAULT 16000
+#define TME_BLOCK_SIZE_DEFAULT 64
+#define TME_EXTRA_SEGMENT_SIZE_DEFAULT 0
+#define TME_LOOKUP_CODE_DEFAULT 0
+#define TME_OUT_LUT_EXEC_DEFAULT 0
+#define TME_DEFAULT_EXEC_DEFAULT 0
+#define TME_MAX_FILL_STATE_DEFAULT 15000
+
+#define IS_VALIDATED(src,index) (src&(1<<index))
+
+#define VALIDATE(src,index) src|=(1<<index);
+
+
+#define FORCE_NO_DELETION(timestamp) (struct timeval*)(timestamp)->tv_sec=0x7fffffff;
+
+/* TME callback prototypes */
+typedef uint32 (*lut_fcn)(uint8 *key, struct __TME_DATA *data,MEM_TYPE *mem_ex, struct time_conv *time_ref );
+typedef uint32 (*exec_fcn)(uint8 *block, uint32 pkt_size, struct __TME_DATA *data, MEM_TYPE *mem_ex, uint8 *mem_data);
+
+/* DO NOT MODIFY THIS STRUCTURE!!!! GV */
+typedef struct __RECORD
+
+{
+ uint32 block;
+ uint32 exec_fcn;
+}
+ RECORD, *PRECORD;
+
+/* TME data registers */
+struct __TME_DATA
+{
+ uint32 lut_entries;
+ uint32 max_fill_state;
+ uint32 rehashing_value;
+ uint32 key_len;
+ uint32 shared_memory_blocks;
+ uint32 filled_entries;
+ uint32 block_size;
+ uint32 extra_segment_size;
+ uint32 filled_blocks;
+ lut_fcn lookup_code;
+ uint32 default_exec;
+ uint32 out_lut_exec;
+ uint8 *lut_base_address;
+ uint8 *shared_memory_base_address;
+ uint8 *extra_segment_base_address;
+ struct timeval last_read;
+ uint32 enable_deletion;
+ uint8 *last_found;
+};
+
+typedef struct __TME_DATA TME_DATA,*PTME_DATA;
+
+
+
+/* TME core */
+typedef struct __TME_CORE
+{
+ uint32 working;
+ uint32 active;
+ uint32 validated_blocks;
+ TME_DATA block_data[MAX_TME_DATA_BLOCKS];
+ uint32 active_read;
+
+} TME_CORE, *PTME_CORE;
+
+static __inline int32 IS_DELETABLE(void *timestamp, TME_DATA *data)
+{
+ struct timeval *ts=(struct timeval*)timestamp;
+
+ if (data->enable_deletion==FALSE)
+ return FALSE;
+ if (data->filled_entries<data->max_fill_state)
+ return FALSE;
+ if ((ts->tv_sec+DELTA_READ)<data->last_read.tv_sec)
+ return TRUE;
+ return FALSE;
+}
+
+/* functions to manage TME */
+uint32 init_tme_block(TME_CORE *tme, uint32 block);
+uint32 validate_tme_block(MEM_TYPE *mem_ex, TME_CORE *tme, uint32 block, uint32 mem_ex_offset);
+uint32 lookup_frontend(MEM_TYPE *mem_ex, TME_CORE *tme,uint32 mem_ex_offset, struct time_conv *time_ref);
+uint32 execute_frontend(MEM_TYPE *mem_ex, TME_CORE *tme, uint32 pkt_size,uint32 offset);
+uint32 set_active_tme_block(TME_CORE *tme, uint32 block);
+uint32 init_extended_memory(uint32 size, MEM_TYPE *mem_ex);
+uint32 reset_tme(TME_CORE *tme);
+uint32 get_tme_block_register(TME_DATA *data,MEM_TYPE *mem_ex,uint32 rgstr,uint32 *rval);
+uint32 set_tme_block_register(TME_DATA *data,MEM_TYPE *mem_ex,uint32 rgstr,uint32 value, int32 init);
+uint32 set_active_read_tme_block(TME_CORE *tme, uint32 block);
+uint32 set_autodeletion(TME_DATA *data, uint32 value);
+
+/* function mappers */
+lut_fcn lut_fcn_mapper(uint32 index);
+exec_fcn exec_fcn_mapper(uint32 index);
+
+#endif