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
diff options
context:
space:
mode:
authordnobori <da.git@softether.co.jp>2014-01-04 17:00:08 +0400
committerdnobori <da.git@softether.co.jp>2014-01-04 17:00:08 +0400
commit749497dde0a1dd08c434a73b9d4e93dc3e3326d9 (patch)
tree7c83a55919c0f1aa1267c4dbcd008f1644f961ee /src/Cedar/Nat.c
parentd433e567a561f8ae094a535025b02c7dc47026c6 (diff)
v4.03-9408-rtm
Diffstat (limited to 'src/Cedar/Nat.c')
-rw-r--r--src/Cedar/Nat.c1876
1 files changed, 1876 insertions, 0 deletions
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/