mirror of
https://github.com/SoftEtherVPN/SoftEtherVPN.git
synced 2024-11-26 19:39:53 +03:00
1819 lines
42 KiB
C
1819 lines
42 KiB
C
// SoftEther VPN Source Code - Developer Edition Master Branch
|
|
// Cedar Communication Module
|
|
|
|
|
|
// 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;
|
|
PACK *ret;
|
|
UINT err;
|
|
bool ok;
|
|
// Validate arguments
|
|
if (r == NULL || name == NULL || p == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
n = (NAT *)r->Param;
|
|
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 = NnIsActiveEx(v, &t->IsRawIpMode);
|
|
}
|
|
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);
|
|
|
|
PackSetCurrentJsonGroupName(p, "DhcpTable");
|
|
for (i = 0;i < t->NumItem;i++)
|
|
{
|
|
RPC_ENUM_DHCP_ITEM *e = &t->Items[i];
|
|
|
|
PackAddIntEx(p, "Id", e->Id, i, t->NumItem);
|
|
PackAddTime64Ex(p, "LeasedTime", e->LeasedTime, i, t->NumItem);
|
|
PackAddTime64Ex(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);
|
|
}
|
|
PackSetCurrentJsonGroupName(p, NULL);
|
|
}
|
|
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);
|
|
|
|
PackSetCurrentJsonGroupName(p, "NatTable");
|
|
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);
|
|
PackAddTime64Ex(p, "CreatedTime", e->CreatedTime, i, t->NumItem);
|
|
PackAddTime64Ex(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);
|
|
}
|
|
PackSetCurrentJsonGroupName(p, NULL);
|
|
}
|
|
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");
|
|
t->IsRawIpMode = PackGetBool(p, "IsRawIpMode");
|
|
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);
|
|
PackAddBool(p, "IsRawIpMode", t->IsRawIpMode);
|
|
}
|
|
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
|
|
Sha0(test, "", 0);
|
|
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();
|
|
Sha0(n->HashedPassword, "", 0);
|
|
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;
|
|
}
|
|
|