// 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 THIS SOFTWARE IN ANOTHER COUNTRY UNLESS // YOU HAVE A CONFIRMATION THAT THIS SOFTWARE DOES NOT VIOLATE ANY // CRIMINAL LAWS OR CIVIL RIGHTS IN THAT PARTICULAR COUNTRY. USING THIS // SOFTWARE IN OTHER COUNTRIES IS COMPLETELY AT YOUR OWN RISK. THE // SOFTETHER VPN PROJECT HAS DEVELOPED AND DISTRIBUTED THIS SOFTWARE TO // COMPLY ONLY WITH THE JAPANESE LAWS AND EXISTING CIVIL RIGHTS INCLUDING // PATENTS WHICH ARE SUBJECTS APPLY IN JAPAN. OTHER COUNTRIES' LAWS OR // CIVIL RIGHTS ARE NONE OF OUR CONCERNS NOR RESPONSIBILITIES. WE HAVE // NEVER INVESTIGATED ANY CRIMINAL REGULATIONS, CIVIL LAWS OR // INTELLECTUAL PROPERTY RIGHTS INCLUDING PATENTS IN ANY OF OTHER 200+ // COUNTRIES AND TERRITORIES. BY NATURE, THERE ARE 200+ REGIONS IN THE // WORLD, WITH DIFFERENT LAWS. IT IS IMPOSSIBLE TO VERIFY EVERY // COUNTRIES' LAWS, REGULATIONS AND CIVIL RIGHTS TO MAKE THE SOFTWARE // COMPLY WITH ALL COUNTRIES' LAWS BY THE PROJECT. EVEN IF YOU WILL BE // SUED BY A PRIVATE ENTITY OR BE DAMAGED BY A PUBLIC SERVANT IN YOUR // COUNTRY, THE DEVELOPERS OF THIS SOFTWARE WILL NEVER BE LIABLE TO // RECOVER OR COMPENSATE SUCH DAMAGES, CRIMINAL OR CIVIL // RESPONSIBILITIES. NOTE THAT THIS LINE IS NOT LICENSE RESTRICTION BUT // JUST A STATEMENT FOR WARNING AND DISCLAIMER. // // // SOURCE CODE CONTRIBUTION // ------------------------ // // Your contribution to SoftEther VPN Project is much appreciated. // Please send patches to us through GitHub. // Read the SoftEther VPN Patch Acceptance Policy in advance: // http://www.softether.org/5-download/src/9.patch // // // 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. // // // NO MEMORY OR RESOURCE LEAKS // --------------------------- // // The memory-leaks and resource-leaks verification under the stress // test has been passed before release this source code. // 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)); t->ApplyDhcpPushRoutes = PackGetBool(p, "ApplyDhcpPushRoutes"); PackGetStr(p, "DhcpPushRoutes", t->DhcpPushRoutes, sizeof(t->DhcpPushRoutes)); } 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); PackAddBool(p, "ApplyDhcpPushRoutes", true); PackAddStr(p, "DhcpPushRoutes", t->DhcpPushRoutes); } // 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)); CfgGetStr(dhcp, "DhcpPushRoutes", o->DhcpPushRoutes, sizeof(o->DhcpPushRoutes)); // Test code // StrCpy(o->DhcpPushRoutes, sizeof(o->DhcpPushRoutes), // "130.158.6.0/24/192.168.9.2 130.158.80.244/255.255.255.255/192.168.9.2"); NormalizeClasslessRouteTableStr(o->DhcpPushRoutes, sizeof(o->DhcpPushRoutes), o->DhcpPushRoutes); o->ApplyDhcpPushRoutes = true; 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); CfgAddStr(dhcp, "DhcpPushRoutes", o->DhcpPushRoutes); 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/