* tar xzf utvpn-src-unix-v101-7101-public-2010.06.27.tar.gz
[lab.git] / utvpn / utvpn-unix-v101-7101-public / src / Cedar / Nat.c
diff --git a/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Nat.c b/utvpn/utvpn-unix-v101-7101-public/src/Cedar/Nat.c
new file mode 100644 (file)
index 0000000..bc7b783
--- /dev/null
@@ -0,0 +1,1778 @@
+// SoftEther UT-VPN SourceCode\r
+// \r
+// Copyright (C) 2004-2010 SoftEther Corporation.\r
+// Copyright (C) 2004-2010 University of Tsukuba, Japan.\r
+// Copyright (C) 2003-2010 Daiyuu Nobori.\r
+// All Rights Reserved.\r
+// \r
+// http://utvpn.tsukuba.ac.jp/\r
+// \r
+// This program is free software; you can redistribute it and/or\r
+// modify it under the terms of the GNU General Public License\r
+// version 2 as published by the Free Software Foundation.\r
+// \r
+// This program is distributed in the hope that it will be useful,\r
+// but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+// GNU General Public License for more details.\r
+// \r
+// You should have received a copy of the GNU General Public License version 2\r
+// along with this program; if not, write to the Free Software\r
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
+// \r
+// このファイルは GPL バージョン 2 ライセンスで公開されています。\r
+// 誰でもこのファイルの内容を複製、改変したり、改変したバージョンを再配布\r
+// することができます。ただし、原著作物を改変した場合は、原著作物の著作権表示\r
+// を除去することはできません。改変した著作物を配布する場合は、改変実施者の\r
+// 著作権表示を原著作物の著作権表示に付随して記載するようにしてください。\r
+// \r
+// この SoftEther UT-VPN オープンソース・プロジェクトは、日本国の\r
+// ソフトイーサ株式会社 (SoftEther Corporation, http://www.softether.co.jp/ )\r
+// および筑波大学 (University of Tsukuba, http://www.tsukuba.ac.jp/ ) によって\r
+// ホストされています。\r
+// 本プログラムの配布者は、本プログラムを、業としての利用以外のため、\r
+// および、試験または研究のために利用が行われることを想定して配布\r
+// しています。\r
+// SoftEther UT-VPN プロジェクトの Web サイトは http://utvpn.tsukuba.ac.jp/ に\r
+// あります。\r
+// 本ソフトウェアの不具合の修正、機能改良、セキュリティホールの修復などのコード\r
+// の改変を行った場合で、その成果物を SoftEther UT-VPN プロジェクトに提出して\r
+// いただける場合は、 http://utvpn.tsukuba.ac.jp/ までソースコードを送付して\r
+// ください。SoftEther UT-VPN プロジェクトの本体リリースまたはブランチリリース\r
+// に組み込みさせていただきます。\r
+// \r
+// GPL に基づいて原著作物が提供される本ソフトウェアの改良版を配布、販売する\r
+// 場合は、そのソースコードを GPL に基づいて誰にでも開示する義務が生じます。\r
+// \r
+// 本ソフトウェアに関連する著作権、特許権、商標権はソフトイーサ株式会社\r
+// (SoftEther Corporation) およびその他の著作権保持者が保有しています。\r
+// ソフトイーサ株式会社等はこれらの権利を放棄していません。本ソフトウェアの\r
+// 二次著作物を配布、販売する場合は、これらの権利を侵害しないようにご注意\r
+// ください。\r
+// \r
+// お願い: どのような通信ソフトウェアにも通常は必ず未発見の\r
+// セキュリティホールが潜んでいます。本ソースコードをご覧いただいた結果、\r
+// UT-VPN にセキュリティホールを発見された場合は、当該セキュリティホールの\r
+// 情報を不特定多数に開示される前に、必ず、ソフトイーサ株式会社\r
+// および脆弱性情報の届出を受け付ける公的機関まで通報いただき、\r
+// 公益保護にご協力いただきますようお願い申し上げます。\r
+// \r
+// ソフトイーサ株式会社は、当該セキュリティホールについて迅速に対処を\r
+// 行い、UT-VPN および UT-VPN に関連するソフトウェアのユーザー・顧客\r
+// を保護するための努力を行います。\r
+// \r
+// ソフトイーサへの届出先: http://www.softether.co.jp/jp/contact/\r
+// 日本国内の脆弱性情報届出受付公的機関:\r
+//         独立行政法人 情報処理推進機構\r
+//         http://www.ipa.go.jp/security/vuln/report/\r
+// \r
+// 上記各事項について不明な点は、ソフトイーサ株式会社までご連絡ください。\r
+// 連絡先: http://www.softether.co.jp/jp/contact/\r
+\r
+// -----------------------------------------------\r
+// [ChangeLog]\r
+// 2010.05.20\r
+//  新規リリース by SoftEther\r
+// -----------------------------------------------\r
+\r
+// Nat.c\r
+// User-mode Router\r
+\r
+#include "CedarPch.h"\r
+\r
+static LOCK *nat_lock = NULL;\r
+static NAT *nat = NULL;\r
+\r
+\r
+// NAT 管理者用接続を切断\r
+void NatAdminDisconnect(RPC *r)\r
+{\r
+       // 引数チェック\r
+       if (r == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       EndRpc(r);\r
+}\r
+\r
+// NAT 管理者用接続\r
+RPC *NatAdminConnect(CEDAR *cedar, char *hostname, UINT port, void *hashed_password, UINT *err)\r
+{\r
+       UCHAR secure_password[SHA1_SIZE];\r
+       UCHAR random[SHA1_SIZE];\r
+       SOCK *sock;\r
+       RPC *rpc;\r
+       PACK *p;\r
+       UINT error;\r
+       // 引数チェック\r
+       if (cedar == NULL || hostname == NULL || port == 0 || hashed_password == NULL || err == NULL)\r
+       {\r
+               if (err != NULL)\r
+               {\r
+                       *err = ERR_INTERNAL_ERROR;\r
+               }\r
+               return NULL;\r
+       }\r
+\r
+       // 接続\r
+       sock = Connect(hostname, port);\r
+       if (sock == NULL)\r
+       {\r
+               *err = ERR_CONNECT_FAILED;\r
+               return NULL;\r
+       }\r
+\r
+       if (StartSSL(sock, NULL, NULL) == false)\r
+       {\r
+               *err = ERR_PROTOCOL_ERROR;\r
+               ReleaseSock(sock);\r
+               return NULL;\r
+       }\r
+\r
+       SetTimeout(sock, 5000);\r
+\r
+       p = HttpClientRecv(sock);\r
+       if (p == NULL)\r
+       {\r
+               *err = ERR_DISCONNECTED;\r
+               ReleaseSock(sock);\r
+               return NULL;\r
+       }\r
+\r
+       if (PackGetData2(p, "auth_random", random, SHA1_SIZE) == false)\r
+       {\r
+               FreePack(p);\r
+               *err = ERR_PROTOCOL_ERROR;\r
+               ReleaseSock(sock);\r
+               return NULL;\r
+       }\r
+\r
+       FreePack(p);\r
+\r
+       SecurePassword(secure_password, hashed_password, random);\r
+\r
+       p = NewPack();\r
+       PackAddData(p, "secure_password", secure_password, SHA1_SIZE);\r
+\r
+       if (HttpClientSend(sock, p) == false)\r
+       {\r
+               FreePack(p);\r
+               *err = ERR_DISCONNECTED;\r
+               ReleaseSock(sock);\r
+               return NULL;\r
+       }\r
+\r
+       FreePack(p);\r
+\r
+       p = HttpClientRecv(sock);\r
+       if (p == NULL)\r
+       {\r
+               *err = ERR_DISCONNECTED;\r
+               ReleaseSock(sock);\r
+               return NULL;\r
+       }\r
+\r
+       error = GetErrorFromPack(p);\r
+\r
+       FreePack(p);\r
+\r
+       if (error != ERR_NO_ERROR)\r
+       {\r
+               *err = error;\r
+               ReleaseSock(sock);\r
+               return NULL;\r
+       }\r
+\r
+       SetTimeout(sock, TIMEOUT_INFINITE);\r
+\r
+       rpc = StartRpcClient(sock, NULL);\r
+       ReleaseSock(sock);\r
+\r
+       return rpc;\r
+}\r
+\r
+// RPC 関数関係マクロ\r
+#define        DECLARE_RPC_EX(rpc_name, data_type, function, in_rpc, out_rpc, free_rpc)                \\r
+       else if (StrCmpi(name, rpc_name) == 0)                                                          \\r
+       {                                                                                                                                       \\r
+               data_type t;                                                                                                    \\r
+               Zero(&t, sizeof(t));                                                                                    \\r
+               in_rpc(&t, p);                                                                                                  \\r
+               err = function(n, &t);                                                                                  \\r
+               if (err == ERR_NO_ERROR)                                                                                \\r
+               {                                                                                                                               \\r
+                       out_rpc(ret, &t);                                                                                       \\r
+               }                                                                                                                               \\r
+               free_rpc(&t);                                                                                                   \\r
+               ok = true;                                                                                                              \\r
+       }\r
+#define        DECLARE_RPC(rpc_name, data_type, function, in_rpc, out_rpc)             \\r
+       else if (StrCmpi(name, rpc_name) == 0)                                                          \\r
+       {                                                                                                                                       \\r
+               data_type t;                                                                                                    \\r
+               Zero(&t, sizeof(t));                                                                                    \\r
+               in_rpc(&t, p);                                                                                                  \\r
+               err = function(n, &t);                                                                                  \\r
+               if (err == ERR_NO_ERROR)                                                                                \\r
+               {                                                                                                                               \\r
+                       out_rpc(ret, &t);                                                                                       \\r
+               }                                                                                                                               \\r
+               ok = true;                                                                                                              \\r
+       }\r
+#define        DECLARE_SC_EX(rpc_name, data_type, function, in_rpc, out_rpc, free_rpc) \\r
+       UINT function(RPC *r, data_type *t)                                                                     \\r
+       {                                                                                                                                       \\r
+               PACK *p, *ret;                                                                                                  \\r
+               UINT err;                                                                                                               \\r
+               if (r == NULL || t == NULL)                                                                             \\r
+               {                                                                                                                               \\r
+                       return ERR_INTERNAL_ERROR;                                                                      \\r
+               }                                                                                                                               \\r
+               p = NewPack();                                                                                                  \\r
+               out_rpc(p, t);                                                                                                  \\r
+               free_rpc(t);                                                                                                    \\r
+               Zero(t, sizeof(data_type));                                                                             \\r
+               ret = AdminCall(r, rpc_name, p);                                                                \\r
+               err = GetErrorFromPack(ret);                                                                    \\r
+               if (err == ERR_NO_ERROR)                                                                                \\r
+               {                                                                                                                               \\r
+                       in_rpc(t, ret);                                                                                         \\r
+               }                                                                                                                               \\r
+               FreePack(ret);                                                                                                  \\r
+               return err;                                                                                                             \\r
+       }\r
+#define        DECLARE_SC(rpc_name, data_type, function, in_rpc, out_rpc)              \\r
+       UINT function(RPC *r, data_type *t)                                                                     \\r
+       {                                                                                                                                       \\r
+               PACK *p, *ret;                                                                                                  \\r
+               UINT err;                                                                                                               \\r
+               if (r == NULL || t == NULL)                                                                             \\r
+               {                                                                                                                               \\r
+                       return ERR_INTERNAL_ERROR;                                                                      \\r
+               }                                                                                                                               \\r
+               p = NewPack();                                                                                                  \\r
+               out_rpc(p, t);                                                                                                  \\r
+               ret = AdminCall(r, rpc_name, p);                                                                \\r
+               err = GetErrorFromPack(ret);                                                                    \\r
+               if (err == ERR_NO_ERROR)                                                                                \\r
+               {                                                                                                                               \\r
+                       in_rpc(t, ret);                                                                                         \\r
+               }                                                                                                                               \\r
+               FreePack(ret);                                                                                                  \\r
+               return err;                                                                                                             \\r
+       }\r
+\r
+// RPC サーバー関数\r
+PACK *NiRpcServer(RPC *r, char *name, PACK *p)\r
+{\r
+       NAT *n = (NAT *)r->Param;\r
+       PACK *ret;\r
+       UINT err;\r
+       bool ok;\r
+       // 引数チェック\r
+       if (r == NULL || name == NULL || p == NULL)\r
+       {\r
+               return NULL;\r
+       }\r
+\r
+       ret = NewPack();\r
+       err = ERR_NO_ERROR;\r
+       ok = false;\r
+\r
+       if (0) {}\r
+\r
+       // RPC 関数定義: ここから\r
+\r
+//     DECLARE_RPC("Online", RPC_DUMMY, NtOnline, InRpcDummy, OutRpcDummy)\r
+//     DECLARE_RPC("Offline", RPC_DUMMY, NtOffline, InRpcDummy, OutRpcDummy)\r
+       DECLARE_RPC("SetHostOption", VH_OPTION, NtSetHostOption, InVhOption, OutVhOption)\r
+       DECLARE_RPC("GetHostOption", VH_OPTION, NtGetHostOption, InVhOption, OutVhOption)\r
+//     DECLARE_RPC_EX("SetClientConfig", RPC_CREATE_LINK, NtSetClientConfig, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)\r
+//     DECLARE_RPC_EX("GetClientConfig", RPC_CREATE_LINK, NtGetClientConfig, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)\r
+       DECLARE_RPC_EX("GetStatus", RPC_NAT_STATUS, NtGetStatus, InRpcNatStatus, OutRpcNatStatus, FreeRpcNatStatus)\r
+//     DECLARE_RPC_EX("GetInfo", RPC_NAT_INFO, NtGetInfo, InRpcNatInfo, OutRpcNatInfo, FreeRpcNatInfo)\r
+       DECLARE_RPC_EX("EnumNatList", RPC_ENUM_NAT, NtEnumNatList, InRpcEnumNat, OutRpcEnumNat, FreeRpcEnumNat)\r
+       DECLARE_RPC_EX("EnumDhcpList", RPC_ENUM_DHCP, NtEnumDhcpList, InRpcEnumDhcp, OutRpcEnumDhcp, FreeRpcEnumDhcp)\r
+//     DECLARE_RPC("SetPassword", RPC_SET_PASSWORD, NtSetPassword, InRpcSetPassword, OutRpcSetPassword)\r
+\r
+       // RPC 関数定義: ここまで\r
+\r
+       if (ok == false)\r
+       {\r
+               err = ERR_NOT_SUPPORTED;\r
+       }\r
+\r
+       PackAddInt(ret, "error", err);\r
+\r
+       return ret;\r
+}\r
+\r
+\r
+\r
+\r
+// RPC 呼び出し定義ここから\r
+\r
+DECLARE_SC("Online", RPC_DUMMY, NcOnline, InRpcDummy, OutRpcDummy)\r
+DECLARE_SC("Offline", RPC_DUMMY, NcOffline, InRpcDummy, OutRpcDummy)\r
+DECLARE_SC("SetHostOption", VH_OPTION, NcSetHostOption, InVhOption, OutVhOption)\r
+DECLARE_SC("GetHostOption", VH_OPTION, NcGetHostOption, InVhOption, OutVhOption)\r
+DECLARE_SC_EX("SetClientConfig", RPC_CREATE_LINK, NcSetClientConfig, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)\r
+DECLARE_SC_EX("GetClientConfig", RPC_CREATE_LINK, NcGetClientConfig, InRpcCreateLink, OutRpcCreateLink, FreeRpcCreateLink)\r
+DECLARE_SC_EX("GetStatus", RPC_NAT_STATUS, NcGetStatus, InRpcNatStatus, OutRpcNatStatus, FreeRpcNatStatus)\r
+DECLARE_SC_EX("GetInfo", RPC_NAT_INFO, NcGetInfo, InRpcNatInfo, OutRpcNatInfo, FreeRpcNatInfo)\r
+DECLARE_SC_EX("EnumNatList", RPC_ENUM_NAT, NcEnumNatList, InRpcEnumNat, OutRpcEnumNat, FreeRpcEnumNat)\r
+DECLARE_SC_EX("EnumDhcpList", RPC_ENUM_DHCP, NcEnumDhcpList, InRpcEnumDhcp, OutRpcEnumDhcp, FreeRpcEnumDhcp)\r
+DECLARE_SC("SetPassword", RPC_SET_PASSWORD, NcSetPassword, InRpcSetPassword, OutRpcSetPassword)\r
+\r
+// RPC 呼び出し定義ここまで\r
+\r
+\r
+\r
+// パスワードを設定する\r
+UINT NtSetPassword(NAT *n, RPC_SET_PASSWORD *t)\r
+{\r
+       Copy(n->HashedPassword, t->HashedPassword, SHA1_SIZE);\r
+\r
+       NiWriteConfig(n);\r
+\r
+       return ERR_NO_ERROR;\r
+}\r
+\r
+// オンラインにする\r
+UINT NtOnline(NAT *n, RPC_DUMMY *t)\r
+{\r
+       UINT ret = ERR_NO_ERROR;\r
+\r
+       Lock(n->lock);\r
+       {\r
+               if (n->Online)\r
+               {\r
+                       // すでにオンラインである\r
+                       ret = ERR_ALREADY_ONLINE;\r
+               }\r
+               else\r
+               {\r
+                       if (n->ClientOption == NULL || n->ClientAuth == NULL)\r
+                       {\r
+                               // 設定がまだ\r
+                               ret = ERR_ACCOUNT_NOT_PRESENT;\r
+                       }\r
+                       else\r
+                       {\r
+                               // OK\r
+                               n->Online = true;\r
+\r
+                               // 接続開始\r
+                               n->Virtual = NewVirtualHostEx(n->Cedar, n->ClientOption, n->ClientAuth,\r
+                                       &n->Option, n);\r
+                       }\r
+               }\r
+       }\r
+       Unlock(n->lock);\r
+\r
+       NiWriteConfig(n);\r
+\r
+       return ret;\r
+}\r
+\r
+// オフラインにする\r
+UINT NtOffline(NAT *n, RPC_DUMMY *t)\r
+{\r
+       UINT ret = ERR_NO_ERROR;\r
+\r
+       Lock(n->lock);\r
+       {\r
+               if (n->Online == false)\r
+               {\r
+                       // オフラインである\r
+                       ret = ERR_OFFLINE;\r
+               }\r
+               else\r
+               {\r
+                       // オフラインにする\r
+                       StopVirtualHost(n->Virtual);\r
+                       ReleaseVirtual(n->Virtual);\r
+                       n->Virtual = NULL;\r
+\r
+                       n->Online = false;\r
+               }\r
+       }\r
+       Unlock(n->lock);\r
+\r
+       NiWriteConfig(n);\r
+\r
+       return ret;\r
+}\r
+\r
+// ホストオプションの設定\r
+UINT NtSetHostOption(NAT *n, VH_OPTION *t)\r
+{\r
+       UINT ret = ERR_NO_ERROR;\r
+\r
+       Lock(n->lock);\r
+       {\r
+               Copy(&n->Option, t, sizeof(VH_OPTION));\r
+       }\r
+       Unlock(n->lock);\r
+\r
+       SetVirtualHostOption(n->Virtual, t);\r
+\r
+       NiWriteConfig(n);\r
+\r
+       return ret;\r
+}\r
+\r
+// ホストオプションの取得\r
+UINT NtGetHostOption(NAT *n, VH_OPTION *t)\r
+{\r
+       UINT ret = ERR_NO_ERROR;\r
+\r
+       Lock(n->lock);\r
+       {\r
+               Copy(t, &n->Option, sizeof(VH_OPTION));\r
+       }\r
+       Unlock(n->lock);\r
+\r
+       return ret;\r
+}\r
+\r
+// 接続設定の設定\r
+UINT NtSetClientConfig(NAT *n, RPC_CREATE_LINK *t)\r
+{\r
+       Lock(n->lock);\r
+       {\r
+               if (n->ClientOption != NULL || n->ClientAuth != NULL)\r
+               {\r
+                       Free(n->ClientOption);\r
+                       CiFreeClientAuth(n->ClientAuth);\r
+               }\r
+\r
+               n->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));\r
+               Copy(n->ClientOption, t->ClientOption, sizeof(CLIENT_OPTION));\r
+               n->ClientAuth = CopyClientAuth(t->ClientAuth);\r
+       }\r
+       Unlock(n->lock);\r
+\r
+       NiWriteConfig(n);\r
+\r
+       if (n->Online)\r
+       {\r
+               NtOffline(n, NULL);\r
+               NtOnline(n, NULL);\r
+       }\r
+\r
+       return ERR_NO_ERROR;\r
+}\r
+\r
+// 接続設定の取得\r
+UINT NtGetClientConfig(NAT *n, RPC_CREATE_LINK *t)\r
+{\r
+       UINT err = ERR_NO_ERROR;\r
+\r
+       Lock(n->lock);\r
+       {\r
+               if (n->ClientOption == NULL || n->ClientAuth == NULL)\r
+               {\r
+                       err = ERR_ACCOUNT_NOT_PRESENT;\r
+               }\r
+               else\r
+               {\r
+                       FreeRpcCreateLink(t);\r
+\r
+                       Zero(t, sizeof(RPC_CREATE_LINK));\r
+                       t->ClientOption = ZeroMalloc(sizeof(CLIENT_OPTION));\r
+                       Copy(t->ClientOption, n->ClientOption, sizeof(CLIENT_OPTION));\r
+                       t->ClientAuth = CopyClientAuth(n->ClientAuth);\r
+               }\r
+       }\r
+       Unlock(n->lock);\r
+\r
+       return err;\r
+}\r
+\r
+// 状態の取得\r
+UINT NtGetStatus(NAT *n, RPC_NAT_STATUS *t)\r
+{\r
+       Lock(n->lock);\r
+       {\r
+               VH *v = n->Virtual;\r
+               FreeRpcNatStatus(t);\r
+               Zero(t, sizeof(RPC_NAT_STATUS));\r
+\r
+               LockVirtual(v);\r
+               {\r
+                       UINT i;\r
+\r
+                       LockList(v->NatTable);\r
+                       {\r
+                               for (i = 0;i < LIST_NUM(v->NatTable);i++)\r
+                               {\r
+                                       NAT_ENTRY *e = LIST_DATA(v->NatTable, i);\r
+\r
+                                       switch (e->Protocol)\r
+                                       {\r
+                                       case NAT_TCP:\r
+                                               t->NumTcpSessions++;\r
+                                               break;\r
+\r
+                                       case NAT_UDP:\r
+                                               t->NumUdpSessions++;\r
+                                               break;\r
+                                       }\r
+                               }\r
+                       }\r
+                       UnlockList(v->NatTable);\r
+\r
+                       t->NumDhcpClients = LIST_NUM(v->DhcpLeaseList);\r
+               }\r
+               UnlockVirtual(v);\r
+       }\r
+       Unlock(n->lock);\r
+\r
+       return ERR_NO_ERROR;\r
+}\r
+\r
+// 情報の取得\r
+UINT NtGetInfo(NAT *n, RPC_NAT_INFO *t)\r
+{\r
+       OS_INFO *info;\r
+       FreeRpcNatInfo(t);\r
+       Zero(t, sizeof(RPC_NAT_INFO));\r
+\r
+       StrCpy(t->NatProductName, sizeof(t->NatProductName), CEDAR_ROUTER_STR);\r
+       StrCpy(t->NatVersionString, sizeof(t->NatVersionString), n->Cedar->VerString);\r
+       StrCpy(t->NatBuildInfoString, sizeof(t->NatBuildInfoString), n->Cedar->BuildInfo);\r
+       t->NatVerInt = n->Cedar->Build;\r
+       t->NatBuildInt = n->Cedar->Build;\r
+\r
+       GetMachineName(t->NatHostName, sizeof(t->NatHostName));\r
+\r
+       info = GetOsInfo();\r
+\r
+       CopyOsInfo(&t->OsInfo, info);\r
+\r
+       GetMemInfo(&t->MemInfo);\r
+\r
+       return ERR_NO_ERROR;\r
+}\r
+\r
+// NAT リストの取得\r
+UINT NtEnumNatList(NAT *n, RPC_ENUM_NAT *t)\r
+{\r
+       UINT ret = ERR_NO_ERROR;\r
+       VH *v = NULL;\r
+\r
+       Lock(n->lock);\r
+       {\r
+               v = n->Virtual;\r
+\r
+               if (n->Online == false || v == NULL)\r
+               {\r
+                       ret = ERR_OFFLINE;\r
+               }\r
+               else\r
+               {\r
+                       LockVirtual(v);\r
+                       {\r
+                               if (v->Active == false)\r
+                               {\r
+                                       ret = ERR_OFFLINE;\r
+                               }\r
+                               else\r
+                               {\r
+                                       FreeRpcEnumNat(t);\r
+                                       Zero(t, sizeof(RPC_ENUM_NAT));\r
+\r
+                                       LockList(v->NatTable);\r
+                                       {\r
+                                               UINT i;\r
+                                               t->NumItem = LIST_NUM(v->NatTable);\r
+                                               t->Items = ZeroMalloc(sizeof(RPC_ENUM_NAT_ITEM) * t->NumItem);\r
+\r
+                                               for (i = 0;i < t->NumItem;i++)\r
+                                               {\r
+                                                       NAT_ENTRY *nat = LIST_DATA(v->NatTable, i);\r
+                                                       RPC_ENUM_NAT_ITEM *e = &t->Items[i];\r
+\r
+                                                       e->Id = nat->Id;\r
+                                                       e->Protocol = nat->Protocol;\r
+                                                       e->SrcIp = nat->SrcIp;\r
+                                                       e->DestIp = nat->DestIp;\r
+                                                       e->SrcPort = nat->SrcPort;\r
+                                                       e->DestPort = nat->DestPort;\r
+\r
+                                                       e->CreatedTime = TickToTime(nat->CreatedTime);\r
+                                                       e->LastCommTime = TickToTime(nat->LastCommTime);\r
+\r
+                                                       IPToStr32(e->SrcHost, sizeof(e->SrcHost), e->SrcIp);\r
+                                                       IPToStr32(e->DestHost, sizeof(e->DestHost), e->DestIp);\r
+\r
+                                                       if (nat->Sock != NULL)\r
+                                                       {\r
+                                                               e->SendSize = nat->Sock->SendSize;\r
+                                                               e->RecvSize = nat->Sock->RecvSize;\r
+\r
+                                                               if (nat->Sock->Type == SOCK_TCP)\r
+                                                               {\r
+                                                                       StrCpy(e->DestHost, sizeof(e->DestHost), nat->Sock->RemoteHostname);\r
+                                                               }\r
+                                                       }\r
+\r
+                                                       e->TcpStatus = nat->TcpStatus;\r
+                                               }\r
+                                       }\r
+                                       UnlockList(v->NatTable);\r
+                               }\r
+                       }\r
+                       UnlockVirtual(v);\r
+               }\r
+       }\r
+       Unlock(n->lock);\r
+\r
+       return ret;\r
+}\r
+\r
+UINT NtEnumDhcpList(NAT *n, RPC_ENUM_DHCP *t)\r
+{\r
+       UINT ret = ERR_NO_ERROR;\r
+       VH *v = NULL;\r
+\r
+       Lock(n->lock);\r
+       {\r
+               v = n->Virtual;\r
+\r
+               if (n->Online == false || v == NULL)\r
+               {\r
+                       ret = ERR_OFFLINE;\r
+               }\r
+               else\r
+               {\r
+                       LockVirtual(v);\r
+                       {\r
+                               if (v->Active == false)\r
+                               {\r
+                                       ret = ERR_OFFLINE;\r
+                               }\r
+                               else\r
+                               {\r
+                                       FreeRpcEnumDhcp(t);\r
+                                       Zero(t, sizeof(RPC_ENUM_DHCP));\r
+\r
+                                       LockList(v->DhcpLeaseList);\r
+                                       {\r
+                                               UINT i;\r
+                                               t->NumItem = LIST_NUM(v->DhcpLeaseList);\r
+                                               t->Items = ZeroMalloc(sizeof(RPC_ENUM_DHCP_ITEM) * t->NumItem);\r
+\r
+                                               for (i = 0;i < t->NumItem;i++)\r
+                                               {\r
+                                                       DHCP_LEASE *dhcp = LIST_DATA(v->DhcpLeaseList, i);\r
+                                                       RPC_ENUM_DHCP_ITEM *e = &t->Items[i];\r
+\r
+                                                       e->Id = dhcp->Id;\r
+                                                       e->LeasedTime = TickToTime(dhcp->LeasedTime);\r
+                                                       e->ExpireTime = TickToTime(dhcp->ExpireTime);\r
+                                                       Copy(e->MacAddress, dhcp->MacAddress, 6);\r
+                                                       e->IpAddress = dhcp->IpAddress;\r
+                                                       e->Mask = dhcp->Mask;\r
+                                                       StrCpy(e->Hostname, sizeof(e->Hostname), dhcp->Hostname);\r
+                                               }\r
+                                       }\r
+                                       UnlockList(v->DhcpLeaseList);\r
+                               }\r
+                       }\r
+                       UnlockVirtual(v);\r
+               }\r
+       }\r
+       Unlock(n->lock);\r
+\r
+       return ret;\r
+}\r
+\r
+// VH_OPTION\r
+void InVhOption(VH_OPTION *t, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (t == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(t, sizeof(VH_OPTION));\r
+       PackGetData2(p, "MacAddress", t->MacAddress, 6);\r
+       PackGetIp(p, "Ip", &t->Ip);\r
+       PackGetIp(p, "Mask", &t->Mask);\r
+       t->UseNat = PackGetBool(p, "UseNat");\r
+       t->Mtu = PackGetInt(p, "Mtu");\r
+       t->NatTcpTimeout = PackGetInt(p, "NatTcpTimeout");\r
+       t->NatUdpTimeout = PackGetInt(p, "NatUdpTimeout");\r
+       t->UseDhcp = PackGetBool(p, "UseDhcp");\r
+       PackGetIp(p, "DhcpLeaseIPStart", &t->DhcpLeaseIPStart);\r
+       PackGetIp(p, "DhcpLeaseIPEnd", &t->DhcpLeaseIPEnd);\r
+       PackGetIp(p, "DhcpSubnetMask", &t->DhcpSubnetMask);\r
+       t->DhcpExpireTimeSpan = PackGetInt(p, "DhcpExpireTimeSpan");\r
+       PackGetIp(p, "DhcpGatewayAddress", &t->DhcpGatewayAddress);\r
+       PackGetIp(p, "DhcpDnsServerAddress", &t->DhcpDnsServerAddress);\r
+       PackGetStr(p, "DhcpDomainName", t->DhcpDomainName, sizeof(t->DhcpDomainName));\r
+       t->SaveLog = PackGetBool(p, "SaveLog");\r
+       PackGetStr(p, "RpcHubName", t->HubName, sizeof(t->HubName));\r
+}\r
+void OutVhOption(PACK *p, VH_OPTION *t)\r
+{\r
+       // 引数チェック\r
+       if (t == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddData(p, "MacAddress", t->MacAddress, 6);\r
+       PackAddIp(p, "Ip", &t->Ip);\r
+       PackAddIp(p, "Mask", &t->Mask);\r
+       PackAddBool(p, "UseNat", t->UseNat);\r
+       PackAddInt(p, "Mtu", t->Mtu);\r
+       PackAddInt(p, "NatTcpTimeout", t->NatTcpTimeout);\r
+       PackAddInt(p, "NatUdpTimeout", t->NatUdpTimeout);\r
+       PackAddBool(p, "UseDhcp", t->UseDhcp);\r
+       PackAddIp(p, "DhcpLeaseIPStart", &t->DhcpLeaseIPStart);\r
+       PackAddIp(p, "DhcpLeaseIPEnd", &t->DhcpLeaseIPEnd);\r
+       PackAddIp(p, "DhcpSubnetMask", &t->DhcpSubnetMask);\r
+       PackAddInt(p, "DhcpExpireTimeSpan", t->DhcpExpireTimeSpan);\r
+       PackAddIp(p, "DhcpGatewayAddress", &t->DhcpGatewayAddress);\r
+       PackAddIp(p, "DhcpDnsServerAddress", &t->DhcpDnsServerAddress);\r
+       PackAddStr(p, "DhcpDomainName", t->DhcpDomainName);\r
+       PackAddBool(p, "SaveLog", t->SaveLog);\r
+       PackAddStr(p, "RpcHubName", t->HubName);\r
+}\r
+\r
+// RPC_ENUM_DHCP\r
+void InRpcEnumDhcp(RPC_ENUM_DHCP *t, PACK *p)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (t == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(t, sizeof(RPC_ENUM_DHCP));\r
+       t->NumItem = PackGetInt(p, "NumItem");\r
+       t->Items = ZeroMalloc(sizeof(RPC_ENUM_DHCP_ITEM) * t->NumItem);\r
+       PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));\r
+\r
+       for (i = 0;i < t->NumItem;i++)\r
+       {\r
+               RPC_ENUM_DHCP_ITEM *e = &t->Items[i];\r
+\r
+               e->Id = PackGetIntEx(p, "Id", i);\r
+               e->LeasedTime = PackGetInt64Ex(p, "LeasedTime", i);\r
+               e->ExpireTime = PackGetInt64Ex(p, "ExpireTime", i);\r
+               PackGetDataEx2(p, "MacAddress", e->MacAddress, 6, i);\r
+               e->IpAddress = PackGetIp32Ex(p, "IpAddress", i);\r
+               e->Mask = PackGetIntEx(p, "Mask", i);\r
+               PackGetStrEx(p, "Hostname", e->Hostname, sizeof(e->Hostname), i);\r
+       }\r
+}\r
+void OutRpcEnumDhcp(PACK *p, RPC_ENUM_DHCP *t)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (p == NULL || t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddInt(p, "NumItem", t->NumItem);\r
+       PackAddStr(p, "HubName", t->HubName);\r
+\r
+       for (i = 0;i < t->NumItem;i++)\r
+       {\r
+               RPC_ENUM_DHCP_ITEM *e = &t->Items[i];\r
+\r
+               PackAddIntEx(p, "Id", e->Id, i, t->NumItem);\r
+               PackAddInt64Ex(p, "LeasedTime", e->LeasedTime, i, t->NumItem);\r
+               PackAddInt64Ex(p, "ExpireTime", e->ExpireTime, i, t->NumItem);\r
+               PackAddDataEx(p, "MacAddress", e->MacAddress, 6, i, t->NumItem);\r
+               PackAddIp32Ex(p, "IpAddress", e->IpAddress, i, t->NumItem);\r
+               PackAddIntEx(p, "Mask", e->Mask, i, t->NumItem);\r
+               PackAddStrEx(p, "Hostname", e->Hostname, i, t->NumItem);\r
+       }\r
+}\r
+void FreeRpcEnumDhcp(RPC_ENUM_DHCP *t)\r
+{\r
+       // 引数チェック\r
+       if (t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Free(t->Items);\r
+}\r
+\r
+// RPC_ENUM_NAT\r
+void InRpcEnumNat(RPC_ENUM_NAT *t, PACK *p)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (t == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(t, sizeof(RPC_ENUM_NAT));\r
+       t->NumItem = PackGetInt(p, "NumItem");\r
+       PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));\r
+       t->Items = ZeroMalloc(sizeof(RPC_ENUM_NAT_ITEM) * t->NumItem);\r
+       for (i = 0;i < t->NumItem;i++)\r
+       {\r
+               RPC_ENUM_NAT_ITEM *e = &t->Items[i];\r
+\r
+               e->Id = PackGetIntEx(p, "Id", i);\r
+               e->Protocol = PackGetIntEx(p, "Protocol", i);\r
+               e->SrcIp = PackGetIntEx(p, "SrcIp", i);\r
+               PackGetStrEx(p, "SrcHost", e->SrcHost, sizeof(e->SrcHost), i);\r
+               e->SrcPort = PackGetIntEx(p, "SrcPort", i);\r
+               e->DestIp = PackGetIntEx(p, "DestIp", i);\r
+               PackGetStrEx(p, "DestHost", e->DestHost, sizeof(e->DestHost), i);\r
+               e->DestPort = PackGetIntEx(p, "DestPort", i);\r
+               e->CreatedTime = PackGetInt64Ex(p, "CreatedTime", i);\r
+               e->LastCommTime = PackGetInt64Ex(p, "LastCommTime", i);\r
+               e->SendSize = PackGetInt64Ex(p, "SendSize", i);\r
+               e->RecvSize = PackGetInt64Ex(p, "RecvSize", i);\r
+               e->TcpStatus = PackGetIntEx(p, "TcpStatus", i);\r
+       }\r
+}\r
+void OutRpcEnumNat(PACK *p, RPC_ENUM_NAT *t)\r
+{\r
+       UINT i;\r
+       // 引数チェック\r
+       if (t == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddInt(p, "NumItem", t->NumItem);\r
+       PackAddStr(p, "HubName", t->HubName);\r
+       for (i = 0;i < t->NumItem;i++)\r
+       {\r
+               RPC_ENUM_NAT_ITEM *e = &t->Items[i];\r
+\r
+               PackAddIntEx(p, "Id", e->Id, i, t->NumItem);\r
+               PackAddIntEx(p, "Protocol", e->Protocol, i, t->NumItem);\r
+               PackAddIp32Ex(p, "SrcIp", e->SrcIp, i, t->NumItem);\r
+               PackAddStrEx(p, "SrcHost", e->SrcHost, i, t->NumItem);\r
+               PackAddIntEx(p, "SrcPort", e->SrcPort, i, t->NumItem);\r
+               PackAddIp32Ex(p, "DestIp", e->DestIp, i, t->NumItem);\r
+               PackAddStrEx(p, "DestHost", e->DestHost, i, t->NumItem);\r
+               PackAddIntEx(p, "DestPort", e->DestPort, i, t->NumItem);\r
+               PackAddInt64Ex(p, "CreatedTime", e->CreatedTime, i, t->NumItem);\r
+               PackAddInt64Ex(p, "LastCommTime", e->LastCommTime, i, t->NumItem);\r
+               PackAddInt64Ex(p, "SendSize", e->SendSize, i, t->NumItem);\r
+               PackAddInt64Ex(p, "RecvSize", e->RecvSize, i, t->NumItem);\r
+               PackAddIntEx(p, "TcpStatus", e->TcpStatus, i, t->NumItem);\r
+       }\r
+}\r
+void FreeRpcEnumNat(RPC_ENUM_NAT *t)\r
+{\r
+       // 引数チェック\r
+       if (t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Free(t->Items);\r
+}\r
+\r
+// RPC_NAT_INFO\r
+void InRpcNatInfo(RPC_NAT_INFO *t, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (t == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(t, sizeof(RPC_NAT_INFO));\r
+       PackGetStr(p, "NatProductName", t->NatProductName, sizeof(t->NatProductName));\r
+       PackGetStr(p, "NatVersionString", t->NatVersionString, sizeof(t->NatVersionString));\r
+       PackGetStr(p, "NatBuildInfoString", t->NatBuildInfoString, sizeof(t->NatBuildInfoString));\r
+       t->NatVerInt = PackGetInt(p, "NatVerInt");\r
+       t->NatBuildInt = PackGetInt(p, "NatBuildInt");\r
+       PackGetStr(p, "NatHostName", t->NatHostName, sizeof(t->NatHostName));\r
+       InRpcOsInfo(&t->OsInfo, p);\r
+       InRpcMemInfo(&t->MemInfo, p);\r
+}\r
+void OutRpcNatInfo(PACK *p, RPC_NAT_INFO *t)\r
+{\r
+       // 引数チェック\r
+       if (t == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddStr(p, "NatProductName", t->NatProductName);\r
+       PackAddStr(p, "NatVersionString", t->NatVersionString);\r
+       PackAddStr(p, "NatBuildInfoString", t->NatBuildInfoString);\r
+       PackAddInt(p, "NatVerInt", t->NatVerInt);\r
+       PackAddInt(p, "NatBuildInt", t->NatBuildInt);\r
+       PackAddStr(p, "NatHostName", t->NatHostName);\r
+       OutRpcOsInfo(p, &t->OsInfo);\r
+       OutRpcMemInfo(p, &t->MemInfo);\r
+}\r
+void FreeRpcNatInfo(RPC_NAT_INFO *t)\r
+{\r
+       // 引数チェック\r
+       if (t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       FreeRpcOsInfo(&t->OsInfo);\r
+}\r
+\r
+// RPC_NAT_STATUS\r
+void InRpcNatStatus(RPC_NAT_STATUS *t, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (t == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(t, sizeof(RPC_NAT_STATUS));\r
+       t->NumTcpSessions = PackGetInt(p, "NumTcpSessions");\r
+       t->NumUdpSessions = PackGetInt(p, "NumUdpSessions");\r
+       t->NumDhcpClients = PackGetInt(p, "NumDhcpClients");\r
+       PackGetStr(p, "HubName", t->HubName, sizeof(t->HubName));\r
+}\r
+void OutRpcNatStatus(PACK *p, RPC_NAT_STATUS *t)\r
+{\r
+       // 引数チェック\r
+       if (p == NULL || t == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddStr(p, "HubName", t->HubName);\r
+       PackAddInt(p, "NumTcpSessions", t->NumTcpSessions);\r
+       PackAddInt(p, "NumUdpSessions", t->NumUdpSessions);\r
+       PackAddInt(p, "NumDhcpClients", t->NumDhcpClients);\r
+}\r
+void FreeRpcNatStatus(RPC_NAT_STATUS *t)\r
+{\r
+}\r
+\r
+// RPC_DUMMY\r
+void InRpcDummy(RPC_DUMMY *t, PACK *p)\r
+{\r
+       // 引数チェック\r
+       if (t == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(t, sizeof(RPC_DUMMY));\r
+       t->DummyValue = PackGetInt(p, "DummyValue");\r
+}\r
+void OutRpcDummy(PACK *p, RPC_DUMMY *t)\r
+{\r
+       // 引数チェック\r
+       if (t == NULL || p == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       PackAddInt(p, "DummyValue", t->DummyValue);\r
+}\r
+\r
+// 管理用メインプロシージャ\r
+void NiAdminMain(NAT *n, SOCK *s)\r
+{\r
+       RPC *r;\r
+       PACK *p;\r
+       // 引数チェック\r
+       if (n == NULL || s == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       p = NewPack();\r
+       HttpServerSend(s, p);\r
+       FreePack(p);\r
+\r
+       r = StartRpcServer(s, NiRpcServer, n);\r
+\r
+       RpcServer(r);\r
+\r
+       RpcFree(r);\r
+}\r
+\r
+// 管理スレッド\r
+void NiAdminThread(THREAD *thread, void *param)\r
+{\r
+       NAT_ADMIN *a = (NAT_ADMIN *)param;\r
+       NAT *n;\r
+       SOCK *s;\r
+       UCHAR random[SHA1_SIZE];\r
+       UINT err;\r
+       // 引数チェック\r
+       if (thread == NULL || param == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // 乱数生成\r
+       Rand(random, sizeof(random));\r
+\r
+       a->Thread = thread;\r
+       AddRef(a->Thread->ref);\r
+       s = a->Sock;\r
+       AddRef(s->ref);\r
+\r
+       n = a->Nat;\r
+\r
+       LockList(n->AdminList);\r
+       {\r
+               Add(n->AdminList, a);\r
+       }\r
+       UnlockList(n->AdminList);\r
+\r
+       NoticeThreadInit(thread);\r
+\r
+       err = ERR_AUTH_FAILED;\r
+\r
+       if (StartSSL(s, n->AdminX, n->AdminK))\r
+       {\r
+               PACK *p;\r
+\r
+               // 乱数を送信する\r
+               p = NewPack();\r
+               PackAddData(p, "auth_random", random, sizeof(random));\r
+\r
+               if (HttpServerSend(s, p))\r
+               {\r
+                       PACK *p;\r
+                       // パスワードを受け取る\r
+                       p = HttpServerRecv(s);\r
+                       if (p != NULL)\r
+                       {\r
+                               UCHAR secure_password[SHA1_SIZE];\r
+                               UCHAR secure_check[SHA1_SIZE];\r
+\r
+                               if (PackGetData2(p, "secure_password", secure_password, sizeof(secure_password)))\r
+                               {\r
+                                       SecurePassword(secure_check, n->HashedPassword, random);\r
+\r
+                                       if (Cmp(secure_check, secure_password, SHA1_SIZE) == 0)\r
+                                       {\r
+                                               UCHAR test[SHA1_SIZE];\r
+                                               // パスワード一致\r
+                                               Hash(test, "", 0, true);\r
+                                               SecurePassword(test, test, random);\r
+\r
+#if    0\r
+                                               if (Cmp(test, secure_check, SHA1_SIZE) == 0 && s->RemoteIP.addr[0] != 127)\r
+                                               {\r
+                                                       // 空白パスワードは外部から接続できない\r
+                                                       err = ERR_NULL_PASSWORD_LOCAL_ONLY;\r
+                                               }\r
+                                               else\r
+#endif\r
+\r
+                                               {\r
+                                                       // 接続成功\r
+                                                       err = ERR_NO_ERROR;\r
+                                                       NiAdminMain(n, s);\r
+                                               }\r
+                                       }\r
+                               }\r
+\r
+                               FreePack(p);\r
+                       }\r
+               }\r
+\r
+               FreePack(p);\r
+\r
+               if (err != ERR_NO_ERROR)\r
+               {\r
+                       p = PackError(err);\r
+                       HttpServerSend(s, p);\r
+                       FreePack(p);\r
+               }\r
+       }\r
+\r
+       Disconnect(s);\r
+       ReleaseSock(s);\r
+}\r
+\r
+// 管理ポート Listen スレッド\r
+void NiListenThread(THREAD *thread, void *param)\r
+{\r
+       NAT *n = (NAT *)param;\r
+       SOCK *a;\r
+       UINT i;\r
+       bool b = false;\r
+       // 引数チェック\r
+       if (thread == NULL || param == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // 管理リストの初期化\r
+       n->AdminList = NewList(NULL);\r
+\r
+       while (true)\r
+       {\r
+               a = Listen(DEFAULT_NAT_ADMIN_PORT);\r
+               if (b == false)\r
+               {\r
+                       b = true;\r
+                       NoticeThreadInit(thread);\r
+               }\r
+               if (a != NULL)\r
+               {\r
+                       break;\r
+               }\r
+\r
+               Wait(n->HaltEvent, NAT_ADMIN_PORT_LISTEN_INTERVAL);\r
+               if (n->Halt)\r
+               {\r
+                       return;\r
+               }\r
+       }\r
+\r
+       n->AdminListenSock = a;\r
+       AddRef(a->ref);\r
+\r
+       // 待ち受け\r
+       while (true)\r
+       {\r
+               SOCK *s = Accept(a);\r
+               THREAD *t;\r
+               NAT_ADMIN *admin;\r
+               if (s == NULL)\r
+               {\r
+                       break;\r
+               }\r
+               if (n->Halt)\r
+               {\r
+                       ReleaseSock(s);\r
+                       break;\r
+               }\r
+\r
+               admin = ZeroMalloc(sizeof(NAT_ADMIN));\r
+               admin->Nat = n;\r
+               admin->Sock = s;\r
+               t = NewThread(NiAdminThread, admin);\r
+               WaitThreadInit(t);\r
+               ReleaseThread(t);\r
+       }\r
+\r
+       // すべての管理コネクションを切断\r
+       LockList(n->AdminList);\r
+       {\r
+               for (i = 0;i < LIST_NUM(n->AdminList);i++)\r
+               {\r
+                       NAT_ADMIN *a = LIST_DATA(n->AdminList, i);\r
+                       Disconnect(a->Sock);\r
+                       WaitThread(a->Thread, INFINITE);\r
+                       ReleaseThread(a->Thread);\r
+                       ReleaseSock(a->Sock);\r
+                       Free(a);\r
+               }\r
+       }\r
+       UnlockList(n->AdminList);\r
+\r
+       ReleaseList(n->AdminList);\r
+\r
+       ReleaseSock(a);\r
+}\r
+\r
+// 管理コマンド受付初期化\r
+void NiInitAdminAccept(NAT *n)\r
+{\r
+       THREAD *t;\r
+       // 引数チェック\r
+       if (n == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       t = NewThread(NiListenThread, n);\r
+       WaitThreadInit(t);\r
+       n->AdminAcceptThread = t;\r
+}\r
+\r
+// 管理コマンド受付終了\r
+void NiFreeAdminAccept(NAT *n)\r
+{\r
+       // 引数チェック\r
+       if (n == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       n->Halt = true;\r
+       Disconnect(n->AdminListenSock);\r
+       Set(n->HaltEvent);\r
+\r
+       while (true)\r
+       {\r
+               if (WaitThread(n->AdminAcceptThread, 1000) == false)\r
+               {\r
+                       Disconnect(n->AdminListenSock);\r
+               }\r
+               else\r
+               {\r
+                       break;\r
+               }\r
+       }\r
+       ReleaseThread(n->AdminAcceptThread);\r
+\r
+       ReleaseSock(n->AdminListenSock);\r
+}\r
+\r
+// ダイナミック仮想 HUB でサポートされていない DHCP オプションをクリアする\r
+void NiClearUnsupportedVhOptionForDynamicHub(VH_OPTION *o, bool initial)\r
+{\r
+       // 引数チェック\r
+       if (o == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       o->UseNat = false;\r
+\r
+       if (initial)\r
+       {\r
+               Zero(&o->DhcpGatewayAddress, sizeof(IP));\r
+               Zero(&o->DhcpDnsServerAddress, sizeof(IP));\r
+               StrCpy(o->DhcpDomainName, sizeof(o->DhcpDomainName), "");\r
+       }\r
+}\r
+\r
+// 仮想ホストのオプションを初期化する\r
+void NiSetDefaultVhOption(NAT *n, VH_OPTION *o)\r
+{\r
+       // 引数チェック\r
+       if (o == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Zero(o, sizeof(VH_OPTION));\r
+       GenMacAddress(o->MacAddress);\r
+\r
+       // 仮想 IP を 192.168.30.1/24 にする\r
+       SetIP(&o->Ip, 192, 168, 30, 1);\r
+       SetIP(&o->Mask, 255, 255, 255, 0);\r
+       o->UseNat = true;\r
+       o->Mtu = 1500;\r
+       o->NatTcpTimeout = 7200;\r
+       o->NatUdpTimeout = 60;\r
+       o->UseDhcp = true;\r
+       SetIP(&o->DhcpLeaseIPStart, 192, 168, 30, 10);\r
+       SetIP(&o->DhcpLeaseIPEnd, 192, 168, 30, 200);\r
+       SetIP(&o->DhcpSubnetMask, 255, 255, 255, 0);\r
+       o->DhcpExpireTimeSpan = 7200;\r
+       o->SaveLog = true;\r
+\r
+       SetIP(&o->DhcpGatewayAddress, 192, 168, 30, 1);\r
+       SetIP(&o->DhcpDnsServerAddress, 192, 168, 30, 1);\r
+\r
+       GetDomainName(o->DhcpDomainName, sizeof(o->DhcpDomainName));\r
+}\r
+\r
+// NAT の設定を初期状態にする\r
+void NiInitDefaultConfig(NAT *n)\r
+{\r
+       // 引数チェック\r
+       if (n == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // 仮想ホストオプション初期化\r
+       NiSetDefaultVhOption(n, &n->Option);\r
+\r
+       // 管理用ポート初期化\r
+       n->AdminPort = DEFAULT_NAT_ADMIN_PORT;\r
+\r
+       // オフライン\r
+       n->Online = false;\r
+\r
+       // ログを保存\r
+       n->Option.SaveLog = true;\r
+}\r
+\r
+// NAT の設定の初期化\r
+void NiInitConfig(NAT *n)\r
+{\r
+       // 引数チェック\r
+       if (n == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // 初期状態\r
+       NiInitDefaultConfig(n);\r
+}\r
+\r
+// 仮想ホストオプションの読み込み (拡張)\r
+void NiLoadVhOptionEx(VH_OPTION *o, FOLDER *root)\r
+{\r
+       FOLDER *host, *nat, *dhcp;\r
+       char mac_address[MAX_SIZE];\r
+       // 引数チェック\r
+       if (o == NULL || root == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       host = CfgGetFolder(root, "VirtualHost");\r
+       nat = CfgGetFolder(root, "VirtualRouter");\r
+       dhcp = CfgGetFolder(root, "VirtualDhcpServer");\r
+\r
+       Zero(o, sizeof(VH_OPTION));\r
+\r
+       GenMacAddress(o->MacAddress);\r
+       if (CfgGetStr(host, "VirtualHostMacAddress", mac_address, sizeof(mac_address)))\r
+       {\r
+               BUF *b = StrToBin(mac_address);\r
+               if (b != NULL)\r
+               {\r
+                       if (b->Size == 6)\r
+                       {\r
+                               Copy(o->MacAddress, b->Buf, 6);\r
+                       }\r
+               }\r
+               FreeBuf(b);\r
+       }\r
+       CfgGetIp(host, "VirtualHostIp", &o->Ip);\r
+       CfgGetIp(host, "VirtualHostIpSubnetMask", &o->Mask);\r
+\r
+       o->UseNat = CfgGetBool(nat, "NatEnabled");\r
+       o->Mtu = CfgGetInt(nat, "NatMtu");\r
+       o->NatTcpTimeout = CfgGetInt(nat, "NatTcpTimeout");\r
+       o->NatUdpTimeout = CfgGetInt(nat, "NatUdpTimeout");\r
+\r
+       o->UseDhcp = CfgGetBool(dhcp, "DhcpEnabled");\r
+       CfgGetIp(dhcp, "DhcpLeaseIPStart", &o->DhcpLeaseIPStart);\r
+       CfgGetIp(dhcp, "DhcpLeaseIPEnd", &o->DhcpLeaseIPEnd);\r
+       CfgGetIp(dhcp, "DhcpSubnetMask", &o->DhcpSubnetMask);\r
+       o->DhcpExpireTimeSpan = CfgGetInt(dhcp, "DhcpExpireTimeSpan");\r
+       CfgGetIp(dhcp, "DhcpGatewayAddress", &o->DhcpGatewayAddress);\r
+       CfgGetIp(dhcp, "DhcpDnsServerAddress", &o->DhcpDnsServerAddress);\r
+       CfgGetStr(dhcp, "DhcpDomainName", o->DhcpDomainName, sizeof(o->DhcpDomainName));\r
+\r
+       Trim(o->DhcpDomainName);\r
+       if (StrLen(o->DhcpDomainName) == 0)\r
+       {\r
+               //GetDomainName(o->DhcpDomainName, sizeof(o->DhcpDomainName));\r
+       }\r
+\r
+       o->SaveLog = CfgGetBool(root, "SaveLog");\r
+}\r
+\r
+// 仮想ホストオプションの読み込み\r
+void NiLoadVhOption(NAT *n, FOLDER *root)\r
+{\r
+       VH_OPTION *o;\r
+       FOLDER *host, *nat, *dhcp;\r
+       char mac_address[MAX_SIZE];\r
+       // 引数チェック\r
+       if (n == NULL || root == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       host = CfgGetFolder(root, "VirtualHost");\r
+       nat = CfgGetFolder(root, "VirtualRouter");\r
+       dhcp = CfgGetFolder(root, "VirtualDhcpServer");\r
+\r
+       o = &n->Option;\r
+       Zero(o, sizeof(VH_OPTION));\r
+\r
+       GenMacAddress(o->MacAddress);\r
+       if (CfgGetStr(host, "VirtualHostMacAddress", mac_address, sizeof(mac_address)))\r
+       {\r
+               BUF *b = StrToBin(mac_address);\r
+               if (b != NULL)\r
+               {\r
+                       if (b->Size == 6)\r
+                       {\r
+                               Copy(o->MacAddress, b->Buf, 6);\r
+                       }\r
+               }\r
+               FreeBuf(b);\r
+       }\r
+       CfgGetIp(host, "VirtualHostIp", &o->Ip);\r
+       CfgGetIp(host, "VirtualHostIpSubnetMask", &o->Mask);\r
+\r
+       o->UseNat = CfgGetBool(nat, "NatEnabled");\r
+       o->Mtu = CfgGetInt(nat, "NatMtu");\r
+       o->NatTcpTimeout = CfgGetInt(nat, "NatTcpTimeout");\r
+       o->NatUdpTimeout = CfgGetInt(nat, "NatUdpTimeout");\r
+\r
+       o->UseDhcp = CfgGetBool(dhcp, "DhcpEnabled");\r
+       CfgGetIp(dhcp, "DhcpLeaseIPStart", &o->DhcpLeaseIPStart);\r
+       CfgGetIp(dhcp, "DhcpLeaseIPEnd", &o->DhcpLeaseIPEnd);\r
+       CfgGetIp(dhcp, "DhcpSubnetMask", &o->DhcpSubnetMask);\r
+       o->DhcpExpireTimeSpan = CfgGetInt(dhcp, "DhcpExpireTimeSpan");\r
+       CfgGetIp(dhcp, "DhcpGatewayAddress", &o->DhcpGatewayAddress);\r
+       CfgGetIp(dhcp, "DhcpDnsServerAddress", &o->DhcpDnsServerAddress);\r
+       CfgGetStr(dhcp, "DhcpDomainName", o->DhcpDomainName, sizeof(o->DhcpDomainName));\r
+\r
+       o->SaveLog = CfgGetBool(root, "SaveLog");\r
+}\r
+\r
+// VPN サーバーからの接続オプションの読み込み\r
+void NiLoadClientData(NAT *n, FOLDER *root)\r
+{\r
+       FOLDER *co, *ca;\r
+       // 引数チェック\r
+       if (n == NULL || root == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       co = CfgGetFolder(root, "VpnClientOption");\r
+       ca = CfgGetFolder(root, "VpnClientAuth");\r
+       if (co == NULL || ca == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       n->ClientOption = CiLoadClientOption(co);\r
+       n->ClientAuth = CiLoadClientAuth(ca);\r
+}\r
+\r
+// VPN サーバーへの接続オプションの書き込み\r
+void NiWriteClientData(NAT *n, FOLDER *root)\r
+{\r
+       // 引数チェック\r
+       if (n == NULL || root == NULL || n->ClientOption == NULL || n->ClientAuth == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       CiWriteClientOption(CfgCreateFolder(root, "VpnClientOption"), n->ClientOption);\r
+       CiWriteClientAuth(CfgCreateFolder(root, "VpnClientAuth"), n->ClientAuth);\r
+}\r
+\r
+// 仮想ホストオプションの書き込み (拡張)\r
+void NiWriteVhOptionEx(VH_OPTION *o, FOLDER *root)\r
+{\r
+       FOLDER *host, *nat, *dhcp;\r
+       char mac_address[MAX_SIZE];\r
+       // 引数チェック\r
+       if (o == NULL || root == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       host = CfgCreateFolder(root, "VirtualHost");\r
+       nat = CfgCreateFolder(root, "VirtualRouter");\r
+       dhcp = CfgCreateFolder(root, "VirtualDhcpServer");\r
+\r
+       MacToStr(mac_address, sizeof(mac_address), o->MacAddress);\r
+       CfgAddStr(host, "VirtualHostMacAddress", mac_address);\r
+       CfgAddIp(host, "VirtualHostIp", &o->Ip);\r
+       CfgAddIp(host, "VirtualHostIpSubnetMask", &o->Mask);\r
+\r
+       CfgAddBool(nat, "NatEnabled", o->UseNat);\r
+       CfgAddInt(nat, "NatMtu", o->Mtu);\r
+       CfgAddInt(nat, "NatTcpTimeout", o->NatTcpTimeout);\r
+       CfgAddInt(nat, "NatUdpTimeout", o->NatUdpTimeout);\r
+\r
+       CfgAddBool(dhcp, "DhcpEnabled", o->UseDhcp);\r
+       CfgAddIp(dhcp, "DhcpLeaseIPStart", &o->DhcpLeaseIPStart);\r
+       CfgAddIp(dhcp, "DhcpLeaseIPEnd", &o->DhcpLeaseIPEnd);\r
+       CfgAddIp(dhcp, "DhcpSubnetMask", &o->DhcpSubnetMask);\r
+       CfgAddInt(dhcp, "DhcpExpireTimeSpan", o->DhcpExpireTimeSpan);\r
+       CfgAddIp(dhcp, "DhcpGatewayAddress", &o->DhcpGatewayAddress);\r
+       CfgAddIp(dhcp, "DhcpDnsServerAddress", &o->DhcpDnsServerAddress);\r
+       CfgAddStr(dhcp, "DhcpDomainName", o->DhcpDomainName);\r
+\r
+       CfgAddBool(root, "SaveLog", o->SaveLog);\r
+}\r
+\r
+// 仮想ホストオプションの書き込み\r
+void NiWriteVhOption(NAT *n, FOLDER *root)\r
+{\r
+       VH_OPTION *o;\r
+       FOLDER *host, *nat, *dhcp;\r
+       char mac_address[MAX_SIZE];\r
+       // 引数チェック\r
+       if (n == NULL || root == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       host = CfgCreateFolder(root, "VirtualHost");\r
+       nat = CfgCreateFolder(root, "VirtualRouter");\r
+       dhcp = CfgCreateFolder(root, "VirtualDhcpServer");\r
+\r
+       o = &n->Option;\r
+\r
+       MacToStr(mac_address, sizeof(mac_address), o->MacAddress);\r
+       CfgAddStr(host, "VirtualHostMacAddress", mac_address);\r
+       CfgAddIp(host, "VirtualHostIp", &o->Ip);\r
+       CfgAddIp(host, "VirtualHostIpSubnetMask", &o->Mask);\r
+\r
+       CfgAddBool(nat, "NatEnabled", o->UseNat);\r
+       CfgAddInt(nat, "NatMtu", o->Mtu);\r
+       CfgAddInt(nat, "NatTcpTimeout", o->NatTcpTimeout);\r
+       CfgAddInt(nat, "NatUdpTimeout", o->NatUdpTimeout);\r
+\r
+       CfgAddBool(dhcp, "DhcpEnabled", o->UseDhcp);\r
+       CfgAddIp(dhcp, "DhcpLeaseIPStart", &o->DhcpLeaseIPStart);\r
+       CfgAddIp(dhcp, "DhcpLeaseIPEnd", &o->DhcpLeaseIPEnd);\r
+       CfgAddIp(dhcp, "DhcpSubnetMask", &o->DhcpSubnetMask);\r
+       CfgAddInt(dhcp, "DhcpExpireTimeSpan", o->DhcpExpireTimeSpan);\r
+       CfgAddIp(dhcp, "DhcpGatewayAddress", &o->DhcpGatewayAddress);\r
+       CfgAddIp(dhcp, "DhcpDnsServerAddress", &o->DhcpDnsServerAddress);\r
+       CfgAddStr(dhcp, "DhcpDomainName", o->DhcpDomainName);\r
+\r
+       CfgAddBool(root, "SaveLog", o->SaveLog);\r
+}\r
+\r
+// 設定ファイルを読み込む\r
+bool NiLoadConfig(NAT *n, FOLDER *root)\r
+{\r
+       FOLDER *host;\r
+       BUF *b;\r
+       // 引数チェック\r
+       if (n == NULL || root == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       host = CfgGetFolder(root, "VirtualHost");\r
+       if (host == NULL)\r
+       {\r
+               return false;\r
+       }\r
+\r
+       CfgGetByte(root, "HashedPassword", n->HashedPassword, sizeof(n->HashedPassword));\r
+       n->AdminPort = CfgGetInt(root, "AdminPort");\r
+       n->Online = CfgGetBool(root, "Online");\r
+\r
+       b = CfgGetBuf(root, "AdminCert");\r
+       if (b != NULL)\r
+       {\r
+               n->AdminX = BufToX(b, false);\r
+               FreeBuf(b);\r
+       }\r
+\r
+       b = CfgGetBuf(root, "AdminKey");\r
+       if (b != NULL)\r
+       {\r
+               n->AdminK = BufToK(b, true, false, NULL);\r
+               FreeBuf(b);\r
+       }\r
+\r
+       NiLoadVhOption(n, root);\r
+\r
+       NiLoadClientData(n, root);\r
+\r
+       return true;\r
+}\r
+\r
+// 設定をファイルに書き込む\r
+void NiWriteConfig(NAT *n)\r
+{\r
+       // 引数チェック\r
+       if (n == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       Lock(n->lock);\r
+       {\r
+               FOLDER *root = CfgCreateFolder(NULL, TAG_ROOT);\r
+               BUF *b;\r
+\r
+               // 証明書\r
+               b = XToBuf(n->AdminX, false);\r
+               CfgAddBuf(root, "AdminCert", b);\r
+               FreeBuf(b);\r
+\r
+               // 秘密鍵\r
+               b = KToBuf(n->AdminK, false, NULL);\r
+               CfgAddBuf(root, "AdminKey", b);\r
+               FreeBuf(b);\r
+\r
+               // パスワード\r
+               CfgAddByte(root, "HashedPassword", n->HashedPassword, sizeof(n->HashedPassword));\r
+               CfgAddInt(root, "AdminPort", n->AdminPort);\r
+               CfgAddBool(root, "Online", n->Online);\r
+\r
+               // 仮想ホストオプション\r
+               NiWriteVhOption(n, root);\r
+\r
+               // 接続オプション\r
+               if (n->ClientOption != NULL && n->ClientAuth != NULL)\r
+               {\r
+                       NiWriteClientData(n, root);\r
+               }\r
+\r
+               SaveCfgRw(n->CfgRw, root);\r
+               CfgDeleteFolder(root);\r
+       }\r
+       Unlock(n->lock);\r
+}\r
+\r
+// NAT の設定の解放\r
+void NiFreeConfig(NAT *n)\r
+{\r
+       // 引数チェック\r
+       if (n == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // 最新の設定の書き込み\r
+       NiWriteConfig(n);\r
+\r
+       // 設定 R/W の解放\r
+       FreeCfgRw(n->CfgRw);\r
+       n->CfgRw = NULL;\r
+\r
+       Free(n->ClientOption);\r
+       CiFreeClientAuth(n->ClientAuth);\r
+\r
+       FreeX(n->AdminX);\r
+       FreeK(n->AdminK);\r
+}\r
+\r
+// NAT の作成\r
+NAT *NiNewNatEx(SNAT *snat, VH_OPTION *o)\r
+{\r
+       NAT *n = ZeroMalloc(sizeof(NAT));\r
+\r
+       n->lock = NewLock();\r
+       Hash(n->HashedPassword, "", 0, true);\r
+       n->HaltEvent = NewEvent();\r
+\r
+       //n->Cedar = NewCedar(NULL, NULL);\r
+\r
+       n->SecureNAT = snat;\r
+\r
+       // 優先順位を上げる\r
+       //OSSetHighPriority();\r
+\r
+       // 設定の初期化\r
+       NiInitConfig(n);\r
+\r
+#if    0\r
+       // 仮想ホストの動作を開始\r
+       if (n->Online && n->ClientOption != NULL)\r
+       {\r
+               n->Virtual = NewVirtualHostEx(n->Cedar, n->ClientOption, n->ClientAuth, &n->Option, n);\r
+       }\r
+       else\r
+       {\r
+               n->Online = false;\r
+               n->Virtual = NULL;\r
+       }\r
+#else\r
+       n->Virtual = NewVirtualHostEx(n->Cedar, NULL, NULL, o, n);\r
+       n->Online = true;\r
+#endif\r
+\r
+       // 管理コマンド開始\r
+       //NiInitAdminAccept(n);\r
+\r
+       return n;\r
+}\r
+NAT *NiNewNat()\r
+{\r
+       return NiNewNatEx(NULL, NULL);\r
+}\r
+\r
+// NAT の解放\r
+void NiFreeNat(NAT *n)\r
+{\r
+       // 引数チェック\r
+       if (n == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       // 管理コマンド終了\r
+       //NiFreeAdminAccept(n);\r
+\r
+       // 仮想ホストが動作中の場合は停止\r
+       Lock(n->lock);\r
+       {\r
+               if (n->Virtual != NULL)\r
+               {\r
+                       StopVirtualHost(n->Virtual);\r
+                       ReleaseVirtual(n->Virtual);\r
+                       n->Virtual = NULL;\r
+               }\r
+       }\r
+       Unlock(n->lock);\r
+\r
+       // 設定の解放\r
+       NiFreeConfig(n);\r
+\r
+       // オブジェクトの削除\r
+       ReleaseCedar(n->Cedar);\r
+       ReleaseEvent(n->HaltEvent);\r
+       DeleteLock(n->lock);\r
+\r
+       Free(n);\r
+}\r
+\r
+// NAT の停止\r
+void NtStopNat()\r
+{\r
+       Lock(nat_lock);\r
+       {\r
+               if (nat != NULL)\r
+               {\r
+                       NiFreeNat(nat);\r
+                       nat = NULL;\r
+               }\r
+       }\r
+       Unlock(nat_lock);\r
+}\r
+\r
+// NAT の開始\r
+void NtStartNat()\r
+{\r
+       Lock(nat_lock);\r
+       {\r
+               if (nat == NULL)\r
+               {\r
+                       nat = NiNewNat();\r
+               }\r
+       }\r
+       Unlock(nat_lock);\r
+}\r
+\r
+// NtXxx 関数の初期化\r
+void NtInit()\r
+{\r
+       if (nat_lock != NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       nat_lock = NewLock();\r
+}\r
+\r
+// NtXxx 関数の解放\r
+void NtFree()\r
+{\r
+       if (nat_lock == NULL)\r
+       {\r
+               return;\r
+       }\r
+\r
+       DeleteLock(nat_lock);\r
+       nat_lock = NULL;\r
+}\r
+\r